#include <SPI.h>
#include <ACAN2517FD.h>

#define PIN_CAN_SCK   12
#define PIN_CAN_MOSI  11
#define PIN_CAN_MISO  13
#define PIN_CAN_CS    10
#define PIN_CAN_INT   255

#define LOOPBACK_TEST  false

SPIClass    gSPI(HSPI);
ACAN2517FD  gCAN(PIN_CAN_CS, gSPI, PIN_CAN_INT);

uint32_t gTxCount = 0;
uint32_t gRxCount = 0;

void setup() {
  Serial.begin(115200);
  delay(500);

  Serial.println("\n====================================");
  Serial.println(" MCP2518FD v3 - INT=255 NULL 콜백");
  Serial.println(LOOPBACK_TEST ? " [STEP1] InternalLoopBack" : " [STEP2] Normal20B 수신");
  Serial.println("====================================");

  gSPI.begin(PIN_CAN_SCK, PIN_CAN_MISO, PIN_CAN_MOSI, PIN_CAN_CS);
  gSPI.setFrequency(5000000);

  ACAN2517FDSettings settings(
    ACAN2517FDSettings::OSC_20MHz,
    500UL * 1000UL,
    DataBitRateFactor::x1
  );

  settings.mRequestedMode = LOOPBACK_TEST
    ? ACAN2517FDSettings::InternalLoopBack
    : ACAN2517FDSettings::Normal20B;

  settings.mControllerReceiveFIFOSize = 16;

  Serial.printf("비트레이트: %lu bps\n", settings.actualArbitrationBitRate());

  // INT=255 폴링모드는 반드시 NULL
  const uint32_t err = gCAN.begin(settings, NULL);

  if (err == 0) {
    Serial.println("[OK] 초기화 성공!");
    Serial.println(LOOPBACK_TEST
      ? "1초마다 자동 송신 -> [LOOPBACK_OK] 뜨면 정상\n"
      : "PC에서 500kbps CAN 프레임 보내세요.\n");
  } else {
    Serial.printf("[ERROR] 0x%08X\n", err);
    while (true) delay(1000);
  }
}

void loop() {
  gCAN.isr();  // 폴링모드: 루프마다 직접 호출

  if (LOOPBACK_TEST) {
    static uint32_t lastTx = 0;
    if (millis() - lastTx >= 1000) {
      lastTx = millis();
      CANFDMessage txMsg;
      txMsg.id  = 0x123;
      txMsg.len = 8;
      for (uint8_t i = 0; i < 8; i++) txMsg.data[i] = i;
      if (gCAN.tryToSend(txMsg)) {
        gTxCount++;
        Serial.printf("TX [%lu]  ID:0x123\n", gTxCount);
      }
    }
  }

  CANFDMessage msg;
  while (gCAN.receive(msg)) {
    gRxCount++;
    if (LOOPBACK_TEST) {
      Serial.printf("[LOOPBACK_OK] RX [%lu]  ID:0x%03X  DLC:%d  Data:",
                    gRxCount, msg.id, msg.len);
    } else {
      Serial.printf("[%5lu] %s  ID:0x%08X  DLC:%d  Data:",
                    gRxCount, msg.ext ? "EXT" : "STD", msg.id, msg.len);
    }
    for (uint8_t i = 0; i < msg.len; i++) Serial.printf(" %02X", msg.data[i]);
    Serial.println();
  }

  static uint32_t lastSt = 0;
  if (millis() - lastSt >= 5000) {
    lastSt = millis();
    if (LOOPBACK_TEST && gRxCount == 0 && gTxCount >= 3)
      Serial.println("!! RX=0 -> 여전히 문제");
    Serial.printf("-- TX=%lu  RX=%lu\n", gTxCount, gRxCount);
  }
}