Initial Commit

This commit is contained in:
2026-07-06 12:06:24 +09:00
parent e55b283b39
commit 38ec75ad78
4 changed files with 68 additions and 184 deletions
+51 -6
View File
@@ -1,7 +1,52 @@
# editors # Zephyr build outputs
*.swp build/
*~ build_*/
twister-out/
.vscode/.west/
# build # West / Zephyr local metadata
/build*/ .zephyr/
log.log .cmake/
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
compile_commands.json
# Generated binaries / firmware images
*.hex
*.bin
*.elf
*.map
*.lst
*.uf2
*.zip
*.signed
*.merged.hex
# Logs
*.log
*.rtt
*.jlink
# Python / test cache
__pycache__/
*.pyc
.pytest_cache/
# Editor / OS
.vscode/ipch/
.vs/
.idea/
.DS_Store
Thumbs.db
# Local env / secrets
.env
*.pem
*.key
# Vim swap files
*.swp
*.swo
.*.swp
.*.swo
+15 -15
View File
@@ -1,7 +1,8 @@
# VesiScan BASIC - Zephyr # VesiScan BASIC - Zephyr
- nRF52840 기반 VesiScan BASIC 펌웨어의 Zephyr/nRF Connect SDK 포팅 프로젝트 - nRF52840 기반 VesiScan BASIC 펌웨어의 Zephyr/nRF Connect SDK 프로젝트
- 현재 빌드 대상은 `nrf52840dk_nrf52840` 기준이며, MCUboot + BLE MCUmgr DFU, BLE NUS 명령, 배터리/IMU/피에조/echo ADC 측정 기능 포함 - 현재 빌드 대상은 `nrf52840dk_nrf52840` 기준
- MCUboot + BLE MCUmgr DFU, BLE NUS 명령, 배터리/IMU/Piezo/echo ADC capture 등 포함
## 프로젝트 구조 ## 프로젝트 구조
@@ -42,7 +43,7 @@ VesiScan-Basic_Zephyr/
## 빌드 ## 빌드
권장 빌드 (nRF Connect SDK / west 사용): nRF Connect SDK / west 사용:
```powershell ```powershell
west build -b nrf52840dk_nrf52840 -p auto west build -b nrf52840dk_nrf52840 -p auto
@@ -83,7 +84,7 @@ west flash
| `ECHO_MISO` | P0.15 | ADC121S051 MISO | | `ECHO_MISO` | P0.15 | ADC121S051 MISO |
| `ECHO_CS` | P0.19 | ADC121S051 CS | | `ECHO_CS` | P0.19 | ADC121S051 CS |
`CONFIG_SERIAL=n`으로 UART0를 비활성화하여 P0.08 충돌 피 `CONFIG_SERIAL=n`으로 UART0를 비활성화하여 P0.08 충돌
## 전원 동작 ## 전원 동작
@@ -102,7 +103,6 @@ west flash
- Normal advertising timeout: 10분 - Normal advertising timeout: 10분
- DFU advertising: SMP UUID, timeout 미적용 - DFU advertising: SMP UUID, timeout 미적용
- NUS UUID 광고 포함 - NUS UUID 광고 포함
- 연결 시 LED 광고 패턴 OFF
- 연결 파라미터 선호값: 15ms / latency 0 / supervision timeout 10s - 연결 파라미터 선호값: 15ms / latency 0 / supervision timeout 10s
- NUS TX는 mutex + completion semaphore로 순차 전송 - NUS TX는 mutex + completion semaphore로 순차 전송
- BLE RX는 별도 work queue에서 명령 처리 - BLE RX는 별도 work queue에서 명령 처리
@@ -118,7 +118,6 @@ west flash
- DATA: 명령별 payload - DATA: 명령별 payload
- CRC16: CRC-CCITT, initial `0xFFFF` - CRC16: CRC-CCITT, initial `0xFFFF`
- 응답 TAG: 보통 요청의 `m``r`로 바꾼 형태, 예: `msn?` -> `rsn:` - 응답 TAG: 보통 요청의 `m``r`로 바꾼 형태, 예: `msn?` -> `rsn:`
- 알 수 없는 명령은 `rxn:` 응답
## 구현된 명령 ## 구현된 명령
@@ -131,15 +130,15 @@ west flash
| `msn?` | `rsn:` | 배터리 전압 측정 | 구현 완료 | | `msn?` | `rsn:` | 배터리 전압 측정 | 구현 완료 |
| `mls?` | `rls:` | LED 상태 변경 | 구현 완료 | | `mls?` | `rls:` | LED 상태 변경 | 구현 완료 |
| `msp?` | `rsp:` | IMU accel/gyro 단발 측정 | 구현 완료 | | `msp?` | `rsp:` | IMU accel/gyro 단발 측정 | 구현 완료 |
| `mst?` | `rso:` | IMU internal temperature | 구현 완료 | | `mst?` | `rst:` | IMU internal temperature | 구현 완료 |
| `mpa?` | `rpa:` | 피에조 전원 ON | 구현 완료 | | `mpa?` | `rpa:` | Piezo 전원 ON | 구현 완료, 테스트용 |
| `mpb?` | `rpb:` | 피에조 전원 OFF | 구현 완료 | | `mpb?` | `rpb:` | Piezo 전원 OFF | 구현 완료, 테스트용 |
| `mpc?` | `rpc:` | 피에조 burst 테스트 | 구현 완료, 주파수 옵션은 제한적 | | `mpc?` | `rpc:` | Piezo burst only | 구현 완료, 테스트용 |
| `mec?` | `reb:` -> `raa:` | 단일 채널 burst + echo capture | 구현 완료 | | `mec?` | `reb:` -> `raa:` | 단일 채널 burst + echo capture | 구현 완료, 테스트용 |
| `mad?` | `reb:` -> `raa:` | ADC only capture | 구현 완료 | | `mad?` | `reb:` -> `raa:` | ADC only capture | 구현 완료, 테스트용 |
| `maa?` | `reb:` x6 -> `raa:` | 6채널 echo sweep | 구현 완료 | | `maa?` | `reb:` x6 -> `raa:` | 6채널 echo sweep | 구현 완료, 테스트용 |
| `mbb?` | `rbb:` -> `reb:` x6 -> `raa:` | 배터리 + IMU + 온도 + 6채널 echo | 구현 완료 | | `mbb?` | `rbb:` -> `reb:` x6 -> `raa:` | 배터리 + IMU + 온도 + 6채널 echo | 구현 완료 |
| `mtb?` | `reb:` x6 + `rim:` -> `raa:` | 피에조 sweep + IMU FIFO | 구현 완료, 실측 검증 필요 | | `mtb?` | `reb:` x6 + `rim:` -> `raa:` | Piezo sweep + IMU FIFO | 구현 완료 |
| `mcf?` | `rcf:` | 측정 파라미터 읽기 | 구현 완료 | | `mcf?` | `rcf:` | 측정 파라미터 읽기 | 구현 완료 |
| `mcs?` | `rcs:` | 측정 파라미터 쓰기 | 구현 완료, NVS 저장 | | `mcs?` | `rcs:` | 측정 파라미터 쓰기 | 구현 완료, NVS 저장 |
| `mid?` | `rid:` | HW/SN/FW identity 읽기 | 구현 완료 | | `mid?` | `rid:` | HW/SN/FW identity 읽기 | 구현 완료 |
@@ -149,7 +148,8 @@ west flash
| `mws?` | `rws:` | Serial number 쓰기 | 구현 완료, NVS 저장 | | `mws?` | `rws:` | Serial number 쓰기 | 구현 완료, NVS 저장 |
| `mrs?` | `rrs:` | Serial number 읽기 | 구현 완료 | | `mrs?` | `rrs:` | Serial number 읽기 | 구현 완료 |
| `mpz?` | `rpz:` | Passkey 쓰기 | 구현 완료, NVS 저장, 최초 1회만 가능 | | `mpz?` | `rpz:` | Passkey 쓰기 | 구현 완료, NVS 저장, 최초 1회만 가능 |
| `mqz?` | `rqz:` | Passkey 읽기 | 구현 완료 | | `mqz?` | `rqz:` | Passkey 읽기 | 구현 완료, 삭제 예정 |
| `mim?` | `rim:` | IMU FIFO | 구현 완료 |
## 저장되는 설정 ## 저장되는 설정
+2 -2
View File
@@ -70,13 +70,13 @@ int cmd_mst(const uint8_t *data, uint8_t data_len)
if ((ret != 0) || (t_cdeg == INT16_MIN)) if ((ret != 0) || (t_cdeg == INT16_MIN))
{ {
cmd_send_response_u16("rso:", 0xFFFF); cmd_send_response_u16("rst:", 0xFFFF);
DBG_PRINTF("[CMD] mst: imu temp read fail ret=%d\r\n", ret); DBG_PRINTF("[CMD] mst: imu temp read fail ret=%d\r\n", ret);
return 1; return 1;
} }
// 음수 온도도 2's complement로 그대로 전송 (앱이 int16로 해석) // 음수 온도도 2's complement로 그대로 전송 (앱이 int16로 해석)
cmd_send_response_u16("rso:", (uint16_t)t_cdeg); cmd_send_response_u16("rst:", (uint16_t)t_cdeg);
DBG_PRINTF("[CMD] mst -> %d.%02d C\r\n", t_cdeg / 100, (t_cdeg < 0 ? -t_cdeg : t_cdeg) % 100); DBG_PRINTF("[CMD] mst -> %d.%02d C\r\n", t_cdeg / 100, (t_cdeg < 0 ? -t_cdeg : t_cdeg) % 100);
return 1; return 1;
} }
-161
View File
@@ -1,161 +0,0 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "../src/main.h"
#define BOOT_THRESHOLD 200
typedef struct {
bool device_on;
bool boot_btn_released;
bool power_btn_suspended;
uint16_t cnt_s;
} boot_sm_t;
static void route_step(const char *name)
{
printf(" -> %s\n", name);
}
static void print_main_boot_route(bool resume_without_button,
bool dfu_confirm_pending,
bool dfu_reset_resume)
{
printf("main() boot route\n");
route_step("boot_context_detect()");
printf(" resume_without_power_button=%u, dfu_confirm_pending=%u, dfu_reset_resume=%u\n",
resume_without_button ? 1U : 0U,
dfu_confirm_pending ? 1U : 0U,
dfu_reset_resume ? 1U : 0U);
route_step("power_hold_init()");
printf(" POWER_HOLD initial=%s\n",
(resume_without_button || dfu_confirm_pending || dfu_reset_resume) ? "ON" : "OFF");
route_step("confirm_running_image()");
route_step("gpio_init()");
route_step("timers_init()");
route_step("log_mcuboot_state()");
route_step("load_default_config()");
route_step("led_init()");
route_step("battery_adc_init()");
route_step("battery_timer_init()");
route_step("imu_init()");
route_step("piezo_config_init()");
route_step("ble_service_init(ble_rx_handler)");
if (resume_without_button || dfu_confirm_pending || dfu_reset_resume) {
route_step("resume_device_after_soft_reset()");
route_step("POWER_HOLD ON, LED_ADVERTISING, battery_timer_start(), adv_start_work");
}
route_step("timers_start()");
route_step("idle loop");
}
static void power_control(bool on, const char *reason)
{
printf(" POWER_HOLD=%s reason=%s\n", on ? "ON" : "OFF", reason);
}
static void boot_button_tick(boot_sm_t *sm, bool button_pressed)
{
if (sm->power_btn_suspended) {
return;
}
if (!sm->device_on) {
if (!button_pressed) {
power_control(false, "boot-button-released-before-latch");
sm->cnt_s = 0;
} else {
sm->cnt_s++;
if (sm->cnt_s == BOOT_THRESHOLD) {
sm->device_on = true;
sm->cnt_s = 0;
power_control(true, "button-2s-latch");
printf(" led_set_state(LED_STATE_ADVERTISING)\n");
printf(" adv_start_work submitted\n");
printf(" battery_timer_start()\n");
}
}
return;
}
if (!sm->boot_btn_released) {
if (!button_pressed) {
sm->boot_btn_released = true;
printf(" boot button released after latch\n");
}
} else if (button_pressed) {
sm->cnt_s++;
if (sm->cnt_s >= BOOT_THRESHOLD) {
printf(" battery_timer_stop()\n");
printf(" adv_stop_work submitted\n");
sm->device_on = false;
sm->boot_btn_released = false;
sm->cnt_s = 0;
printf(" sleep_mode_enter_reason(button-long-press)\n");
}
} else {
sm->cnt_s = 0;
}
}
static void simulate_short_press(void)
{
boot_sm_t sm = {0};
printf("\nscenario: short press during boot\n");
for (int i = 0; i < 80; i++) {
boot_button_tick(&sm, true);
}
boot_button_tick(&sm, false);
printf(" result: device_on=%u cnt_s=%u\n", sm.device_on ? 1U : 0U, sm.cnt_s);
}
static void simulate_long_press_boot(void)
{
boot_sm_t sm = {0};
printf("\nscenario: hold button until boot latch\n");
for (int i = 0; i < BOOT_THRESHOLD; i++) {
boot_button_tick(&sm, true);
}
boot_button_tick(&sm, false);
printf(" result: device_on=%u boot_btn_released=%u cnt_s=%u\n",
sm.device_on ? 1U : 0U,
sm.boot_btn_released ? 1U : 0U,
sm.cnt_s);
}
static void simulate_power_off_after_boot(void)
{
boot_sm_t sm = {
.device_on = true,
.boot_btn_released = true,
};
printf("\nscenario: long press while already ON\n");
for (int i = 0; i < BOOT_THRESHOLD; i++) {
boot_button_tick(&sm, true);
}
printf(" result: device_on=%u cnt_s=%u\n", sm.device_on ? 1U : 0U, sm.cnt_s);
}
int main(void)
{
printf("PC GCC boot-route simulator for %s\n\n", FIRMWARE_VERSION);
print_main_boot_route(false, false, false);
printf("\nsoft-reset/DFU resume route\n");
print_main_boot_route(true, false, false);
simulate_short_press();
simulate_long_press_boot();
simulate_power_off_after_boot();
return 0;
}