/* * audi_immobiliser.c * * Created on: Sep 17, 2025 * Author: herli */ #include "audi_immobiliser.h" #include "timeouts.h" // for Timeout_StartIfStopped #include #include #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: " " */ 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); } */