Files
hpsg5-controller_v2-stm32g4/Core/Kline_Libs/IKW1281Connection.c

275 lines
8.9 KiB
C

/* IKW1281Connection.c — byte pump, RX FIFO, no HAL_Delay() in hot path */
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "IKW1281Connection.h"
#include "main.h"
extern UART_HandleTypeDef huart1;
uint8_t K_TxData[KLINE_BUFFER_SIZE];
volatile uint8_t rx_done_flag = 0;
// ---------- RX FIFO ----------
static uint8_t rx_fifo[KLINE_RX_FIFO_SZ];
static volatile uint16_t rx_head = 0, rx_tail = 0;
static inline int rx_fifo_push(uint8_t b){
uint16_t next = (uint16_t)((rx_head + 1U) % KLINE_RX_FIFO_SZ);
if (next == rx_tail) rx_tail = (uint16_t)((rx_tail + 1U) % KLINE_RX_FIFO_SZ); // drop oldest
rx_fifo[rx_head] = b;
rx_head = next;
rx_done_flag = 1;
return 1;
}
int KLine_RxFifo_Pop(uint8_t *out){
if (rx_head == rx_tail) return 0;
uint8_t b = rx_fifo[rx_tail];
rx_tail = (uint16_t)((rx_tail + 1U) % KLINE_RX_FIFO_SZ);
if (out) *out = b;
return 1;
}
// ---------- Non-blocking TX "byte pump" ----------
volatile KTxEngine ktx = {0};
static uint8_t tx_byte_1;
static uint8_t _packetCounter = 0;
static uint8_t _packetCounterInitialized = 0;
void KLine_BytePump_Init(void){ memset((void*)&ktx, 0, sizeof(ktx)); }
int KLine_TxStart(const uint8_t *data, uint16_t len, uint8_t append_end, uint8_t require_ack){
if (ktx.active==1) return 0;
if (len > KLINE_TXBUF_MAX) {
// defensive: refuse too-long sends (KWP1281 blocks are small, so this is fine)
return 0;
}
memcpy(ktx.ibuf, data, len);
ktx.buf = ktx.ibuf;
ktx.using_ibuf = 1;
ktx.active = 1; ktx.len = len; ktx.idx = 0;
ktx.append_end = append_end; ktx.last_tx = 0; ktx.awaiting_echo = 0;
ktx.require_ack = require_ack; ktx.tx_inflight = 0; ktx.next_time_ms = HAL_GetTick();
return 1;
}
int KLine_TxBusy(void){ return ktx.active || ktx.tx_inflight || ktx.awaiting_echo; }
void KLine_BytePump_Service(void){
if (!ktx.active) return;
uint32_t now = HAL_GetTick();
if (ktx.awaiting_echo) return;
//if (ktx.tx_inflight) return;
if ((int32_t)(now - ktx.next_time_ms) < 0) return;
uint8_t b;
if (ktx.idx < ktx.len) b = ktx.buf[ktx.idx++];
else if (ktx.append_end) {
b = PACKET_END_EXPECTED;
ktx.append_end = 0;
ktx.active = 2; //ENDING
}
else { // === FINISHED: make sure state is fully reset ===
ktx.active = 0;
//ktx.awaiting_echo = 0; // <— add //TODO
//ktx.tx_inflight = 0; // <— add
// (optional) ktx.next_time_ms = now;
return;
}
tx_byte_1 = b;
if (HAL_UART_Transmit_IT(&huart1, &tx_byte_1, 1) == HAL_OK){
//ktx.tx_inflight = 1;
ktx.last_tx = b;
if (ktx.require_ack && ktx.active == 1){
ktx.awaiting_echo = 1; // expect tester's ~b
} else {
ktx.awaiting_echo = 0;
}
ktx.next_time_ms = now + KWP_P1_GAP_MS;
}
}
//int pepe = 0;
// Called from HAL_UART_RxCpltCallback (kline.c)
void KLine_OnByteReceived(uint8_t byte)
{
uint32_t now = HAL_GetTick();
// ---- Self-echo suppression: only within a tiny time window after our TX ----
if(ktx.active){
if ((uint32_t)(now - ktx.last_tx_done_ms) <= KWP_ECHO_SUPPRESS_MS && byte == ktx.last_tx) {
if(ktx.active == 2){
ktx.active = 0;
ktx.awaiting_echo = 0;
}
return; // echo of our own last TX byte
//no se bien si me quita el echo o el counter, habra que ver despues cuando los mensajes no sean de 03
}
}
/*if(pepe==2){
pepe++;
}*/
/*if(ktx.awaiting_ack && byte == ktx.last_tx){
return;
}*/
// ---- Tester complement for our TX byte? consume only if it matches ~last_tx ----
if (ktx.active == 1) {
if(ktx.awaiting_echo){
if (byte == (uint8_t)~ktx.last_tx) {
ktx.awaiting_echo = 0;
//return; // consumed tester's complement
} else {
// Not a complement: treat as inbound payload, drop awaiting flag to resync
ktx.awaiting_echo = 0;
//ktx.active = 0; //we are done, communication failed drop message.
//return;
// fall through to inbound handling
}
}
}
else{
//WriteComplement(byte); //then its inboud payload, echo
rx_fifo_push(byte);
}
// ---- Inbound byte from tester: ACK it immediately so we never race timing ----
// (Tiny 1-byte blocking write; safe and deterministic at 9600 bps.)
//WriteComplement(byte);
// Push for higher-level parsing
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
if (huart->Instance == USART1) {
//ktx.tx_inflight = 0;
ktx.last_tx_done_ms = HAL_GetTick(); // <-- NEW
}
}
// ---------- Legacy/compat API (kept) ----------
uint8_t ReadByte(){
uint32_t timeout = HAL_GetTick() + 1000;
uint8_t b;
while (!KLine_RxFifo_Pop(&b)){
if ((int32_t)(HAL_GetTick() - timeout) >= 0) return 0xFF;
}
return b;
}
uint8_t ReadAndAckByte(void){ uint8_t b = ReadByte(); WriteComplement(b); return b; }
void WriteComplement(uint8_t b){
uint8_t c = (uint8_t)~b;
WriteByteRaw(c); }
void WriteByteRaw(uint8_t b){
ktx.active = 0;
KLine_TxStart(&b, 1, 0, 0);
while (KLine_TxBusy()) KLine_BytePump_Service();
/*ktx.last_tx = b;
ktx.active = 2;
pepe++;
if(b == 0x01){
pepe++;
}
extern UART_HandleTypeDef huart1;
(void)HAL_UART_Transmit(&huart1, &b, 1, 5);*/
}
#define MAX_PACKETS 16
static ParsedPacket packets_buffer[MAX_PACKETS];
ParsedPacket* ReceivePackets(int *out_count){
int count = 0;
while (1){
if (count >= MAX_PACKETS) break;
ParsedPacket p = ReceivePacket();
packets_buffer[count++] = p;
if (p.isAckNak) break;
SendAckPacket();
}
if (out_count) *out_count = count;
return packets_buffer;
}
ParsedPacket ReceivePacket(){
ParsedPacket packet = (ParsedPacket){0};
uint8_t idx = 0;
uint8_t packetLength = ReadAndAckByte(); packet.raw[idx++] = packetLength;
uint8_t packetCounter = ReadPacketCounter(); packet.raw[idx++] = packetCounter;
uint8_t packetCommand = ReadAndAckByte(); packet.raw[idx++] = packetCommand;
for (int i=0;i<packetLength-3;i++){
uint8_t b = ReadAndAckByte(); packet.raw[idx++] = b;
}
uint8_t end = ReadByte(); packet.raw[idx++] = end; packet.length = idx;
if (end != PACKET_END_EXPECTED) return packet;
packet.title = packetCommand;
switch (packetCommand){
case PACKET_CMD_ACK: packet.type = PACKET_TYPE_ACK; packet.isAckNak = 1; break;
case PACKET_CMD_NAK: packet.type = PACKET_TYPE_NAK; packet.isAckNak = 1; break;
case PACKET_CMD_AsciiData:
packet.type = (packet.raw[3] == 0x00) ? PACKET_TYPE_CODING_WSC : 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;
default: packet.type = PACKET_TYPE_UNKNOWN; break;
}
return packet;
}
void ResetPacketCounter(){ _packetCounter = 0; _packetCounterInitialized = 0; }
uint8_t ReadPacketCounter(){
uint8_t v = ReadAndAckByte();
if (!_packetCounterInitialized){ _packetCounter = v; _packetCounterInitialized = 1; }
else if (v != _packetCounter){ /* optional mismatch handling */ }
_packetCounter++;
return v;
}
inline int32_t tick_diff(uint32_t a, uint32_t b){ return (int32_t)(a - b); }
int ReadByte_Tmo(uint32_t ms, uint8_t *out){
uint32_t deadline = HAL_GetTick() + ms; uint8_t b;
while (!KLine_RxFifo_Pop(&b)){
if ((int32_t)(HAL_GetTick() - deadline) >= 0) return 0;
}
if (out) *out = b; return 1;
}
int ReadPacketCounter_Tmo(uint32_t ms, uint8_t *out){
uint8_t v; if (!ReadByte_Tmo(ms, &v)) return 0;
if (!_packetCounterInitialized){ _packetCounter = v; _packetCounterInitialized = 1; }
else if (v != _packetCounter){ _packetCounter = v+1; return 0; }
_packetCounter++; WriteComplement(v);
if (out) *out = v; return 1;
}
int ReadAndAckByte_Tmo(uint32_t ms, uint8_t *out){
uint8_t b; if (!ReadByte_Tmo(ms, &b)) return 0; WriteComplement(b); if (out) *out = b; return 1;
}
void SendAckPacket(){ uint8_t a = (uint8_t)PACKET_CMD_ACK; SendPacket(&a, 1); }
void SendPacket(uint8_t* payload, uint8_t length){
uint8_t packetLength = (uint8_t)(length + 2);
static uint8_t packet[1 + 1 + MAX_PACKET_SIZE + 1];
int idx = 0;
packet[idx++] = packetLength;
packet[idx++] = _packetCounter++;
for (int i=0;i<length;i++) packet[idx++] = payload[i];
KLine_TxStart(packet, idx, 1 /*append 0x03*/, 1 /*expect complement*/);
while (KLine_TxBusy()) KLine_BytePump_Service(); // cooperative wait (no HAL_Delay)
}
// Convenience used by your code
ParsedPacket* SendCustom(const uint8_t* data, int len, int *out_count, uint8_t isBRKT){
(void)isBRKT; SendPacket((uint8_t*)data, len);
int count = 0; ParsedPacket* p = ReceivePackets(&count);
if (out_count) *out_count = count; return p;
}