diff --git a/bpdt-firmware/bpdt-adapter-stm32h5/.cproject b/bpdt-firmware/bpdt-adapter-stm32h5/.cproject
index 5598d8b..b3b7c90 100644
--- a/bpdt-firmware/bpdt-adapter-stm32h5/.cproject
+++ b/bpdt-firmware/bpdt-adapter-stm32h5/.cproject
@@ -32,6 +32,10 @@
+
@@ -48,6 +52,8 @@
+
+
@@ -105,12 +111,16 @@
-
-
+
+
+
@@ -126,6 +136,8 @@
+
+
diff --git a/bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.c b/bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.c
new file mode 100644
index 0000000..71f4f3c
--- /dev/null
+++ b/bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.c
@@ -0,0 +1,743 @@
+#include "hc_06.h"
+#include
+#include
+#include
+#include "IKW1281Connection.h"
+#include "kline.h"
+
+extern UART_HandleTypeDef huart2;
+
+/* =========================
+ TX delay / non-blocking queue
+ =========================
+ Goal: delay every binary reply by ~10ms without blocking the CPU.
+ Implementation: enqueue TX buffers with a due timestamp, then send using
+ HAL_UART_Transmit_IT() when due, chaining via TxCplt callback.
+
+ Notes:
+ - Only binary frames (HC06_SendFrame / HC06_SendDataReply) use this queue.
+ - ASCII helpers remain blocking (debug only).
+*/
+#define HC06_TX_DELAY_MS 10u
+#define HC06_TX_QUEUE_LEN 8u
+#define HC06_TX_BUF_MAX 80u // enough for max CMD_DATA_REQUEST reply (~70B)
+
+typedef struct {
+ uint32_t due_ms;
+ uint16_t len;
+ uint8_t buf[HC06_TX_BUF_MAX];
+} hc06_tx_item_t;
+
+static volatile uint8_t s_tx_head = 0;
+static volatile uint8_t s_tx_tail = 0;
+static volatile uint8_t s_tx_count = 0;
+static volatile uint8_t s_tx_busy = 0;
+static hc06_tx_item_t s_tx_q[HC06_TX_QUEUE_LEN];
+
+static void HC06_TxReset(void)
+{
+ s_tx_head = 0;
+ s_tx_tail = 0;
+ s_tx_count = 0;
+ s_tx_busy = 0;
+}
+
+static HAL_StatusTypeDef HC06_TxEnqueue(const uint8_t *data, uint16_t len)
+{
+ if (!data || len == 0u || len > HC06_TX_BUF_MAX) return HAL_ERROR;
+ if (s_tx_count >= HC06_TX_QUEUE_LEN) return HAL_BUSY;
+
+ hc06_tx_item_t *it = &s_tx_q[s_tx_tail];
+ memcpy(it->buf, data, len);
+ it->len = len;
+ it->due_ms = HAL_GetTick() + HC06_TX_DELAY_MS;
+
+ s_tx_tail = (uint8_t)((s_tx_tail + 1u) % HC06_TX_QUEUE_LEN);
+ s_tx_count++;
+ return HAL_OK;
+}
+
+static void HC06_TxKick(void)
+{
+ if (s_tx_busy) return;
+ if (s_tx_count == 0u) return;
+
+ hc06_tx_item_t *it = &s_tx_q[s_tx_head];
+
+ // wait until due timestamp
+ if ((int32_t)(HAL_GetTick() - it->due_ms) < 0) return;
+
+ if (HAL_UART_Transmit_IT(&huart2, it->buf, it->len) == HAL_OK) {
+ s_tx_busy = 1u;
+ }
+}
+
+// Call this from HAL_UART_TxCpltCallback() for USART2
+void HC06_UART_TxCpltCallback(UART_HandleTypeDef *huart)
+{
+ if (!huart) return;
+ if (huart->Instance != huart2.Instance) return;
+ if (!s_tx_busy) return;
+
+ // pop the item that just finished
+ if (s_tx_count > 0u) {
+ s_tx_head = (uint8_t)((s_tx_head + 1u) % HC06_TX_QUEUE_LEN);
+ s_tx_count--;
+ }
+ s_tx_busy = 0u;
+
+ // send next (if already due)
+ HC06_TxKick();
+}
+
+/* =========================
+ Your project functions
+ ========================= */
+extern void InitPSG5Comm(void);
+extern float ReadDfi(void);
+extern int WriteDfi(float dfi, int version);
+extern int ClearFaultCodes(void);
+extern uint8_t ReadAudiPin(uint16_t* pin);
+static void HC06_ForceRearmRx(void);
+
+static void BT_InitPSG5Comm(void);
+static void BT_ReadDfi(void);
+static void BT_WriteDfi(void);
+static void BT_ReadDTC(void);
+static void BT_ClearDTC(void);
+static void BT_ReadAudiPin(void);
+
+/* =========================
+ USER SETTINGS (edit)
+ ========================= */
+#define HC06_DO_AT_SETUP_AT_BOOT 1
+#define HC06_NAME "HC - dFi Tool v1"
+
+// Many HC-06 firmwares do NOT support PIN change; leave disabled unless proven.
+#define HC06_TRY_SET_PIN 0
+#define HC06_PIN_STR "1234"
+
+// AT command send style: you already confirmed AT\r\n works.
+#define HC06_AT_USE_CRLF 1
+
+// AT wait timeouts (ms)
+#define HC06_AT_WAIT_MS_AT 600
+#define HC06_AT_WAIT_MS_NAME 800
+#define HC06_AT_WAIT_MS_PIN 800
+
+/* =========================
+ Globals
+ ========================= */
+volatile uint8_t g_hc06_frame_ready = 0;
+hc06_frame_t g_hc06_frame;
+
+/* 1-byte RX for everything */
+static uint8_t rx_byte;
+uint8_t commandPending = 0;
+
+/* =========================
+ Mode
+ ========================= */
+typedef enum {
+ HC06_MODE_AT = 0,
+ HC06_MODE_BIN = 1
+} hc06_mode_t;
+
+static volatile hc06_mode_t s_mode = HC06_MODE_AT;
+
+/* =========================
+ AT capture
+ ========================= */
+static volatile char s_at_buf[64];
+static volatile uint8_t s_at_len = 0;
+static volatile uint8_t s_at_done = 0;
+
+static void AT_Clear(void)
+{
+ s_at_len = 0;
+ s_at_done = 0;
+ memset((void*)s_at_buf, 0, sizeof(s_at_buf));
+}
+
+static void AT_Wait(uint32_t timeout_ms)
+{
+ uint32_t t0 = HAL_GetTick();
+ while (!s_at_done && (HAL_GetTick() - t0) < timeout_ms) {
+ // idle
+ }
+}
+
+/* =========================
+ Binary frame parser
+ ========================= */
+typedef enum {
+ ST_SYNC = 0,
+ ST_CMD,
+ ST_REQ_ID,
+ ST_REQ_CRC,
+ ST_D0, ST_D1, ST_D2, ST_D3, ST_D4, ST_D5,
+ ST_CRC
+} hc06_rx_state_t;
+
+static hc06_rx_state_t st = ST_SYNC;
+static uint8_t payload[7]; // [0]=cmd, [1..6]=data bytes
+static uint8_t pi = 0;
+static uint8_t crc = 0;
+
+static uint16_t u16_le(uint8_t lo, uint8_t hi)
+{
+ return (uint16_t)lo | ((uint16_t)hi << 8);
+}
+
+static void u16_to_le(uint16_t v, uint8_t *lo, uint8_t *hi)
+{
+ *lo = (uint8_t)(v & 0xFF);
+ *hi = (uint8_t)((v >> 8) & 0xFF);
+}
+
+/* CRC-8 poly 0x07, init 0x00, over [cmd + 6 data bytes] */
+static uint8_t crc8_update(uint8_t c, uint8_t data)
+{
+ c ^= data;
+ for (int i = 0; i < 8; i++) {
+ c = (c & 0x80) ? (uint8_t)((c << 1) ^ 0x07) : (uint8_t)(c << 1);
+ }
+ return c;
+}
+
+/* =========================
+ Public: DFI scaling
+ ========================= */
+int16_t HC06_DfiFloatToS16(float dfi)
+{
+ float s = dfi * (256.0f / 3.0f);
+ if (s > 32767.0f) s = 32767.0f;
+ if (s < -32768.0f) s = -32768.0f;
+ return (int16_t)lroundf(s);
+}
+
+float HC06_DfiS16ToFloat(int16_t s)
+{
+ return ((float)s) * (3.0f / 256.0f);
+}
+
+/* =========================
+ TX helpers
+ ========================= */
+HAL_StatusTypeDef HC06_SendAscii(const char *s)
+{
+ if (!s) return HAL_ERROR;
+ return HAL_UART_Transmit(&huart2, (uint8_t*)s, (uint16_t)strlen(s), 200);
+}
+
+HAL_StatusTypeDef HC06_SendAsciiLn(const char *s)
+{
+ HAL_StatusTypeDef a = HC06_SendAscii(s);
+ HAL_StatusTypeDef b = HC06_SendAscii("\r\n");
+ return (a == HAL_OK && b == HAL_OK) ? HAL_OK : HAL_ERROR;
+}
+
+HAL_StatusTypeDef HC06_SendFrame(uint8_t cmd, uint16_t w1, uint16_t w2, uint16_t w3)
+{
+ uint8_t buf[9]; // sync + cmd + 6 data + crc
+ uint8_t c = 0;
+
+ buf[0] = HC06_SYNC;
+ buf[1] = cmd;
+
+ uint8_t lo, hi;
+ u16_to_le(w1, &lo, &hi); buf[2] = lo; buf[3] = hi;
+ u16_to_le(w2, &lo, &hi); buf[4] = lo; buf[5] = hi;
+ u16_to_le(w3, &lo, &hi); buf[6] = lo; buf[7] = hi;
+
+ for (int i = 1; i <= 7; i++) c = crc8_update(c, buf[i]);
+ buf[8] = c;
+
+ // Non-blocking + delayed TX
+ HAL_StatusTypeDef st = HC06_TxEnqueue(buf, (uint16_t)sizeof(buf));
+ HC06_TxKick();
+ return st;
+}
+
+/* =========================
+ AT send helpers
+ ========================= */
+static void AT_SendRaw(const char *s)
+{
+ (void)HC06_SendAscii(s);
+}
+
+static void AT_SendCmd(const char *cmd_no_prefix)
+{
+ char buf[96];
+#if HC06_AT_USE_CRLF
+ snprintf(buf, sizeof(buf), "AT+%s\r\n", cmd_no_prefix);
+#else
+ snprintf(buf, sizeof(buf), "AT+%s", cmd_no_prefix);
+#endif
+ AT_SendRaw(buf);
+}
+
+/* =========================
+ Init
+ ========================= */
+void HC06_Init(void)
+{
+ s_mode = HC06_MODE_AT;
+ HC06_TxReset();
+ g_hc06_frame_ready = 0;
+ HC06_ForceRearmRx();
+}
+
+/* Call once at boot (optional). Module must be NOT connected (LED blinking). */
+void HC06_AT_BootSetup(void)
+{
+#if HC06_DO_AT_SETUP_AT_BOOT
+ // Ensure we're in AT mode and buffer is clean
+ s_mode = HC06_MODE_AT;
+ AT_Clear();
+
+ // 1) Basic AT check
+#if HC06_AT_USE_CRLF
+ AT_SendRaw("AT\r\n");
+#else
+ AT_SendRaw("AT");
+#endif
+ AT_Wait(HC06_AT_WAIT_MS_AT);
+ // Expect "OK" in s_at_buf (you saw OKsetname for name)
+
+ // 2) Set name
+ AT_Clear();
+ {
+ char cmd[64];
+ snprintf(cmd, sizeof(cmd), "NAME%s", HC06_NAME);
+ AT_SendCmd(cmd);
+ }
+ AT_Wait(HC06_AT_WAIT_MS_NAME);
+ // Expect "OKsetname"
+
+#if HC06_TRY_SET_PIN
+ AT_Clear();
+ {
+ char cmd[32];
+ snprintf(cmd, sizeof(cmd), "PIN%s", HC06_PIN_STR);
+ AT_SendCmd(cmd);
+ }
+ AT_Wait(HC06_AT_WAIT_MS_PIN);
+#endif
+
+ // Switch to BIN mode after setup
+ s_mode = HC06_MODE_BIN;
+#else
+ // Directly start in binary mode
+ s_mode = HC06_MODE_BIN;
+#endif
+ HC06_ForceRearmRx();
+}
+
+// Variable-length reply for CMD 0x84: SYNC, CMD, STATUS, LEN(u16 LE), PAYLOAD, CRC
+// CRC is over [CMD, STATUS, LENlo, LENhi, PAYLOAD]
+#define HC06_MAX_PAYLOAD 64
+static HAL_StatusTypeDef HC06_SendDataReply(uint8_t status, const uint8_t *payloadIn, uint16_t len)
+{
+ if (status != 0x00) {
+ len = 0;
+ payloadIn = NULL;
+ }
+ if (len > HC06_MAX_PAYLOAD) len = HC06_MAX_PAYLOAD;
+
+ uint8_t buf[1 + 1 + 1 + 2 + HC06_MAX_PAYLOAD + 1];
+ uint16_t idx = 0;
+ uint8_t c = 0;
+
+ buf[idx++] = HC06_SYNC;
+ buf[idx++] = 0x84;
+ buf[idx++] = status;
+
+ uint8_t lo, hi;
+ u16_to_le(len, &lo, &hi);
+ buf[idx++] = lo;
+ buf[idx++] = hi;
+
+ for (uint16_t i = 0; i < len; i++) {
+ buf[idx++] = payloadIn ? payloadIn[i] : 0;
+ }
+
+ for (uint16_t i = 1; i < idx; i++) c = crc8_update(c, buf[i]);
+ buf[idx++] = c;
+
+ // Non-blocking + delayed TX
+ HAL_StatusTypeDef st = HC06_TxEnqueue(buf, idx);
+ HC06_TxKick();
+ return st;
+}
+
+/* =========================
+ RX callback (1 byte)
+ ========================= */
+void HC06_UART_RxByteCallback(UART_HandleTypeDef *huart)
+{
+ if (huart->Instance != huart2.Instance) return;
+
+ uint8_t x = rx_byte;
+
+ if (s_mode == HC06_MODE_AT)
+ {
+ char c = (char)x;
+
+ // Capture until newline or full
+ if (c == '\n' || s_at_len >= (sizeof(s_at_buf) - 1))
+ {
+ s_at_buf[s_at_len] = 0;
+ s_at_done = 1;
+ }
+ else if (c != '\r')
+ {
+ s_at_buf[s_at_len++] = c;
+ }
+
+ // continue RX
+ HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
+ return;
+ }
+
+ // Binary frame parsing (robust resync + CRC)
+ switch (st)
+ {
+ case ST_SYNC:
+ if (x == HC06_SYNC) {
+ st = ST_CMD;
+ pi = 0;
+ crc = 0;
+ }
+ break;
+
+ case ST_CMD:
+ payload[pi++] = x; // cmd
+ crc = crc8_update(crc, x);
+ if (x == CMD_DATA_REQUEST) {
+ // short request: SYNC, CMD(0x04), REQ_ID, CRC
+ st = ST_REQ_ID;
+ } else {
+ st = ST_D0;
+ }
+ break;
+
+ case ST_REQ_ID:
+ payload[pi++] = x; // req_id
+ crc = crc8_update(crc, x);
+ st = ST_REQ_CRC;
+ break;
+
+ case ST_REQ_CRC:
+ if (x == crc) {
+ g_hc06_frame.cmd = payload[0];
+ g_hc06_frame.w1 = (uint16_t)payload[1]; // REQ_ID in low byte
+ g_hc06_frame.w2 = 0;
+ g_hc06_frame.w3 = 0;
+ g_hc06_frame_ready = 1;
+ }
+ st = ST_SYNC;
+ break;
+
+ case ST_D0: case ST_D1: case ST_D2: case ST_D3: case ST_D4: case ST_D5:
+ payload[pi++] = x; // data bytes
+ crc = crc8_update(crc, x);
+ if (pi >= 7) st = ST_CRC;
+ else st = (hc06_rx_state_t)((int)st + 1);
+ break;
+
+ case ST_CRC:
+ if (x == crc) {
+ g_hc06_frame.cmd = payload[0];
+ g_hc06_frame.w1 = u16_le(payload[1], payload[2]);
+ g_hc06_frame.w2 = u16_le(payload[3], payload[4]);
+ g_hc06_frame.w3 = u16_le(payload[5], payload[6]);
+ g_hc06_frame_ready = 1;
+ }
+ st = ST_SYNC; // resync always
+ break;
+
+ default:
+ st = ST_SYNC;
+ break;
+ }
+
+ HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
+}
+
+/* =========================
+ Command processing
+ ========================= */
+static uint8_t reply_cmd(uint8_t cmd) { return (uint8_t)(cmd | 0x80); }
+
+// -------------------------------
+// Data Request placeholder handlers
+// -------------------------------
+static uint8_t HC06_HandleReq_FwVersion(uint8_t *out, uint16_t *outLen) { (void)out; *outLen = 0; return HC06_STATUS_OK; }
+
+// These must exist somewhere in your project (or change to match your actual symbols)
+extern char identStr[11];
+extern uint8_t connectionAlive;
+//extern uint8_t BitBang;
+
+static uint8_t HC06_HandleReq_Ident(uint8_t *out, uint16_t *outLen)
+{
+ // Send exactly 11 bytes (no null terminator expected/required)
+ uint8_t empty = 1;
+ for (uint16_t i = 0; i < 11; i++) {
+ if((uint8_t)identStr[i]){
+ empty = 0;
+ break;
+ }
+ }
+ if(empty){
+ IdentifyEcu();
+ }
+ for (uint16_t i = 0; i < 11; i++) {
+ out[i] = (uint8_t)identStr[i];
+ }
+ *outLen = 11;
+ return HC06_STATUS_OK;
+}
+
+static uint8_t HC06_HandleReq_Status(uint8_t *out, uint16_t *outLen)
+{
+ out[0] = connectionAlive;
+ out[1] = BitBang;
+ *outLen = 2;
+ return HC06_STATUS_OK;
+}
+
+int N_fc = 0;
+FaultCode fault_codes[16];
+
+static uint8_t HC06_HandleReq_Error(uint8_t *out, uint16_t *outLen)
+{
+ for (uint16_t i = 0; i < N_fc; i++) {
+ uint8_t ind = 2*i;
+ out[ind] = fault_codes[i].dtc;
+ out[ind+1] = fault_codes[i].status;
+ }
+ *outLen = 2*N_fc;
+ return HC06_STATUS_OK;
+}
+
+static uint8_t HC06_HandleReq_Config(uint8_t *out, uint16_t *outLen) { (void)out; *outLen = 0; return HC06_STATUS_NOT_IMPLEMENTED; }
+static uint8_t HC06_HandleReq_Reserved(uint8_t *out, uint16_t *outLen) { (void)out; *outLen = 0; return HC06_STATUS_NOT_IMPLEMENTED; }
+
+static uint8_t HC06_DispatchDataRequest(uint8_t reqId, uint8_t *out, uint16_t *outLen)
+{
+ switch (reqId) {
+ case REQ_FW_VERSION: return HC06_HandleReq_FwVersion(out, outLen);
+ case REQ_IDENT: return HC06_HandleReq_Ident(out, outLen);
+ case REQ_STATUS: return HC06_HandleReq_Status(out, outLen);
+ case REQ_CONFIG: return HC06_HandleReq_Config(out, outLen);
+ case REQ_ERROR: return HC06_HandleReq_Error(out, outLen);
+ case REQ_RESERVED:
+ default: return HC06_HandleReq_Reserved(out, outLen);
+ }
+}
+
+void HC06_Process(void)
+{
+ // Always allow delayed TX queue to progress
+ HC06_TxKick();
+
+ if (!g_hc06_frame_ready) return;
+ g_hc06_frame_ready = 0;
+
+ const uint8_t cmd = g_hc06_frame.cmd;
+ const uint16_t w3 = g_hc06_frame.w3;
+
+ if(commandPending){return;}
+
+ commandPending = 1;
+ switch (cmd)
+ {
+ case CMD_INIT_COMM:
+ {
+ BT_InitPSG5Comm();
+ } break;
+
+ case CMD_READ_DFI:
+ {
+ //first should check if connection is alive
+ BT_ReadDfi();
+ } break;
+
+ case CMD_WRITE_DFI:
+ {
+ BT_WriteDfi();
+ } break;
+
+ case CMD_DATA_REQUEST:
+ {
+ uint8_t reqId = (uint8_t)(g_hc06_frame.w1 & 0xFF);
+ uint8_t out[HC06_MAX_PAYLOAD];
+ uint16_t outLen = 0;
+
+ uint8_t stc = HC06_DispatchDataRequest(reqId, out, &outLen);
+ (void)HC06_SendDataReply(stc, out, outLen);
+ } break;
+
+ case CMD_READ_DTC:
+ {
+ BT_ReadDTC();
+ } break;
+
+ case CMD_ERASE_DTC:
+ {
+ BT_ClearDTC();
+ } break;
+ case CMD_READ_AUDI_PIN:
+ {
+ BT_ReadAudiPin();
+ } break;
+ case CMD_WRITE_AUDI_PIN:
+ {
+ BT_ReadAudiPin();
+ } break;
+
+ default:
+ {
+ HC06_SendAsciiLn("ERR Unknown CMD");
+ // Return error frame with original cmd in w3
+ HC06_SendFrame(0xFF, 0, 0, (uint16_t)cmd);
+ } break;
+ }
+ commandPending = 0;
+}
+
+static void HC06_ForceRearmRx(void)
+{
+ // Stop anything currently running on UART2
+ HAL_UART_AbortReceive_IT(&huart2);
+ HAL_UART_AbortReceive(&huart2);
+ HAL_UART_AbortTransmit(&huart2);
+
+ // Reset queued TX as well (avoid sending stale frames after re-arm)
+ HC06_TxReset();
+
+ // Clear UART error flags properly
+ __HAL_UART_CLEAR_OREFLAG(&huart2);
+ __HAL_UART_CLEAR_NEFLAG(&huart2);
+ __HAL_UART_CLEAR_FEFLAG(&huart2);
+ __HAL_UART_CLEAR_PEFLAG(&huart2);
+
+ // Ensure peripheral interrupt enable bits are set
+ __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);
+ __HAL_UART_ENABLE_IT(&huart2, UART_IT_ERR);
+
+ // Also clear any pending interrupt in NVIC (rare but helps)
+ NVIC_ClearPendingIRQ(USART2_IRQn);
+
+ // Reset parser/AT state so it doesn't wait on stale state
+ st = ST_SYNC;
+ pi = 0;
+ crc = 0;
+ AT_Clear();
+
+ // Rearm 1-byte RX no matter what mode
+ HAL_StatusTypeDef rst = HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
+ (void)rst;
+ crc = 0;
+}
+
+
+/*
+ *
+ * API
+ *
+ */
+
+void BT_KLINE_ERROR(){
+ HC06_SendFrame(reply_cmd(CMD_INIT_COMM), CONN_HEAVY, 0, 0);
+}
+
+void BT_ReadDfi(){
+ if(connectionAlive){
+ float dfi = ReadDfi();
+ int16_t s = HC06_DfiFloatToS16(dfi);
+ HC06_SendFrame(reply_cmd(CMD_READ_DFI), 0, 0, (uint16_t)(uint16_t)s);
+ }else{
+ HC06_SendFrame(reply_cmd(CMD_READ_DFI), CONN_DEAD, 0, 0);
+ }
+}
+
+void BT_InitPSG5Comm(){
+ if(!connectionAlive){
+ BitBang = 1;
+ }else{
+ HC06_SendFrame(reply_cmd(CMD_INIT_COMM), CONN_ALIVE, 0, 0);
+ }
+}
+
+void BT_WriteDfi(){
+ if(connectionAlive){
+ int16_t s = (int16_t)g_hc06_frame.w3;
+ float dfi = HC06_DfiS16ToFloat(s);
+
+ int res=WriteDfi(dfi, 0);
+ HC06_SendFrame(reply_cmd(CMD_WRITE_DFI), !res * KLINE_ERROR, 0, 0);
+ }else{
+ HC06_SendFrame(reply_cmd(CMD_WRITE_DFI), CONN_DEAD, 0, 0);
+ }
+}
+
+void BT_OnPSG5CommEstablished(){
+ if(KeepAlive()){
+ HC06_SendFrame(reply_cmd(CMD_INIT_COMM), 0, 0, 0);
+ }else{
+ HC06_SendFrame(reply_cmd(CMD_INIT_COMM), CONN_HEAVY, 0, 0);
+ }
+}
+
+void BT_ReadDTC(){
+ if(connectionAlive){
+ N_fc = ReadFaultCodes(fault_codes, 16);
+ int res = (N_fc == -1) ? 0 : 1;
+ HC06_SendFrame(reply_cmd(CMD_READ_DTC), !res * KLINE_ERROR, 0, (uint16_t)N_fc);
+ }
+ else{
+ HC06_SendFrame(reply_cmd(CMD_READ_DTC), CONN_DEAD, 0, 0);
+ }
+}
+
+void BT_ClearDTC(){
+ if(connectionAlive){
+ int res = ClearFaultCodes();
+ HC06_SendFrame(reply_cmd(CMD_ERASE_DTC), !res * KLINE_ERROR, 0, 0);
+ }
+ else{
+ HC06_SendFrame(reply_cmd(CMD_ERASE_DTC), CONN_DEAD, 0, 0);
+ }
+}
+void BT_ReadAudiPin(){
+ uint16_t pin = 0;
+ if(connectionAlive){
+ HC06_SendFrame(reply_cmd(CMD_READ_AUDI_PIN), !ReadAudiPin(&pin) * KLINE_ERROR, 0, (uint16_t)pin);
+ }
+ else{
+ HC06_SendFrame(reply_cmd(CMD_READ_AUDI_PIN), CONN_DEAD, 0, 0);
+ }
+}
+void BT_WriteAudiPin(){
+ /*if(connectionAlive){
+ uint16_t pin = (uint16_t)g_hc06_frame.w3;
+ HC06_SendFrame(reply_cmd(CMD_READ_AUDI_PIN), !WriteAudiPin(pin) * KLINE_ERROR, 0, 0);
+ }
+ else{
+ HC06_SendFrame(reply_cmd(CMD_READ_AUDI_PIN), CONN_DEAD, 0, 0);
+ }*/
+}
+
+void BT_SendCommStatus(){
+ uint16_t volt = 0;
+ if(connectionAlive){
+ HC06_SendFrame(reply_cmd(CMD_TOOL_COMM_STATUS), !ReadVoltage(&volt) * KLINE_ERROR, 0, (uint16_t)volt);
+ }
+ else{
+ HC06_SendFrame(reply_cmd(CMD_TOOL_COMM_STATUS), CONN_DEAD, 0, 0);
+ }
+}
diff --git a/bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.h b/bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.h
new file mode 100644
index 0000000..b6506ee
--- /dev/null
+++ b/bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.h
@@ -0,0 +1,98 @@
+#ifndef INC_HC_06_H_
+#define INC_HC_06_H_
+
+#include "main.h"
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* =========================
+ User config
+ ========================= */
+#define HC06_SYNC 0xA5
+
+/* =========================
+ Frame type
+ ========================= */
+typedef struct {
+ uint8_t cmd;
+ uint16_t w1;
+ uint16_t w2;
+ uint16_t w3;
+} hc06_frame_t;
+
+typedef enum {
+ CMD_INIT_COMM = 0x01,
+ CMD_READ_DFI = 0x02,
+ CMD_WRITE_DFI = 0x03,
+ CMD_DATA_REQUEST = 0x04,
+ CMD_READ_DTC = 0x05,
+ CMD_ERASE_DTC = 0x06,
+ CMD_READ_AUDI_PIN = 0x07,
+ CMD_WRITE_AUDI_PIN = 0x08,
+ CMD_TOOL_COMM_STATUS = 0x09,
+
+} hc_06_CMD;
+
+typedef enum {
+ REQ_FW_VERSION = 0x00,
+ REQ_IDENT = 0x01,
+ REQ_STATUS = 0x02,
+ REQ_CONFIG = 0x03,
+ REQ_ERROR = 0x04,
+ REQ_RESERVED = 0x05,
+} hc06_req_id_t;
+
+typedef enum {
+ HC06_STATUS_OK = 0x00,
+ CONN_DEAD = 0x01,
+ CONN_ALIVE = 0x02,
+ CONN_HEAVY = 0x03,
+ KLINE_ERROR = 0x04,
+ HC06_STATUS_NOT_IMPLEMENTED = 0x10,
+} hc06_status_t;
+
+/* Latest received frame */
+extern volatile uint8_t g_hc06_frame_ready;
+extern hc06_frame_t g_hc06_frame;
+
+/* =========================
+ Public API
+ ========================= */
+void BT_KLINE_ERROR(void);
+
+void BT_OnPSG5CommEstablished(void);
+
+void BT_SendCommStatus(void);
+// Call once after MX_USART2_UART_Init()
+void HC06_Init(void);
+
+// Optional: call once at boot to configure HC-06 (name, optional PIN)
+void HC06_AT_BootSetup(void);
+
+// Call from HAL_UART_RxCpltCallback()
+void HC06_UART_RxByteCallback(UART_HandleTypeDef *huart);
+
+// Call from HAL_UART_TxCpltCallback()
+void HC06_UART_TxCpltCallback(UART_HandleTypeDef *huart);
+
+// Call repeatedly in main loop
+void HC06_Process(void);
+
+// TX helpers
+HAL_StatusTypeDef HC06_SendAscii(const char *s);
+HAL_StatusTypeDef HC06_SendAsciiLn(const char *s);
+HAL_StatusTypeDef HC06_SendFrame(uint8_t cmd, uint16_t w1, uint16_t w2, uint16_t w3);
+
+// DFI scaling helpers (signed int16, factor 256/3)
+int16_t HC06_DfiFloatToS16(float dfi); // s16 = round(dfi * 256/3)
+float HC06_DfiS16ToFloat(int16_t s); // dfi = s * 3/256
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INC_HC_06_H_ */
diff --git a/bpdt-firmware/bpdt-adapter-stm32h5/Core/Inc/main.h b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Inc/main.h
index 1a934a9..cb9ec44 100644
--- a/bpdt-firmware/bpdt-adapter-stm32h5/Core/Inc/main.h
+++ b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Inc/main.h
@@ -36,7 +36,8 @@ extern "C" {
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
-
+extern UART_HandleTypeDef huart1;
+extern UART_HandleTypeDef huart2;
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
diff --git a/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/IKW1281Connection.c b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/IKW1281Connection.c
new file mode 100644
index 0000000..6ec905d
--- /dev/null
+++ b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/IKW1281Connection.c
@@ -0,0 +1,294 @@
+/*
+ * IKW1281Connection.c
+ *
+ * Created on: Apr 9, 2025
+ * Author: herli
+ */
+
+#include
+#include
+#include
+#include
+
+#include "IKW1281Connection.h"
+#include "main.h"
+
+
+static void SendAckPacket(void);
+
+static void WriteComplement(uint8_t b);
+static void WriteByteAndDiscardEcho(uint8_t b);
+static void WriteByteAndReadAck(uint8_t b);
+static void WriteByteRaw(uint8_t b);
+
+uint8_t timeoutdata[] = "TimeoutNigga\r\n";
+//uint8_t RxData[1];
+uint8_t TxData[KLINE_BUFFER_SIZE];
+uint8_t KlineData[KLINE_BUFFER_SIZE];
+volatile uint8_t rx_done_flag = 0;
+uint8_t connectionAlive = 0;
+
+uint8_t ReadByte(){
+ if (!connectionAlive){ return 0;}
+ rx_done_flag = 0;
+ uint32_t timeout = HAL_GetTick() + 1000; // 1-second timeout
+
+ while (!rx_done_flag)
+ {
+ if (HAL_GetTick() > timeout) {
+ // Timeout occurred
+
+ //HAL_UART_Transmit(&huart2, (uint8_t*)timeoutdata, strlen(timeoutdata), 1000);
+ //CDC_Transmit_FS((uint8_t*)timeoutdata, strlen(timeoutdata));
+ connectionAlive = 0;
+ return 0xFF; // Or some special error code
+ }
+
+ // Optional: add a timeout check here
+ // This loop blocks until RX is done
+ }
+ /*for (int k = 0; k < KLINE_BUFFER_SIZE ; k++){
+ KlineData[k]=KlineData[k+1];
+ }
+ KlineData[KLINE_BUFFER_SIZE] = 0;
+ return KlineData[0];*/
+ return RxData[0];
+}
+uint8_t ReadAndAckByte(void){
+ uint8_t b = ReadByte();
+ WriteComplement(b);
+ return b;
+}
+void ReadComplement(uint8_t b){
+ uint8_t expectedComplement = (uint8_t)~b;
+ uint8_t actualComplement = ReadByte();
+ //if(actualComplement != expectedComplement){return;}
+}
+void WriteComplement(uint8_t b){
+ uint8_t complement = (uint8_t)~b;
+ WriteByteAndDiscardEcho(complement);
+}
+void WriteByteAndDiscardEcho(uint8_t b){
+ WriteByteRaw(b);
+ uint8_t echo = ReadByte();
+ //if(echo != b){return;}
+}
+
+void WriteByteRaw(uint8_t b){
+ TxData[0] = b;
+ HAL_UART_Transmit(&huart1, TxData, 1, 100);
+}
+
+#define MAX_PACKETS 16 // adjust to your needs
+static ParsedPacket packets_buffer[MAX_PACKETS];
+#define MAX_PACKETS 16
+
+// static buffer, persistent between calls
+static ParsedPacket packets_buffer[MAX_PACKETS];
+
+ParsedPacket* ReceivePackets(int *out_count)
+{
+ int count = 0;
+
+ while (1) {
+ if (count >= MAX_PACKETS) {
+ // reached max, stop receiving more
+ break;
+ }
+
+ ParsedPacket packet = ReceivePacket();
+ packets_buffer[count++] = packet;
+
+ if (packet.isAckNak) {
+ break;
+ }
+
+ SendAckPacket();
+ }
+
+ if (out_count) {
+ *out_count = count;
+ }
+ return packets_buffer; // returns pointer to static buffer
+}
+/*
+ParsedPacket* ReceivePackets(int *out_count) {
+ int capacity = 16; // initial capacity
+ int count = 0;
+ ParsedPacket *packets = malloc(capacity * sizeof(ParsedPacket));
+ if (!packets) return NULL;
+
+ while (1) {
+ ParsedPacket packet = ReceivePacket();
+
+ // Resize array if needed
+ if (count >= capacity) {
+ capacity *= 2;
+ ParsedPacket *new_packets = realloc(packets, capacity * sizeof(ParsedPacket));
+ if (!new_packets) {
+ free(packets);
+ return NULL;
+ }
+ packets = new_packets;
+ }
+
+ packets[count++] = packet;
+
+ if (packet.isAckNak) break;
+
+ SendAckPacket();
+ }
+
+ if (out_count) *out_count = count;
+ return packets;
+}*/
+
+uint8_t _packetCounter = 0;
+uint8_t _packetCounterInitialized = 0;
+
+ParsedPacket ReceivePacket()
+{
+ ParsedPacket packet = {0};
+ uint8_t index = 0;
+
+ uint8_t packetLength = ReadAndAckByte();
+ //packet.raw = (uint8_t*)malloc(packetLength*sizeof(uint8_t));
+
+ packet.raw[index++] = packetLength;
+
+ uint8_t packetCounter = ReadPacketCounter();
+ packet.raw[index++] = packetCounter;
+
+ uint8_t packetCommand = ReadAndAckByte();
+ packet.raw[index++] = packetCommand;
+
+ for (int i = 0; i < packetLength - 3; i++) {
+ uint8_t b = ReadAndAckByte();
+ packet.raw[index++] = b;
+ }
+
+ uint8_t packetEnd = ReadByte(); // no ACK
+ packet.raw[index++] = packetEnd;
+ packet.length = index; //tiene que ser index
+
+ if (packetEnd != 0x03) {
+ // Protocol error handling here
+ return packet;
+ }
+
+ // Now classify the packet type
+ packet.title = packetCommand;
+
+ switch (packetCommand) {
+ case PACKET_CMD_ACK:
+ packet.type = PACKET_TYPE_ACK;
+ packet.isAckNak = 1;
+ break;
+
+ case PACKET_CMD_AsciiData:
+ if (packet.raw[3] == 0x00)
+ packet.type = PACKET_TYPE_CODING_WSC;
+ else
+ packet.type = PACKET_TYPE_ASCII_DATA;
+ break;
+
+ case PACKET_CMD_ReadEepromResponse:
+ packet.type = PACKET_TYPE_READ_EEPROM_RESPONSE;
+ break;
+
+ case PACKET_CMD_ReadRomEepromResponse:
+ packet.type = PACKET_TYPE_READ_ROM_EEPROM_RESPONSE;
+ break;
+
+ case PACKET_CMD_NAK:
+ packet.type = PACKET_TYPE_NAK;
+ packet.isAckNak = 1;
+ default:
+ packet.type = PACKET_TYPE_UNKNOWN;
+ break;
+ }
+ return packet;
+}
+void ResetPacketCounter(){
+ _packetCounter = 0;
+}
+uint8_t ReadPacketCounter()
+{
+ uint8_t packetCounter = ReadAndAckByte();
+
+ if (!_packetCounterInitialized)
+ {
+ _packetCounter = packetCounter;
+ _packetCounterInitialized = 1;
+ }
+ else if (packetCounter != _packetCounter)
+ {
+ // Handle mismatch (drop packet, reset, etc.)
+ }
+
+ _packetCounter++;
+ return packetCounter;
+}
+void SendAckPacket()
+{
+ uint8_t ackByte = (uint8_t)PACKET_CMD_ACK;
+ SendPacket(&ackByte, 1);
+}
+void SendPacket(uint8_t* payload, uint8_t length)
+{
+ uint8_t packetLength = length + 2; // +2 for length and counter
+ uint8_t packet[packetLength];
+
+ int index = 0;
+
+ packet[index++] = packetLength; //0
+ packet[index++] = _packetCounter++; //1
+
+ for (int i = 0; i < length; i++)
+ {
+ packet[index++] = payload[i];
+ }
+ for (int i = 0; i < index; i++)
+ {
+ WriteByteAndReadAck(packet[i]);
+ HAL_Delay(5); // Small delay between bytes
+ }
+ WriteByteRaw(PACKET_END_EXPECTED); // End byte, no ACK expected
+}
+
+void WriteByteAndReadAck(uint8_t b)
+{
+ WriteByteRaw(b);
+ uint8_t ack = ReadByte();
+
+ uint8_t expectedAck = (uint8_t)~b;
+ if (ack != expectedAck)
+ {
+ // Handle NAK or retry
+ }
+}
+
+// Placeholder for platform-specific read functions
+
+uint8_t KeepAlive() {
+ SendAckPacket();
+ ParsedPacket packet = ReceivePacket();
+ if(packet.type != PACKET_TYPE_ACK){
+ return 0;
+ }
+ return 1;
+}
+void EndCommunication(){
+ uint8_t endPacket = (uint8_t)PACKET_CMD_End;
+ SendPacket((uint8_t*)endPacket, 1);
+ ResetPacketCounter();
+}
+
+ParsedPacket* SendCustom(const uint8_t* data, int len, int *out_count) {
+ SendPacket((uint8_t*)data, len); //antes &
+ int count = 0;
+ ParsedPacket* packets = ReceivePackets(&count);
+ *out_count = count;
+ return packets;
+}
+
diff --git a/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/IKW1281Connection.h b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/IKW1281Connection.h
new file mode 100644
index 0000000..9f49127
--- /dev/null
+++ b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/IKW1281Connection.h
@@ -0,0 +1,101 @@
+/*
+ * IKW1281Connection.h
+ *
+ * Created on: Apr 9, 2025
+ * Author: herli
+ */
+
+#ifndef INC_IKW1281CONNECTION_H_
+#define INC_IKW1281CONNECTION_H_
+
+#include
+#include "stdint.h"
+
+extern uint8_t RxData[];
+extern volatile uint8_t rx_done_flag;
+extern uint8_t connectionAlive;
+
+#define KLINE_BUFFER_SIZE 20
+
+#define PACKET_END_EXPECTED 0x03
+
+
+
+
+//typedef uint8_t PacketCommand;
+#define MAX_PACKET_SIZE 512 // if too big it will crash 128length - 1; i++) {
+ char c = packet->raw[i] & 0x7F;
+ if (len < sizeof(data) - 2) {
+ data[len++] = c;
+ }
+ }
+
+ // Null-terminate and add newline
+ data[len++] = '\r\n';
+ data[len] = '\0';
+
+ HAL_UART_Transmit(huart, (uint8_t*)data, len, 1000);
+
+ // Optional: report more data
+ if (packet->raw[3] > 0x7F) {
+ const char more[] = "More data available via ReadIdent\r\n";
+ HAL_UART_Transmit(huart, (uint8_t*)more, sizeof(more) - 1, 1000);
+ }
+}*/
+
+int FilterNonAckNak(ParsedPacket* all, int total, ParsedPacket* filtered, int max)
+{
+ int j = 0;
+ for (int i = 0; i < total && j < max; i++) {
+ if (!all[i].isAckNak) {
+ filtered[j++] = all[i];
+ }
+ }
+ return j;
+}
+static ControllerInfo info = {0}; // Zero init all strings
+
+ControllerInfo ReadEcuInfo() {
+ int packet_count = 0;
+ ParsedPacket *packets = ReceivePackets(&packet_count);
+
+ char combined[128] = {0}; // Temporary buffer to build full ASCII text
+
+ if (packets != NULL) {
+ for (int i = 0; i < packet_count; i++) {
+ ParsedPacket *p = &packets[i];
+ if (p->type == PACKET_TYPE_ASCII_DATA && p->length > 4) {
+ size_t len = p->length - 4; // Exclude first 3 and last byte
+ strncat(combined, (char*)(p->raw + 3), len);
+ }
+ }
+ //free(packets); // clean up when done
+ }
+
+ memset(&info, 0, sizeof(ControllerInfo));
+
+ // Fill ControllerInfo fields from combined text
+ strncpy(info.client_ident, combined, 12);
+ strncpy(info.unk_ident1, combined + 12, 10);
+ strncpy(info.soft_info, combined + 22, 10);
+
+ if (strlen(combined) > 40)
+ strncpy(info.unk_ident2, combined + 32, 10);
+ if (strlen(combined) > 50)
+ strncpy(info.unk_ident3, combined + 42, 10);
+
+ //free(combined);
+ return info;
+}
+
+/*void PrintEcuInfo(ControllerInfo* info) {
+ char data[64];
+
+ sprintf(data, "client_ident: %s\t\r\n", info->client_ident);
+ //HAL_UART_Transmit(&huart2, (uint8_t*)data, strlen(data), 1000);
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));
+ HAL_Delay(10); // allow USB stack to flush
+
+ sprintf(data, "unk_ident1: %s\t\r\n", info->unk_ident1);
+ //HAL_UART_Transmit(&huart2, (uint8_t*)data, strlen(data), 1000);
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));
+ HAL_Delay(10); // allow USB stack to flush
+
+ sprintf(data, "soft_info: %s\t\r\n", info->soft_info);
+ //HAL_UART_Transmit(&huart2, (uint8_t*)data, strlen(data), 1000);
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));
+ HAL_Delay(10); // allow USB stack to flush
+
+ if (strlen(info->unk_ident2) > 0) {
+ sprintf(data, "unk_ident2: %s\t\r\n", info->unk_ident2);
+ //HAL_UART_Transmit(&huart2, (uint8_t*)data, strlen(data), 1000);
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));
+ HAL_Delay(10); // allow USB stack to flush
+
+ }
+
+ if (strlen(info->unk_ident3) > 0) {
+ sprintf(data, "unk_ident3: %s\t\r\n", info->unk_ident3);
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));
+ HAL_Delay(10); // allow USB stack to flush
+
+// HAL_UART_Transmit(&huart2, (uint8_t*)data, strlen(data), 1000);
+ }
+}*/
+#define MAX_EEPROM_DATA 256 // adjust to your ECU’s max response
+#define MAX_PACKETS 16
+
+static ParsedPacket packet_buffer[MAX_PACKETS];
+static uint8_t eeprom_result[MAX_EEPROM_DATA];
+
+uint8_t* ReadRomEeprom(uint16_t address, uint8_t count, int* outLength)
+{
+ uint8_t request[4] = {
+ PACKET_CMD_ReadRomEeprom, // 0x08 usually
+ count,
+ (uint8_t)(address >> 8),
+ (uint8_t)(address & 0xFF)
+ };
+
+ int packetCount = 0;
+ ParsedPacket* packets = SendCustom(request, sizeof(request), &packetCount);
+ if (!packets || packetCount == 0) {
+ *outLength = 0;
+ return NULL;
+ }
+
+ // Check for NAK
+ if (packetCount == 1 && packets[0].type == PACKET_TYPE_NAK) {
+ *outLength = 0;
+ return NULL;
+ }
+
+ // Collect useful packets (non-Ack/Nak)
+ int usefulCount = 0;
+ for (int i = 0; i < packetCount && usefulCount < MAX_PACKETS; i++) {
+ if (!packets[i].isAckNak) {
+ packet_buffer[usefulCount++] = packets[i];
+ }
+ }
+
+ if (usefulCount != 1) {
+ *outLength = 0;
+ return NULL; // Expect exactly one useful packet
+ }
+
+ int dataLen = packet_buffer[0].length - 4; // skip 3-byte header + 1-byte end
+ if (dataLen > MAX_EEPROM_DATA) {
+ dataLen = MAX_EEPROM_DATA; // clamp to buffer size
+ }
+
+ memcpy(eeprom_result, packet_buffer[0].raw + 3, dataLen);
+ *outLength = dataLen;
+
+ return eeprom_result; // static buffer pointer
+}
+/*
+uint8_t* ReadRomEeprom(uint16_t address, uint8_t count, int* outLength) {
+ uint8_t request[4] = {
+ PACKET_CMD_ReadRomEeprom, // 0x08 usually
+ count,
+ (uint8_t)(address >> 8),
+ (uint8_t)(address & 0xFF)
+ };
+
+ int packetCount = 0;
+ ParsedPacket* packets = SendCustom(request, sizeof(request), &packetCount, 0);
+ if (!packets || packetCount == 0) {
+ *outLength = 0;
+ return NULL;
+ }
+
+ // Check for NAK
+ if (packetCount == 1 && packets[0].type == PACKET_TYPE_NAK) {
+ freeParsedPackets(packets, packetCount);
+ *outLength = 0;
+ return NULL;
+ }
+
+ // Filter to exclude Ack/Nak
+ ParsedPacket* useful = malloc(packetCount * sizeof(ParsedPacket));
+ int usefulCount = 0;
+ for (int i = 0; i < packetCount; i++) {
+ if (!packets[i].isAckNak) {
+ useful[usefulCount++] = packets[i];
+ } else {
+ // If dynamically allocated, free individual packet.raw
+ free(packets[i].raw);
+ }
+ }
+ free(packets); // Free the original array pointer (but not the reused raw data)
+
+ if (usefulCount != 1) {
+ freeParsedPackets(useful, usefulCount);
+ *outLength = 0;
+ return NULL; // Or handle as error
+ }
+
+ uint8_t* result = malloc(useful[0].length - 4); // Remove 3-byte header + end (or however yours works)
+ if (!result) {
+ freeParsedPackets(useful, usefulCount);
+ *outLength = 0;
+ return NULL;
+ }
+
+ memcpy(result, useful[0].raw + 3, useful[0].length - 4); // Adjust if header is different
+ *outLength = useful[0].length - 4;
+
+ freeParsedPackets(useful, usefulCount);
+ return result;
+}*/
+
+void ReadSerialNumber(char* serialOut, int maxLen) {
+ uint8_t request[] = { 0x19, 0x06, 0x00, 0x80 };
+
+ int packetCount = 0;
+ ParsedPacket* packets = SendCustom(request, sizeof(request), &packetCount);
+
+ if (!packets || packetCount == 0) {
+ serialOut[0] = '\0';
+ return;
+ }
+
+ for (int i = 0; i < packetCount; i++) {
+ ParsedPacket* p = &packets[i];
+ if (!p->isAckNak && p->type == PACKET_TYPE_READ_EEPROM_RESPONSE) {
+ int dataLen = p->length - 4; // Skip length, counter, command, end byte
+ if (dataLen > maxLen - 1) {
+ dataLen = maxLen - 1;
+ }
+
+ memcpy(serialOut, p->raw + 3, dataLen); // Adjust if needed
+ serialOut[dataLen] = '\0';
+
+ //freeParsedPackets(packets, packetCount);
+ return;
+ }
+ }
+
+ serialOut[0] = '\0';
+ //freeParsedPackets(packets, packetCount);
+}
+
+/*void freeParsedPackets(ParsedPacket* packets, int count) {
+ if (!packets) return;
+
+ for (int i = 0; i < count; i++) {
+ if (packets[i].raw != NULL) {
+ //free(packets[i].raw);
+ //packets[i].raw = NULL; // Avoid double free
+ }
+ }
+
+ //free(packets); // Free the packet array itself
+}*/
+
+uint16_t ExtractEepromAddress(ParsedPacket *packets, int packet_count) {
+ for (int i = 0; i < packet_count; i++) {
+ ParsedPacket *p = &packets[i];
+ if (!p->isAckNak && p->length > 4) {
+ uint32_t address = (p->raw[3+1] << 8) | p->raw[3];
+ return address - 10;
+ }
+ }
+ return 0;
+}
+float ReadDfi(){
+ float Dfi = 0.0;
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(0);
+ return 0.0;
+ }
+ uint8_t request[] = { 0x18, 0x00, 0x03, 0xFF, 0xFF }; //TODO ERROR ENVIA AC 7E 00 20 00
+ int packet_count = 0;
+ //ParsedPacket* packets = SendCustom(request, 5, &packet_count, 1); //this changes with pump version but for now no exceptions
+ ParsedPacket* packets = SendCustom((uint8_t[]){ 0x18, 0x00, 0x03, 0xFF, 0xFF }, 5, &packet_count);
+
+ //Dfi = 1.0;
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(0);
+ return 0.0;
+ }
+
+ uint8_t request2[] = { 0x19, 0x02, 0x00, 0x44};
+ packets = SendCustom(request2, 4, &packet_count); //this changes with pump version but for now no exceptions
+
+
+ // Filter to exclude Ack/Nak
+ for (int i = 0; i < packet_count; i++) {
+ if (!packets[i].isAckNak) {
+ Dfi = ((int8_t)packets[i].raw[3] * 3.0) / 256.0;
+ }
+ }
+ //free(packets); // Free the original array pointer (but not the reused raw data)
+ /*if(Dfi != 0.0){
+
+ }*/
+ return Dfi;
+}
+
+/**
+ * Write DFI parameter (EEPROM 0x44) after password unlock.
+ *
+ * version mapping (as in your C#):
+ * default: {18 00 03 2F FF ...}
+ * version==1: {18 00 03 2F F2 ...}
+ * version==2 or 3: {18 00 03 FF F2 ...}
+ *
+ * Returns 1 on success, 0 on failure (non-alive).
+ */
+int WriteDfi(float dfi, int version)
+{
+ if (!KeepAlive()) {
+ KLINE_THROW_NONALIVE_EXCEPTION(0);
+ return 0;
+ }
+
+ // Password packets (14 bytes)
+ static const uint8_t pass_default[14] = {
+ 0x18, 0x00, 0x03, 0x2F, 0xFF, 0x4B, 0x48, 0x54, 0x43, 0x41, 0x38, 0x47, 0x30, 0x45
+ }; // V1 KHTCA8G0E (per your comment)
+ static const uint8_t pass_v2[14] = {
+ 0x18, 0x00, 0x03, 0x2F, 0xF2, 0x4B, 0x48, 0x54, 0x43, 0x41, 0x38, 0x47, 0x30, 0x45
+ }; // V2 KHTCA8G0E
+ static const uint8_t pass_v3v4[14] = {
+ 0x18, 0x00, 0x03, 0xFF, 0xF2, 0x4B, 0x48, 0x54, 0x43, 0x41, 0x38, 0x47, 0x30, 0x45
+ }; // V3, V4
+
+ const uint8_t *password_packet = pass_default;
+ if (version == 1) {
+ password_packet = pass_v2;
+ } else if (version == 2 || version == 3) {
+ password_packet = pass_v3v4;
+ }
+
+ int packet_count = 0;
+ (void)SendCustom(password_packet, 14, &packet_count); // throwOnNak=1 (strict)
+
+ if (!KeepAlive()) {
+ KLINE_THROW_NONALIVE_EXCEPTION(0);
+ return 0;
+ }
+
+ // C#:
+ // sbyte value = (sbyte)((dfi * 256.0) / 3);
+ // if (value == 0) value = 1;
+ //
+ // NOTE: with dfi up to +1.5, math gives 128.0. That does not fit in int8_t.
+ // We clamp to [-128..127] to avoid wrap to -128.
+ int vi = (int)((dfi * 256.0f) / 3.0f); // trunc toward 0 (matches typical C# unchecked cast behavior for in-range)
+ vi = vi > 127 ? 127:vi;
+ vi = vi < -128 ? -128:vi;
+ //vi = clamp_int(vi, -128, 127);
+ int8_t value = (int8_t)vi;
+ if (value == 0) value = 1;
+
+ // byte value_csum = (byte)(0 - (byte)value);
+ uint8_t value_u = (uint8_t)value;
+ uint8_t value_csum = (uint8_t)(0u - value_u);
+
+ // Write command
+ uint8_t req[7] = { 0x1A, 0x02, 0x00, 0x44, value_u, value_csum, 0x03 };
+ (void)SendCustom(req, 7, &packet_count); // throwOnNak=1 (strict)
+
+ if (!KeepAlive()) {
+ KLINE_THROW_NONALIVE_EXCEPTION(0);
+ return 0;
+ }
+
+ return 1;
+}
+void ReadCustomerChangeIndex(){
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(0);
+ return;
+ }
+ uint8_t request[] = { 0x18, 0x00, 0x00, 0x82, 0x33 };
+
+ int packet_count = 0;
+ ParsedPacket* packets = SendCustom(request, 5, &packet_count); //this changes with pump version but for now no exceptions
+
+ char message[40];
+ //sprintf(message, "Reading customer change index\r\n");
+ //HAL_UART_Transmit(&huart2, (uint8_t*)message, strlen(message), 1000);
+
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(12);
+ return;
+ }
+
+ uint16_t cust_change_address = 0;
+
+ int data_length = 0;
+
+ uint8_t* test_data = ReadRomEeprom(0x9FFE, 2, &data_length);
+ if(data_length > 1){
+ cust_change_address = (uint16_t)((test_data[1] << 8) | test_data[0]);
+ cust_change_address += 3;
+ }
+
+ test_data = ReadRomEeprom(cust_change_address, 6, &data_length);
+
+ char cust_change_index[12];
+
+ if (test_data && data_length > 0) {
+ for (int i = 0; i < data_length; i++) {
+ cust_change_index[i] = (char)test_data[i]; // Convert byte to char
+ }
+ }
+ //sprintf(message, "Mod. Index : %s\r\n", cust_change_index);
+ //CDC_Transmit_FS((uint8_t*)message, strlen(message));
+ /*char cust_change_index[12];
+
+ if (test_data && data_length > 0) {
+ int copy_len = (data_length < (sizeof(cust_change_index) - 1))
+ ? data_length
+ : (sizeof(cust_change_index) - 1);
+
+ for (int i = 0; i < copy_len; i++) {
+ cust_change_index[i] = (char)test_data[i];
+ }
+ cust_change_index[copy_len] = '\0'; // Null-terminate
+ }
+
+ sprintf(message, "Mod. Index : %s\r\n", cust_change_index);
+ CDC_Transmit_FS((uint8_t*)message, strlen(message));*/
+ //HAL_UART_Transmit(&huart2, (uint8_t*)cust_change_index, strlen(cust_change_index), 1000);
+}
+char identStr[11]; //11+1
+
+void IdentifyEcu() {
+ char outputStr[35];
+ //float dFi = ReadDfi();
+ //sprintf(outputStr, "dFi: %d.%02d\t\t\r\n", (int)dFi, (int)((dFi - (int)dFi) * 100));
+
+ //CDC_Transmit_FS((uint8_t*)outputStr, strlen(outputStr));
+
+ ReadCustomerChangeIndex();//Necessary
+
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(0);
+ return;
+ }
+ int packet_count = 0;
+ ParsedPacket* packets = SendCustom((uint8_t[]){ 0x01, 0x02, 0x00, 0xC6 }, 4, &packet_count);
+
+ //uint16_t address = ExtractEepromAddress(packets, count);
+
+ uint16_t address = ExtractEepromAddress(packets, packet_count);
+
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(1);
+ return;
+ }
+
+ if (address != 0) {
+ int data_length = 0;
+ uint8_t* test_data = ReadRomEeprom(address, 10, &data_length);
+
+ for (int i = 0; i < data_length && i < sizeof(identStr) - 1; i++) {
+ identStr[i] = (char)test_data[i];
+ } //identStr[10] = '\0';
+ //HAL_UART_Transmit(&huart2, (uint8_t*)identStr, strlen(identStr), 1000);
+ //sprintf(outputStr, "Ident. : %s\t\r\n", identStr);
+
+ //CDC_Transmit_FS((uint8_t*)outputStr, strlen(outputStr));
+
+ }
+
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(2);
+ return;
+ }
+
+ char serial[20];
+ ReadSerialNumber(serial, sizeof(serial));
+ //sprintf(serial, "serial numb: %s\r\n", serial);
+ //HAL_UART_Transmit(&huart2, (uint8_t*)serial, strlen(serial), 1000);
+ /*sprintf(outputStr, "Serial N. : %s\t\r\n", serial);
+
+ CDC_Transmit_FS((uint8_t*)outputStr, strlen(outputStr));*/
+
+ //sprintf(serial, "serial numb: %s\r\n", serial);
+ //HAL_UART_Transmit(&huart2, (uint8_t*)data, strlen(data), 1000);
+}
+
+
+/* FAULT CODE READING */
+
+
+#define FAULTCODE_NONE_DTC 0x00
+
+/* --- Tuning limits (adapt to your max) --- */
+#define MAX_FAULTCODES 20
+#define MAX_FC_AGGREGATE_LEN 512 // total concatenated body bytes
+
+int ReadFaultCodes(FaultCode* outCodes, int maxCodes)
+{
+ char logmsg[64];
+
+ if (!outCodes || maxCodes <= 0) return -1;
+
+ // Keep the link alive as you do elsewhere TODO
+ if (!KeepAlive()) {
+ KLINE_THROW_NONALIVE_EXCEPTION(0);
+ return -1;
+ }
+
+ // "Sending ReadFaultCodes packet"
+ /*sprintf(logmsg, "Sending ReadFaultCodes packet\r\n");
+ CDC_Transmit_FS((uint8_t*)logmsg, (uint16_t)strlen(logmsg));*/
+
+ // Send single-byte payload with command 0x07
+ uint8_t cmd = (uint8_t)PACKET_CMD_FaultCodesRead; // already defined in your enum
+ SendPacket(&cmd, 1);
+
+ // Receive all response packets
+ int packet_count = 0;
+ ParsedPacket* packets = ReceivePackets(&packet_count);
+ if (!packets || packet_count <= 0) {
+ return 0; // no codes
+ }
+
+ // Concatenate all bodies from non-ACK/NAK packets
+ // Body = raw[3 .. (3 + body_len - 1)], where body_len = (length - 3).
+ // Full raw frame is: [len][counter][command][body...][end]
+ // Your receiver code writes the end byte separately (0x03).
+ // NOTE: guard against malformed lengths.
+ uint8_t fc_buf[64];
+ int fc_len = 0;
+
+ for (int i = 0; i < packet_count; i++) {
+ if (packets[i].isAckNak) continue;
+
+ // If you classify types and want to be strict, enforce here:
+ if (packets[i].title != PACKET_CMD_FaultCodesResponse) {
+ /*sprintf(logmsg, "Expected FaultCodesPacket but got type=0x%02X\r\n", packets[i].type);
+ CDC_Transmit_FS((uint8_t*)logmsg, (uint16_t)strlen(logmsg));*/
+ //free(packets);
+ return -1;
+ }
+
+ if (!packets[i].raw || packets[i].length < 3) continue;
+
+ int body_len = (int)packets[i].length - 4; // subtract [len, counter, command]
+ if (body_len <= 0) continue;
+
+ // Defensive: make sure the raw buffer actually has those bytes (+1 end is read separately)
+ // We assume your parser filled .raw accordingly.
+
+ if ((fc_len + body_len) > (int)sizeof(fc_buf)) {
+ /*sprintf(logmsg, "Fault code buffer overflow\r\n");
+ CDC_Transmit_FS((uint8_t*)logmsg, (uint16_t)strlen(logmsg));*/
+ //free(packets);
+ return -1;
+ }
+
+ memcpy(&fc_buf[fc_len], &packets[i].raw[3], (size_t)body_len);
+ fc_len += body_len;
+ }
+
+ // Done with the packet list (your comment: free only the array, not reused raw)
+ //free(packets);
+
+ // Parse aggregated data:
+ // C# does: take first 3 bytes (dtc,status,extra), then Skip(8) per record.
+ // That means record stride = 8 bytes, but only first 3 matter here.
+ // Stop when fewer than 3 bytes remain.
+ int produced = 0;
+ int off = 0;
+
+ while (off + 3 <= fc_len) {
+ uint8_t dtc = fc_buf[off + 0];
+ uint8_t status = fc_buf[off + 1];
+ uint8_t extra = fc_buf[off + 2];
+
+ if (dtc != FAULTCODE_NONE_DTC) {
+ if (produced < maxCodes) {
+ outCodes[produced].dtc = dtc;
+ outCodes[produced].status = status;
+ outCodes[produced].extra = extra;
+ produced++;
+ } else {
+ /*sprintf(logmsg, "Fault code output full (%d)\r\n", maxCodes);
+ CDC_Transmit_FS((uint8_t*)logmsg, (uint16_t)strlen(logmsg));*/
+ break;
+ }
+ }
+
+ // Advance to next 8-byte record
+ off += 8;
+ }
+
+ return produced; // number of valid fault codes in outCodes[]
+}
+int ClearFaultCodes(void)
+{
+ int packet_count = 0;
+ uint8_t req[1] = { PACKET_CMD_FaultCodesDelete };
+
+ ParsedPacket *packets = SendCustom(req, 1, &packet_count);
+
+ // C# expects exactly 1 packet
+ if (packet_count != 1) {
+ // in embedded: return error code (or assert/log)
+ return 0;
+ }
+
+ ParsedPacket *p = &packets[0];
+
+ // Must be ACK or NAK
+ if (!p->isAckNak) {
+ return 0;
+ }
+
+ if (p->type == PACKET_TYPE_NAK) return 0;
+ if (p->type == PACKET_TYPE_ACK) return 1;
+
+ return 0;
+}
+
+/*void PrintFaultCodes(const FaultCode* list, int n)
+{
+ if (!list || n <= 0) {
+ const char* msg = "No fault codes\r\n";
+ CDC_Transmit_FS((uint8_t*)msg, (uint16_t)strlen(msg));
+ return;
+ }
+ for (int i = 0; i < n; i++) {
+ PrintFaultCode(&list[i]);
+ HAL_Delay(10);
+ }
+}*/
+
+typedef struct { uint8_t code; const char* text; } DtcMapEntry;
+
+static const DtcMapEntry DTC_MAP[] = {
+ {0x50, "Fuel quantity solenoid valve Output stage error"},
+ {0x51, "Fuel quantity solenoid valve."},
+ {0x52, "Angle sensor/ IWZ system."},
+ {0x53, "Angle sensor/ IWZ system"},
+ {0x54, "Control unit temperature sensor, temperature too high"},
+ {0x55, "Control unit temperature sensor"},
+ {0x56, "Battery voltage out of range"},
+ {0x57, "Timing device control. Permanent control deviation"},
+ {0x58, "Fuel quantity / timing solenoid valve"},
+ {0x59, "BIP Fault (Begin of Injection Point)"},
+ {0x5A, "Engine speed signal"},
+ {0x5B, "Engine speed signal"},
+ {0x5C, "CAN-Bus (sporadic)"},
+ {0x5D, "CAN bus error"},
+ {0x5E, "Self-test error"},
+};
+
+static const char* GetDtcText(uint8_t code)
+{
+ for (unsigned i = 0; i < (sizeof(DTC_MAP)/sizeof(DTC_MAP[0])); i++) {
+ if (DTC_MAP[i].code == code) return DTC_MAP[i].text;
+ }
+ return "Unknown Error Code";
+}
+/*int FaultCode_ToString(const FaultCode* fc, char* dst, int dst_len)
+{
+ if (!fc || !dst || dst_len <= 0) return 0;
+
+ uint8_t status1 = (uint8_t)(fc->status & 0x7F);
+ const char* txt = GetDtcText(fc->dtc);
+
+ // Format like: "5A Engine speed signal (03)\r\n"
+ // (use %02u to mimic ":d2" from your C# example)
+ int n = snprintf(dst, (size_t)dst_len, "%02X %s (%02u)\r\n",
+ fc->dtc, txt, status1);
+ if (n < 0) n = 0;
+ if (n >= dst_len) n = dst_len - 1;
+ return n;
+}*/
+/*void PrintFaultCode(const FaultCode* fc)
+{
+ char line[128];
+ int n = FaultCode_ToString(fc, line, sizeof(line));
+ if (n > 0) {
+ CDC_Transmit_FS((uint8_t*)line, (uint16_t)n);
+ }
+}*/
+
+void KLINE_THROW_NONALIVE_EXCEPTION(uint8_t id){
+ char erroralive[20];
+ //sprintf(erroralive, "isnt alive %u\r\r\n", id);
+ BT_KLINE_ERROR();
+ //HAL_UART_Transmit(&huart2, (uint8_t*)erroralive, strlen(erroralive), 1000);
+ //CDC_Transmit_FS((uint8_t*)erroralive, strlen(erroralive));
+
+}
+
+uint8_t ReadAudiPin(uint16_t* pin) {
+ int data_length = 0;
+ uint8_t* data = ReadRomEeprom(0x04FA, 2, &data_length);
+ if(data_length < 1){return 0;}
+ *pin = (uint16_t)((data[1] << 8) | data[0]);
+ return 1;
+}
+uint8_t WriteAudiPin(uint16_t pin) {
+ /*uint8_t* data = ReadRomEeprom(0x04FA, 2, &data_length);
+ if(data_length < 1){return 0;}
+ *pin = (uint16_t)((data[1] << 8) | data[0]);*/
+ return 1;
+}
+
+uint8_t ReadVoltage(uint16_t* volt) {
+ int data_length = 0;
+ uint8_t* data = ReadRomEeprom(0x0142, 2, &data_length);
+ if(data_length < 1){return 0;}
+ *volt = (uint16_t)((data[1] << 8) | data[0]);
+ return 1;
+}
diff --git a/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/kline.h b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/kline.h
new file mode 100644
index 0000000..19b8ecd
--- /dev/null
+++ b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Kline_Master_Libs/kline.h
@@ -0,0 +1,34 @@
+/*
+ * kline.h
+ *
+ * Created on: Aug 18, 2025
+ * Author: herli
+ */
+
+#ifndef INC_KLINE_H_
+#define INC_KLINE_H_
+
+#include "IKW1281Connection.h"
+
+#define ECU_INIT_ADDRESS 0xF1
+
+#define KLINE_GPIO_PORT GPIOA
+#define KLINE_PIN GPIO_PIN_9
+
+extern uint8_t BitBang;
+
+typedef struct {
+ uint8_t dtc; // Primary DTC byte
+ uint8_t status; // Status byte
+ uint8_t extra; // Third byte in the 3-byte header (kept for parity with C#)
+} FaultCode;
+
+extern ControllerInfo ReadEcuInfo(void);
+int WakeUp(uint8_t controllerAddress, uint8_t evenParity);
+void IdentifyEcu(void);
+int ReadFaultCodes(FaultCode* outCodes, int maxCodes);
+uint8_t ReadVoltage(uint16_t* volt);
+extern void KLINE_THROW_NONALIVE_EXCEPTION(uint8_t id);
+int FaultCode_ToString(const FaultCode* fc, char* dst, int dst_len);
+
+#endif /* INC_KLINE_H_ */
diff --git a/bpdt-firmware/bpdt-adapter-stm32h5/Core/Src/main.c b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Src/main.c
index 38f3c28..10ffbe0 100644
--- a/bpdt-firmware/bpdt-adapter-stm32h5/Core/Src/main.c
+++ b/bpdt-firmware/bpdt-adapter-stm32h5/Core/Src/main.c
@@ -21,7 +21,9 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
-
+#include "kline.h"
+#include "IKW1281Connection.h"
+#include "hc_06.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -74,7 +76,70 @@ static void MX_USART6_UART_Init(void);
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
+uint8_t RxData[1];
+ControllerInfo ecuinfo = {0};
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
+{
+ if (huart->Instance == huart2.Instance)
+ {
+ HC06_UART_RxByteCallback(huart);
+ }else{
+ rx_done_flag = 1;
+ HAL_UART_Receive_IT(&huart1, RxData, 1);
+ }
+}
+void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
+{
+ HC06_UART_TxCpltCallback(huart);
+}
+uint8_t pc_connected = 0;
+uint8_t sent_init_message = 0;
+
+uint8_t psg_connected = 0;
+
+void OnEnterReceived(void) {
+ BitBang = 1;
+}
+
+uint32_t alive_due_ms =0;
+
+void TryConnection(void){
+ BitBang = 0;
+
+ char data[32];
+
+ /*sprintf(data, "Starting communication with PSGx...\r\n");
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));
+ sprintf(data, "\r\n");
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));
+ */
+ int protocolVersion = WakeUp(ECU_INIT_ADDRESS, 0);
+ //WriteByteRaw(0x69);
+ //memset(data, 0, sizeof data);
+ /*sprintf(data, "Protocol Version : %d\t\r\n", protocolVersion);
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));*/
+
+ //HAL_UART_Transmit(&huart2, data, 12, 1000);
+
+ ecuinfo = ReadEcuInfo();
+
+ //PrintEcuInfo(&ecuinfo);
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(4);
+ return;
+ }
+ IdentifyEcu();
+
+ /*FaultCode fault_codes[20]; // buffer for up to 32 codes (tune size as needed)
+ int N_fc = ReadFaultCodes(fault_codes, 20);
+ PrintFaultCodes(fault_codes, N_fc);*/
+ //free(fault_code)
+ psg_connected = 1;
+ alive_due_ms = HAL_GetTick() + 500;
+
+ BT_OnPSG5CommEstablished();
+}
/* USER CODE END 0 */
/**
@@ -119,7 +184,10 @@ int main(void)
MX_USART3_UART_Init();
MX_USART6_UART_Init();
/* USER CODE BEGIN 2 */
-
+ HAL_UART_Receive_IT(&huart1, RxData, 1);
+ //HAL_Delay(25); // Wait before starting UART (standard KWP wait time)
+ HC06_Init();
+ HC06_AT_BootSetup(); // sets NAME, then switches to BIN mode
/* USER CODE END 2 */
/* Infinite loop */
@@ -129,6 +197,36 @@ int main(void)
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
+
+ HC06_Process();
+
+ /*if(pc_connected && !sent_init_message){
+ sprintf(data, "Press any key to read data...\r\n");
+ CDC_Transmit_FS((uint8_t*)data, strlen(data));
+ sent_init_message = 1;
+ }*/
+ //HAL_UART_Transmit_DMA(&huart1, data, 5);
+ //CDC_Transmit_FS((uint8_t*)data, strlen(data));
+
+
+ if(BitBang){
+ //HAL_GPIO_WritePin(KLINE_GPIO_PORT, GPIO_PIN_8, GPIO_PIN_RESET);
+ TryConnection();
+ //AQUI HARIA FALTA IMPLEMENTAR UN TIMER QUE CADA x ms haga un keep alive
+ //EndCommunication();
+ }
+ if(psg_connected){
+ if ((int32_t)(HAL_GetTick() - alive_due_ms) < 0){
+ if(!KeepAlive()){
+ KLINE_THROW_NONALIVE_EXCEPTION(4);
+ psg_connected = 0;
+ //return;
+ }
+ BT_SendCommStatus();
+ alive_due_ms = HAL_GetTick() + 500;
+ }
+
+ }
}
/* USER CODE END 3 */
}