Updated C code (fixed ~50 errors) and cleaned up vestigials, should test now
This commit is contained in:
@@ -32,6 +32,10 @@
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.definedsymbols.166077643" name="Define symbols (-D)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.definedsymbols" valueType="definedSymbols">
|
||||
<listOptionValue builtIn="false" value="DEBUG"/>
|
||||
</option>
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.includepaths.295803752" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.includepaths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/Core/Kline_Master_Libs}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/Core/BT_HC06_Libs}""/>
|
||||
</option>
|
||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.input.419205202" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.input"/>
|
||||
</tool>
|
||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.686310707" name="MCU/MPU GCC Compiler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler">
|
||||
@@ -48,6 +52,8 @@
|
||||
<listOptionValue builtIn="false" value="../Drivers/STM32H5xx_HAL_Driver/Inc/Legacy"/>
|
||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32H5xx/Include"/>
|
||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/Core/Kline_Master_Libs}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/Core/BT_HC06_Libs}""/>
|
||||
</option>
|
||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c.1903972581" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c"/>
|
||||
</tool>
|
||||
@@ -105,12 +111,16 @@
|
||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board.113809730" name="Board" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board" useByScannerDiscovery="false" value="NUCLEO-H533RE" valueType="string"/>
|
||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults.165871031" name="Defaults" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults" useByScannerDiscovery="false" value="com.st.stm32cube.ide.common.services.build.inputs.revA.1.0.6 || Release || false || Executable || com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain.value.workspace || NUCLEO-H533RE || 0 || 0 || arm-none-eabi- || ${gnu_tools_for_stm32_compiler_path} || ../Core/Inc | ../Drivers/STM32H5xx_HAL_Driver/Inc | ../Drivers/STM32H5xx_HAL_Driver/Inc/Legacy | ../Drivers/CMSIS/Device/ST/STM32H5xx/Include | ../Drivers/CMSIS/Include || || || USE_HAL_DRIVER | STM32H533xx || || Drivers | Core/Startup | Core || || || ${workspace_loc:/${ProjName}/STM32H533RETX_FLASH.ld} || true || NonSecure || || secure_nsclib.o || || None || || || || ::" valueType="string"/>
|
||||
<option id="com.st.stm32cube.ide.mcu.debug.option.cpuclock.1430752187" name="Cpu clock frequence" superClass="com.st.stm32cube.ide.mcu.debug.option.cpuclock" useByScannerDiscovery="false" value="32" valueType="string"/>
|
||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.converthex.247049569" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.converthex" value="true" valueType="boolean"/>
|
||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.convertbinary.1040440588" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.convertbinary" value="true" valueType="boolean"/>
|
||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.converthex.247049569" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.converthex" useByScannerDiscovery="false" value="true" valueType="boolean"/>
|
||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.convertbinary.1040440588" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.convertbinary" useByScannerDiscovery="false" value="true" valueType="boolean"/>
|
||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform.987603817" isAbstract="false" osList="all" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform"/>
|
||||
<builder buildPath="${workspace_loc:/bpdt-adapter-stm32h5}/Release" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder.568789294" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder"/>
|
||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.1736608173" name="MCU/MPU GCC Assembler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler">
|
||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel.10517238" name="Debug level" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel.value.g0" valueType="enumerated"/>
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.includepaths.1084208325" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.includepaths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/Core/Kline_Master_Libs}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/Core/BT_HC06_Libs}""/>
|
||||
</option>
|
||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.input.1231801121" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.input"/>
|
||||
</tool>
|
||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.1085501967" name="MCU/MPU GCC Compiler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler">
|
||||
@@ -126,6 +136,8 @@
|
||||
<listOptionValue builtIn="false" value="../Drivers/STM32H5xx_HAL_Driver/Inc/Legacy"/>
|
||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32H5xx/Include"/>
|
||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/Core/Kline_Master_Libs}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/Core/BT_HC06_Libs}""/>
|
||||
</option>
|
||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c.393750469" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c"/>
|
||||
</tool>
|
||||
|
||||
743
bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.c
Normal file
743
bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.c
Normal file
@@ -0,0 +1,743 @@
|
||||
#include "hc_06.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
98
bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.h
Normal file
98
bpdt-firmware/bpdt-adapter-stm32h5/Core/BT_HC06_Libs/hc_06.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#ifndef INC_HC_06_H_
|
||||
#define INC_HC_06_H_
|
||||
|
||||
#include "main.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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_ */
|
||||
@@ -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 --------------------------------------------------------*/
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* IKW1281Connection.c
|
||||
*
|
||||
* Created on: Apr 9, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* IKW1281Connection.h
|
||||
*
|
||||
* Created on: Apr 9, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#ifndef INC_IKW1281CONNECTION_H_
|
||||
#define INC_IKW1281CONNECTION_H_
|
||||
|
||||
#include <string.h>
|
||||
#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 128<max<256 //funcionando en 256
|
||||
//si es menor, no funciona????
|
||||
#define EEPROM_RESPONSE_BODY_MAX 64 // Adjust as needed
|
||||
|
||||
#define MAX_CONTROLLER_PACKETS 8
|
||||
#define MAX_PACKET_BODY_LENGTH 64
|
||||
|
||||
|
||||
typedef struct {
|
||||
char client_ident[13]; // 12 + null
|
||||
char unk_ident1[11];
|
||||
char soft_info[11];
|
||||
char unk_ident2[11];
|
||||
char unk_ident3[11];
|
||||
} ControllerInfo;
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[EEPROM_RESPONSE_BODY_MAX];
|
||||
uint8_t length;
|
||||
uint8_t valid;
|
||||
} EepromResult;
|
||||
|
||||
typedef enum {
|
||||
PACKET_CMD_ReadIdent = 0x00,
|
||||
PACKET_CMD_ReadRomEeprom = 0x03,
|
||||
PACKET_CMD_ActuatorTest = 0x04,
|
||||
PACKET_CMD_FaultCodesDelete = 0x05,
|
||||
PACKET_CMD_End = 0x06,
|
||||
PACKET_CMD_FaultCodesRead = 0x07,
|
||||
PACKET_CMD_ACK = 0x09,
|
||||
PACKET_CMD_NAK = 0x0A,
|
||||
PACKET_CMD_SoftwareCoding = 0x10,
|
||||
PACKET_CMD_ReadEeprom = 0x19,
|
||||
PACKET_CMD_WriteEeprom = 0x1A,
|
||||
PACKET_CMD_Custom = 0x1B,
|
||||
PACKET_CMD_GroupReading = 0x29,
|
||||
PACKET_CMD_Login = 0x2B,
|
||||
PACKET_CMD_GroupReadingResponse = 0xE7,
|
||||
PACKET_CMD_ReadEepromResponse = 0xEF,
|
||||
PACKET_CMD_ActuatorTestResponse = 0xF5,
|
||||
PACKET_CMD_AsciiData = 0xF6,
|
||||
PACKET_CMD_WriteEepromResponse = 0xF9,
|
||||
PACKET_CMD_FaultCodesResponse = 0xFC,
|
||||
PACKET_CMD_ReadRomEepromResponse = 0xFD
|
||||
} PacketCommand;
|
||||
|
||||
typedef enum {
|
||||
PACKET_TYPE_UNKNOWN = 0,
|
||||
PACKET_TYPE_ACK,
|
||||
PACKET_TYPE_NAK,
|
||||
PACKET_TYPE_ASCII_DATA,
|
||||
PACKET_TYPE_CODING_WSC,
|
||||
PACKET_TYPE_READ_EEPROM_RESPONSE,
|
||||
PACKET_TYPE_READ_ROM_EEPROM_RESPONSE
|
||||
} PacketType;
|
||||
|
||||
typedef struct {
|
||||
PacketType type;
|
||||
uint8_t title;
|
||||
uint8_t length;
|
||||
uint8_t raw[MAX_PACKET_SIZE]; // raw bytes
|
||||
uint8_t isAckNak;
|
||||
} ParsedPacket;
|
||||
|
||||
extern void ResetPacketCounter(void);
|
||||
extern uint8_t ReadPacketCounter(void);
|
||||
extern ParsedPacket ReceivePacket(void);
|
||||
extern uint8_t ReadByte();
|
||||
extern uint8_t ReadAndAckByte(void);
|
||||
extern uint8_t KeepAlive(void);
|
||||
|
||||
void SendPacket(uint8_t* payload, uint8_t length);
|
||||
ParsedPacket* SendCustom(const uint8_t* data, int len, int *out_count);
|
||||
ParsedPacket* ReceivePackets(int *out_count);
|
||||
|
||||
#endif /* INC_IKW1281CONNECTION_H_ */
|
||||
@@ -0,0 +1,782 @@
|
||||
/*
|
||||
* kline.c
|
||||
*
|
||||
* Created on: Aug 18, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#include "kline.h"
|
||||
#include "IKW1281Connection.h"
|
||||
#include "hc_06.h"
|
||||
|
||||
#include "stdint.h"
|
||||
#include "main.h"
|
||||
|
||||
uint8_t BitBang = 0;
|
||||
|
||||
void KLine_Send5Baud(uint8_t data)
|
||||
{
|
||||
HAL_UART_DeInit(&huart1);
|
||||
|
||||
// Reconfigure TX pin as output
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
GPIO_InitStruct.Pin = KLINE_PIN;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(KLINE_GPIO_PORT, &GPIO_InitStruct);
|
||||
|
||||
// 5 baud = 200ms per bit
|
||||
const uint32_t bit_delay_ms = 200;
|
||||
|
||||
// Start bit (low)
|
||||
HAL_GPIO_WritePin(KLINE_GPIO_PORT, KLINE_PIN, GPIO_PIN_RESET);
|
||||
HAL_Delay(bit_delay_ms);
|
||||
|
||||
// Send 8 bits, LSB first
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (data & (1 << i)) {
|
||||
HAL_GPIO_WritePin(KLINE_GPIO_PORT, KLINE_PIN, GPIO_PIN_SET);
|
||||
} else {
|
||||
HAL_GPIO_WritePin(KLINE_GPIO_PORT, KLINE_PIN, GPIO_PIN_RESET);
|
||||
}
|
||||
HAL_Delay(bit_delay_ms);
|
||||
}
|
||||
|
||||
// Stop bit (high)
|
||||
HAL_GPIO_WritePin(KLINE_GPIO_PORT, KLINE_PIN, GPIO_PIN_SET);
|
||||
HAL_Delay(bit_delay_ms);
|
||||
|
||||
HAL_UART_Init(&huart1); // ensures TX idles high, necessary for g431
|
||||
HAL_UART_Receive_IT(&huart1, RxData, 1);
|
||||
}
|
||||
|
||||
int WakeUp(uint8_t controllerAddress, uint8_t evenParity){
|
||||
KLine_Send5Baud(controllerAddress); // ECU address
|
||||
connectionAlive = 1;
|
||||
uint8_t syncByte = ReadByte();
|
||||
if(syncByte != 0x55){return 0;}
|
||||
uint8_t keywordLsb = ReadByte();
|
||||
uint8_t keywordMsb = ReadAndAckByte();
|
||||
|
||||
int protocolVersion = ((keywordMsb & 0x7F) << 7) + (keywordLsb & 0x7F);
|
||||
return protocolVersion;
|
||||
}
|
||||
|
||||
/*void PrintAsciiPayload(const ParsedPacket* packet, UART_HandleTypeDef* huart)
|
||||
{
|
||||
char data[128]; // adjust size as needed
|
||||
int len = 0;
|
||||
|
||||
// Start with a label
|
||||
len += sprintf(&data[len], "ASCII: ");
|
||||
|
||||
for (int i = 4; i < packet->length - 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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user