Initial Commit
This commit is contained in:
+51
-6
@@ -1,7 +1,52 @@
|
||||
# editors
|
||||
*.swp
|
||||
*~
|
||||
# Zephyr build outputs
|
||||
build/
|
||||
build_*/
|
||||
twister-out/
|
||||
.vscode/.west/
|
||||
|
||||
# build
|
||||
/build*/
|
||||
log.log
|
||||
# West / Zephyr local metadata
|
||||
.zephyr/
|
||||
.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
|
||||
@@ -1,7 +1,8 @@
|
||||
# VesiScan BASIC - Zephyr
|
||||
|
||||
- nRF52840 기반 VesiScan BASIC 펌웨어의 Zephyr/nRF Connect SDK 포팅 프로젝트
|
||||
- 현재 빌드 대상은 `nrf52840dk_nrf52840` 기준이며, MCUboot + BLE MCUmgr DFU, BLE NUS 명령, 배터리/IMU/피에조/echo ADC 측정 기능 포함
|
||||
- nRF52840 기반 VesiScan BASIC 펌웨어의 Zephyr/nRF Connect SDK 프로젝트
|
||||
- 현재 빌드 대상은 `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
|
||||
west build -b nrf52840dk_nrf52840 -p auto
|
||||
@@ -83,7 +84,7 @@ west flash
|
||||
| `ECHO_MISO` | P0.15 | ADC121S051 MISO |
|
||||
| `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분
|
||||
- DFU advertising: SMP UUID, timeout 미적용
|
||||
- NUS UUID 광고 포함
|
||||
- 연결 시 LED 광고 패턴 OFF
|
||||
- 연결 파라미터 선호값: 15ms / latency 0 / supervision timeout 10s
|
||||
- NUS TX는 mutex + completion semaphore로 순차 전송
|
||||
- BLE RX는 별도 work queue에서 명령 처리
|
||||
@@ -118,7 +118,6 @@ west flash
|
||||
- DATA: 명령별 payload
|
||||
- CRC16: CRC-CCITT, initial `0xFFFF`
|
||||
- 응답 TAG: 보통 요청의 `m`을 `r`로 바꾼 형태, 예: `msn?` -> `rsn:`
|
||||
- 알 수 없는 명령은 `rxn:` 응답
|
||||
|
||||
## 구현된 명령
|
||||
|
||||
@@ -131,15 +130,15 @@ west flash
|
||||
| `msn?` | `rsn:` | 배터리 전압 측정 | 구현 완료 |
|
||||
| `mls?` | `rls:` | LED 상태 변경 | 구현 완료 |
|
||||
| `msp?` | `rsp:` | IMU accel/gyro 단발 측정 | 구현 완료 |
|
||||
| `mst?` | `rso:` | IMU internal temperature | 구현 완료 |
|
||||
| `mpa?` | `rpa:` | 피에조 전원 ON | 구현 완료 |
|
||||
| `mpb?` | `rpb:` | 피에조 전원 OFF | 구현 완료 |
|
||||
| `mpc?` | `rpc:` | 피에조 burst 테스트 | 구현 완료, 주파수 옵션은 제한적 |
|
||||
| `mec?` | `reb:` -> `raa:` | 단일 채널 burst + echo capture | 구현 완료 |
|
||||
| `mad?` | `reb:` -> `raa:` | ADC only capture | 구현 완료 |
|
||||
| `maa?` | `reb:` x6 -> `raa:` | 6채널 echo sweep | 구현 완료 |
|
||||
| `mst?` | `rst:` | IMU internal temperature | 구현 완료 |
|
||||
| `mpa?` | `rpa:` | Piezo 전원 ON | 구현 완료, 테스트용 |
|
||||
| `mpb?` | `rpb:` | Piezo 전원 OFF | 구현 완료, 테스트용 |
|
||||
| `mpc?` | `rpc:` | Piezo burst only | 구현 완료, 테스트용 |
|
||||
| `mec?` | `reb:` -> `raa:` | 단일 채널 burst + echo capture | 구현 완료, 테스트용 |
|
||||
| `mad?` | `reb:` -> `raa:` | ADC only capture | 구현 완료, 테스트용 |
|
||||
| `maa?` | `reb:` x6 -> `raa:` | 6채널 echo sweep | 구현 완료, 테스트용 |
|
||||
| `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:` | 측정 파라미터 읽기 | 구현 완료 |
|
||||
| `mcs?` | `rcs:` | 측정 파라미터 쓰기 | 구현 완료, NVS 저장 |
|
||||
| `mid?` | `rid:` | HW/SN/FW identity 읽기 | 구현 완료 |
|
||||
@@ -149,7 +148,8 @@ west flash
|
||||
| `mws?` | `rws:` | Serial number 쓰기 | 구현 완료, NVS 저장 |
|
||||
| `mrs?` | `rrs:` | Serial number 읽기 | 구현 완료 |
|
||||
| `mpz?` | `rpz:` | Passkey 쓰기 | 구현 완료, NVS 저장, 최초 1회만 가능 |
|
||||
| `mqz?` | `rqz:` | Passkey 읽기 | 구현 완료 |
|
||||
| `mqz?` | `rqz:` | Passkey 읽기 | 구현 완료, 삭제 예정 |
|
||||
| `mim?` | `rim:` | IMU FIFO | 구현 완료 |
|
||||
|
||||
## 저장되는 설정
|
||||
|
||||
|
||||
@@ -70,13 +70,13 @@ int cmd_mst(const uint8_t *data, uint8_t data_len)
|
||||
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 음수 온도도 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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user