/*
 * STM32F407 串口双向透传
 * ------------------------------------------------------------
 * 485主机接口  : PB6(RX)/PB7(TX)/PB5(EN)  9600
 * 井下数据口   : PA2(TX)/PA3(RX)  300 (软件 bit-bang 发送)
 * 调试口       : PA9/PA10(USART1) 9600
 *
 * 调试开关: DBG 改 0 关闭全部调试打印
 */

#include <Arduino.h>
#include <SoftwareSerial.h>

// ==================== 调试开关 ====================
#define DBG 1

#if DBG
  #define DBG_PRINT(x)     Serial1.print(x)
  #define DBG_PRINTLN(x)   Serial1.println(x)
  #define DBG_PRINTHEX(x)  do { if ((x) < 0x10) Serial1.print('0'); Serial1.print((x), HEX); } while (0)
#else
  #define DBG_PRINT(x)     do { } while (0)
  #define DBG_PRINTLN(x)   do { } while (0)
  #define DBG_PRINTHEX(x)  do { } while (0)
#endif

// ==================== 硬件配置 ====================
#define RS485_RX PB7
#define RS485_TX PB6
#define RS485_EN PB5

#define EEPROM_BASE   0x080E0000
#define EEPROM_SECTOR 11

// ==================== 引脚定义 ====================
#define CL_0 PB0
#define CL_1 PB1
#define KZ   PE10

#define ENCODE_PB2 PB2
#define ENCODE_PE7 PE7
#define ENCODE_PE8 PE8
#define ENCODE_PE9 PE9

#define ADC1_PIN PA5
#define DS_PIN   PA6
#define CS_PIN   PA7

#define PCODE_PIN PA1
#define NCODE_PIN PA0

#define LED_PIN PD6

// 井下口 (软件 bit-bang)
#define JX_TX_PIN PA2
#define JX_RX_PIN PA3
#define JX_BAUD   300UL

// ==================== 串口对象 ====================
Uart Serial1(USART1);                       // 调试口
SoftwareSerial rs485(RS485_RX, RS485_TX);   // RS485

// ==================== 协议常量 ====================
static const uint8_t  PROTO_ADDR_AA       = 0xAA;
static const uint8_t  FUNC_READ_HOLDING   = 0x03;
static const uint8_t  FUNC_WRITE_MULTI    = 0x10;

static const uint16_t REG_VOLTAGE_CURRENT = 0x0018;
static const uint16_t REG_CABLE_LENGTH    = 0x0020;
static const uint16_t REG_GAIN            = 0x0021;

static const int MAX_FRAME_LEN = 30;
static const int MIN_FRAME_LEN = 8;

// ==================== 全局配置缓存 ====================
uint8_t cdzyBuf[4];

// ==================== 调试计数器 ====================
static uint32_t g_frameCnt = 0;
static uint32_t g_jxTxCnt  = 0;
static uint32_t g_rsTxCnt  = 0;

// ==================== 前置声明 ====================
void processReceivedData(uint8_t* data, int length);

// ============================================================
// RS485 方向控制
// ============================================================
static inline void rs485SetReceive() {
  digitalWrite(RS485_EN, LOW);
  delayMicroseconds(10);
}

static inline void rs485SetTransmit() {
  digitalWrite(RS485_EN, HIGH);
  delayMicroseconds(10);
}

// ============================================================
// RS485 发送
// ============================================================
void rs485WriteBuffer(const uint8_t* buf, uint16_t len) {
  g_rsTxCnt++;
  DBG_PRINT("[485] TX cnt=");
  DBG_PRINT(g_rsTxCnt);
  DBG_PRINT(" len=");
  DBG_PRINTLN(len);

  rs485SetTransmit();
  rs485.write(buf, len);
  rs485.flush();
  delay(1);
  rs485SetReceive();

  DBG_PRINTLN("[485] TX done");
}

// ============================================================
// PA2 软件 bit-bang 发送 (300bps)
// ============================================================
static void jxSendByte(uint8_t b) {
  uint32_t bitUs = 1000000UL / JX_BAUD;   // 3333us

  // 起始位
  digitalWrite(JX_TX_PIN, LOW);
  delayMicroseconds(bitUs);

  // 8 个数据位 (LSB first)
  for (int i = 0; i < 8; i++) {
    digitalWrite(JX_TX_PIN, (b >> i) & 1);
    delayMicroseconds(bitUs);
  }

  // 停止位
  digitalWrite(JX_TX_PIN, HIGH);
  delayMicroseconds(bitUs);
}

static void jxSendBuffer(const uint8_t* data, int length) {
  for (int i = 0; i < length; i++) {
    jxSendByte(data[i]);
  }
}

// ============================================================
// 透传到井下口
// ============================================================
static void forwardToDownhole(uint8_t* data, int length) {
  g_jxTxCnt++;
  DBG_PRINT("[JX] forward #");
  DBG_PRINT(g_jxTxCnt);
  DBG_PRINT(" len=");
  DBG_PRINTLN(length);

  pinMode(JX_TX_PIN, OUTPUT);
  digitalWrite(JX_TX_PIN, HIGH);
  delayMicroseconds(10);

  jxSendBuffer(data, length);

  // 发送完毕, 让 PA2 空闲为高电平 (空闲态)
  digitalWrite(JX_TX_PIN, HIGH);
}

// ============================================================
// Flash 读写
// ============================================================
void saveData(const uint8_t* data, uint16_t len) {
  HAL_FLASH_Unlock();
  FLASH_EraseInitTypeDef e = {};
  e.TypeErase    = FLASH_TYPEERASE_SECTORS;
  e.Sector       = EEPROM_SECTOR;
  e.NbSectors    = 1;
  e.VoltageRange = FLASH_VOLTAGE_RANGE_3;
  uint32_t err;
  HAL_FLASHEx_Erase(&e, &err);
  for (uint16_t i = 0; i < len; i += 2) {
    uint16_t w = data[i];
    if (i + 1 < len) w |= (data[i + 1] << 8);
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, EEPROM_BASE + i, w);
  }
  HAL_FLASH_Lock();
}

void loadData(uint8_t* buf, uint16_t len) {
  for (uint16_t i = 0; i < len; i++) {
    buf[i] = *(volatile uint8_t*)(EEPROM_BASE + i);
  }
}

// ============================================================
// GPIO 控制
// ============================================================
void setCableLength(uint8_t val) {
  digitalWrite(CL_0, (val >> 0) & 0x01);
  digitalWrite(CL_1, (val >> 1) & 0x01);
}

void setGain(uint8_t val) {
  digitalWrite(ENCODE_PE9, (val >> 0) & 0x01);
  digitalWrite(ENCODE_PE8, (val >> 1) & 0x01);
  digitalWrite(ENCODE_PE7, (val >> 2) & 0x01);
  digitalWrite(ENCODE_PB2, (val >> 3) & 0x01);
}

// ============================================================
// 超时接收
// ============================================================
bool readWithTimeout(Stream& port, uint8_t* buffer, uint16_t maxLen,
                     uint16_t* len, uint32_t timeoutMs) {
  *len = 0;
  if (!buffer || maxLen == 0) return false;
  if (!port.available()) return false;

  uint32_t start = millis();
  while (*len < maxLen && (millis() - start) < timeoutMs) {
    if (port.available()) {
      buffer[(*len)++] = port.read();
      start = millis();
    }
    delayMicroseconds(50);
  }
  return (*len > 0);
}

// ============================================================
// Modbus CRC16
// ============================================================
uint16_t modbusCRC16(const uint8_t* data, uint16_t len) {
  uint16_t crc = 0xFFFF;
  for (uint16_t i = 0; i < len; i++) {
    crc ^= data[i];
    for (uint8_t j = 0; j < 8; j++) {
      if (crc & 0x0001) { crc >>= 1; crc ^= 0xA001; }
      else { crc >>= 1; }
    }
  }
  return crc;
}

static void appendCRC(uint8_t* buf, uint16_t payloadLen) {
  uint16_t crc = modbusCRC16(buf, payloadLen);
  buf[payloadLen]     = crc & 0xFF;
  buf[payloadLen + 1] = (crc >> 8) & 0xFF;
}

// ============================================================
// ADC
// ============================================================
void readADC(int& cableAdc, int& voltageAdc, int& currentAdc) {
  cableAdc   = analogRead(ADC1_PIN);
  voltageAdc = analogRead(DS_PIN);
  currentAdc = analogRead(CS_PIN);
}

// ============================================================
// Modbus 响应构造
// ============================================================
static uint16_t buildReadResponse(uint8_t* out, uint8_t addr,
                                  const uint8_t* payload, uint8_t payloadLen) {
  out[0] = addr;
  out[1] = FUNC_READ_HOLDING;
  out[2] = payloadLen;
  memcpy(&out[3], payload, payloadLen);
  appendCRC(out, 3 + payloadLen);
  return 3 + payloadLen + 2;
}

static uint16_t buildWriteResponse(uint8_t* out, const uint8_t* req) {
  memcpy(out, req, 6);
  appendCRC(out, 6);
  return 8;
}

// ============================================================
// 寄存器读处理
// ============================================================
static void handleReadVoltageCurrent(uint8_t* req, uint8_t* resp) {
  uint8_t addr = req[0];
  int cableAdc, voltageAdc, currentAdc;
  readADC(cableAdc, voltageAdc, currentAdc);
  uint16_t voltage = (uint16_t)(voltageAdc * 0.3065f + 0.5f);
  uint16_t current = (uint16_t)(currentAdc * 0.1007f + 0.5f);
  uint8_t payload[4];
  payload[0] = (voltage >> 8) & 0xFF;
  payload[1] = voltage & 0xFF;
  payload[2] = (current >> 8) & 0xFF;
  payload[3] = current & 0xFF;
  uint16_t frameLen = buildReadResponse(resp, addr, payload, 4);
  rs485WriteBuffer(resp, frameLen);
}

static void handleReadCableLength(uint8_t* req, uint8_t* resp) {
  uint8_t addr = req[0];
  uint8_t payload[2] = { cdzyBuf[0], cdzyBuf[1] };
  uint16_t frameLen = buildReadResponse(resp, addr, payload, 2);
  rs485WriteBuffer(resp, frameLen);
}

static void handleReadGain(uint8_t* req, uint8_t* resp) {
  uint8_t addr = req[0];
  uint8_t payload[2] = { cdzyBuf[2], cdzyBuf[3] };
  uint16_t frameLen = buildReadResponse(resp, addr, payload, 2);
  rs485WriteBuffer(resp, frameLen);
}

// ============================================================
// 寄存器写处理
// ============================================================
static void handleWriteCableLength(uint8_t* req, uint8_t* resp) {
  cdzyBuf[0] = req[7];
  cdzyBuf[1] = req[8];
  setCableLength(cdzyBuf[1]);
  saveData(cdzyBuf, sizeof(cdzyBuf));
  uint16_t frameLen = buildWriteResponse(resp, req);
  rs485WriteBuffer(resp, frameLen);
}

static void handleWriteGain(uint8_t* req, uint8_t* resp) {
  cdzyBuf[2] = req[7];
  cdzyBuf[3] = req[8];
  setGain(cdzyBuf[3]);
  saveData(cdzyBuf, sizeof(cdzyBuf));
  uint16_t frameLen = buildWriteResponse(resp, req);
  rs485WriteBuffer(resp, frameLen);
}

// ============================================================
// Modbus 帧处理
// ============================================================
static bool handleModbusFrame(uint8_t* data, int length) {
  if (length < MIN_FRAME_LEN || length > MAX_FRAME_LEN) return false;

  uint16_t recvCRC = (data[length - 1] << 8) | data[length - 2];
  uint16_t calcCRC = modbusCRC16(data, length - 2);
  if (recvCRC != calcCRC) return false;

  uint8_t  func       = data[1];
  uint16_t regAddress = (data[2] << 8) | data[3];
  uint8_t  resp[24];

  if (func == FUNC_READ_HOLDING) {
    switch (regAddress) {
      case REG_VOLTAGE_CURRENT: handleReadVoltageCurrent(data, resp); return true;
      case REG_CABLE_LENGTH:    handleReadCableLength(data, resp);    return true;
      case REG_GAIN:            handleReadGain(data, resp);           return true;
      default: return false;
    }
  }

  if (func == FUNC_WRITE_MULTI) {
    switch (regAddress) {
      case REG_CABLE_LENGTH: handleWriteCableLength(data, resp); return true;
      case REG_GAIN:         handleWriteGain(data, resp);        return true;
      default: return false;
    }
  }

  return false;
}

// ============================================================
// 主处理入口
// ============================================================
void processReceivedData(uint8_t* data, int length) {
  if (length <= 0) return;

  if (data[0] == PROTO_ADDR_AA) {
    DBG_PRINTLN("[PROC] Modbus 0xAA");
    handleModbusFrame(data, length);
  } else {
    DBG_PRINTLN("[PROC] forward to downhole");
    forwardToDownhole(data, length);
    rs485SetReceive();
  }
}

// ============================================================
// 系统时钟
// ============================================================
extern "C" void SystemClock_Config(void) {
  RCC_OscInitTypeDef RCC_OscInitStruct = {};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {};

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState       = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource  = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM       = 12;
  RCC_OscInitStruct.PLL.PLLN       = 336;
  RCC_OscInitStruct.PLL.PLLP       = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ       = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) Error_Handler();

  RCC_ClkInitStruct.ClockType      = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK
                                   | RCC_CLOCKTYPE_PCLK1  | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource   = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider  = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) Error_Handler();

  SystemCoreClock = 168000000UL;
}

// ============================================================
// 初始化
// ============================================================
static void initPins() {
  pinMode(RS485_EN, OUTPUT);
  pinMode(RS485_RX, INPUT_PULLUP);
  pinMode(RS485_TX, OUTPUT);
  rs485SetReceive();

  pinMode(CL_0, OUTPUT);
  pinMode(CL_1, OUTPUT);
  pinMode(ENCODE_PB2, OUTPUT);
  pinMode(ENCODE_PE7, OUTPUT);
  pinMode(ENCODE_PE8, OUTPUT);
  pinMode(ENCODE_PE9, OUTPUT);
  pinMode(LED_PIN, OUTPUT);

  pinMode(ADC1_PIN, INPUT_ANALOG);
  pinMode(DS_PIN,   INPUT_ANALOG);
  pinMode(CS_PIN,   INPUT_ANALOG);
  analogReadResolution(12);

  // 井下口 PA2: 初始化为输出高 (空闲态)
  pinMode(JX_TX_PIN, OUTPUT);
  digitalWrite(JX_TX_PIN, HIGH);
  pinMode(JX_RX_PIN, INPUT);
}

static void initSerial() {
  Serial1.begin(9600);   // 调试口
  rs485.begin(9600);     // RS485
}

static void loadConfigOrDefault() {
  loadData(cdzyBuf, sizeof(cdzyBuf));
  if (cdzyBuf[0] == 0xFF) {
    cdzyBuf[0] = 0x00; cdzyBuf[1] = 0x00;
    cdzyBuf[2] = 0x00; cdzyBuf[3] = 0x03;
  }
  setCableLength(cdzyBuf[1]);
  setGain(cdzyBuf[3]);
}

void setup() {
  initPins();
  initSerial();
  loadConfigOrDefault();

  DBG_PRINTLN("=== BOOT ===");
}

// ============================================================
// 主循环
// ============================================================
void loop() {
  uint8_t buffer[64];
  uint16_t len = 0;

  // RS485 接收 → 透传到井下
  if (readWithTimeout(rs485, buffer, sizeof(buffer), &len, 5)) {
    g_frameCnt++;

    DBG_PRINT("[RX] frame#");
    DBG_PRINT(g_frameCnt);
    DBG_PRINT(" len=");
    DBG_PRINT(len);
    DBG_PRINT(" data=");
    for (uint16_t i = 0; i < len; i++) { DBG_PRINTHEX(buffer[i]); DBG_PRINT(' '); }
    DBG_PRINTLN("");

    processReceivedData(buffer, len);
    memset(buffer, 0, len);
  }

  // 心跳灯 + 心跳打印
  static uint32_t lastBlink = 0;
  if (millis() - lastBlink > 500) {
    lastBlink = millis();
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    DBG_PRINT("[HB] frameCnt=");
    DBG_PRINT(g_frameCnt);
    DBG_PRINT(" jxTxCnt=");
    DBG_PRINT(g_jxTxCnt);
    DBG_PRINT(" rsTxCnt=");
    DBG_PRINTLN(g_rsTxCnt);
  }
}
主楼