/*
 * can_read_pump_data.c
 *
 *  Created on: Sep 18, 2025
 *      Author: herli
 */

#include "can_read_pump_data.h"
#include "timeouts.h"        // Timeout_StartIfStopped

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

/* If you kept helper APIs, you can include them instead of the flag.
   Using the simple pending flag as per your final setup: */
extern volatile uint8_t s_empf2_pending;

/* Mapped by can_db.c (EMPF2 defined as 8×U8 symbols) */
volatile uint8_t EMPF2_BYTES[8] = {0};

/* === Local storage for the four fields (defaults kept exactly as in your final working files) === */
/* NOTE: You can change these at runtime via the *_set_* functions below. */
static char g_mod_index[8] = "000006";

// static char g_client_model[16] = "059 130 106L";
static char g_client_model[16] = "  www.herlics";

// static char g_serial[16]      = "686759";
static char g_serial[16]       = "-V602-";

// static char g_sw[24]          = "C150_1.V79";
static char g_sw[24]           = "on.es HPSG5";

// static char g_pin[8]          = "389";
static char g_date[8]           = "925";

/* Full ASCII payload built as:
 *   trimmed_modindex + client_model + sw + serial + pin
 * (no extra spaces added between tokens; client_model contains its own spaces) */
static char     g_full_str[40] = {0};
static uint16_t g_full_len     = 0;

/* ---- Public setters ---- */
void can_read_pump_data_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 can_read_pump_data_set_serial(const char *ascii) {
    if (ascii) { strncpy(g_serial, ascii, sizeof(g_serial)-1); g_serial[sizeof(g_serial)-1] = '\0'; }
}
void can_read_pump_data_set_sw(const char *ascii) {
    if (ascii) { strncpy(g_sw, ascii, sizeof(g_sw)-1); g_sw[sizeof(g_sw)-1] = '\0'; }
}
void can_read_pump_data_set_pin(const char *ascii) {
    if (ascii) { strncpy(g_date, ascii, sizeof(g_date)-1); g_date[sizeof(g_date)-1] = '\0'; }
}

/* Build the concatenated ASCII in the correct order */
void can_read_pump_data_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 order: mod_trim + client_model + sw + serial + pin
    const char *parts[] = { mod, g_client_model, g_sw, g_serial, g_date };
    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;
}

/* ---- Pump data chunking: index A5..AB maps to 6-byte slices ---- */
static inline int is_pump_index(uint8_t idx_hi) { return (idx_hi >= 0xA5u) && (idx_hi <= 0xABu); }

/* Copy 6 bytes from g_full_str starting at (idx - A5)*6; pad with 0x00 if past end */
static void pump_slice_fill(uint8_t idx_hi, uint8_t out6[6])
{
    uint16_t start = (uint16_t)((idx_hi - 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 pump-data request: [FF FF] [idx_hi idx_lo=0x00] [...]
 *   -> we build EMPF2_BYTES = [idx_hi 0x00 d0 d1 d2 d3 d4 d5] and queue reply via 60 ms path.
 * Else: forward to the normal address→value handler.
 */
static void can_read_pump_data_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_pump_index(idx_hi)) {
        uint8_t slice[6];
        pump_slice_fill(idx_hi, slice);

        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];

        // Use your simple 60 ms gate: mark pending, start-if-stopped (index 17)
        s_empf2_pending = 1;
        Timeout_StartIfStopped(17, (uint16_t)TIM16->CNT);
        return; // handled by pump-data path
    }

    // Not a pump-data request -> normal 0x502 address→value handling
    can_manager_rx_address_request(msg, in, tx);
}

void can_read_pump_data_register(void)
{
    // Ensure payload exists
    if (g_full_len == 0) can_read_pump_data_init();

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