/*
 * audi_immobiliser.c
 *
 *  Created on: Sep 17, 2025
 *      Author: herli
 */

#include "audi_immobiliser.h"
#include "timeouts.h"        // for Timeout_StartIfStopped

#include <string.h>
#include <stddef.h>
#include "can_db_symbols.h"   // MSG_ID_SEND2, MSG_ID_EMPF2
#include "can_manager.h"      // can_manager_register_handler_msg, can_manager_rx_address_request
#include "can_port.h"         // can_port_send_msg_def


extern bool can_manager_empf2_has_pending(void);
extern void can_manager_empf2_clear_pending(void);
// Option B (simple flag): uncomment if you used a raw flag in your code
extern volatile uint8_t s_empf2_pending;

volatile uint8_t EMPF2_BYTES[8] = {0};

/* === Local storage for the four fields (defaults from your spec/trace) === */
//static char g_mod_index[8] 		= "000006";  // full value in storage
static char g_mod_index[8] 		= "pelele";  // full value in storage

//static char g_client_model[16] 	= "059 130 106L";  // client model
static char g_client_model[16] 	= "tonto el que";  // client model

//static char g_serial[16]       	= "686759";        // serial number
static char g_serial[16]       	= "lo lea";        // serial number

//static char g_sw[24]           	= "C150_1.V79";    // software version
static char g_sw[24]           	= "kkkvcdskk";    // software version

//static char g_pin[8]           	= "389";           // custom pin
static char g_pin[8]           	= " si";           // custom pin

/* Full ASCII payload built as: "<client_model> <serial> <sw> <pin>" */
static char     g_full_str[40] = {0};
static uint16_t g_full_len     = 0;

/* ---- Public setters ---- */
void audi_immobiliser_set_client_model(const char *ascii) {
    if (ascii) { strncpy(g_client_model, ascii, sizeof(g_client_model)-1); g_client_model[sizeof(g_client_model)-1] = '\0'; }
}
void audi_immobiliser_set_serial(const char *ascii) {
    if (ascii) { strncpy(g_serial, ascii, sizeof(g_serial)-1); g_serial[sizeof(g_serial)-1] = '\0'; }
}
void audi_immobiliser_set_sw(const char *ascii) {
    if (ascii) { strncpy(g_sw, ascii, sizeof(g_sw)-1); g_sw[sizeof(g_sw)-1] = '\0'; }
}
void audi_immobiliser_set_pin(const char *ascii) {
    if (ascii) { strncpy(g_pin, ascii, sizeof(g_pin)-1); g_pin[sizeof(g_pin)-1] = '\0'; }
}

/* Build the concatenated ASCII */
void audi_immobiliser_init(void)
{
    size_t off = 0;
    memset(g_full_str, 0, sizeof(g_full_str));

    // Trim exactly one leading '0' so "000006" -> "00006"
    const char *mod = g_mod_index;
    if (mod[0] == '0' && mod[1] != '\0') mod++;

    // Concatenate in the correct order, with NO added spaces between tokens
    // (client model already has its spaces inside, e.g., "059 130 106L")
    const char *parts[] = { mod, g_client_model, g_sw, g_serial, g_pin };
    for (int i = 0; i < (int)(sizeof(parts)/sizeof(parts[0])); ++i) {
        size_t plen = strlen(parts[i]);
        if (off + plen >= sizeof(g_full_str)) plen = sizeof(g_full_str) - 1 - off;
        memcpy(&g_full_str[off], parts[i], plen);
        off += plen;
        if (off >= sizeof(g_full_str) - 1) break;
    }
    g_full_len = (uint16_t)off;
}

/* ---- Immobiliser chunking: index A5..AB maps to 6-byte slices ---- */
static inline int is_immo_index(uint16_t idx) { return (idx >= 0xA5u) && (idx <= 0xABu); }

/* Copy 6 bytes from g_full_str starting at (idx - A5)*6; pad with 0x00 if past end */
static void immo_slice_fill(uint16_t idx, uint8_t out6[6])
{
    uint16_t start = (uint16_t)((idx - 0xA5u) * 6u);
    for (uint8_t i = 0; i < 6; ++i) {
        uint16_t pos = (uint16_t)(start + i);
        out6[i] = (pos < g_full_len) ? (uint8_t)g_full_str[pos] : 0x00;
    }
}

/* ---- Wrapper handler for 0x502 (MSG_ID_SEND2) ----
 * If payload is immobiliser request: [FF FF] [idx_hi idx_lo] [.. ..] [.. ..]
 *   -> we build EMPF2_BYTES = [idx_hi idx_lo d0 d1 d2 d3 d4 d5] and SEND EMPF2 immediately.
 * Else: forward to the normal address→value handler.
 */
static void audi_immo_502_wrapper(const CanMessageDef *msg, const uint8_t in[8], CanTxFn tx)
{
    (void)tx;

    const uint16_t word0  = (uint16_t)((in[0] << 8) | in[1]);  // must be 0xFFFF
    const uint8_t  idx_hi = in[2];                             // A5..AB
    const uint8_t  idx_lo = in[3];                             // must be 0x00

    if (word0 == 0xFFFFu && idx_lo == 0x00u && is_immo_index(idx_hi)) {
        // Build 6-byte slice from the concatenated immobiliser string
        uint8_t slice[6];
        immo_slice_fill(idx_hi, slice);

        // Fill the common EMPF2 byte buffer (data-only mapping in can_db.c)
        EMPF2_BYTES[0] = idx_hi;   // e.g., A5
        EMPF2_BYTES[1] = 0x00;
        EMPF2_BYTES[2] = slice[0];
        EMPF2_BYTES[3] = slice[1];
        EMPF2_BYTES[4] = slice[2];
        EMPF2_BYTES[5] = slice[3];
        EMPF2_BYTES[6] = slice[4];
        EMPF2_BYTES[7] = slice[5];

        // Mark pending and start the 60 ms window (index 17) ONLY if not already running
        // Use whichever pending API you kept:
        // Option A (helpers):
        //   if (!can_manager_empf2_has_pending()) s_empf2_pending = 1; // or use a setter
        // Option B (simple flag):
        s_empf2_pending = 1;

        Timeout_StartIfStopped(17, (uint16_t)TIM16->CNT);

        // Do NOT send now; the 60 ms timeout (or your event path when RPM>250)
        // will transmit EMPF2 and clear the pending flag.
        return;
    }

    // Not immobiliser → fall back to standard 0x502 address→value handling
    can_manager_rx_address_request(msg, in, tx);
}


void audi_immobiliser_register(void)
{
    // Ensure we have a built payload
    if (g_full_len == 0) audi_immobiliser_init();

    // Hook our wrapper to the 0x502 definition (DB remains data-only)
    can_manager_register_handler_msg(&MSG_ID_SEND2, audi_immo_502_wrapper);
}
*/
