/*
 * 配置相关
 */

/* Includes ----------------------------------------------------------------- */
#include "module/config.h"
#include <stdbool.h>
#include "bsp/flash.h"
#include <string.h>
#include "device/sx1281_driver/sx1281.h"
/* Private typedef ---------------------------------------------------------- */
/* Private define ----------------------------------------------------------- */
/* Private macro ------------------------------------------------------------ */
/* Private variables -------------------------------------------------------- */

/* Exported variables ------------------------------------------------------- */

// 机器人参数配置
Config_t robot_config = {
  0
};

/* Private function prototypes ---------------------------------------------- */
/* Exported functions ------------------------------------------------------- */

/**
 * @brief 获取机器人配置参数
 * @return 机器人配置参数指针
 */
Config_t* Config_Get(void) {
    return &robot_config;
}

/**
 * @brief Validate MR16 parameter values read from flash
 * @param p MR16_Param_t pointer to validate
 * @return true if values look valid, false otherwise
 */
/* Helper validators for sparse enums */
static bool is_valid_gfsk_ble_bitrate(uint8_t v) {
  switch (v) {
    case GFS_BLE_BR_2_000_BW_2_4:
    case GFS_BLE_BR_1_600_BW_2_4:
    case GFS_BLE_BR_1_000_BW_2_4:
    case GFS_BLE_BR_1_000_BW_1_2:
    case GFS_BLE_BR_0_800_BW_2_4:
    case GFS_BLE_BR_0_800_BW_1_2:
    case GFS_BLE_BR_0_500_BW_1_2:
    case GFS_BLE_BR_0_500_BW_0_6:
    case GFS_BLE_BR_0_400_BW_1_2:
    case GFS_BLE_BR_0_400_BW_0_6:
    case GFS_BLE_BR_0_250_BW_0_6:
    case GFS_BLE_BR_0_250_BW_0_3:
    case GFS_BLE_BR_0_125_BW_0_3:
      return true;
    default:
      return false;
  }
}

static bool is_valid_flrc_bitrate(uint8_t v) {
  switch (v) {
    case FLRC_BR_2_600_BW_2_4:
    case FLRC_BR_2_080_BW_2_4:
    case FLRC_BR_1_300_BW_1_2:
    case FLRC_BR_1_040_BW_1_2:
    case FLRC_BR_0_650_BW_0_6:
    case FLRC_BR_0_520_BW_0_6:
    case FLRC_BR_0_325_BW_0_3:
    case FLRC_BR_0_260_BW_0_3:
      return true;
    default:
      return false;
  }
}

static bool is_valid_lora_sf(uint8_t v) {
  switch (v) {
    case LORA_SF5: case LORA_SF6: case LORA_SF7: case LORA_SF8:
    case LORA_SF9: case LORA_SF10: case LORA_SF11: case LORA_SF12:
      return true;
    default:
      return false;
  }
}

static bool is_valid_lora_bw(uint8_t v) {
  switch (v) {
    case LORA_BW_0200: case LORA_BW_0400: case LORA_BW_0800: case LORA_BW_1600:
      return true;
    default:
      return false;
  }
}

static bool is_valid_mod_shaping(uint8_t v) {
  switch (v) {
    case RADIO_MOD_SHAPING_BT_OFF: case RADIO_MOD_SHAPING_BT_1_0: case RADIO_MOD_SHAPING_BT_0_5:
      return true;
    default:
      return false;
  }
}

static bool Config_ValidateMR16(const MR16_Param_t *p) {
  if (p == NULL) return false;

  /* Basic sanity checks */
  if (p->TX_ID <= 0x0000 || p->TX_ID >= 0xFFFF) return false;

  /* RF frequency should be within 2.4GHz ISM band (2400..2500 MHz) */
  if (p->radioParams.rfFrequency < 2400000000ULL || p->radioParams.rfFrequency > 2500000000ULL) return false;

  /* TX power reasonable check per SX1281 datasheet (-18dBm to +13dBm) */
  if (p->radioParams.txOutputPower < -18 || p->radioParams.txOutputPower > 13) return false;

  /* Data format must be in enum range */
  if (p->format >= MR16_FORMAT_NUM) return false;
  
  /* Fixed length must be reasonable (1..123 bytes, max 127 - Header(2) - CRC(2)) */
  if (p->fixedLength < 1 || p->fixedLength > 123) return false;

  /* Validate ramp time enum (must be one of defined values) */
  switch (p->radioParams.rampTime) {
    case RADIO_RAMP_02_US: case RADIO_RAMP_04_US: case RADIO_RAMP_06_US: case RADIO_RAMP_08_US:
    case RADIO_RAMP_10_US: case RADIO_RAMP_12_US: case RADIO_RAMP_16_US: case RADIO_RAMP_20_US:
      break;
    default:
      return false;
  }

  /* Validate baudrate enums */
  if (p->radioParams.baudrate.ble >= RF_BAUDRATE_BLE_NUM) return false;
  if (p->radioParams.baudrate.lora >= RF_BAUDRATE_LORA_NUM) return false;
  if (p->radioParams.baudrate.gfks >= RF_BAUDRATE_GFSK_NUM) return false;
  if (p->radioParams.baudrate.flrc >= RF_BAUDRATE_FLRC_NUM) return false;

  /* PacketType consistency: modulation & packet params must agree */
  // if (p->radioParams.modulationParams.PacketType != p->radioParams.packetParams.PacketType) return false;

  /* Validate modulation parameters based on packet type */
  switch (p->radioParams.modulationParams.PacketType) {
    case PACKET_TYPE_BLE:
      if (!is_valid_gfsk_ble_bitrate((uint8_t)p->radioParams.modulationParams.Params.Ble.BitrateBandwidth)) return false;
      if (p->radioParams.modulationParams.Params.Ble.ModulationIndex > GFS_BLE_MOD_IND_4_00) return false;
      if (!is_valid_mod_shaping((uint8_t)p->radioParams.modulationParams.Params.Ble.ModulationShaping)) return false;
      break;

    case PACKET_TYPE_GFSK:
      if (!is_valid_gfsk_ble_bitrate((uint8_t)p->radioParams.modulationParams.Params.Gfsk.BitrateBandwidth)) return false;
      if (p->radioParams.modulationParams.Params.Gfsk.ModulationIndex > GFS_BLE_MOD_IND_4_00) return false;
      if (!is_valid_mod_shaping((uint8_t)p->radioParams.modulationParams.Params.Gfsk.ModulationShaping)) return false;
      break;

    case PACKET_TYPE_LORA:
      if (!is_valid_lora_sf((uint8_t)p->radioParams.modulationParams.Params.LoRa.SpreadingFactor)) return false;
      if (!is_valid_lora_bw((uint8_t)p->radioParams.modulationParams.Params.LoRa.Bandwidth)) return false;
      if (p->radioParams.modulationParams.Params.LoRa.CodingRate < LORA_CR_4_5 ||
          p->radioParams.modulationParams.Params.LoRa.CodingRate > LORA_CR_LI_4_7) return false;
      break;

    case PACKET_TYPE_FLRC:
      if (!is_valid_flrc_bitrate((uint8_t)p->radioParams.modulationParams.Params.Flrc.BitrateBandwidth)) return false;
      if (p->radioParams.modulationParams.Params.Flrc.CodingRate > FLRC_CR_1_0) return false;
      if (!is_valid_mod_shaping((uint8_t)p->radioParams.modulationParams.Params.Flrc.ModulationShaping)) return false;
      break;

    default:
      return false;
  }

  /* Validate packet parameters based on packet type */
  switch (p->radioParams.packetParams.PacketType) {
    case PACKET_TYPE_BLE:
      if (p->radioParams.packetParams.Params.Ble.BlePacketType > BLE_RXTX_TEST_MODE) return false;
      if (p->radioParams.packetParams.Params.Ble.ConnectionState > BLE_RXTX_TEST_MODE) return false;
      if (p->radioParams.packetParams.Params.Ble.CrcField != BLE_CRC_3B && p->radioParams.packetParams.Params.Ble.CrcField != BLE_CRC_OFF) return false;
      if (p->radioParams.packetParams.Params.Ble.Whitening != RADIO_WHITENING_ON && p->radioParams.packetParams.Params.Ble.Whitening != RADIO_WHITENING_OFF) return false;
      break;

    case PACKET_TYPE_GFSK:
      switch (p->radioParams.packetParams.Params.Gfsk.PreambleLength) {
        case PREAMBLE_LENGTH_04_BITS: case PREAMBLE_LENGTH_08_BITS: case PREAMBLE_LENGTH_12_BITS: case PREAMBLE_LENGTH_16_BITS:
        case PREAMBLE_LENGTH_20_BITS: case PREAMBLE_LENGTH_24_BITS: case PREAMBLE_LENGTH_28_BITS: case PREAMBLE_LENGTH_32_BITS:
          break;
        default: return false;
      }
      switch (p->radioParams.packetParams.Params.Gfsk.SyncWordLength) {
        case GFS_SYNCWORD_LENGTH_1_BYTE: case GFS_SYNCWORD_LENGTH_2_BYTE: case GFS_SYNCWORD_LENGTH_3_BYTE:
        case GFS_SYNCWORD_LENGTH_4_BYTE: case GFS_SYNCWORD_LENGTH_5_BYTE: break;
        default: return false;
      }
      switch (p->radioParams.packetParams.Params.Gfsk.SyncWordMatch) {
        case RADIO_RX_MATCH_SYNCWORD_OFF: case RADIO_RX_MATCH_SYNCWORD_1: case RADIO_RX_MATCH_SYNCWORD_2: case RADIO_RX_MATCH_SYNCWORD_1_2:
        case RADIO_RX_MATCH_SYNCWORD_3: case RADIO_RX_MATCH_SYNCWORD_1_3: case RADIO_RX_MATCH_SYNCWORD_2_3: case RADIO_RX_MATCH_SYNCWORD_1_2_3:
          break;
        default: return false;
      }
      if (p->radioParams.packetParams.Params.Gfsk.HeaderType != RADIO_PACKET_VARIABLE_LENGTH && p->radioParams.packetParams.Params.Gfsk.HeaderType != RADIO_PACKET_FIXED_LENGTH) return false;
      if (p->radioParams.packetParams.Params.Gfsk.PayloadLength == 0 || p->radioParams.packetParams.Params.Gfsk.PayloadLength > 255) return false;
      switch (p->radioParams.packetParams.Params.Gfsk.CrcLength) {
        case RADIO_CRC_OFF: case RADIO_CRC_1_BYTES: case RADIO_CRC_2_BYTES: case RADIO_CRC_3_BYTES: break;
        default: return false;
      }
      if (p->radioParams.packetParams.Params.Gfsk.Whitening != RADIO_WHITENING_ON && p->radioParams.packetParams.Params.Gfsk.Whitening != RADIO_WHITENING_OFF) return false;
      break;

    case PACKET_TYPE_LORA:
      if (p->radioParams.packetParams.Params.LoRa.PreambleLength == 0 || p->radioParams.packetParams.Params.LoRa.PreambleLength > 65535) return false;
      if (p->radioParams.packetParams.Params.LoRa.HeaderType != LORA_PACKET_VARIABLE_LENGTH && p->radioParams.packetParams.Params.LoRa.HeaderType != LORA_PACKET_FIXED_LENGTH) return false;
      if (p->radioParams.packetParams.Params.LoRa.PayloadLength == 0 || p->radioParams.packetParams.Params.LoRa.PayloadLength > 255) return false;
      if (p->radioParams.packetParams.Params.LoRa.CrcMode != LORA_CRC_ON && p->radioParams.packetParams.Params.LoRa.CrcMode != LORA_CRC_OFF) return false;
      if (p->radioParams.packetParams.Params.LoRa.InvertIQ != LORA_IQ_NORMAL && p->radioParams.packetParams.Params.LoRa.InvertIQ != LORA_IQ_INVERTED) return false;
      break;

    case PACKET_TYPE_FLRC:
      switch (p->radioParams.packetParams.Params.Flrc.PreambleLength) {
        case PREAMBLE_LENGTH_04_BITS: case PREAMBLE_LENGTH_08_BITS: case PREAMBLE_LENGTH_12_BITS: case PREAMBLE_LENGTH_16_BITS:
        case PREAMBLE_LENGTH_20_BITS: case PREAMBLE_LENGTH_24_BITS: case PREAMBLE_LENGTH_28_BITS: case PREAMBLE_LENGTH_32_BITS:
          break;
        default: return false;
      }
      if (p->radioParams.packetParams.Params.Flrc.SyncWordLength != FLRC_NO_SYNCWORD && p->radioParams.packetParams.Params.Flrc.SyncWordLength != FLRC_SYNCWORD_LENGTH_4_BYTE) return false;
      switch (p->radioParams.packetParams.Params.Flrc.SyncWordMatch) {
        case RADIO_RX_MATCH_SYNCWORD_OFF: case RADIO_RX_MATCH_SYNCWORD_1: case RADIO_RX_MATCH_SYNCWORD_2: case RADIO_RX_MATCH_SYNCWORD_1_2:
        case RADIO_RX_MATCH_SYNCWORD_3: case RADIO_RX_MATCH_SYNCWORD_1_3: case RADIO_RX_MATCH_SYNCWORD_2_3: case RADIO_RX_MATCH_SYNCWORD_1_2_3:
          break;
        default: return false;
      }
      if (p->radioParams.packetParams.Params.Flrc.HeaderType != RADIO_PACKET_VARIABLE_LENGTH && p->radioParams.packetParams.Params.Flrc.HeaderType != RADIO_PACKET_FIXED_LENGTH) return false;
      if (p->radioParams.packetParams.Params.Flrc.PayloadLength == 0 || p->radioParams.packetParams.Params.Flrc.PayloadLength > 255) return false;
      switch (p->radioParams.packetParams.Params.Flrc.CrcLength) {
        case RADIO_CRC_OFF: case RADIO_CRC_1_BYTES: case RADIO_CRC_2_BYTES: case RADIO_CRC_3_BYTES: break;
        default: return false;
      }
      /* FLRC whitening handled in packetParams, allowed values validated above */
      break;

    default:
      return false;
  }

  /* RX_ID array: each ID must be within valid 16-bit range; 0xFFFF reserved invalid, 0x0000 allowed (broadcast) */
  for (int i = 0; i < 3; ++i) {
    if (p->RX_ID[i] == 0xFFFF) return false;
  }

  return true;
}

/**
 * @brief Try to load MR16 parameters from Flash and validate them.
 *        If valid, copy into runtime config and return pointer; otherwise return NULL.
 * @return pointer to `robot_config.mr16` on success, NULL on invalid/missing flash data
 */ 
Config_t* Config_LoadMR16FromFlash(void) {
  /* Read complete config from flash directly to robot_config (STMFLASH_Read expects half-words count) */
  STMFLASH_Read(FLASH_SAVE_ADDR, (uint16_t*)&robot_config, sizeof(Config_t)/2);
  if (Config_ValidateMR16(&robot_config.mr16)) {
    return &robot_config;
  }
  return NULL;
}

/**
 * @brief Read MR16 params from flash and validate them.
 *        If valid, copy into runtime config and return true; otherwise return false.
 * @return true if flash contained valid MR16 params and they were loaded into config
 */
bool Config_LoadMR16FromFlashBool(void) {
  STMFLASH_Read(FLASH_SAVE_ADDR, (uint16_t*)&robot_config, sizeof(Config_t)/2);
  if (Config_ValidateMR16(&robot_config.mr16)) {
    return true;
  }
  return false;
}



/**
 * @brief Load MR16 parameters from flash (assumes flash is valid)
 */
void Config_LoadFromFlash(void) {
  STMFLASH_Read(FLASH_SAVE_ADDR, (uint16_t*)&robot_config, sizeof(Config_t)/2);
}

/**
 * @brief Set default values for MR16 parameters
 */
void Config_SetDefaults(void) {
  /* MR16 defaults */
  robot_config.mr16.TX_ID = 0x0001;
  robot_config.mr16.RX_ID[0] = 0x0001;
  robot_config.mr16.RX_ID[1] = 0x0002;
  robot_config.mr16.RX_ID[2] = 0x0003;
  robot_config.mr16.format = MR16_FORMAT_FIXED;  /* 默认使用固定长度格式 */
  robot_config.mr16.fixedLength = MR16_DEFAULT_FIXED_LEN;  /* 默认14字节(用户数据+CRC) */
  robot_config.mr16.radioParams.RadioRole = RadioRoleTX;
  /* Radio defaults */
  robot_config.mr16.radioParams.rfFrequency = 2426000000;
  robot_config.mr16.radioParams.txOutputPower = 13;
  robot_config.mr16.radioParams.rampTime = RADIO_RAMP_02_US;
  robot_config.mr16.radioParams.radioMode = RADIOMODE_FLRC;
  /* Baudrate defaults - high-level user configurations */
  robot_config.mr16.radioParams.baudrate.ble = RF_BAUDRATE_BLE_1M;
  robot_config.mr16.radioParams.baudrate.lora = RF_BAUDRATE_LORA_005K;
  robot_config.mr16.radioParams.baudrate.gfks = RF_BAUDRATE_GFSK_125K;
  robot_config.mr16.radioParams.baudrate.flrc = RF_BAUDRATE_FLRC_130K;
  
  /* Set detailed modulation parameters to default values based on baudrate */
  /* BLE parameters */
  robot_config.mr16.radioParams.modulationParams.Params.Ble.BitrateBandwidth = GFS_BLE_BR_1_000_BW_2_4;  // Default for RF_BAUDRATE_BLE_1M
  robot_config.mr16.radioParams.modulationParams.Params.Ble.ModulationIndex = GFS_BLE_MOD_IND_0_50;
  robot_config.mr16.radioParams.modulationParams.Params.Ble.ModulationShaping = RADIO_MOD_SHAPING_BT_0_5;
  robot_config.mr16.radioParams.packetParams.Params.Ble.BlePacketType = BLE_EYELONG_1_0;
  robot_config.mr16.radioParams.packetParams.Params.Ble.ConnectionState = BLE_ADVERTISER;
  robot_config.mr16.radioParams.packetParams.Params.Ble.CrcField = BLE_CRC_3B;
  robot_config.mr16.radioParams.packetParams.Params.Ble.Whitening = RADIO_WHITENING_ON;
  
  /* LoRa parameters */
  robot_config.mr16.radioParams.modulationParams.Params.LoRa.SpreadingFactor = LORA_SF12;
  robot_config.mr16.radioParams.modulationParams.Params.LoRa.Bandwidth = LORA_BW_0200;
  robot_config.mr16.radioParams.modulationParams.Params.LoRa.CodingRate = LORA_CR_LI_4_7;
  robot_config.mr16.radioParams.packetParams.Params.LoRa.PreambleLength = 12;
  robot_config.mr16.radioParams.packetParams.Params.LoRa.HeaderType = LORA_PACKET_VARIABLE_LENGTH;
  robot_config.mr16.radioParams.packetParams.Params.LoRa.PayloadLength = BUFFER_SIZE;
  robot_config.mr16.radioParams.packetParams.Params.LoRa.CrcMode = LORA_CRC_ON;
  robot_config.mr16.radioParams.packetParams.Params.LoRa.InvertIQ = LORA_IQ_NORMAL;
  
  /* GFSK parameters */
  robot_config.mr16.radioParams.modulationParams.Params.Gfsk.BitrateBandwidth = GFS_BLE_BR_0_125_BW_0_3;
  robot_config.mr16.radioParams.modulationParams.Params.Gfsk.ModulationIndex = GFS_BLE_MOD_IND_0_50;
  robot_config.mr16.radioParams.modulationParams.Params.Gfsk.ModulationShaping = RADIO_MOD_SHAPING_BT_0_5;
  robot_config.mr16.radioParams.packetParams.Params.Gfsk.PreambleLength = PREAMBLE_LENGTH_32_BITS;
  robot_config.mr16.radioParams.packetParams.Params.Gfsk.SyncWordLength = GFS_SYNCWORD_LENGTH_5_BYTE;
  robot_config.mr16.radioParams.packetParams.Params.Gfsk.SyncWordMatch = RADIO_RX_MATCH_SYNCWORD_1;
  robot_config.mr16.radioParams.packetParams.Params.Gfsk.HeaderType = RADIO_PACKET_VARIABLE_LENGTH;
  robot_config.mr16.radioParams.packetParams.Params.Gfsk.PayloadLength = BUFFER_SIZE;
  robot_config.mr16.radioParams.packetParams.Params.Gfsk.CrcLength = RADIO_CRC_3_BYTES;
  robot_config.mr16.radioParams.packetParams.Params.Gfsk.Whitening = RADIO_WHITENING_ON;
  
  /* FLRC parameters */
  robot_config.mr16.radioParams.modulationParams.Params.Flrc.BitrateBandwidth = FLRC_BR_0_260_BW_0_3;
  robot_config.mr16.radioParams.modulationParams.Params.Flrc.CodingRate = FLRC_CR_1_2;
  robot_config.mr16.radioParams.modulationParams.Params.Flrc.ModulationShaping = RADIO_MOD_SHAPING_BT_1_0;
  robot_config.mr16.radioParams.packetParams.Params.Flrc.PreambleLength = PREAMBLE_LENGTH_32_BITS;
  robot_config.mr16.radioParams.packetParams.Params.Flrc.SyncWordLength = FLRC_SYNCWORD_LENGTH_4_BYTE;
  robot_config.mr16.radioParams.packetParams.Params.Flrc.SyncWordMatch = RADIO_RX_MATCH_SYNCWORD_1;
  robot_config.mr16.radioParams.packetParams.Params.Flrc.HeaderType = RADIO_PACKET_VARIABLE_LENGTH;
  robot_config.mr16.radioParams.packetParams.Params.Flrc.PayloadLength = BUFFER_SIZE;
  robot_config.mr16.radioParams.packetParams.Params.Flrc.CrcLength = RADIO_CRC_3_BYTES;
  robot_config.mr16.radioParams.packetParams.Params.Flrc.Whitening = RADIO_WHITENING_OFF;
  
  /* Sync Word defaults */
  /* GFSK sync words (5 bytes each) */
  const uint8_t gfsk_sync1[5] = {0x12, 0x34, 0x56, 0x78, 0x9A};
  const uint8_t gfsk_sync2[5] = {0x23, 0x45, 0x67, 0x89, 0xAB};
  const uint8_t gfsk_sync3[5] = {0x34, 0x56, 0x78, 0x9A, 0xBC};
  memcpy(robot_config.mr16.radioParams.syncWord.gfsk.first, gfsk_sync1, 5);
  memcpy(robot_config.mr16.radioParams.syncWord.gfsk.second, gfsk_sync2, 5);
  memcpy(robot_config.mr16.radioParams.syncWord.gfsk.third, gfsk_sync3, 5);
  
  /* FLRC sync words (4 bytes each) */
  const uint8_t flrc_sync1[4] = {0x12, 0x23, 0x34, 0x45};
  const uint8_t flrc_sync2[4] = {0x56, 0x67, 0x78, 0x89};
  const uint8_t flrc_sync3[4] = {0x9A, 0xAB, 0xBC, 0xCD};
  memcpy(robot_config.mr16.radioParams.syncWord.flrc.first, flrc_sync1, 4);
  memcpy(robot_config.mr16.radioParams.syncWord.flrc.second, flrc_sync2, 4);
  memcpy(robot_config.mr16.radioParams.syncWord.flrc.third, flrc_sync3, 4);
}