ADC까지, 신호 확인 필요(반사 신호 약함 or 뒤쪽을 찍고 있음)
This commit is contained in:
+170
-26
@@ -28,6 +28,15 @@
|
||||
|
||||
LOG_MODULE_REGISTER(vesiscan, LOG_LEVEL_INF);
|
||||
|
||||
#define BLE_CMD_MAX_LEN 256
|
||||
#define BLE_CMD_WORKQ_STACK_SZ 8192
|
||||
/*
|
||||
* mbb?는 piezo sweep, ADC capture, BLE 응답 패킷 조립까지 한 스레드에서 처리한다.
|
||||
* 초기 4096 바이트로는 "어떤 날은 되고 어떤 날은 리셋되는" 경계 상태가 날 수 있어서
|
||||
* 디버깅 중에는 여유 있게 8192 바이트로 올려 둔다.
|
||||
*/
|
||||
#define BLE_CMD_WORKQ_PRIORITY 10
|
||||
|
||||
/*==============================================================================
|
||||
* Devicetree GPOP Settings
|
||||
*============================================================================*/
|
||||
@@ -51,13 +60,14 @@ volatile bool processing = false; /* 센서 데이터 처리 중 플
|
||||
bool bond_data_delete = true; /* 본딩 데이터 삭제 요청 */
|
||||
uint32_t m_life_cycle = 0; /* 디바이스 수명 카운터 */
|
||||
uint8_t m_reset_status = 1; /* 리셋 상태 코드 */
|
||||
char SERIAL_NO[SERIAL_NO_LENGTH]; /* 시리얼 번호 */
|
||||
char HW_NO[HW_NO_LENGTH]; /* 하드웨어 번호 */
|
||||
char m_static_passkey[PASSKEY_LENGTH]; /* BLE 정적 패스키 */
|
||||
char SERIAL_NO[SERIAL_NO_BUF_SIZE]; /* 시리얼 번호 */
|
||||
char HW_NO[HW_NO_BUF_SIZE]; /* 하드웨어 번호 */
|
||||
char m_static_passkey[PASSKEY_BUF_SIZE]; /* BLE 정적 패스키 */
|
||||
|
||||
static uint16_t cnt_s; /* 전원 버튼 폴링 카운터 (5ms 단위) */
|
||||
static bool device_on = false; /* 디바이스 전원 상태 (래치 완료 여부) */
|
||||
static bool boot_btn_released = false; /* 부팅 후 버튼 놓았는지 여부 */
|
||||
static bool power_btn_suspended; /* 측정 중 전원 버튼 상태머신 일시 정지 */
|
||||
|
||||
/*
|
||||
* BLE advertising 제어용 워크 아이템
|
||||
@@ -72,6 +82,56 @@ static bool boot_btn_released = false; /* 부팅 후 버튼 놓았는지 여
|
||||
static struct k_work adv_start_work;
|
||||
static struct k_work adv_stop_work;
|
||||
|
||||
/*
|
||||
* BLE RX 콜백 안에서 무거운 일을 바로 처리하지 않기 위해 별도 work queue를 둔다.
|
||||
*
|
||||
* 이유:
|
||||
* - BLE 콜백은 "일단 빨리 빠져나오는 것"이 중요하다.
|
||||
* - 그 안에서 mbb? 같은 긴 측정을 돌리면 BLE 스택 타이밍을 망칠 수 있다.
|
||||
* - 그래서 수신 데이터는 일단 복사만 하고,
|
||||
* 실제 파싱/측정은 아래 work queue 스레드에서 천천히 처리한다.
|
||||
*
|
||||
* 현재 구조는 "동시에 여러 명령 처리"가 아니라 "한 번에 하나만 처리" 모델이다.
|
||||
* 즉, 긴 명령 하나가 끝날 때까지 다음 명령은 drop된다.
|
||||
*/
|
||||
static struct k_work_q ble_cmd_work_q;
|
||||
K_THREAD_STACK_DEFINE(ble_cmd_workq_stack, BLE_CMD_WORKQ_STACK_SZ);
|
||||
static struct k_work ble_cmd_work;
|
||||
static struct k_spinlock ble_cmd_lock;
|
||||
static uint8_t ble_cmd_buf[BLE_CMD_MAX_LEN];
|
||||
static uint16_t ble_cmd_len;
|
||||
static bool ble_cmd_pending;
|
||||
|
||||
static void ble_cmd_work_handler(struct k_work *work)
|
||||
{
|
||||
ARG_UNUSED(work);
|
||||
|
||||
/* work queue 스레드에서 쓸 로컬 복사본. 원본 공유 버퍼를 오래 잡고 있지 않기 위해 만든다. */
|
||||
uint8_t local_buf[BLE_CMD_MAX_LEN];
|
||||
uint16_t local_len = 0U;
|
||||
|
||||
k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock);
|
||||
if (ble_cmd_pending) {
|
||||
local_len = ble_cmd_len;
|
||||
memcpy(local_buf, ble_cmd_buf, local_len);
|
||||
}
|
||||
k_spin_unlock(&ble_cmd_lock, key);
|
||||
|
||||
if (local_len == 0U) {
|
||||
DBG_ERR("[BLE RX] worker: empty\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 여기서부터는 BLE 콜백 문맥이 아니라 일반 스레드 문맥이라 긴 작업을 해도 된다. */
|
||||
DBG_CORE("[BLE RX] worker dispatch len=%u\r\n", local_len);
|
||||
dr_parser(local_buf, local_len);
|
||||
|
||||
key = k_spin_lock(&ble_cmd_lock);
|
||||
ble_cmd_pending = false;
|
||||
ble_cmd_len = 0U;
|
||||
k_spin_unlock(&ble_cmd_lock, key);
|
||||
}
|
||||
|
||||
/* 시스템 워크큐에서 BLE advertising 시작 */
|
||||
static void adv_start_work_handler(struct k_work *work)
|
||||
{
|
||||
@@ -91,17 +151,50 @@ static void adv_stop_work_handler(struct k_work *work)
|
||||
*============================================================================*/
|
||||
static void ble_rx_handler(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
DBG_PRINTF("[BLE RX] %d bytes: ", len);
|
||||
DBG_CORE("[BLE RX] %u bytes:", len);
|
||||
for (uint16_t i = 0; i < len && i < 32; i++)
|
||||
{
|
||||
DBG_PRINTF("%02X ", data[i]);
|
||||
DBG_CORE(" %02X", data[i]);
|
||||
}
|
||||
if (len > 32)
|
||||
{
|
||||
DBG_PRINTF("...");
|
||||
DBG_CORE(" ...");
|
||||
}
|
||||
DBG_CORE("\r\n");
|
||||
|
||||
if (len > BLE_CMD_MAX_LEN)
|
||||
{
|
||||
DBG_ERR("[BLE RX] drop: len=%u exceeds %d\r\n", len, BLE_CMD_MAX_LEN);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 이미 긴 명령 하나를 처리 중이면 새 명령은 받지 않는다.
|
||||
* 지금은 안정성 우선이라 "큐에 여러 개 쌓기"보다 "한 번에 하나"가 더 안전하다.
|
||||
*/
|
||||
k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock);
|
||||
if (ble_cmd_pending)
|
||||
{
|
||||
k_spin_unlock(&ble_cmd_lock, key);
|
||||
DBG_ERR("[BLE RX] drop: command busy\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(ble_cmd_buf, data, len);
|
||||
ble_cmd_len = len;
|
||||
ble_cmd_pending = true;
|
||||
k_spin_unlock(&ble_cmd_lock, key);
|
||||
|
||||
DBG_CORE("[BLE RX] queued len=%u\r\n", len);
|
||||
int err = k_work_submit_to_queue(&ble_cmd_work_q, &ble_cmd_work);
|
||||
if (err < 0)
|
||||
{
|
||||
key = k_spin_lock(&ble_cmd_lock);
|
||||
ble_cmd_pending = false;
|
||||
ble_cmd_len = 0U;
|
||||
k_spin_unlock(&ble_cmd_lock, key);
|
||||
DBG_ERR("[BLE RX] queue submit fail err=%d\r\n", err);
|
||||
}
|
||||
DBG_PRINTF("\r\n");
|
||||
dr_parser(data, len);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
@@ -121,7 +214,6 @@ static void power_control_handler(on_off_cont_t device_power_st)
|
||||
{
|
||||
if (device_power_st == OFF) {
|
||||
gpio_pin_set_dt(&power_hold, 0); /* P0.08 LOW → 전원 래치 해제 → 전원 차단 */
|
||||
DBG_PRINTF("[PWR] OFF\r\n");
|
||||
} else {
|
||||
gpio_pin_set_dt(&power_hold, 1); /* P0.08 HIGH → 전원 유지 */
|
||||
DBG_PRINTF("[PWR] ON\r\n");
|
||||
@@ -143,16 +235,33 @@ static void gpio_init(void)
|
||||
*============================================================================*/
|
||||
static void load_default_config(void)
|
||||
{
|
||||
memset(SERIAL_NO, 0, SERIAL_NO_LENGTH);
|
||||
memcpy(SERIAL_NO, SERIAL_NUMBER, strlen(SERIAL_NUMBER));
|
||||
size_t serial_len = strlen(SERIAL_NUMBER);
|
||||
size_t hw_len = strlen(HARDWARE_VERSION);
|
||||
size_t passkey_len = strlen(DEFAULT_PASSKEY);
|
||||
|
||||
memset(m_static_passkey, 0, PASSKEY_LENGTH);
|
||||
memcpy(m_static_passkey, DEFAULT_PASSKEY, PASSKEY_LENGTH);
|
||||
if (serial_len > SERIAL_NO_LENGTH) {
|
||||
serial_len = SERIAL_NO_LENGTH;
|
||||
}
|
||||
if (hw_len > HW_NO_LENGTH) {
|
||||
hw_len = HW_NO_LENGTH;
|
||||
}
|
||||
if (passkey_len > PASSKEY_LENGTH) {
|
||||
passkey_len = PASSKEY_LENGTH;
|
||||
}
|
||||
|
||||
memset(SERIAL_NO, 0, sizeof(SERIAL_NO));
|
||||
memcpy(SERIAL_NO, SERIAL_NUMBER, serial_len);
|
||||
|
||||
memset(HW_NO, 0, sizeof(HW_NO));
|
||||
memcpy(HW_NO, HARDWARE_VERSION, hw_len);
|
||||
|
||||
memset(m_static_passkey, 0, sizeof(m_static_passkey));
|
||||
memcpy(m_static_passkey, DEFAULT_PASSKEY, passkey_len);
|
||||
|
||||
m_reset_status = 1;
|
||||
bond_data_delete = true;
|
||||
|
||||
DBG_PRINTF("[CFG] Default (S/N=%s)\r\n", SERIAL_NO);
|
||||
DBG_CORE("[CFG] Default (S/N=%s)\r\n", SERIAL_NO);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
@@ -184,6 +293,18 @@ void device_power_off(void)
|
||||
k_timer_start(&m_power_off_delay_timer, K_MSEC(POWER_OFF_DELAY), K_NO_WAIT);
|
||||
}
|
||||
|
||||
void power_button_suspend(bool suspend)
|
||||
{
|
||||
/*
|
||||
* maa?/mbb?처럼 측정 시간이 길 때 전원 버튼 상태머신이 끼어들지 않게 잠깐 멈춘다.
|
||||
*
|
||||
* 이 함수는 "부팅을 막는 함수"가 아니다.
|
||||
* 이미 켜진 뒤, 특정 커맨드 처리 중에만 버튼 폴링 판단을 잠깐 쉬게 하는 역할이다.
|
||||
*/
|
||||
power_btn_suspended = suspend;
|
||||
cnt_s = 0;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* 전원 버튼 상태머신 (5ms 폴링)
|
||||
*
|
||||
@@ -209,7 +330,7 @@ static void main_s(struct k_timer *timer)
|
||||
{
|
||||
if (!button_pressed) /* 버튼 놓음 → 2초 미만이면 전원 OFF */
|
||||
{
|
||||
DBG_PRINTF("[BTN] Short press (%d) -> OFF\r\n", cnt_s);
|
||||
//DBG_PRINTF("[BTN] Short press (%d) -> OFF\r\n", cnt_s);
|
||||
power_control_handler(OFF);
|
||||
cnt_s = 0;
|
||||
}
|
||||
@@ -281,6 +402,12 @@ static void timers_init(void)
|
||||
k_timer_init(&m_power_off_delay_timer, t_power_off_timeout_handler, NULL);
|
||||
k_work_init(&adv_start_work, adv_start_work_handler);
|
||||
k_work_init(&adv_stop_work, adv_stop_work_handler);
|
||||
k_work_init(&ble_cmd_work, ble_cmd_work_handler);
|
||||
k_work_queue_start(&ble_cmd_work_q,
|
||||
ble_cmd_workq_stack,
|
||||
K_THREAD_STACK_SIZEOF(ble_cmd_workq_stack),
|
||||
BLE_CMD_WORKQ_PRIORITY,
|
||||
NULL);
|
||||
power_timer_init();
|
||||
}
|
||||
|
||||
@@ -299,11 +426,28 @@ int main(void)
|
||||
power_hold_init();
|
||||
cnt_s = 0;
|
||||
|
||||
DBG_PRINTF("\r\n========================================\r\n");
|
||||
DBG_PRINTF(" VesiScan BASIC %s (Zephyr)\r\n", FIRMWARE_VERSION);
|
||||
DBG_PRINTF("========================================\r\n");
|
||||
/*
|
||||
* 현재는 전원 버튼/mbb 문제를 같이 디버깅 중이라
|
||||
* "버튼을 2초 이상 눌러야 래치 ON" 규칙이 오히려 부팅 자체를 막고 있다.
|
||||
*
|
||||
* 그래서 디버깅 동안만, MCU가 main()까지 올라오면 바로 P0.08 래치를 ON으로 잡는다.
|
||||
*
|
||||
* 의미:
|
||||
* - 사용자는 전원 버튼을 "부팅이 시작될 만큼만" 누르면 된다.
|
||||
* - 예전처럼 2초를 정확히 맞춰 길게 누를 필요가 없다.
|
||||
* - 일단 켜진 뒤의 BLE/측정/로그 문제를 보기 쉬워진다.
|
||||
*
|
||||
* 나중에 전원 시퀀스 디버깅이 끝나면 이 블록은 다시 제거하면 된다.
|
||||
*/
|
||||
device_on = false;
|
||||
boot_btn_released = false;
|
||||
|
||||
DBG_PRINTF("[1] HW Init\r\n");
|
||||
DBG_CORE("\r\n========================================\r\n");
|
||||
DBG_CORE(" TEST BUILD %s (Zephyr)\r\n", FIRMWARE_VERSION);
|
||||
DBG_CORE(" BUILD TAG: TEST-ADV-UNIT-042\r\n");
|
||||
DBG_CORE("========================================\r\n");
|
||||
|
||||
DBG_CORE("[1] HW Init\r\n");
|
||||
gpio_init();
|
||||
timers_init();
|
||||
load_default_config();
|
||||
@@ -312,25 +456,25 @@ int main(void)
|
||||
battery_timer_init();
|
||||
imu_init();
|
||||
temp_init();
|
||||
DBG_PRINTF(" gpio/timer/config/led/batt/imu/temp OK\r\n");
|
||||
DBG_CORE(" gpio/timer/config/led/batt/imu/temp OK\r\n");
|
||||
|
||||
/*── Phase 2: BLE 스택 + NUS ──*/
|
||||
DBG_PRINTF("[2] BLE Init\r\n");
|
||||
DBG_CORE("[2] BLE Init\r\n");
|
||||
if (ble_service_init(ble_rx_handler) == 0)
|
||||
{
|
||||
DBG_PRINTF(" ble/nus OK\r\n");
|
||||
DBG_CORE(" ble/nus OK\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG_PRINTF(" ble FAIL\r\n");
|
||||
DBG_ERR(" ble FAIL\r\n");
|
||||
}
|
||||
|
||||
/*── Phase 3: FDS/NVS (TODO) ──*/
|
||||
/*── Phase 4: 애플리케이션 (TODO) ──*/
|
||||
|
||||
DBG_PRINTF("\r\n========================================\r\n");
|
||||
DBG_PRINTF(" READY [%s]\r\n", SERIAL_NO);
|
||||
DBG_PRINTF("========================================\r\n\r\n");
|
||||
DBG_CORE("\r\n========================================\r\n");
|
||||
DBG_CORE(" READY [%s]\r\n", SERIAL_NO);
|
||||
DBG_CORE("========================================\r\n\r\n");
|
||||
|
||||
/* 전원 버튼 상태머신 시작 (부팅 시 버튼이 눌려있는 상태) */
|
||||
timers_start();
|
||||
|
||||
Reference in New Issue
Block a user