기타등등

This commit is contained in:
2026-06-11 17:48:35 +09:00
parent d7c5b34da3
commit 1f7436e27d
14 changed files with 714 additions and 124 deletions
+8 -1
View File
@@ -15,6 +15,7 @@
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/mgmt/mcumgr/transport/smp_bt.h>
#include <bluetooth/services/nus.h>
#include "ble_service.h"
@@ -135,7 +136,13 @@ static const struct bt_data ad[] =
static const struct bt_data sd[] =
{
BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
/*
* Legacy NUS + DFU(SMP) UUIDs together exceed the 31-byte scan response
* limit for legacy advertising. Keep the device name in the advertising
* packet and expose only SMP here so DFU remains discoverable.
BT_DATA_BYTES(BT_DATA_UUID128_SOME, SMP_BT_SVC_UUID_VAL), // BLE DFU 동작을 위한 SMP UUDI 광고 */
BT_DATA_BYTES(BT_DATA_UUID128_SOME, BT_UUID_NUS_VAL), // UUID에 NUS 안 넣으면 Web bluetooth 앱에서 안 보임
};
/*==============================================================================
+26 -13
View File
@@ -87,7 +87,8 @@ static inline void nop_delay_14(void)
static inline void nop_delay_32(void)
{
for (int i = 0; i < 32; i++) {
for (int i = 0; i < 32; i++)
{
burst_nop();
}
}
@@ -107,23 +108,28 @@ static void piezo_drive_idle(void)
int piezo_init(void)
{
if (piezo_initialized) {
if (piezo_initialized)
{
return 0;
}
const struct gpio_dt_spec *pins[] = {
const struct gpio_dt_spec *pins[] =
{
&piezo_pwr, &piezo_pe, &piezo_p_out, &piezo_n_out,
&piezo_dmp, &mux_en_a, &mux_en_b, &mux_sel0, &mux_sel1
};
for (size_t i = 0; i < ARRAY_SIZE(pins); i++) {
if (!device_is_ready(pins[i]->port)) {
for (size_t i = 0; i < ARRAY_SIZE(pins); i++)
{
if (!device_is_ready(pins[i]->port))
{
DBG_PRINTF("[PIEZO] GPIO device not ready (%d)\r\n", (int)i);
return -ENODEV;
}
int err = gpio_pin_configure_dt(pins[i], GPIO_OUTPUT_INACTIVE);
if (err) {
if (err)
{
DBG_PRINTF("[PIEZO] GPIO init fail idx=%d err=%d\r\n", (int)i, err);
return err;
}
@@ -146,7 +152,8 @@ int piezo_init(void)
void piezo_power_on(void)
{
if (!piezo_initialized && piezo_init() != 0) {
if (!piezo_initialized && piezo_init() != 0)
{
return;
}
@@ -155,7 +162,8 @@ void piezo_power_on(void)
void piezo_power_off(void)
{
if (!piezo_initialized && piezo_init() != 0) {
if (!piezo_initialized && piezo_init() != 0)
{
return;
}
@@ -165,14 +173,17 @@ void piezo_power_off(void)
int piezo_select_channel(uint8_t channel)
{
if (!piezo_initialized) {
if (!piezo_initialized)
{
int err = piezo_init();
if (err) {
if (err)
{
return err;
}
}
if (channel >= PIEZO_NUM_CHANNELS) {
if (channel >= PIEZO_NUM_CHANNELS)
{
return -EINVAL;
}
@@ -187,7 +198,8 @@ int piezo_select_channel(uint8_t channel)
void piezo_burst_sw(uint8_t cycles)
{
if (!piezo_initialized || cycles == 0U) {
if (!piezo_initialized || cycles == 0U)
{
return;
}
@@ -203,7 +215,8 @@ void piezo_burst_sw(uint8_t cycles)
NRF_P1->OUT = p1_all_low;
NRF_P0->OUTSET = piezo_pe_mask;
for (uint8_t i = 0; i < cycles; i++) {
for (uint8_t i = 0; i < cycles; i++)
{
NRF_P1->OUT = p1_p_high_n_low;
nop_delay_14();
+148 -30
View File
@@ -15,6 +15,8 @@
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>
#include <zephyr/dfu/mcuboot.h>
#include <hal/nrf_power.h>
#include "main.h"
#include "debug_print.h"
@@ -79,6 +81,8 @@ static bool power_btn_suspended; /* 측정 중 전원 버튼 상태
* k_work를 사용하면 시스템 워크큐 스레드에서 실행되므로 안전하게 BLE API 호출 가능.
* main_s() 타이머 콜백에서 k_work_submit()으로 예약하여 사용한다.
*/
static bool resume_without_power_button;
static uint32_t boot_reset_reason;
static struct k_work adv_start_work;
static struct k_work adv_stop_work;
@@ -111,13 +115,15 @@ static void ble_cmd_work_handler(struct k_work *work)
uint16_t local_len = 0U;
k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock);
if (ble_cmd_pending) {
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) {
if (local_len == 0U)
{
DBG_ERR("[BLE RX] worker: empty\r\n");
return;
}
@@ -204,17 +210,43 @@ static void ble_rx_handler(const uint8_t *data, uint16_t len)
/* 전원 유지 핀(P0.08) 초기화 - 아직 래치하지 않음
* 버튼을 물리적으로 누르고 있는 동안만 전원 유지됨
* 2초 후 main_s()에서 래치(HIGH) 설정 */
static void boot_context_detect(void)
{
boot_reset_reason = nrf_power_resetreas_get(NRF_POWER);
resume_without_power_button =
(boot_reset_reason & (NRF_POWER_RESETREAS_SREQ_MASK |
NRF_POWER_RESETREAS_DOG_MASK |
NRF_POWER_RESETREAS_LOCKUP_MASK |
NRF_POWER_RESETREAS_RESETPIN_MASK)) != 0U;
if (boot_reset_reason != 0U)
{
nrf_power_resetreas_clear(NRF_POWER, boot_reset_reason);
}
}
static void power_hold_init(void)
{
gpio_pin_configure_dt(&power_hold, GPIO_OUTPUT_INACTIVE);
#if defined(CONFIG_BOOTLOADER_MCUBOOT)
bool dfu_confirm_pending = !boot_is_img_confirmed();
#else
bool dfu_confirm_pending = false;
#endif
gpio_pin_configure_dt(&power_hold,
(resume_without_power_button || dfu_confirm_pending) ? GPIO_OUTPUT_ACTIVE
: GPIO_OUTPUT_INACTIVE);
}
/* 전원 ON/OFF 제어 - P0.08 핀으로 물리적 전원 래치/해제 */
static void power_control_handler(on_off_cont_t device_power_st)
{
if (device_power_st == OFF) {
if (device_power_st == OFF)
{
gpio_pin_set_dt(&power_hold, 0); /* P0.08 LOW → 전원 래치 해제 → 전원 차단 */
} else {
}
else
{
gpio_pin_set_dt(&power_hold, 1); /* P0.08 HIGH → 전원 유지 */
DBG_PRINTF("[PWR] ON\r\n");
}
@@ -239,13 +271,16 @@ static void load_default_config(void)
size_t hw_len = strlen(HARDWARE_VERSION);
size_t passkey_len = strlen(DEFAULT_PASSKEY);
if (serial_len > SERIAL_NO_LENGTH) {
if (serial_len > SERIAL_NO_LENGTH)
{
serial_len = SERIAL_NO_LENGTH;
}
if (hw_len > HW_NO_LENGTH) {
if (hw_len > HW_NO_LENGTH)
{
hw_len = HW_NO_LENGTH;
}
if (passkey_len > PASSKEY_LENGTH) {
if (passkey_len > PASSKEY_LENGTH)
{
passkey_len = PASSKEY_LENGTH;
}
@@ -403,11 +438,7 @@ static void timers_init(void)
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);
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();
}
@@ -417,59 +448,145 @@ static void timers_start(void)
k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT);
}
static void resume_device_after_soft_reset(void)
{
if (!resume_without_power_button)
{
return;
}
device_on = true;
cnt_s = 0;
boot_btn_released = (gpio_pin_get_dt(&power_btn) != 1);
m_reset_status = 1;
power_control_handler(ON);
led_set_state(LED_STATE_ADVERTISING);
battery_timer_start();
k_work_submit(&adv_start_work);
DBG_CORE("[BOOT] Resume after resetreas=0x%08x\r\n", boot_reset_reason);
}
static void confirm_running_image(void)
{
#if defined(CONFIG_BOOTLOADER_MCUBOOT)
if (!boot_is_img_confirmed())
{
int err = boot_write_img_confirmed();
if (err == 0)
{
DBG_CORE("[DFU] Running image confirmed\r\n");
}
else
{
DBG_ERR("[DFU] Image confirm failed (err %d)\r\n", err);
}
}
else
{
DBG_CORE("[DFU] Running image already confirmed\r\n");
}
#endif
}
static const char *swap_type_to_str(int swap_type)
{
switch (swap_type)
{
case BOOT_SWAP_TYPE_NONE:
return "none";
case BOOT_SWAP_TYPE_TEST:
return "test";
case BOOT_SWAP_TYPE_PERM:
return "perm";
case BOOT_SWAP_TYPE_REVERT:
return "revert";
case BOOT_SWAP_TYPE_FAIL:
return "fail";
default:
return "unknown";
}
}
static void log_mcuboot_state(void)
{
#if defined(CONFIG_BOOTLOADER_MCUBOOT)
struct mcuboot_img_header header;
uint8_t active_slot = boot_fetch_active_slot();
int swap_type = mcuboot_swap_type();
int err = boot_read_bank_header(active_slot, &header, sizeof(header));
DBG_CORE("[DFU] active_slot=%u swap_type=%s(%d) confirmed=%d\r\n",
active_slot,
swap_type_to_str(swap_type),
swap_type,
boot_is_img_confirmed());
if (err == 0)
{
DBG_CORE("[DFU] image version %u.%u.%u+%u size=0x%x\r\n",
header.h.v1.sem_ver.major,
header.h.v1.sem_ver.minor,
header.h.v1.sem_ver.revision,
header.h.v1.sem_ver.build_num,
header.h.v1.image_size);
}
else
{
DBG_ERR("[DFU] image header read failed (slot %u, err %d)\r\n",
active_slot,
err);
}
#endif
}
/*==============================================================================
* 메인 함수
*============================================================================*/
int main(void)
{
boot_context_detect();
/*── Phase 1: 하드웨어 기본 초기화 ──*/
power_hold_init();
cnt_s = 0;
/*
* 현재는 전원 버튼/mbb 문제를 같이 디버깅 중이라
* "버튼을 2초 이상 눌러야 래치 ON" 규칙이 오히려 부팅 자체를 막고 있다.
*
* 그래서 디버깅 동안만, MCU가 main()까지 올라오면 바로 P0.08 래치를 ON으로 잡는다.
*
* 의미:
* - 사용자는 전원 버튼을 "부팅이 시작될 만큼만" 누르면 된다.
* - 예전처럼 2초를 정확히 맞춰 길게 누를 필요가 없다.
* - 일단 켜진 뒤의 BLE/측정/로그 문제를 보기 쉬워진다.
*
* 나중에 전원 시퀀스 디버깅이 끝나면 이 블록은 다시 제거하면 된다.
*/
device_on = false;
boot_btn_released = false;
confirm_running_image();
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(" BUILD TAG: TEST-ADV-UNIT-000\r\n");
DBG_CORE("========================================\r\n");
DBG_CORE("[1] HW Init\r\n");
gpio_init();
timers_init();
log_mcuboot_state();
load_default_config();
led_init();
battery_adc_init();
battery_timer_init();
imu_init();
temp_init();
DBG_CORE(" gpio/timer/config/led/batt/imu/temp OK\r\n");
piezo_config_init();
DBG_CORE(" gpio/timer/config/led/batt/imu/temp/piezo-cfg OK\r\n");
/*── Phase 2: BLE 스택 + NUS ──*/
DBG_CORE("[2] BLE Init\r\n");
if (ble_service_init(ble_rx_handler) == 0)
{
DBG_CORE(" ble/nus OK\r\n");
resume_device_after_soft_reset();
}
else
{
DBG_ERR(" ble FAIL\r\n");
}
/*── Phase 3: FDS/NVS (TODO) ──*/
/*── Phase 3: FDS/NVS ──*/
/*── Phase 4: 애플리케이션 (TODO) ──*/
DBG_CORE("\r\n========================================\r\n");
@@ -480,7 +597,8 @@ int main(void)
timers_start();
/* 메인 루프 - idle */
for (;;) {
for (;;)
{
k_msleep(100);
}
+242 -48
View File
@@ -8,6 +8,11 @@
* 현재 구현된 커맨드: msn? (배터리 측정), mls? (LED 상태 설정)
******************************************************************************/
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#if IS_ENABLED(CONFIG_SETTINGS)
#include <zephyr/settings/settings.h>
#endif
#include <errno.h>
#include <string.h>
#include <limits.h>
@@ -40,9 +45,15 @@
#define PIEZO_CFG_DELAY_DEFAULT 10
#define PIEZO_CFG_SAMPLES_DEFAULT 100
#define PIEZO_CFG_AVG_DEFAULT 10
#define PIEZO_CFG_AVG_MAX 100
#define PIEZO_CFG_DELAY_MAX_US 1000
#define PIEZO_POST_SELECT_SETTLE_US 500
#define PIEZO_AVG_INTER_BURST_GAP_US 500
#define PIEZO_SETTINGS_NAME "vesiscan"
#define PIEZO_SETTINGS_CFG_KEY "piezo"
#define PIEZO_SETTINGS_FULL_KEY "vesiscan/piezo"
static uint16_t piezo_channels[PIEZO_NUM_CHANNELS][ECHO_ADC_MAX_SAMPLES];
static uint16_t echo_capture[ECHO_ADC_MAX_SAMPLES];
static uint32_t echo_accum[ECHO_ADC_MAX_SAMPLES];
@@ -52,6 +63,140 @@ static uint8_t tx_echo_buf[4 + 2 + (ECHO_ADC_MAX_SAMPLES * 2) + 2];
static uint8_t tx_bundle_buf[22];
static uint8_t tx_cfg_buf[16];
static uint8_t tx_ascii_buf[4 + HW_NO_LENGTH + 2];
static piezo_config_t g_piezo_config = {
.freq = PIEZO_CFG_FREQ_DEFAULT,
.cycles = PIEZO_CFG_CYCLES_DEFAULT,
.avg = PIEZO_CFG_AVG_DEFAULT,
.delay_us = PIEZO_CFG_DELAY_DEFAULT,
.samples = PIEZO_CFG_SAMPLES_DEFAULT,
};
static bool piezo_config_validate(const piezo_config_t *cfg)
{
if (cfg == NULL) {
return false;
}
if (cfg->freq != PIEZO_CFG_FREQ_DEFAULT) {
return false;
}
if ((cfg->cycles < 3U) || (cfg->cycles > 7U)) {
return false;
}
if ((cfg->avg == 0U) || (cfg->avg > PIEZO_CFG_AVG_MAX)) {
return false;
}
if (cfg->delay_us > PIEZO_CFG_DELAY_MAX_US) {
return false;
}
if ((cfg->samples == 0U) || (cfg->samples > ECHO_ADC_MAX_SAMPLES)) {
return false;
}
return true;
}
static void piezo_config_log(const char *prefix, const piezo_config_t *cfg)
{
DBG_PRINTF("%s freq=%u cycles=%u avg=%u delay=%u samples=%u\r\n",
prefix,
cfg->freq,
cfg->cycles,
cfg->avg,
cfg->delay_us,
cfg->samples);
}
const piezo_config_t *piezo_config_get(void)
{
return &g_piezo_config;
}
#if IS_ENABLED(CONFIG_SETTINGS)
static int piezo_settings_set(const char *name, size_t len,
settings_read_cb read_cb, void *cb_arg)
{
const char *next;
int rc;
if (settings_name_steq(name, PIEZO_SETTINGS_CFG_KEY, &next) && (next == NULL))
{
piezo_config_t loaded;
if (len != sizeof(loaded)) {
DBG_ERR("[CFG] piezo settings size mismatch (%u)\r\n", (uint32_t)len);
return -EINVAL;
}
rc = read_cb(cb_arg, &loaded, sizeof(loaded));
if (rc < 0) {
DBG_ERR("[CFG] piezo settings read failed err=%d\r\n", rc);
return rc;
}
if (rc != sizeof(loaded)) {
DBG_ERR("[CFG] piezo settings short read (%d)\r\n", rc);
return -EINVAL;
}
if (!piezo_config_validate(&loaded)) {
DBG_ERR("[CFG] piezo settings invalid, keep defaults\r\n");
return 0;
}
g_piezo_config = loaded;
piezo_config_log("[CFG] piezo restored", &g_piezo_config);
return 0;
}
return -ENOENT;
}
SETTINGS_STATIC_HANDLER_DEFINE(piezo_settings,
PIEZO_SETTINGS_NAME,
NULL,
piezo_settings_set,
NULL,
NULL);
#endif
int piezo_config_init(void)
{
#if IS_ENABLED(CONFIG_SETTINGS)
int err = settings_subsys_init();
if (err && (err != -EALREADY)) {
DBG_ERR("[CFG] settings init failed err=%d\r\n", err);
return err;
}
err = settings_load_subtree(PIEZO_SETTINGS_NAME);
if (err) {
DBG_ERR("[CFG] piezo settings load failed err=%d\r\n", err);
return err;
}
#endif
piezo_config_log("[CFG] piezo active", &g_piezo_config);
return 0;
}
static int piezo_config_save(void)
{
#if IS_ENABLED(CONFIG_SETTINGS)
int err = settings_save_one(PIEZO_SETTINGS_FULL_KEY,
&g_piezo_config,
sizeof(g_piezo_config));
if (err) {
DBG_ERR("[CFG] piezo settings save failed err=%d\r\n", err);
}
return err;
#else
return 0;
#endif
}
/*==============================================================================
* CRC16 (CRC-CCITT, Nordic SDK 호환)
@@ -312,6 +457,13 @@ static int start_piezo_session(void)
static int perform_piezo_sweep(void)
{
const piezo_config_t *cfg = piezo_config_get();
uint16_t capture_delay_us = cfg->delay_us;
if (capture_delay_us < PIEZO_BURST_TO_ADC_DELAY_US) {
capture_delay_us = PIEZO_BURST_TO_ADC_DELAY_US;
}
for (uint8_t ch = 0; ch < PIEZO_NUM_CHANNELS; ch++)
{
DBG_PRINTF("[MBB] sweep ch=%d start\r\n", ch);
@@ -334,32 +486,32 @@ static int perform_piezo_sweep(void)
memset(echo_accum, 0, sizeof(echo_accum));
for (uint8_t avg = 0; avg < PIEZO_AVERAGE_COUNT; avg++)
for (uint16_t avg = 0; avg < cfg->avg; avg++)
{
if (avg > 0U)
{
k_busy_wait(PIEZO_AVG_INTER_BURST_GAP_US);
}
piezo_burst_sw(PIEZO_SW_BURST_CYCLES);
k_busy_wait(PIEZO_BURST_TO_ADC_DELAY_US);
piezo_burst_sw((uint8_t)cfg->cycles);
k_busy_wait(capture_delay_us);
err = echo_adc_capture(echo_capture, ECHO_ADC_MAX_SAMPLES);
err = echo_adc_capture(echo_capture, cfg->samples);
if (err)
{
DBG_PRINTF("[ECHO] capture fail ch=%d avg=%d err=%d\r\n", ch, avg, err);
return ECHO_STATUS_CAPTURE;
}
for (uint16_t i = 0; i < ECHO_ADC_MAX_SAMPLES; i++)
for (uint16_t i = 0; i < cfg->samples; i++)
{
echo_accum[i] += echo_capture[i];
}
}
for (uint16_t i = 0; i < ECHO_ADC_MAX_SAMPLES; i++)
for (uint16_t i = 0; i < cfg->samples; i++)
{
piezo_channels[ch][i] = (uint16_t)(echo_accum[i] / PIEZO_AVERAGE_COUNT);
piezo_channels[ch][i] = (uint16_t)(echo_accum[i] / cfg->avg);
}
DBG_PRINTF("[MBB] sweep ch=%d done\r\n", ch);
@@ -521,12 +673,15 @@ static int cmd_mst(const uint8_t *data, uint8_t data_len)
return 1;
}
/**
* 테스트용
* mpa?: piezo TX/RX 전원 레일만 켬
*/
static int cmd_mpa(const uint8_t *data, uint8_t data_len)
{
ARG_UNUSED(data);
ARG_UNUSED(data_len);
/* mpa?: piezo TX/RX 전원 레일만 켠다. 측정은 하지 않는다. */
DBG_CORE("[MPA] enter\r\n");
if (piezo_init() != 0) {
DBG_ERR("[MPA] piezo_init failed\r\n");
@@ -563,10 +718,16 @@ static int cmd_mpb(const uint8_t *data, uint8_t data_len)
return 1;
}
/**
* 테스트용
* mpc?: burst만 한 번 발생시키는 테스트 명령
* echo를 읽지 않고 초음파가 나가는지만 볼 때 사용
*/
static int cmd_mpc(const uint8_t *data, uint8_t data_len)
{
uint16_t cycles = 5;
uint16_t freq_option = 1;
const piezo_config_t *cfg = piezo_config_get();
uint16_t cycles = cfg->cycles;
uint16_t freq_option = cfg->freq;
uint16_t piezo_ch = 0;
get_data_u16_be(data, data_len, 0, &cycles);
@@ -575,10 +736,6 @@ static int cmd_mpc(const uint8_t *data, uint8_t data_len)
ARG_UNUSED(freq_option);
/*
* mpc?: burst만 한 번 발생시키는 테스트 명령.
* echo를 읽지 않으므로 "초음파가 나가는지"만 빠르게 볼 때 쓴다.
*/
if ((cycles < 3U) || (cycles > 7U))
{
send_response_u16("rpc:", 2);
@@ -603,8 +760,8 @@ static int cmd_mpc(const uint8_t *data, uint8_t data_len)
}
/*
* 현재 Zephyr 포팅본은 2.1MHz SW burst 하나만 구현되어 있다.
* 레거시의 freq_option 값은 받아두되, 아직은 같은 burst 함수로 처리한다.
* 현재 Zephyr 포팅본은 2.1MHz SW burst 하나만 구현되어 있
* 레거시의 freq_option 값은 받아두되, 아직은 같은 burst 함수로 처리
*/
piezo_burst_sw((uint8_t)cycles);
piezo_power_off();
@@ -616,11 +773,12 @@ static int cmd_mpc(const uint8_t *data, uint8_t data_len)
static int cmd_mec(const uint8_t *data, uint8_t data_len)
{
uint16_t freq_option = 1;
uint16_t delay_us = PIEZO_BURST_TO_ADC_DELAY_US;
uint16_t num_samples = ECHO_ADC_MAX_SAMPLES;
uint16_t cycles = PIEZO_SW_BURST_CYCLES;
uint16_t averaging = 1;
const piezo_config_t *cfg = piezo_config_get();
uint16_t freq_option = cfg->freq;
uint16_t delay_us = cfg->delay_us;
uint16_t num_samples = cfg->samples;
uint16_t cycles = cfg->cycles;
uint16_t averaging = cfg->avg;
uint16_t piezo_ch = 0;
get_data_u16_be(data, data_len, 0, &freq_option);
@@ -633,8 +791,8 @@ static int cmd_mec(const uint8_t *data, uint8_t data_len)
ARG_UNUSED(freq_option);
/*
* mec?: 단일 채널 burst + echo capture.
* maa?/mbb?보다 가벼워서 "한 채널만 먼저 살아 있는지" 확인하기 좋다.
* 테스트용
* mec?: 단일 채널 burst + echo capture
*/
if (num_samples > ECHO_ADC_MAX_SAMPLES) {
num_samples = ECHO_ADC_MAX_SAMPLES;
@@ -671,19 +829,19 @@ static int cmd_mec(const uint8_t *data, uint8_t data_len)
return 1;
}
/**
* 테스트용(이전 정렬모드)
* maa?:
* - piezo 6채널 burst 순서대로 쏘고
* - echo 샘플을 채널별로 모은 뒤
* - reb: 패킷 6개 전송
* - raa: 상태값은 전체 작업 성공/실패 요약
*/
static int cmd_maa(const uint8_t *data, uint8_t data_len)
{
ARG_UNUSED(data);
ARG_UNUSED(data_len);
/*
* maa?:
* - piezo 6채널을 순서대로 쏘고
* - echo 샘플을 채널별로 모은 뒤
* - reb: 패킷 6개를 보낸다.
*
* 마지막 raa: 상태값은 "전체 작업 성공/실패 요약"이다.
*/
processing = true;
power_button_suspend(true);
@@ -697,7 +855,7 @@ static int cmd_maa(const uint8_t *data, uint8_t data_len)
{
for (uint8_t ch = 0; ch < PIEZO_NUM_CHANNELS; ch++)
{
send_response_echo(piezo_channels[ch], ECHO_ADC_MAX_SAMPLES);
send_response_echo(piezo_channels[ch], piezo_config_get()->samples);
}
}
@@ -710,6 +868,9 @@ static int cmd_maa(const uint8_t *data, uint8_t data_len)
return 1;
}
/**
* 전체 측정 시 사용
*/
static int cmd_mbb(const uint8_t *data, uint8_t data_len)
{
ARG_UNUSED(data);
@@ -747,7 +908,7 @@ static int cmd_mbb(const uint8_t *data, uint8_t data_len)
if (status == ECHO_STATUS_OK)
{
/* info 성격 데이터는 echo sweep이 정상 끝났을 때만 읽는다. */
/* info 성격 데이터는 echo sweep이 정상 끝났을 때만 읽 */
DBG_PRINTF("[MBB] battery read\r\n");
batt_mv = battery_read_mv();
if (batt_mv < 0)
@@ -777,7 +938,7 @@ static int cmd_mbb(const uint8_t *data, uint8_t data_len)
if (status == ECHO_STATUS_OK)
{
/* rbb: 한 번에 보내는 "요약 정보 묶음" 패킷 */
/* rbb: 센서(배터리+IMU+온도) 정보 패킷 */
DBG_PRINTF("[MBB] response tx start\r\n");
send_response_bundle((uint16_t)batt_mv, accel, gyro, temp_cdeg);
@@ -785,7 +946,7 @@ static int cmd_mbb(const uint8_t *data, uint8_t data_len)
{
/* reb: 채널별 raw echo 파형 */
DBG_PRINTF("[MBB] tx reb ch=%d\r\n", ch);
send_response_echo(piezo_channels[ch], ECHO_ADC_MAX_SAMPLES);
send_response_echo(piezo_channels[ch], piezo_config_get()->samples);
}
}
@@ -799,22 +960,52 @@ static int cmd_mbb(const uint8_t *data, uint8_t data_len)
return 1;
}
/**
* mcf?: piezo 측정 파라미터 읽기
* 응답 rcf: + 설정값 echo back
*/
static int cmd_mcf(const uint8_t *data, uint8_t data_len)
{
ARG_UNUSED(data);
ARG_UNUSED(data_len);
send_response_piezo_config(PIEZO_CFG_FREQ_DEFAULT,
PIEZO_CFG_CYCLES_DEFAULT,
PIEZO_CFG_AVG_DEFAULT,
PIEZO_CFG_DELAY_DEFAULT,
PIEZO_CFG_SAMPLES_DEFAULT);
DBG_PRINTF("[CMD] mcf -> freq=%d cycles=%d avg=%d delay=%d samples=%d\r\n",
PIEZO_CFG_FREQ_DEFAULT,
PIEZO_CFG_CYCLES_DEFAULT,
PIEZO_CFG_AVG_DEFAULT,
PIEZO_CFG_DELAY_DEFAULT,
PIEZO_CFG_SAMPLES_DEFAULT);
const piezo_config_t *cfg = piezo_config_get();
send_response_piezo_config(cfg->freq, cfg->cycles, cfg->avg, cfg->delay_us, cfg->samples);
piezo_config_log("[CMD] mcf ->", cfg);
return 1;
}
/**
* mcs?: piezo 측정 파라미터 쓰기
*/
static int cmd_mcs(const uint8_t *data, uint8_t data_len)
{
piezo_config_t cfg;
if (data_len < 10U)
{
send_response_u16("rcs:", 0xFFFF);
DBG_PRINTF("[CMD] mcs: insufficient data len=%u\r\n", data_len);
return 1;
}
get_data_u16_be(data, data_len, 0, &cfg.freq);
get_data_u16_be(data, data_len, 1, &cfg.cycles);
get_data_u16_be(data, data_len, 2, &cfg.avg);
get_data_u16_be(data, data_len, 3, &cfg.delay_us);
get_data_u16_be(data, data_len, 4, &cfg.samples);
if (!piezo_config_validate(&cfg))
{
send_response_u16("rcs:", 0xFFFE);
piezo_config_log("[CMD] mcs invalid", &cfg);
return 1;
}
g_piezo_config = cfg;
int err = piezo_config_save();
send_response_u16("rcs:", (err == 0) ? 0U : 0xFFFD);
piezo_config_log("[CMD] mcs saved", &g_piezo_config);
return 1;
}
@@ -977,6 +1168,7 @@ static const cmd_entry_t cmd_table[] =
{ "maa?", cmd_maa },
{ "mbb?", cmd_mbb },
{ "mcf?", cmd_mcf },
{ "mcs?", cmd_mcs },
{ "mfv?", cmd_mfv },
{ "mwh?", cmd_mwh },
{ "mrh?", cmd_mrh },
@@ -1026,7 +1218,8 @@ int dr_parser(const uint8_t *buf, uint16_t len)
}
/* TAG 추출 (4바이트) */
char tag[5] = {
char tag[5] =
{
ascii_to_lower((char)buf[0]),
ascii_to_lower((char)buf[1]),
ascii_to_lower((char)buf[2]),
@@ -1050,7 +1243,8 @@ int dr_parser(const uint8_t *buf, uint16_t len)
}
DBG_ERR("[CMD] Unknown: raw=%s normalized=%s\r\n", raw_tag, tag);
if (send_response_tag_echo("rxx:", raw_tag) != 0) {
if (send_response_tag_echo("rxx:", raw_tag) != 0)
{
DBG_ERR("[CMD] rxx tx failed\r\n");
}
return 0;
+11
View File
@@ -9,6 +9,17 @@
#include <stdint.h>
typedef struct
{
uint16_t freq;
uint16_t cycles;
uint16_t avg;
uint16_t delay_us;
uint16_t samples;
} piezo_config_t;
int piezo_config_init(void);
const piezo_config_t *piezo_config_get(void);
int dr_parser(const uint8_t *buf, uint16_t len);
#endif /* CMD_PARSER_H__ */