/*
 * kline_fsm.h
 * Non-blocking KWP1281 protocol state machine for STM32H533.
 *
 * Design rules:
 *   - KLine_FSM_Run() is called every main-loop iteration. It never blocks.
 *   - Timing is always "store a deadline, check it next tick". No HAL_Delay.
 *   - UART1 RX bytes are consumed from the ring buffer (kline_ring.h).
 *   - UART1 TX is synchronous (HAL_UART_Transmit with short timeout) because
 *     TX completes in microseconds at 9600 baud and does not race with anything.
 */

#ifndef INC_KLINE_FSM_H_
#define INC_KLINE_FSM_H_

#include <stdint.h>
#include "IKW1281Connection.h"   /* ParsedPacket, PacketCommand, ControllerInfo */

/* ------------------------------------------------------------------ */
/*  Public result / status types                                        */
/* ------------------------------------------------------------------ */

typedef enum {
    KLINE_STATUS_IDLE = 0,
    KLINE_STATUS_CONNECTING,
    KLINE_STATUS_CONNECTED,
    KLINE_STATUS_ERROR,
} KLine_Status;

/* ------------------------------------------------------------------ */
/*  Internal FSM states (exposed in header for debuggability)          */
/* ------------------------------------------------------------------ */

typedef enum {

    /* --- Idle --- */
    ST_IDLE,

    /* --- 5-baud init sequence --- */
    ST_BITBANG_START,           /* De-init UART, configure TX pin as GPIO    */
    ST_BITBANG_STARTBIT,        /* Drive line low (start bit)                */
    ST_BITBANG_DATABIT,         /* Clock out 8 data bits one by one          */
    ST_BITBANG_STOPBIT,         /* Drive line high (stop bit)                */
    ST_BITBANG_DONE,            /* Re-init UART, arm RX ring                 */

    /* --- Sync byte from ECU (0x55) --- */
    ST_WAIT_SYNC,

    /* --- Keywords --- */
    ST_READ_KW1,
    ST_READ_KW2,
    ST_SEND_KW2_COMPLEMENT,     /* Write ~KW2 after inter-byte delay         */

    /* --- ECU info packets (initial ReceivePackets burst) --- */
    ST_RECV_ECUINFO_PACKET,
    ST_SEND_ECUINFO_ACK,

    /* --- IdentifyEcu sub-sequence --- */
    ST_IDENT_KEEPALIVE_SEND,
    ST_IDENT_KEEPALIVE_RECV,
    ST_IDENT_RECV_PACKET,
    ST_IDENT_SEND_ACK,

    /* --- Steady-state keep-alive --- */
    ST_KA_SEND_ACK_PACKET,      /* Send ACK packet to ECU                   */
    ST_KA_RECV_ACK,             /* Expect ACK packet back                   */
    ST_KA_WAIT,                 /* Idle until next KA is due                */

    /* --- Generic packet TX (SendPacket) --- */
    ST_SENDPKT_BYTE,            /* Send one byte of the outgoing packet      */
    ST_SENDPKT_WAIT_ACK,        /* Wait for complement-ACK from ECU          */
    ST_SENDPKT_NEXT_BYTE,       /* Inter-byte delay then next byte           */
    ST_SENDPKT_END,             /* Send 0x03 end byte, no ACK                */

    /* --- Generic packet RX (ReceivePackets) --- */
    ST_RECVPKT_LENGTH,
    ST_RECVPKT_COUNTER,
    ST_RECVPKT_COMMAND,
    ST_RECVPKT_BODY,
    ST_RECVPKT_END,
    ST_RECVPKT_SEND_ACK,        /* Send ACK packet after non-ACK/NAK packet  */

    /* --- Error / disconnected --- */
    ST_ERROR,

} KLine_FSMState;

/* ------------------------------------------------------------------ */
/*  Public API                                                          */
/* ------------------------------------------------------------------ */

/* Call after all HAL inits, before the while(1) loop */
void KLine_FSM_Init(void);

/* Call every main-loop iteration – returns immediately */
void KLine_FSM_Run(void);

/* Trigger a connection attempt (replaces BitBang = 1 / TryConnection()) */
void KLine_FSM_RequestConnect(uint8_t ecuAddress);

/* Query current status */
KLine_Status KLine_FSM_GetStatus(void);

/* True while a keep-alive session is active */
uint8_t KLine_FSM_IsConnected(void);

/* Access last-received ECU info */
const ControllerInfo* KLine_FSM_GetEcuInfo(void);

/* Access last-received fault codes */
typedef struct {
    uint8_t dtc;
    uint8_t status;
    uint8_t extra;
} KLine_FaultCode;

#define KLINE_MAX_FAULT_CODES 20
const KLine_FaultCode* KLine_FSM_GetFaultCodes(int *out_count);

/* ------------------------------------------------------------------ */
/*  Operations support API                                              */
/* ------------------------------------------------------------------ */

/*
 * Return the current packet counter and increment it.
 * Used by kline_operations.c so that operation packets share the same
 * session counter the FSM uses.  Must only be called from main-loop context.
 */
uint8_t KLine_FSM_GetNextCounter(void);

/*
 * Suspend / resume keep-alive ticks.
 * When suspend != 0, the FSM will NOT send keep-alive packets while in
 * ST_KA_WAIT.  The caller must resume (suspend=0) when the operation
 * finishes so that keep-alive resumes normally.
 *
 * This also resets the KA timer so the next keep-alive fires a full
 * period after the operation ends, preventing an immediate timeout.
 */
void KLine_FSM_SuspendKA(uint8_t suspend);

/*
 * Manually reset the keep-alive deadline to "now + period".
 * Called by operation code after finishing so the ECU doesn't time out.
 */
void KLine_FSM_ResetKATimer(void);

/* ------------------------------------------------------------------ */
/*  Low-level TX helper (shared with kline_operations.c)               */
/* ------------------------------------------------------------------ */

void KLine_FSM_TxByte(uint8_t b);

/* ------------------------------------------------------------------ */
/*  Callbacks – implement in main.c / hc_06 glue                       */
/* ------------------------------------------------------------------ */

void KLine_OnConnected(void);        /* called when session established       */
void KLine_OnDisconnected(void);     /* called on timeout / error             */
void KLine_OnKeepAliveTick(void);    /* called each successful keep-alive     */

#endif /* INC_KLINE_FSM_H_ */
