1190 lines
30 KiB
C
1190 lines
30 KiB
C
/*******************************************************************************
|
|
* @file cmd.c
|
|
* @brief Command handlers and command table
|
|
* @author Charles KWON <charleskwon@medithings.co.kr>
|
|
* @date 2025-01-30
|
|
* @copyright (c) 2025 Medithings Inc. All rights reserved.
|
|
*
|
|
* @details Platform-specific command implementations.
|
|
* Command table is exported to parser for dispatch.
|
|
******************************************************************************/
|
|
|
|
#include "cmd.h"
|
|
#include "parser.h"
|
|
#include "dr_util.h"
|
|
#include <string.h>
|
|
|
|
#include "nrf_gpio.h"
|
|
#include "nrf_delay.h"
|
|
#include "../drivers/w25q32/w25q32.h" /* Flash driver */
|
|
#include "../storage/dr_mem.h" /* Name-based memory API */
|
|
#include "../fstorage.h" /* m_config */
|
|
#include "../debug_print.h"
|
|
|
|
/*==============================================================================
|
|
* HARDWARE DEFINES
|
|
*============================================================================*/
|
|
|
|
#define GAIN_SW_PIN NRF_GPIO_PIN_MAP(0,20)
|
|
#define AGC_GAIN_SW(x) do { \
|
|
if ((x) == true) nrf_gpio_pin_set(GAIN_SW_PIN); \
|
|
else nrf_gpio_pin_clear(GAIN_SW_PIN); \
|
|
} while(0)
|
|
|
|
/*==============================================================================
|
|
* EXTERNAL FUNCTION DECLARATIONS
|
|
*============================================================================*/
|
|
|
|
/* Sensor functions */
|
|
extern void battery_level_meas(void);
|
|
extern void pressure_all_level_meas(void);
|
|
extern void tmp235_voltage_level_meas(void);
|
|
extern void simple_mesurement_start(void);
|
|
extern void full_agc_mesurement_start(void);
|
|
|
|
/* Device control functions */
|
|
extern int device_activated(void);
|
|
extern int device_sleep_mode(void);
|
|
|
|
/* Error handling */
|
|
extern void param_error(const char *cmd);
|
|
|
|
/* BLE transmission */
|
|
extern void single_format_data(uint8_t *buffer, const char *tag, uint16_t value);
|
|
extern void format_data(uint8_t *buffer, const char *tag, const uint16_t *data_array, size_t length);
|
|
extern void format_data_byte(uint8_t *buffer, const char *tag, const uint8_t *data_array, size_t length);
|
|
extern void ascii_format_data(uint8_t *buffer, const char *tag, const char *data_ascii, size_t length);
|
|
extern void binary_tx_handler(const uint8_t *buffer, uint16_t length);
|
|
|
|
/* Timer functions */
|
|
extern void battery_timer_stop(void);
|
|
extern void main_timer_start(void);
|
|
|
|
/*==============================================================================
|
|
* EXTERNAL VARIABLES
|
|
*============================================================================*/
|
|
|
|
extern volatile bool processing;
|
|
extern bool device_status;
|
|
extern uint8_t resetCount;
|
|
extern uint8_t ble_bin_buffer[];
|
|
|
|
extern uint8_t ADC_PD_MODE;
|
|
extern bool low_battery_check;
|
|
extern bool info4;
|
|
extern bool ble_got_new_data;
|
|
extern uint8_t m48_samples_in_buffer;
|
|
extern uint8_t m_pd_adc_cnt;
|
|
extern uint16_t m_pd_delay_us;
|
|
extern uint16_t led_pd_dac_v[];
|
|
extern uint32_t m_life_cycle;
|
|
extern bool pd_adc_m48_start;
|
|
extern bool go_batt;
|
|
extern bool motion_data_once;
|
|
|
|
/*==============================================================================
|
|
* UTILITY FUNCTIONS
|
|
*============================================================================*/
|
|
|
|
bool cmd_get_u16(const ParsedCmd *cmd, uint8_t word_index, uint16_t *out)
|
|
{
|
|
uint8_t pos = (uint8_t)(word_index * 2);
|
|
if (cmd->data_len < (uint8_t)(pos + 2)) {
|
|
return false;
|
|
}
|
|
*out = (uint16_t)cmd->data[pos]
|
|
| (uint16_t)((uint16_t)cmd->data[pos + 1] << 8);
|
|
return true;
|
|
}
|
|
|
|
void cmd_get_ascii(const ParsedCmd *cmd, uint8_t offset, char *out, uint8_t max_len)
|
|
{
|
|
uint8_t i;
|
|
uint8_t remain;
|
|
|
|
if (offset >= cmd->data_len) {
|
|
out[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
remain = (uint8_t)(cmd->data_len - offset);
|
|
if (remain > max_len) {
|
|
remain = max_len;
|
|
}
|
|
|
|
for (i = 0; i < remain; i++) {
|
|
out[i] = (char)cmd->data[offset + i];
|
|
}
|
|
out[remain] = '\0';
|
|
}
|
|
|
|
/*==============================================================================
|
|
* COMMAND HANDLER PROTOTYPES
|
|
*============================================================================*/
|
|
|
|
/* A. Device Status */
|
|
static int Cmd_mta(const ParsedCmd *cmd);
|
|
static int Cmd_sta(const ParsedCmd *cmd);
|
|
static int Cmd_mqq(const ParsedCmd *cmd);
|
|
static int Cmd_str(const ParsedCmd *cmd);
|
|
|
|
/* B. AGC / Gain Measurement */
|
|
static int Cmd_mag(const ParsedCmd *cmd);
|
|
static int Cmd_sar(const ParsedCmd *cmd);
|
|
|
|
/* C. LED DP Value */
|
|
static int Cmd_ssa(const ParsedCmd *cmd);
|
|
static int Cmd_sab(const ParsedCmd *cmd);
|
|
static int Cmd_ssb(const ParsedCmd *cmd);
|
|
static int Cmd_srb(const ParsedCmd *cmd);
|
|
|
|
/* D. LED On/Off & Gain Control */
|
|
static int Cmd_ssc(const ParsedCmd *cmd);
|
|
static int Cmd_ssd(const ParsedCmd *cmd);
|
|
static int Cmd_sse(const ParsedCmd *cmd);
|
|
static int Cmd_ssf(const ParsedCmd *cmd);
|
|
static int Cmd_sif(const ParsedCmd *cmd);
|
|
static int Cmd_ssg(const ParsedCmd *cmd);
|
|
|
|
/* E. Simple PD Measurement */
|
|
static int Cmd_ssh(const ParsedCmd *cmd);
|
|
|
|
/* F. PD-ADC M48 Full Measurement Series */
|
|
static int Cmd_mcj(const ParsedCmd *cmd);
|
|
static int Cmd_sdj(const ParsedCmd *cmd);
|
|
static int Cmd_sej(const ParsedCmd *cmd);
|
|
static int Cmd_sfj(const ParsedCmd *cmd);
|
|
static int Cmd_ssj(const ParsedCmd *cmd);
|
|
static int Cmd_szj(const ParsedCmd *cmd);
|
|
|
|
/* G. IMM ADC */
|
|
static int Cmd_saj(const ParsedCmd *cmd);
|
|
|
|
/* H. PD-ADC Count & Delay */
|
|
static int Cmd_ssk(const ParsedCmd *cmd);
|
|
static int Cmd_srk(const ParsedCmd *cmd);
|
|
static int Cmd_ssl(const ParsedCmd *cmd);
|
|
static int Cmd_srl(const ParsedCmd *cmd);
|
|
|
|
/* I. Sensor Measurements */
|
|
static int Cmd_msn(const ParsedCmd *cmd);
|
|
static int Cmd_spn(const ParsedCmd *cmd);
|
|
static int Cmd_sso(const ParsedCmd *cmd);
|
|
static int Cmd_ssp(const ParsedCmd *cmd);
|
|
|
|
/* J. Power / Reset / Version / Security */
|
|
static int Cmd_ssq(const ParsedCmd *cmd);
|
|
static int Cmd_ssr(const ParsedCmd *cmd);
|
|
static int Cmd_sss(const ParsedCmd *cmd);
|
|
static int Cmd_sst(const ParsedCmd *cmd);
|
|
static int Cmd_ssv(const ParsedCmd *cmd);
|
|
|
|
/* K. Serial / Passkey System */
|
|
static int Cmd_ssz(const ParsedCmd *cmd);
|
|
static int Cmd_spz(const ParsedCmd *cmd);
|
|
static int Cmd_sqz(const ParsedCmd *cmd);
|
|
static int Cmd_srz(const ParsedCmd *cmd);
|
|
|
|
/* L. EEPROM UInt16 Array */
|
|
static int Cmd_sez(const ParsedCmd *cmd);
|
|
static int Cmd_sfz(const ParsedCmd *cmd);
|
|
static int Cmd_sgz(const ParsedCmd *cmd);
|
|
|
|
/* M. Hardware No / Life Cycle */
|
|
static int Cmd_siz(const ParsedCmd *cmd);
|
|
static int Cmd_shz(const ParsedCmd *cmd);
|
|
static int Cmd_sxz(const ParsedCmd *cmd);
|
|
static int Cmd_syz(const ParsedCmd *cmd);
|
|
|
|
/* N. Memory Read (dr_mem) */
|
|
static int Cmd_mrh(const ParsedCmd *cmd);
|
|
static int Cmd_mrs(const ParsedCmd *cmd);
|
|
static int Cmd_mrp(const ParsedCmd *cmd);
|
|
static int Cmd_mrb(const ParsedCmd *cmd);
|
|
static int Cmd_mrr(const ParsedCmd *cmd);
|
|
static int Cmd_mrc(const ParsedCmd *cmd);
|
|
static int Cmd_mrd(const ParsedCmd *cmd);
|
|
static int Cmd_mrg(const ParsedCmd *cmd);
|
|
static int Cmd_mrl(const ParsedCmd *cmd);
|
|
|
|
/* O. Memory Write (dr_mem) */
|
|
static int Cmd_mwh(const ParsedCmd *cmd);
|
|
static int Cmd_mws(const ParsedCmd *cmd);
|
|
static int Cmd_mwp(const ParsedCmd *cmd);
|
|
static int Cmd_mwb(const ParsedCmd *cmd);
|
|
static int Cmd_mwr(const ParsedCmd *cmd);
|
|
static int Cmd_mwc(const ParsedCmd *cmd);
|
|
static int Cmd_mwd(const ParsedCmd *cmd);
|
|
static int Cmd_mwg(const ParsedCmd *cmd);
|
|
static int Cmd_mwl(const ParsedCmd *cmd);
|
|
|
|
/* P. Debug / Test */
|
|
static int Cmd_cmd(const ParsedCmd *cmd);
|
|
|
|
/*==============================================================================
|
|
* COMMAND TABLE
|
|
*============================================================================*/
|
|
|
|
CmdEntry g_cmd_table[] = {
|
|
/* Debug command */
|
|
{ "cmd?", true, Cmd_cmd }, // GPIO Test
|
|
|
|
/* A. Device Status */
|
|
{ "mta?", true, Cmd_mta },
|
|
{ "sta?", true, Cmd_sta },
|
|
{ "str?", false, Cmd_str },
|
|
{ "mqq?", true, Cmd_mqq },
|
|
|
|
/* B. AGC / Gain Measurement */
|
|
{ "mag?", true, Cmd_mag },
|
|
{ "sag?", true, Cmd_mag },
|
|
{ "sar?", false, Cmd_sar },
|
|
|
|
/* C. LED Power / DP Value */
|
|
{ "ssa?", false, Cmd_ssa },
|
|
{ "sab?", false, Cmd_sab },
|
|
{ "ssb?", false, Cmd_ssb },
|
|
{ "srb?", false, Cmd_srb },
|
|
|
|
/* D. LED On/Off & Gain Control */
|
|
{ "ssc?", false, Cmd_ssc },
|
|
{ "ssd?", false, Cmd_ssd },
|
|
{ "sse?", false, Cmd_sse },
|
|
{ "ssf?", false, Cmd_ssf },
|
|
{ "sif?", false, Cmd_sif },
|
|
{ "ssg?", false, Cmd_ssg },
|
|
|
|
/* E. Simple PD Measurement */
|
|
{ "ssh?", false, Cmd_ssh },
|
|
|
|
/* F. PD-ADC M48 Full Measurement Series */
|
|
{ "mcj?", true, Cmd_mcj },
|
|
{ "scj?", true, Cmd_mcj },
|
|
{ "sdj?", false, Cmd_sdj },
|
|
{ "sej?", false, Cmd_sej },
|
|
{ "sfj?", false, Cmd_sfj },
|
|
{ "ssj?", false, Cmd_ssj },
|
|
{ "szj?", false, Cmd_szj },
|
|
|
|
/* G. IMM ADC */
|
|
{ "saj?", false, Cmd_saj },
|
|
|
|
/* H. PD-ADC Count & Delay */
|
|
{ "ssk?", false, Cmd_ssk },
|
|
{ "srk?", false, Cmd_srk },
|
|
{ "ssl?", false, Cmd_ssl },
|
|
{ "srl?", false, Cmd_srl },
|
|
|
|
/* I. Sensor Measurements */
|
|
{ "msn?", true, Cmd_msn },
|
|
{ "ssn?", true, Cmd_msn },
|
|
{ "spn?", false, Cmd_spn },
|
|
{ "sso?", false, Cmd_sso },
|
|
{ "ssp?", false, Cmd_ssp },
|
|
|
|
/* J. Power / Reset / Version / Security */
|
|
{ "ssq?", false, Cmd_ssq },
|
|
{ "ssr?", false, Cmd_ssr },
|
|
{ "sss?", false, Cmd_sss },
|
|
{ "sst?", false, Cmd_sst },
|
|
{ "ssv?", false, Cmd_ssv },
|
|
|
|
/* K. Serial / Passkey System */
|
|
{ "ssz?", false, Cmd_ssz },
|
|
{ "spz?", false, Cmd_spz },
|
|
{ "sqz?", false, Cmd_sqz },
|
|
{ "srz?", false, Cmd_srz },
|
|
|
|
/* L. EEPROM UInt16 Array */
|
|
{ "sez?", false, Cmd_sez },
|
|
{ "sfz?", false, Cmd_sfz },
|
|
{ "sgz?", false, Cmd_sgz },
|
|
|
|
/* M. Hardware No / Life Cycle */
|
|
{ "siz?", true, Cmd_siz },
|
|
{ "shz?", true, Cmd_shz },
|
|
{ "sxz?", false, Cmd_sxz },
|
|
{ "syz?", false, Cmd_syz },
|
|
|
|
/* N. Memory Read (dr_mem) */
|
|
{ "mrh?", true, Cmd_mrh }, /* hw_no → rrh: + 12B ASCII */
|
|
{ "mrs?", true, Cmd_mrs }, /* serial_no → rrs: + 12B ASCII */
|
|
{ "mrp?", true, Cmd_mrp }, /* passkey → rrp: + 6B */
|
|
{ "mrb?", true, Cmd_mrb }, /* bond_delete → rrb: + uint16 */
|
|
{ "mrr?", true, Cmd_mrr }, /* reset_status → rrr: + uint16 */
|
|
{ "mrc?", true, Cmd_mrc }, /* pd_adc_cnt → rrc: + uint16 */
|
|
{ "mrd?", true, Cmd_mrd }, /* pd_delay → rrd: + uint16 */
|
|
{ "mrg?", true, Cmd_mrg }, /* agc_gain → rrg: + 48*uint16 */
|
|
{ "mrl?", true, Cmd_mrl }, /* life_cycle → rrl: + uint32 */
|
|
|
|
/* O. Memory Write (dr_mem) */
|
|
{ "mwh?", true, Cmd_mwh }, /* hw_no ← 12B ASCII → rwh: + status */
|
|
{ "mws?", true, Cmd_mws }, /* serial_no ← 12B ASCII → rws: + status */
|
|
{ "mwp?", true, Cmd_mwp }, /* passkey ← 6B → rwp: + status */
|
|
{ "mwb?", true, Cmd_mwb }, /* bond_delete ← uint16 → rwb: + status */
|
|
{ "mwr?", true, Cmd_mwr }, /* reset_status ← uint16 → rwr: + status */
|
|
{ "mwc?", true, Cmd_mwc }, /* pd_adc_cnt ← uint16 → rwc: + status */
|
|
{ "mwd?", true, Cmd_mwd }, /* pd_delay ← uint16 → rwd: + status */
|
|
{ "mwg?", true, Cmd_mwg }, /* agc_gain ← 48*uint16 → rwg: + status */
|
|
{ "mwl?", true, Cmd_mwl }, /* life_cycle ← uint32 → rwl: + status */
|
|
};
|
|
|
|
const uint16_t g_cmd_count = (uint16_t)(sizeof(g_cmd_table) / sizeof(g_cmd_table[0]));
|
|
|
|
/*==============================================================================
|
|
* COMMAND HANDLER IMPLEMENTATIONS
|
|
*============================================================================*/
|
|
|
|
/* A. Device Status */
|
|
static int Cmd_mta(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t mode = 0;
|
|
|
|
resetCount = 0;
|
|
(void)cmd_get_u16(cmd, 0, &mode);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_mta] mode=%u\r\n", mode);
|
|
}
|
|
|
|
if (mode == 1) {
|
|
if (device_activated() == 0) {
|
|
device_status = true;
|
|
}
|
|
}
|
|
else if (mode == 0) {
|
|
if (device_status == true) {
|
|
if (device_sleep_mode() == 0) {
|
|
device_status = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_plat.tx_bin) {
|
|
single_format_data(ble_bin_buffer, "rta:", mode);
|
|
binary_tx_handler(ble_bin_buffer, 3);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sta(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t mode = 0;
|
|
|
|
resetCount = 0;
|
|
(void)cmd_get_u16(cmd, 0, &mode);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sta] mode=%u\r\n", mode);
|
|
}
|
|
|
|
if (mode == 1) {
|
|
if (device_activated() == 0) {
|
|
device_status = true;
|
|
}
|
|
}
|
|
else if (mode == 0) {
|
|
if (device_status == true) {
|
|
if (device_sleep_mode() == 0) {
|
|
device_status = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_plat.tx_bin) {
|
|
single_format_data(ble_bin_buffer, "sta:", mode);
|
|
binary_tx_handler(ble_bin_buffer, 3);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_str(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
uint8_t status = 1;
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_str] read status=%u\n", status);
|
|
}
|
|
|
|
if (g_plat.tx_bin) {
|
|
uint8_t resp[4] = { 'r','t','r', status };
|
|
g_plat.tx_bin(resp, 4);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mqq(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
simple_mesurement_start();
|
|
return 1;
|
|
}
|
|
|
|
/* B. AGC / Gain Measurement */
|
|
static int Cmd_mag(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_mag] Full AGC measurement request\r\n");
|
|
}
|
|
|
|
if (device_status != true) {
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_mag] ERROR: Device not activated\r\n");
|
|
}
|
|
if (g_plat.tx_bin) {
|
|
param_error("mag?");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
processing = true;
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_mag] full_agc_mesurement_start()\r\n");
|
|
}
|
|
|
|
full_agc_mesurement_start();
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sar(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sar] Read LED-PD gain array\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* C. LED Power / DP Value */
|
|
static int Cmd_ssa(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t led_index = 0;
|
|
(void)cmd_get_u16(cmd, 0, &led_index);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssa] LED index=%u\n", led_index);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sab(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sab] Read AGC-related LED data\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssb(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t led_index = 0;
|
|
uint16_t power = 0;
|
|
(void)cmd_get_u16(cmd, 0, &led_index);
|
|
(void)cmd_get_u16(cmd, 1, &power);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssb] LED index=%u, power=%u\n", led_index, power);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_srb(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_srb] Read all 48 LED DP values\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* D. LED On/Off & Gain Control */
|
|
static int Cmd_ssc(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t led_index = 0;
|
|
(void)cmd_get_u16(cmd, 0, &led_index);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssc] LED On/Off index=%u\n", led_index);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssd(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t on_off = 0;
|
|
(void)cmd_get_u16(cmd, 0, &on_off);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssd] AGC on_off=%u\n", on_off);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sse(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sse] Measure DAC voltage\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssf(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t led_index = 0;
|
|
uint16_t dac_value = 0;
|
|
(void)cmd_get_u16(cmd, 0, &led_index);
|
|
(void)cmd_get_u16(cmd, 1, &dac_value);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssf] Set LED DP DAC: index=%u, dac=%u\n", led_index, dac_value);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sif(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t dac_value = 0;
|
|
(void)cmd_get_u16(cmd, 0, &dac_value);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sif] Immediate gain set: dac=%u\n", dac_value);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssg(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t pd_index = 0;
|
|
(void)cmd_get_u16(cmd, 0, &pd_index);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssg] Set PD channel=%u\n", pd_index);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* E. Simple PD Measurement */
|
|
static int Cmd_ssh(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssh] Simple PD measurement start\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* F. PD-ADC M48 Full Measurement Series */
|
|
static int Cmd_mcj(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_mcj] PD-ADC M48 MODE=2 (Press + M48)\r\n");
|
|
}
|
|
|
|
if (device_status != true) {
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_mcj] ERROR: Device not activated\r\n");
|
|
}
|
|
if (g_plat.tx_bin) {
|
|
param_error("mcj?");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
ADC_PD_MODE = 2;
|
|
info4 = true;
|
|
ble_got_new_data = false;
|
|
processing = true;
|
|
|
|
pressure_all_level_meas();
|
|
AGC_GAIN_SW(false);
|
|
|
|
m48_samples_in_buffer = m_pd_adc_cnt;
|
|
pd_adc_m48_start = true;
|
|
battery_timer_stop();
|
|
|
|
go_batt = true;
|
|
motion_data_once = true;
|
|
main_timer_start();
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_mcj] Measurement started\r\n");
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sdj(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sdj] MODE=3 (M48 only)\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sej(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sej] MODE=4 (M48 + batt + IMU)\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sfj(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sfj] MODE=5 (M48 + init)\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssj(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssj] MODE=0 (M48 + batt/IMU combined)\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_szj(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t off_dac = 0;
|
|
uint16_t off_pd = 0;
|
|
(void)cmd_get_u16(cmd, 0, &off_dac);
|
|
(void)cmd_get_u16(cmd, 1, &off_pd);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_szj] FAST mode: off_dac=%u, off_pd=%u\n", off_dac, off_pd);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* G. IMM ADC */
|
|
static int Cmd_saj(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t led0 = 0, led1 = 0, led2 = 0, led3 = 0;
|
|
(void)cmd_get_u16(cmd, 0, &led0);
|
|
(void)cmd_get_u16(cmd, 1, &led1);
|
|
(void)cmd_get_u16(cmd, 2, &led2);
|
|
(void)cmd_get_u16(cmd, 3, &led3);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_saj] IMM ADC LEDs: %u,%u,%u,%u\n", led0, led1, led2, led3);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* H. PD-ADC Count & Delay */
|
|
static int Cmd_ssk(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t count = 0;
|
|
(void)cmd_get_u16(cmd, 0, &count);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssk] Set PD ADC count=%u\n", count);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_srk(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_srk] Read PD ADC count\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssl(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t delay_us = 0;
|
|
(void)cmd_get_u16(cmd, 0, &delay_us);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssl] Set PD delay=%u us\n", delay_us);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_srl(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_srl] Read PD delay\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* I. Sensor Measurements */
|
|
static int Cmd_msn(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_msn] Measure battery level\n");
|
|
}
|
|
low_battery_check = false; /* Ensure response is sent via BLE */
|
|
battery_level_meas();
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_spn(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_spn] Measure pressure1 & 2\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sso(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sso] Measure LED temperature\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssp(const ParsedCmd *cmd)
|
|
{
|
|
char mode = '1';
|
|
if (cmd->data_len > 0) {
|
|
mode = (char)cmd->data[0];
|
|
}
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssp] Motion sensor raw, mode='%c'\n", mode);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* J. Power / Reset / Version / Security */
|
|
static int Cmd_ssq(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssq] Power off\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssr(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssr] Bond delete\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sss(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sss] Device reset\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sst(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sst] Ready\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_ssv(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssv] Read firmware version\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* K. Serial / Passkey System */
|
|
static int Cmd_ssz(const ParsedCmd *cmd)
|
|
{
|
|
char serial[13];
|
|
cmd_get_ascii(cmd, 0, serial, 12);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_ssz] Write Serial='%s'\n", serial);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_spz(const ParsedCmd *cmd)
|
|
{
|
|
char pass[7];
|
|
cmd_get_ascii(cmd, 0, pass, 6);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_spz] Write Passkey='%s'\n", pass);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sqz(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sqz] Read Passkey\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_srz(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_srz] Read Serial Number\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* L. EEPROM UInt16 Array */
|
|
static int Cmd_sez(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t addr = 0;
|
|
(void)cmd_get_u16(cmd, 0, &addr);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sez] Write 48*uint16 at addr=0x%04X\n", addr);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sfz(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t addr = 0;
|
|
(void)cmd_get_u16(cmd, 0, &addr);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sfz] Read 48*uint16 from addr=0x%04X\n", addr);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sgz(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t addr = 0;
|
|
(void)cmd_get_u16(cmd, 0, &addr);
|
|
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sgz] Load DP preset from EEPROM addr=0x%04X\n", addr);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* M. Hardware No / Life Cycle */
|
|
static int Cmd_siz(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
char buf[12];
|
|
dr_memRead("hw_no", buf, 12);
|
|
ascii_format_data(ble_bin_buffer, "riz:", buf, 12);
|
|
binary_tx_handler(ble_bin_buffer, 8); /* (4+12)/2 = 8 words */
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_shz(const ParsedCmd *cmd)
|
|
{
|
|
char hw[13];
|
|
memset(hw, 0, sizeof(hw));
|
|
cmd_get_ascii(cmd, 0, hw, 12);
|
|
DBG_PRINTF("[shz] hw='%s'\r\n", hw);
|
|
ret_code_t err = dr_memWrite("hw_no", hw, 12);
|
|
dr_ble_return_1("rhz:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_sxz(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t hi = 0, lo = 0;
|
|
(void)cmd_get_u16(cmd, 0, &hi);
|
|
(void)cmd_get_u16(cmd, 1, &lo);
|
|
|
|
{
|
|
uint32_t life = ((uint32_t)hi << 16) | (uint32_t)lo;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_sxz] Write Life Cycle=%lu\n", (unsigned long)life);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_syz(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
if (g_plat.log && g_log_enable) {
|
|
g_plat.log("[Cmd_syz] Read Life Cycle\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* N. Memory Read (dr_mem) */
|
|
|
|
static int Cmd_mrh(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
char buf[12];
|
|
char tmp[13] = {0};
|
|
dr_memRead("hw_no", buf, 12);
|
|
memcpy(tmp, buf, 12);
|
|
DBG_PRINTF("[mrh] hw='%s' hex:%02X%02X%02X%02X\r\n", tmp,
|
|
(uint8_t)buf[0], (uint8_t)buf[1], (uint8_t)buf[2], (uint8_t)buf[3]);
|
|
ascii_format_data(ble_bin_buffer, "rrh:", buf, 12);
|
|
binary_tx_handler(ble_bin_buffer, 8); /* (4+12)/2 = 8 words */
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mrs(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
char buf[12];
|
|
char tmp[13] = {0};
|
|
dr_memRead("serial_no", buf, 12);
|
|
memcpy(tmp, buf, 12);
|
|
DBG_PRINTF("[mrs] sn='%s' hex:%02X%02X%02X%02X\r\n", tmp,
|
|
(uint8_t)buf[0], (uint8_t)buf[1], (uint8_t)buf[2], (uint8_t)buf[3]);
|
|
ascii_format_data(ble_bin_buffer, "rrs:", buf, 12);
|
|
binary_tx_handler(ble_bin_buffer, 8); /* (4+12)/2 = 8 words */
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mrp(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
uint8_t buf[6];
|
|
dr_memRead("passkey", buf, 6);
|
|
format_data_byte(ble_bin_buffer, "rrp:", buf, 6);
|
|
binary_tx_handler(ble_bin_buffer, 5); /* (4+6)/2 = 5 words */
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mrb(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
uint8_t val = 0;
|
|
dr_memRead("bond_delete", &val, 1);
|
|
dr_ble_return_1("rrb:", (uint16_t)val);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mrr(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
uint8_t val = 0;
|
|
dr_memRead("reset_status", &val, 1);
|
|
dr_ble_return_1("rrr:", (uint16_t)val);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mrc(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
uint8_t val = 0;
|
|
dr_memRead("pd_adc_cnt", &val, 1);
|
|
dr_ble_return_1("rrc:", (uint16_t)val);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mrd(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
uint16_t val = 0;
|
|
dr_memRead("pd_delay", &val, 2);
|
|
dr_ble_return_1("rrd:", val);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mrg(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
/* Read from RAM global (W25Q32 may not be initialized at boot) */
|
|
format_data(ble_bin_buffer, "rrg:", led_pd_dac_v, 48);
|
|
binary_tx_handler(ble_bin_buffer, 50); /* (4+96)/2 = 50 words */
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mrl(const ParsedCmd *cmd)
|
|
{
|
|
(void)cmd;
|
|
/* Read from RAM global (W25Q32 may not be initialized at boot) */
|
|
uint16_t hi = (uint16_t)(m_life_cycle >> 16);
|
|
uint16_t lo = (uint16_t)(m_life_cycle & 0xFFFF);
|
|
dr_ble_return_2("rrl:", hi, lo);
|
|
return 1;
|
|
}
|
|
|
|
/* N. Config Write Commands (mw* → rw* responses) */
|
|
|
|
static int Cmd_mwh(const ParsedCmd *cmd)
|
|
{
|
|
char hw[13];
|
|
memset(hw, 0, sizeof(hw));
|
|
cmd_get_ascii(cmd, 0, hw, 12);
|
|
ret_code_t err = dr_memWrite("hw_no", hw, 12);
|
|
dr_ble_return_1("rwh:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mws(const ParsedCmd *cmd)
|
|
{
|
|
char serial[13];
|
|
memset(serial, 0, sizeof(serial));
|
|
cmd_get_ascii(cmd, 0, serial, 12);
|
|
DBG_PRINTF("[mws] serial='%s'\r\n", serial);
|
|
|
|
ret_code_t err = dr_memWrite("serial_no", serial, 12);
|
|
dr_ble_return_1("rws:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mwp(const ParsedCmd *cmd)
|
|
{
|
|
char pass[7];
|
|
memset(pass, 0, sizeof(pass));
|
|
cmd_get_ascii(cmd, 0, pass, 6);
|
|
ret_code_t err = dr_memWrite("passkey", pass, 6);
|
|
dr_ble_return_1("rwp:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mwb(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t val = 0;
|
|
(void)cmd_get_u16(cmd, 0, &val);
|
|
uint8_t u8val = (uint8_t)val;
|
|
ret_code_t err = dr_memWrite("bond_delete", &u8val, 1);
|
|
dr_ble_return_1("rwb:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mwr(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t val = 0;
|
|
(void)cmd_get_u16(cmd, 0, &val);
|
|
uint8_t u8val = (uint8_t)val;
|
|
ret_code_t err = dr_memWrite("reset_status", &u8val, 1);
|
|
dr_ble_return_1("rwr:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mwc(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t val = 0;
|
|
(void)cmd_get_u16(cmd, 0, &val);
|
|
uint8_t u8val = (uint8_t)val;
|
|
ret_code_t err = dr_memWrite("pd_adc_cnt", &u8val, 1);
|
|
m_pd_adc_cnt = u8val;
|
|
dr_ble_return_1("rwc:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mwd(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t val = 0;
|
|
(void)cmd_get_u16(cmd, 0, &val);
|
|
ret_code_t err = dr_memWrite("pd_delay", &val, 2);
|
|
m_pd_delay_us = val;
|
|
dr_ble_return_1("rwd:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mwg(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t gains[48];
|
|
uint8_t i;
|
|
for (i = 0; i < 48; i++) {
|
|
if (!cmd_get_u16(cmd, i, &gains[i])) {
|
|
gains[i] = 0;
|
|
}
|
|
}
|
|
ret_code_t err = dr_memWrite("agc_gain", gains, sizeof(gains));
|
|
/* Update RAM copy */
|
|
for (i = 0; i < 48; i++) {
|
|
led_pd_dac_v[i] = gains[i];
|
|
}
|
|
dr_ble_return_1("rwg:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
static int Cmd_mwl(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t hi = 0, lo = 0;
|
|
(void)cmd_get_u16(cmd, 0, &hi);
|
|
(void)cmd_get_u16(cmd, 1, &lo);
|
|
uint32_t life = ((uint32_t)hi << 16) | (uint32_t)lo;
|
|
ret_code_t err = dr_memWrite("life_cycle", &life, 4);
|
|
m_life_cycle = life;
|
|
dr_ble_return_1("rwl:", err == NRF_SUCCESS ? 0 : 1);
|
|
return 1;
|
|
}
|
|
|
|
/* O. Debug / Test */
|
|
static int Cmd_cmd(const ParsedCmd *cmd)
|
|
{
|
|
uint16_t v1, v2, v3;
|
|
uint32_t pin_number;
|
|
|
|
DBG_PRINTF("[CMD] cmd? received, data_len=%u\r\n", cmd->data_len);
|
|
|
|
if (cmd->data_len < 6) {
|
|
DBG_PRINTF("[CMD] data_len < 6, return 0\r\n");
|
|
dr_ble_return_1("rmd:", 0);
|
|
return 1;
|
|
}
|
|
|
|
v1 = (uint16_t)cmd->data[0] | ((uint16_t)cmd->data[1] << 8);
|
|
v2 = (uint16_t)cmd->data[2] | ((uint16_t)cmd->data[3] << 8);
|
|
v3 = (uint16_t)cmd->data[4] | ((uint16_t)cmd->data[5] << 8);
|
|
|
|
DBG_PRINTF("[CMD] v1=%u v2=%u v3=%u\r\n", v1, v2, v3);
|
|
|
|
/* v1=99: Flash Test */
|
|
if (v1 == 99) {
|
|
DBG_PRINTF("[CMD] Flash Test Start!\r\n");
|
|
uint16_t result = 0;
|
|
if (w25q32_init()) {
|
|
result = 1; /* Success */
|
|
DBG_PRINTF("[CMD] Flash Test OK\r\n");
|
|
} else {
|
|
DBG_PRINTF("[CMD] Flash Test FAIL\r\n");
|
|
}
|
|
dr_ble_return_1("rmd:", result);
|
|
return 1;
|
|
}
|
|
|
|
/* Default: GPIO Test */
|
|
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;
|
|
}
|