parser 분리

- 파서 인프라/커맨드 핸들러로 분리
- 커맨드 핸들러는 기기 제어/기기 정보/센서/Piezo로 분리
This commit is contained in:
2026-04-16 01:28:11 +09:00
parent c11ce4ec3e
commit c98d9ae14e
18 changed files with 1469 additions and 1410 deletions

View File

@@ -0,0 +1,94 @@
/*==============================================================================
* cmd_common.h - Shared header for command handlers
*
* Bundles every include / extern declaration / macro used in common across
* the cmd_*.c modules. A handler module only needs this header plus its own
* area-specific driver headers.
*============================================================================*/
#ifndef CMD_COMMON_H
#define CMD_COMMON_H
#include "parser.h"
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "debug_print.h"
#include "dr_util.h"
#include "main.h"
#include "app_timer.h"
#include "fstorage.h" /* config_data_t */
/*------------------------------------------------------------------------------
* BLE transmission / formatting (defined in main.c)
*----------------------------------------------------------------------------*/
extern uint8_t ble_bin_buffer[];
extern void single_format_data(uint8_t *buffer, const char *tag, uint16_t value);
extern void ascii_format_data(uint8_t *buffer, const char *tag, const char *ascii, size_t length);
extern void format_data(uint8_t *buffer, const char *tag, const uint16_t *data_array, size_t length);
extern void dr_binary_tx_safe(const uint8_t *buffer, uint16_t length); /* length: word count */
extern void dr_sd_delay_ms(uint32_t ms);
extern volatile bool data_tx_in_progress;
/*------------------------------------------------------------------------------
* Device state / flags
*----------------------------------------------------------------------------*/
extern volatile bool processing;
extern bool device_status;
extern bool con_single;
extern bool lock_check;
extern uint8_t resetCount;
/*------------------------------------------------------------------------------
* Measurement functions (defined elsewhere)
*----------------------------------------------------------------------------*/
extern void battery_level_meas(void);
extern void pressure_all_level_meas(void);
extern void tmp235_voltage_level_meas(void);
extern int imu_read_direct(void);
extern void battery_timer_stop(void);
extern void main_timer_start(void);
extern void hw_i2c_init_once(void);
/*------------------------------------------------------------------------------
* info4 mode sensor cache (used to assemble the rbb: response in mbb?)
*----------------------------------------------------------------------------*/
extern bool info4;
extern bool ble_got_new_data;
extern bool go_batt;
extern bool motion_data_once;
extern bool motion_raw_data_enabled;
extern volatile uint16_t info_batt;
extern volatile uint16_t info_temp;
extern volatile uint16_t info_imu[6];
extern volatile bool tmp235_saadc_done;
extern volatile bool battery_saadc_done;
/*------------------------------------------------------------------------------
* Device identifiers / passkey (FDS-backed)
*----------------------------------------------------------------------------*/
extern char SERIAL_NO[12];
extern char HW_NO[12];
extern char m_static_passkey[6];
extern uint32_t m_life_cycle;
/*------------------------------------------------------------------------------
* Power / reset / bonding control
*----------------------------------------------------------------------------*/
extern bool go_device_power_off;
extern bool go_NVIC_SystemReset;
extern bool bond_data_delete;
extern uint8_t m_reset_status;
extern void config_save(void);
extern config_data_t m_config;
/*------------------------------------------------------------------------------
* AGC gain switch (P0.20)
*----------------------------------------------------------------------------*/
#define GAIN_SW_PIN NRF_GPIO_PIN_MAP(0, 20)
#define AGC_GAIN_SW(x) do { if(x) nrf_gpio_pin_set(GAIN_SW_PIN); else nrf_gpio_pin_clear(GAIN_SW_PIN); } while(0)
#endif /* CMD_COMMON_H */

View File

@@ -0,0 +1,64 @@
/*==============================================================================
* cmd_table.c - Command table definition
*
* This file is the only linkage point between parser.c and the cmd_*.c
* handler modules. It pulls in every cmd_*.h to gather handler prototypes,
* builds the CmdEntry array, and injects the table into the parser via
* dr_parser_init() inside cmd_table_init().
*
* Adding a new command:
* 1) Implement the handler in the appropriate cmd_*.c
* 2) Add the prototype to the matching cmd_*.h
* 3) Append { "tag?", true, Cmd_xxx } to m_cmd_table[] below
*============================================================================*/
#include "parser.h"
#include "cmd_table.h"
#include "cmd_device.h"
#include "cmd_info.h"
#include "cmd_sensor.h"
#include "cmd_piezo.h"
static const CmdEntry m_cmd_table[] = {
/* A. Device state control */
{ "msq?", true, Cmd_msq },
{ "mss?", true, Cmd_mss },
#if FEATURE_SECURE_CONNECTION
{ "msr?", true, Cmd_msr },
#endif
{ "cmd?", true, Cmd_cmd },
/* B. Device information */
{ "mfv?", true, Cmd_mfv },
{ "mid?", true, Cmd_mid },
{ "mwh?", true, Cmd_mwh },
{ "mws?", true, Cmd_mws },
{ "mrh?", true, Cmd_mrh },
{ "mrs?", true, Cmd_mrs },
{ "mpz?", true, Cmd_mpz },
{ "mqz?", true, Cmd_mqz },
/* C. Sensor measurement */
{ "msn?", true, Cmd_msn },
{ "mso?", true, Cmd_mso },
{ "msp?", true, Cmd_msp },
{ "msi?", true, Cmd_msi },
/* D. Piezo ultrasound */
{ "mpa?", true, Cmd_mpa },
{ "mpb?", true, Cmd_mpb },
{ "mpc?", true, Cmd_mpc },
{ "mec?", true, Cmd_mec },
{ "maa?", true, Cmd_maa },
{ "mbb?", true, Cmd_mbb },
{ "mcf?", true, Cmd_mcf },
{ "mcs?", true, Cmd_mcs },
/* E. LED control (handler in cmd_device.c) */
{ "mls?", true, Cmd_mls },
};
void cmd_table_init(void)
{
dr_parser_init(m_cmd_table, sizeof(m_cmd_table) / sizeof(m_cmd_table[0]));
}

View File

@@ -0,0 +1,12 @@
/*==============================================================================
* cmd_table.h - Command table registration entry point
*
* main.c calls cmd_table_init() at boot to inject the command table into
* the parser.
*============================================================================*/
#ifndef CMD_TABLE_H
#define CMD_TABLE_H
void cmd_table_init(void);
#endif /* CMD_TABLE_H */

View File

@@ -1,3 +1,11 @@
/*==============================================================================
* dr_util.c - BLE response formatting helpers
*
* Convenience wrappers used by command handlers to assemble and transmit
* short BLE responses. Each helper prepends a 4-char TAG and writes the
* supplied uint16 values in Big-Endian order.
*============================================================================*/
#include "dr_util.h"
#include "parser.h"

View File

@@ -1,3 +1,6 @@
/*==============================================================================
* dr_util.h - BLE response helper API
*============================================================================*/
#ifndef DR_UTIL_H
#define DR_UTIL_H
@@ -8,11 +11,10 @@ void dr_ble_return_2(const char *tag, uint16_t v1, uint16_t v2);
void dr_ble_return_3(const char *tag, uint16_t v1, uint16_t v2, uint16_t v3);
void dr_ble_return_3_be(const char *tag, uint16_t v1, uint16_t v2, uint16_t v3);
/* Piezo dedicated BLE return - uses separate buffer to avoid conflicts */
/* Piezo dedicated BLE return - uses a separate buffer to avoid conflicts. */
void dr_ble_return_piezo_1(const char *tag, uint16_t value);
/* BLE debug output - sends "dbg:" + point_id + value */
/* BLE debug output - sends "dbg:" + point_id + value. */
void dr_ble_debug(uint16_t point_id, uint16_t value);
#endif /* DR_UTIL_H */

View File

@@ -0,0 +1,169 @@
/*==============================================================================
* cmd_device.c - Device state control handlers
*
* A. msq? -> rsq: device power OFF
* B. mss? -> rss: device soft reset
* C. msr? -> rsr: BLE bond delete + reset (FEATURE_SECURE_CONNECTION)
* D. cmd? -> rmd: direct GPIO pin control (debug / test only)
* E. mls? -> rls: set LED state
*============================================================================*/
#include "cmd_common.h"
#include "cmd_device.h"
#include "fstorage.h"
#include "led_control.h"
/*==============================================================================
* msq? -> rsq: Device power OFF
*
* Request: [TAG 4B "msq?"] [val 2B BE] [CRC 2B]
* Response: [TAG 4B "rsq:"] [val 2B BE] [CRC 2B]
*
* Sends BLE response first; the actual power-off is performed from the main
* loop. Powering off immediately would prevent the response from reaching
* the host, so a flag + timer pattern is used instead.
*============================================================================*/
int Cmd_msq(const ParsedCmd *cmd)
{
uint16_t val = 0;
dr_get_u16(cmd, 0, &val);
if (g_plat.log)
{
g_plat.log("[Cmd_msq] Power off val=%u\r\n", val);
}
single_format_data(ble_bin_buffer, "rsq:", val);
dr_binary_tx_safe(ble_bin_buffer, 2);
go_device_power_off = true;
main_timer_start();
return 1;
}
/*==============================================================================
* mss? -> rss: Device soft reset
*
* Request: [TAG 4B "mss?"] [val 2B BE] [CRC 2B]
* Response: [TAG 4B "rss:"] [val 2B BE] [CRC 2B]
*
* Resets without erasing bond information. Reset status code is persisted
* to FDS so the boot path can identify the cause.
*============================================================================*/
int Cmd_mss(const ParsedCmd *cmd)
{
uint16_t val = 0;
dr_get_u16(cmd, 0, &val);
single_format_data(ble_bin_buffer, "rss:", val);
dr_binary_tx_safe(ble_bin_buffer, 2);
m_reset_status = 2;
m_config.reset_status = m_reset_status;
config_save();
nrf_delay_ms(5);
go_NVIC_SystemReset = true;
main_timer_start();
return 1;
}
/*==============================================================================
* msr? -> rsr: Delete BLE bonding info + system reset
*
* Request: [TAG 4B "msr?"] [val 2B BE] [CRC 2B]
* Response: [TAG 4B "rsr:"] [val 2B BE] [CRC 2B]
*
* 1. Send BLE response
* 2. Persist bond-delete flag and reset status to FDS
* 3. Wait 5 ms for FDS write completion
* 4. Set NVIC system reset flag
*============================================================================*/
#if FEATURE_SECURE_CONNECTION
int Cmd_msr(const ParsedCmd *cmd)
{
uint16_t val = 0;
dr_get_u16(cmd, 0, &val);
single_format_data(ble_bin_buffer, "rsr:", val);
dr_binary_tx_safe(ble_bin_buffer, 2);
bond_data_delete = true;
m_config.bond_data_delete = (uint8_t)bond_data_delete;
m_reset_status = 2;
m_config.reset_status = m_reset_status;
config_save();
nrf_delay_ms(5);
go_NVIC_SystemReset = true;
main_timer_start();
return 1;
}
#endif
/*==============================================================================
* cmd? -> rmd: Direct GPIO pin control (debug / test)
*
* Request: [TAG 4B "cmd?"] [port 2B BE] [pin 2B BE] [state 2B BE] [CRC 2B]
* Response: [TAG 4B "rmd:"] [port 2B BE] [pin 2B BE] [state 2B BE] [CRC 2B]
* Error: rmd: + 0 (insufficient data)
*
* port : GPIO port (0 or 1)
* pin : pin number (0..31)
* state: 1=HIGH, 0=LOW
*
* Misuse can damage hardware - intended for debug only.
*============================================================================*/
int Cmd_cmd(const ParsedCmd *cmd)
{
uint16_t v1, v2, v3;
uint32_t pin_number;
if (cmd->data_len < 6)
{
dr_ble_return_1("rmd:", 0);
return 1;
}
if (!dr_get_u16(cmd, 0, &v1)) v1 = 0;
if (!dr_get_u16(cmd, 1, &v2)) v2 = 0;
if (!dr_get_u16(cmd, 2, &v3)) v3 = 0;
pin_number = NRF_GPIO_PIN_MAP(v1, v2);
nrf_gpio_cfg_output(pin_number);
if (v3 == 1)
{
nrf_gpio_pin_set(pin_number);
}
else
{
nrf_gpio_pin_clear(pin_number);
}
dr_ble_return_3("rmd:", v1, v2, v3);
return 1;
}
/*==============================================================================
* mls? -> rls: Set LED state (app -> device)
*
* Request: [TAG 4B "mls?"] [state 2B BE] [CRC 2B]
* state: led_state_t enum value
* 0=OFF, 4=DETACH_WARNING, 5=ALIGN_SEARCHING, 6=ALIGN_COMPLETE
* Response: [TAG 4B "rls:"] [state 2B] [CRC 2B]
* Error: rls: + 0xFFFF (insufficient data)
* rls: + 0xFFFE (state out of range)
*============================================================================*/
int Cmd_mls(const ParsedCmd *cmd)
{
if (cmd->data_len < 2) {
dr_ble_return_1("rls:", 0xFFFF);
return 1;
}
uint16_t state;
dr_get_u16(cmd, 0, &state);
if (state > LED_STATE_ERROR) {
dr_ble_return_1("rls:", 0xFFFE);
return 1;
}
led_set_state((led_state_t)state);
dr_ble_return_1("rls:", state);
return 1;
}

View File

@@ -0,0 +1,17 @@
/*==============================================================================
* cmd_device.h - Device state control handlers (power / reset / GPIO / LED)
*============================================================================*/
#ifndef CMD_DEVICE_H
#define CMD_DEVICE_H
#include "parser.h"
int Cmd_msq(const ParsedCmd *cmd); /* msq? -> rsq: device power OFF */
int Cmd_mss(const ParsedCmd *cmd); /* mss? -> rss: device soft reset */
#if FEATURE_SECURE_CONNECTION
int Cmd_msr(const ParsedCmd *cmd); /* msr? -> rsr: bond delete + reset */
#endif
int Cmd_cmd(const ParsedCmd *cmd); /* cmd? -> rmd: direct GPIO control */
int Cmd_mls(const ParsedCmd *cmd); /* mls? -> rls: set LED state */
#endif /* CMD_DEVICE_H */

View File

@@ -0,0 +1,164 @@
/*==============================================================================
* cmd_info.c - Device information read/write handlers
*
* Commands that read or write FDS-persisted data: firmware version, hardware version, serial number, BLE passkey.
* Typically written once at the factory and read back later for identification.
*============================================================================*/
#include "cmd_common.h"
#include "cmd_info.h"
#include "fstorage.h"
/*==============================================================================
* mfv? -> rfv: Read firmware version
*
* Request: [TAG 4B "mfv?"] [CRC 2B]
* Response: [TAG 4B "rfv:"] [FW_VER 12B ASCII] [CRC 2B]
*============================================================================*/
int Cmd_mfv(const ParsedCmd *cmd)
{
(void)cmd;
ascii_format_data(ble_bin_buffer, "rfv:", FIRMWARE_VERSION, 12);
dr_binary_tx_safe(ble_bin_buffer, 8); /* 16 bytes = 8 words */
return 1;
}
/*==============================================================================
* mid? -> rid: Read HW number + serial number + FW version together
*
* Request: [TAG 4B "mid?"] [CRC 2B]
* Response: [TAG 4B "rid:"] [HW 12B] [SN 12B] [FW 12B] [CRC 2B]
*============================================================================*/
int Cmd_mid(const ParsedCmd *cmd)
{
uint8_t *buf = ble_bin_buffer;
(void)cmd;
memcpy(HW_NO, m_config.hw_no, 12);
memcpy(SERIAL_NO, m_config.serial_no, 12);
buf[0] = 'r'; buf[1] = 'i'; buf[2] = 'd'; buf[3] = ':';
memcpy(&buf[4], HW_NO, 12);
memcpy(&buf[16], SERIAL_NO, 12);
memcpy(&buf[28], FIRMWARE_VERSION, 12);
dr_binary_tx_safe(buf, 20); /* 40 bytes = 20 words */
return 1;
}
/*==============================================================================
* mwh? -> rwh: Write HW number to FDS
*
* Request: [TAG 4B "mwh?"] [HW 12B ASCII] [CRC 2B]
* Response: [TAG 4B "rwh:"] [HW 12B ASCII] [CRC 2B]
* Error: rwh: + 0xFFFF (insufficient data)
*============================================================================*/
int Cmd_mwh(const ParsedCmd *cmd)
{
char buf[13];
if (cmd->data_len < 12) {
dr_ble_return_1("rwh:", 0xFFFF);
return 1;
}
dr_get_ascii(cmd, 0, buf, 12);
memcpy(HW_NO, buf, 12);
memcpy(m_config.hw_no, buf, 12);
config_save();
ascii_format_data(ble_bin_buffer, "rwh:", buf, 12);
dr_binary_tx_safe(ble_bin_buffer, 8);
return 1;
}
/*==============================================================================
* mws? -> rws: Write serial number to FDS
*
* Request: [TAG 4B "mws?"] [SN 12B ASCII] [CRC 2B]
* Response: [TAG 4B "rws:"] [SN 12B ASCII] [CRC 2B]
* Error: rws: + 0xFFFF (insufficient data)
*============================================================================*/
int Cmd_mws(const ParsedCmd *cmd)
{
char buf[13];
if (cmd->data_len < 12) {
dr_ble_return_1("rws:", 0xFFFF);
return 1;
}
dr_get_ascii(cmd, 0, buf, 12);
memcpy(SERIAL_NO, buf, 12);
memcpy(m_config.serial_no, buf, 12);
config_save();
ascii_format_data(ble_bin_buffer, "rws:", buf, 12);
dr_binary_tx_safe(ble_bin_buffer, 8);
return 1;
}
/*==============================================================================
* mrh? -> rrh: Read HW number from FDS
*
* Request: [TAG 4B "mrh?"] [CRC 2B]
* Response: [TAG 4B "rrh:"] [HW 12B ASCII] [CRC 2B]
*============================================================================*/
int Cmd_mrh(const ParsedCmd *cmd)
{
(void)cmd;
memcpy(HW_NO, m_config.hw_no, 12);
ascii_format_data(ble_bin_buffer, "rrh:", HW_NO, 12);
dr_binary_tx_safe(ble_bin_buffer, 8);
return 1;
}
/*==============================================================================
* mrs? -> rrs: Read serial number from FDS
*
* Request: [TAG 4B "mrs?"] [CRC 2B]
* Response: [TAG 4B "rrs:"] [SN 12B ASCII] [CRC 2B]
*============================================================================*/
int Cmd_mrs(const ParsedCmd *cmd)
{
(void)cmd;
memcpy(SERIAL_NO, m_config.serial_no, 12);
ascii_format_data(ble_bin_buffer, "rrs:", SERIAL_NO, 12);
dr_binary_tx_safe(ble_bin_buffer, 8);
return 1;
}
/*==============================================================================
* mpz? -> rpz: Write BLE passkey to FDS
*
* Request: [TAG 4B "mpz?"] [passkey 6B ASCII] [CRC 2B]
* Response: [TAG 4B "rpz:"] [passkey 6B ASCII] [CRC 2B]
*============================================================================*/
int Cmd_mpz(const ParsedCmd *cmd)
{
char passkey[7] = {0};
dr_get_ascii(cmd, 0, passkey, 6);
memcpy(m_static_passkey, passkey, 6);
memcpy(m_config.static_passkey, m_static_passkey, 6);
config_save();
ascii_format_data(ble_bin_buffer, "rpz:", passkey, 6);
dr_binary_tx_safe(ble_bin_buffer, 5);
return 1;
}
/*==============================================================================
* mqz? -> rqz: Read BLE passkey from FDS
*
* Request: [TAG 4B "mqz?"] [CRC 2B]
* Response: [TAG 4B "rqz:"] [passkey 6B ASCII] [CRC 2B]
*============================================================================*/
int Cmd_mqz(const ParsedCmd *cmd)
{
(void)cmd;
memcpy(m_static_passkey, m_config.static_passkey, 6);
ascii_format_data(ble_bin_buffer, "rqz:", m_static_passkey, 6);
dr_binary_tx_safe(ble_bin_buffer, 5);
return 1;
}

View File

@@ -0,0 +1,18 @@
/*==============================================================================
* cmd_info.h - Device information read/write handlers
*============================================================================*/
#ifndef CMD_INFO_H
#define CMD_INFO_H
#include "parser.h"
int Cmd_mfv(const ParsedCmd *cmd); /* mfv? -> rfv: read firmware version */
int Cmd_mid(const ParsedCmd *cmd); /* mid? -> rid: read HW + SN + FW together */
int Cmd_mwh(const ParsedCmd *cmd); /* mwh? -> rwh: write HW number */
int Cmd_mws(const ParsedCmd *cmd); /* mws? -> rws: write serial number */
int Cmd_mrh(const ParsedCmd *cmd); /* mrh? -> rrh: read HW number */
int Cmd_mrs(const ParsedCmd *cmd); /* mrs? -> rrs: read serial number */
int Cmd_mpz(const ParsedCmd *cmd); /* mpz? -> rpz: write BLE passkey */
int Cmd_mqz(const ParsedCmd *cmd); /* mqz? -> rqz: read BLE passkey */
#endif /* CMD_INFO_H */

View File

@@ -0,0 +1,305 @@
/*==============================================================================
* cmd_piezo.c - Piezo ultrasound measurement handlers
*
* mpa? -> rpa: TX/RX power ON
* mpb? -> rpb: TX/RX power OFF
* mpc? -> rpc: burst generation (test)
* mec? -> reb:+raa: single-channel burst + echo capture
* maa? -> reb:+raa: 6-channel asynchronous capture
* mbb? -> rbb:+reb:+raa: bulk sensor measurement + 6-channel capture
* mcf? -> rcf: read piezo parameters
* mcs? -> rcs: write piezo parameters
*============================================================================*/
#include "cmd_common.h"
#include "cmd_piezo.h"
#include "cmd_sensor.h" /* all_sensors() */
#include "dr_piezo.h"
#include "dr_adc121s051.h"
/*==============================================================================
* mpa? -> rpa: Enable piezo TX/RX circuit
*
* Request: [TAG 4B "mpa?"] [CRC 2B]
* Response: [TAG 4B "rpa:"] [1 2B] [CRC 2B]
*
* Must be called before mec? / maa?.
*============================================================================*/
int Cmd_mpa(const ParsedCmd *cmd)
{
(void)cmd;
dr_piezo_power_on();
if (g_plat.tx_bin) {
single_format_data(ble_bin_buffer, "rpa:", 1);
dr_binary_tx_safe(ble_bin_buffer, 3);
}
return 1;
}
/*==============================================================================
* mpb? -> rpb: Disable piezo TX/RX circuit
*
* Request: [TAG 4B "mpb?"] [CRC 2B]
* Response: [TAG 4B "rpb:"] [1 2B] [CRC 2B]
*
* Power saving once measurement is complete.
*============================================================================*/
int Cmd_mpb(const ParsedCmd *cmd)
{
(void)cmd;
dr_piezo_power_off();
if (g_plat.tx_bin) {
single_format_data(ble_bin_buffer, "rpb:", 1);
dr_binary_tx_safe(ble_bin_buffer, 3);
}
return 1;
}
/*==============================================================================
* mpc? -> rpc: Piezo burst generation (test / debug)
*
* Request: [TAG 4B "mpc?"] [cycles 2B] [freq_option 2B] [piezo_ch 2B] [CRC 2B]
* cycles : 3..7 (default 5)
* freq_option : 0=1.8MHz, 1=2.1MHz(default), 2=2.0MHz, 3=1.7MHz, 4=2.2MHz
* piezo_ch : 0..7
* Response: [TAG 4B "rpc:"] [cycles 2B] [CRC 2B]
* Error: rpc: + 2 (cycles out of range)
*
* Generates the burst only - no echo capture.
*============================================================================*/
int Cmd_mpc(const ParsedCmd *cmd)
{
uint16_t cycles = 5;
uint16_t freq_option = 1;
uint16_t piezo_ch = 0;
(void)dr_get_u16(cmd, 0, &cycles);
(void)dr_get_u16(cmd, 1, &freq_option);
(void)dr_get_u16(cmd, 2, &piezo_ch);
if (piezo_ch >= MAA_NUM_CHANNELS) piezo_ch = 0;
if (cycles < 3 || cycles > 7) {
dr_ble_return_1("rpc:", 2);
return 1;
}
dr_piezo_select_channel((uint8_t)piezo_ch);
switch (freq_option) {
case 0: dr_piezo_burst_sw_18mhz((uint8_t)cycles); break;
case 2: dr_piezo_burst_sw_20mhz((uint8_t)cycles); break;
case 3: dr_piezo_burst_sw_17mhz((uint8_t)cycles); break;
case 4: dr_piezo_burst_sw_22mhz((uint8_t)cycles); break;
case 1:
default: dr_piezo_burst_sw((uint8_t)cycles); break;
}
dr_ble_return_1("rpc:", (uint8_t)cycles);
return 1;
}
/*==============================================================================
* mec? -> reb:+raa: Piezo burst + echo capture (16-bit raw)
*
* Request: [TAG 4B "mec?"] [freq 2B] [delay_us 2B] [num_samples 2B]
* [cycles 2B] [averaging 2B] [piezo_ch 2B] [CRC 2B]
* Response: reb: [num_samples 2B] [raw_data up to 238B] (red: follow-up if needed)
* raa: [status 2B]
* Error: rer: + (0xEE00|err) + num_samples
*
* Sends raw 16-bit ADC values directly. Suited for short-range (~25cm).
*============================================================================*/
int Cmd_mec(const ParsedCmd *cmd)
{
uint16_t freq_option = 0;
uint16_t delay_us = 20;
uint16_t num_samples = 140;
uint16_t cycles = 5;
uint16_t averaging = 1;
uint16_t piezo_ch = 0;
if (!dr_piezo_is_power_on()) {
dr_piezo_power_on();
}
(void)dr_get_u16(cmd, 0, &freq_option);
(void)dr_get_u16(cmd, 1, &delay_us);
(void)dr_get_u16(cmd, 2, &num_samples);
(void)dr_get_u16(cmd, 3, &cycles);
(void)dr_get_u16(cmd, 4, &averaging);
(void)dr_get_u16(cmd, 5, &piezo_ch);
if (averaging == 0) averaging = 1;
if (averaging > 1000) averaging = 1000;
if (piezo_ch >= MAA_NUM_CHANNELS) piezo_ch = 0;
dr_adc_err_t err = dr_adc_burst_capture_transmit(
(uint8_t)freq_option, delay_us, num_samples, (uint8_t)cycles,
(uint16_t)averaging, (uint8_t)piezo_ch, ble_bin_buffer, 0);
if (err != DR_ADC_OK) {
dr_ble_return_2("rer:", 0xEE00 | (uint16_t)err, num_samples);
}
dr_piezo_power_off();
return 1;
}
/*==============================================================================
* maa? -> reb:+raa: 6-channel asynchronous full capture
*
* Request: [TAG 4B "maa?"] [CRC 2B]
* Response: per channel reb: [num_samples 2B] [raw_data...]
* final raa: [status 2B]
* Error: raa: + 0xFFFE (previous capture in progress)
* raa: + (0xFF00|err) (start failed)
*
* Asynchronous state machine - the BLE_NUS_EVT_TX_RDY callback drives the
* follow-up packet transmissions. Parameters are loaded from m_config (FDS).
*============================================================================*/
int Cmd_maa(const ParsedCmd *cmd)
{
dr_adc_err_t err;
(void)cmd;
if (maa_async_is_busy()) {
dr_ble_return_1("raa:", 0xFFFE);
return 1;
}
if (!dr_piezo_is_power_on()) {
dr_piezo_power_on();
}
err = maa_async_start(
m_config.piezo_freq_option,
m_config.piezo_delay_us,
m_config.piezo_num_samples,
m_config.piezo_cycles,
m_config.piezo_averaging,
ble_bin_buffer
);
if (err != DR_ADC_OK) {
if (g_plat.log) g_plat.log("[Cmd_maa] start failed err=%d\r\n", err);
single_format_data(ble_bin_buffer, "raa:", (uint16_t)(0xFF00 | err));
dr_binary_tx_safe(ble_bin_buffer, 3);
dr_piezo_power_off();
return 1;
}
return 1;
}
/*==============================================================================
* mbb? -> rbb:+reb:+raa: Bulk sensor measurement + 6-channel full capture
*
* Request: [TAG 4B "mbb?"] [CRC 2B]
* Response: rbb: [batt 2B] [IMU 12B] [temp 2B]
* reb: [num_samples 2B] [raw_data...] (per channel)
* raa: [status 2B]
* Error: raa: + 0xFFFE (previous capture in progress)
* raa: + (0xFF00|err) (start failed)
*
* 1) all_sensors() measures battery / IMU / temperature and emits rbb:
* 2) Starts 6-channel capture in pre-capture-all mode
*============================================================================*/
int Cmd_mbb(const ParsedCmd *cmd)
{
dr_adc_err_t err;
(void)cmd;
all_sensors();
if (maa_async_is_busy()) {
dr_ble_return_1("raa:", 0xFFFE);
return 1;
}
maa_async_set_pre_capture_all(true);
err = maa_async_start(
m_config.piezo_freq_option,
m_config.piezo_delay_us,
m_config.piezo_num_samples,
m_config.piezo_cycles,
m_config.piezo_averaging,
ble_bin_buffer
);
if (err != DR_ADC_OK) {
if (g_plat.log) g_plat.log("[Cmd_mbb] start failed err=%d\r\n", err);
single_format_data(ble_bin_buffer, "raa:", (uint16_t)(0xFF00 | err));
dr_binary_tx_safe(ble_bin_buffer, 3);
dr_piezo_power_off();
return 1;
}
return 1;
}
/*==============================================================================
* mcf? -> rcf: Read piezo parameters from FDS
*
* Request: [TAG 4B "mcf?"] [CRC 2B]
* Response: [TAG 4B "rcf:"] [freq 2B] [cycles 2B] [avg 2B]
* [delay_us 2B] [num_samples 2B] [CRC 2B]
*============================================================================*/
int Cmd_mcf(const ParsedCmd *cmd)
{
(void)cmd;
uint8_t *buf = ble_bin_buffer;
buf[0] = 'r'; buf[1] = 'c'; buf[2] = 'f'; buf[3] = ':';
buf[4] = 0; buf[5] = m_config.piezo_freq_option;
buf[6] = 0; buf[7] = m_config.piezo_cycles;
buf[8] = (uint8_t)(m_config.piezo_averaging >> 8); buf[9] = (uint8_t)(m_config.piezo_averaging & 0xFF);
buf[10] = (uint8_t)(m_config.piezo_delay_us >> 8); buf[11] = (uint8_t)(m_config.piezo_delay_us & 0xFF);
buf[12] = (uint8_t)(m_config.piezo_num_samples >> 8); buf[13] = (uint8_t)(m_config.piezo_num_samples & 0xFF);
dr_binary_tx_safe(buf, 7); /* 14 bytes = 7 words */
return 1;
}
/*==============================================================================
* mcs? -> rcs: Write piezo parameters to FDS
*
* Request: [TAG 4B "mcs?"] [freq 2B] [cycles 2B] [avg 2B]
* [delay_us 2B] [num_samples 2B] [CRC 2B]
* Response: [TAG 4B "rcs:"] [stored 5 values] [CRC 2B]
* Error: rcs: + 0xFFFF (insufficient data)
*============================================================================*/
int Cmd_mcs(const ParsedCmd *cmd)
{
if (cmd->data_len < 10) {
if (g_plat.log) g_plat.log("[Cmd_mcs] missing params (data_len=%u)\r\n", cmd->data_len);
dr_ble_return_1("rcs:", 0xFFFF);
return 1;
}
uint16_t freq, cycles, averaging, delay_us, num_samples;
dr_get_u16(cmd, 0, &freq);
dr_get_u16(cmd, 1, &cycles);
dr_get_u16(cmd, 2, &averaging);
dr_get_u16(cmd, 3, &delay_us);
dr_get_u16(cmd, 4, &num_samples);
m_config.piezo_freq_option = (uint8_t)freq;
m_config.piezo_cycles = (uint8_t)cycles;
m_config.piezo_averaging = averaging;
m_config.piezo_delay_us = delay_us;
m_config.piezo_num_samples = num_samples;
config_save();
uint8_t *buf = ble_bin_buffer;
buf[0] = 'r'; buf[1] = 'c'; buf[2] = 's'; buf[3] = ':';
buf[4] = 0; buf[5] = m_config.piezo_freq_option;
buf[6] = 0; buf[7] = m_config.piezo_cycles;
buf[8] = (uint8_t)(m_config.piezo_averaging >> 8); buf[9] = (uint8_t)(m_config.piezo_averaging & 0xFF);
buf[10] = (uint8_t)(m_config.piezo_delay_us >> 8); buf[11] = (uint8_t)(m_config.piezo_delay_us & 0xFF);
buf[12] = (uint8_t)(m_config.piezo_num_samples >> 8); buf[13] = (uint8_t)(m_config.piezo_num_samples & 0xFF);
dr_binary_tx_safe(buf, 7);
return 1;
}

View File

@@ -0,0 +1,18 @@
/*==============================================================================
* cmd_piezo.h - Piezo ultrasound measurement handlers
*============================================================================*/
#ifndef CMD_PIEZO_H
#define CMD_PIEZO_H
#include "parser.h"
int Cmd_mpa(const ParsedCmd *cmd); /* mpa? -> rpa: TX/RX power ON */
int Cmd_mpb(const ParsedCmd *cmd); /* mpb? -> rpb: TX/RX power OFF */
int Cmd_mpc(const ParsedCmd *cmd); /* mpc? -> rpc: burst generation */
int Cmd_mec(const ParsedCmd *cmd); /* mec? -> reb:+raa: single-channel capture */
int Cmd_maa(const ParsedCmd *cmd); /* maa? -> reb:+raa: 6-channel async capture */
int Cmd_mbb(const ParsedCmd *cmd); /* mbb? -> rbb:+reb:+raa: sensors + capture */
int Cmd_mcf(const ParsedCmd *cmd); /* mcf? -> rcf: read piezo parameters */
int Cmd_mcs(const ParsedCmd *cmd); /* mcs? -> rcs: write piezo parameters */
#endif /* CMD_PIEZO_H */

View File

@@ -0,0 +1,138 @@
/*==============================================================================
* cmd_sensor.c - Sensor measurement handlers
*
* msn? -> rsn: battery ADC measurement
* mso? -> rso: TMP235 temperature reading
* msp? -> rsp: IMU 6-axis single read
* msi? -> rsi: IMU motion streaming start
* all_sensors() bulk-measurement helper used by the mbb? handler
*============================================================================*/
#include "cmd_common.h"
#include "cmd_sensor.h"
#include "dr_piezo.h"
/*==============================================================================
* msn? -> rsn: Battery level ADC measurement
*
* Request: [TAG 4B "msn?"] [CRC 2B]
* Response: rsn: + battery voltage in mV (sent from battery_saadc.c callback)
*============================================================================*/
int Cmd_msn(const ParsedCmd *cmd)
{
(void)cmd;
battery_level_meas();
return 1;
}
/*==============================================================================
* mso? -> rso: TMP235-Q1 temperature sensor measurement
*
* Request: [TAG 4B "mso?"] [CRC 2B]
* Response: rso: + temperature (sent from tmp235_q1.c callback)
*============================================================================*/
int Cmd_mso(const ParsedCmd *cmd)
{
(void)cmd;
tmp235_voltage_level_meas();
return 1;
}
/*==============================================================================
* msp? -> rsp: IMU 6-axis single read
*
* Request: [TAG 4B "msp?"] [CRC 2B]
* Response: rsp: + accel(xyz) + gyro(xyz) (transmitted inside imu_read_direct)
*
* Reads IMU registers directly over I2C and transmits over BLE. Synchronous.
*============================================================================*/
int Cmd_msp(const ParsedCmd *cmd)
{
(void)cmd;
hw_i2c_init_once();
imu_read_direct();
return 1;
}
/*==============================================================================
* msi? -> rsi: IMU motion sensor streaming start
*
* Request: [TAG 4B "msi?"] [mode 1B] [CRC 2B]
* mode = 'c': continuous (repeats on timer)
* else : single shot (one read then auto stop)
* Response: rsi: + IMU data (sent from main timer callback)
*============================================================================*/
int Cmd_msi(const ParsedCmd *cmd)
{
hw_i2c_init_once();
motion_raw_data_enabled = true;
ble_got_new_data = false;
if (cmd->data_len > 0 && (char)cmd->data[0] == 'c') {
motion_data_once = false;
} else {
motion_data_once = true;
}
main_timer_start();
return 1;
}
/*==============================================================================
* all_sensors() - Bulk-measurement helper for the mbb? handler
*
* Stores sensor values into globals via info4 mode, then transmits them as a
* single rbb: packet. SAADC measurements run asynchronously (callback), so
* dr_sd_delay_ms() is used to wait for completion.
*
* Order: battery -> IMU -> (Piezo TX/RX ON) -> temperature
* Response: rbb: [batt 2B] [IMU 6x2B] [temp 2B] = 20 bytes = 10 words
*============================================================================*/
void all_sensors(void)
{
uint8_t *buf;
uint32_t timeout_cnt;
info4 = true;
/* 1. Battery voltage -> info_batt */
battery_saadc_done = false;
battery_level_meas();
for (timeout_cnt = 0; !battery_saadc_done && timeout_cnt < 100; timeout_cnt++) {
dr_sd_delay_ms(1);
}
/* 2. IMU 6-axis single read -> info_imu[6] */
hw_i2c_init_once();
imu_read_direct();
/* 3. Temperature -> info_temp (TMP235 needs Piezo TX/RX power) */
if (!dr_piezo_is_power_on()) {
dr_piezo_power_on();
}
tmp235_saadc_done = false;
tmp235_voltage_level_meas();
for (timeout_cnt = 0; !tmp235_saadc_done && timeout_cnt < 100; timeout_cnt++) {
dr_sd_delay_ms(1);
}
info4 = false;
/* Assemble and transmit the rbb: packet */
buf = ble_bin_buffer;
buf[0] = 'r'; buf[1] = 'b'; buf[2] = 'b'; buf[3] = ':';
buf[4] = (uint8_t)(info_batt >> 8);
buf[5] = (uint8_t)(info_batt & 0xFF);
for (int i = 0; i < 6; i++) {
buf[6 + i * 2] = (uint8_t)(info_imu[i] >> 8);
buf[6 + i * 2 + 1] = (uint8_t)(info_imu[i] & 0xFF);
}
buf[18] = (uint8_t)(info_temp >> 8);
buf[19] = (uint8_t)(info_temp & 0xFF);
dr_binary_tx_safe(buf, 10); /* 20 bytes = 10 words */
}

View File

@@ -0,0 +1,19 @@
/*==============================================================================
* cmd_sensor.h - Sensor measurement handlers (battery / temperature / IMU)
*============================================================================*/
#ifndef CMD_SENSOR_H
#define CMD_SENSOR_H
#include "parser.h"
int Cmd_msn(const ParsedCmd *cmd); /* msn? -> rsn: battery ADC measurement */
int Cmd_mso(const ParsedCmd *cmd); /* mso? -> rso: TMP235 temperature reading */
int Cmd_msp(const ParsedCmd *cmd); /* msp? -> rsp: IMU 6-axis single read */
int Cmd_msi(const ParsedCmd *cmd); /* msi? -> rsi: IMU streaming start */
/* Helper for the mbb? handler: sequentially measures battery / IMU /
* temperature, then emits a single rbb: response. Called from
* Cmd_mbb() in cmd_piezo.c. */
void all_sensors(void);
#endif /* CMD_SENSOR_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,75 @@
/* parser.h */
/*==============================================================================
* parser.h - BLE command parser public API
*
* Parser infrastructure (parsing/CRC/dispatch) and command handlers are
* decoupled:
* - Parser: parser.c (defines the functions here)
* - Handlers: handlers/cmd_device.c / cmd_info.c / ...
* - Table: cmd_table.c (injected via cmd_table_init)
*
* Boot sequence: main.c calls cmd_table_init() -> dr_parser_init() to inject
* the command table pointer into the parser.
*============================================================================*/
#ifndef PARSER_H
#define PARSER_H
#include <stdint.h>
#include <stdbool.h>
/* Platform-dependent function pointer set */
/* Maximum payload length (excludes TAG) */
#define DR_MAX_DATA 128
/*------------------------------------------------------------------------------
* Platform interface
*----------------------------------------------------------------------------*/
typedef struct {
void (*log)(const char *fmt, ...);
void (*tx_bin)(const uint8_t *buf, uint16_t len);
bool crc_check;
void (*tx_bin)(const uint8_t *buf, uint16_t len); /* len: word (uint16) count */
bool crc_check;
} dr_platform_if_t;
/* Global interface & log flag */
extern dr_platform_if_t g_plat;
extern bool g_log_enable;
extern bool g_log_enable;
/* Main parser entry point */
int dr_cmd_parser(const uint8_t *buf, uint8_t len);
/*------------------------------------------------------------------------------
* Parsed command - input passed to handlers
*----------------------------------------------------------------------------*/
typedef struct {
char tag[5]; /* Command TAG (e.g. "mid?") + '\0' */
uint8_t data[DR_MAX_DATA]; /* Payload bytes following the TAG */
uint8_t data_len; /* Valid length of data[] */
} ParsedCmd;
/*------------------------------------------------------------------------------
* Command table entry - defined in cmd_table.c
*----------------------------------------------------------------------------*/
typedef struct {
char tag[5]; /* TAG: 4 chars + '\0' */
bool enabled; /* false -> rxd: response */
int (*handler)(const ParsedCmd *cmd); /* 1=success, 0=failure */
} CmdEntry;
/*------------------------------------------------------------------------------
* Parser API
*----------------------------------------------------------------------------*/
/* Inject command table (called once at boot). */
void dr_parser_init(const CmdEntry *table, uint16_t count);
/* Entry point: invoked from BLE NUS / UART receive callbacks. */
int dr_cmd_parser(const uint8_t *buf, uint8_t len);
/*------------------------------------------------------------------------------
* Public utilities for handlers
*----------------------------------------------------------------------------*/
/* Extract Big-Endian uint16. Returns false if not enough data. */
bool dr_get_u16(const ParsedCmd *cmd, uint8_t word_index, uint16_t *out);
/* Extract null-terminated ASCII string. out must hold at least max_len+1. */
void dr_get_ascii(const ParsedCmd *cmd, uint8_t offset, char *out, uint8_t max_len);
/* CRC16 (Nordic SDK CRC-CCITT variant). p_crc=NULL -> initial 0xFFFF. */
uint16_t dr_crc16_compute(const uint8_t *p_data, uint32_t size, const uint16_t *p_crc);
#endif /* PARSER_H */

View File

@@ -111,6 +111,7 @@
/* ── 암호화/명령 파서/디버그 ── */
#include "nrf_crypto.h" /* nRF 암호화 라이브러리 (AES 등) */
#include "parser.h" /* 새 바이너리 명령 파서 (dr_cmd_parser) */
#include "cmd_table.h" /* 명령 테이블 등록 (cmd_table_init) */
#include "debug_print.h" /* 디버그 출력 매크로 (DBG_PRINTF) */
#include "fstorage.h" /* Flash Storage 래퍼 (FDS 초기화/저장/로드) */
#include "dr_piezo.h" /* 피에조 초음파 드라이버 */
@@ -1840,6 +1841,7 @@ int main(void)
g_plat.tx_bin = dr_binary_tx_safe;
g_plat.crc_check = true;
g_log_enable = true;
cmd_table_init(); /* 명령 테이블을 파서에 주입 */
dr_piezo_init();
DBG_PRINTF(" parser/piezo OK\r\n");