/*******************************************************************************
 * @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;
}
