Initial import of STM32CubeIDE project
This commit is contained in:
1
Core/CAN_Libs/CAN_COMPATIBILITY
Normal file
1
Core/CAN_Libs/CAN_COMPATIBILITY
Normal file
@@ -0,0 +1 @@
|
||||
This can library with its can_db and can_answers works with T15021.cfg
|
||||
418
Core/CAN_Libs/can_db.c
Normal file
418
Core/CAN_Libs/can_db.c
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* can_db.c (Flash-resident map; no HAL here)
|
||||
*/
|
||||
#include <id.h>
|
||||
#include "can_schema.h"
|
||||
#include "can_db_symbols.h"
|
||||
#include <stddef.h>
|
||||
#include "injection.h"
|
||||
|
||||
#if ENABLE_AUDI_IMMO
|
||||
#include "audi_immo.h"
|
||||
#endif
|
||||
#if defined(T06301)
|
||||
#include "ford_immo.h"
|
||||
#endif
|
||||
|
||||
#if defined(T06301)
|
||||
#define ID_EMPF1 0x112
|
||||
#define ID_EMPF2 0x222
|
||||
#define ID_EMPF3 0x712
|
||||
#define ID_EMPF4 0x312
|
||||
#define ID_SEND1 0x100
|
||||
#define ID_SEND2 0x221
|
||||
#define ID_SEND3 0x700
|
||||
#define ID_SEND4 0x300
|
||||
#elif defined(T06215) || defined(T06211)
|
||||
#define ID_EMPF1 0x112
|
||||
#define ID_EMPF2 0x512
|
||||
#define ID_EMPF3 0x712
|
||||
#define ID_SEND1 0x100
|
||||
#define ID_SEND2 0x500
|
||||
#define ID_SEND3 0x700
|
||||
#elif defined(T15021) || defined(T31804)
|
||||
#define ID_EMPF1 0x114
|
||||
#define ID_EMPF2 0x516
|
||||
#define ID_EMPF3 0x714
|
||||
#define ID_SEND1 0x10E
|
||||
#define ID_SEND2 0x502
|
||||
#define ID_SEND3 0x702
|
||||
#elif defined(T06209) || defined(T06216)
|
||||
#define ID_EMPF1 0x028
|
||||
#define ID_EMPF2 0x508
|
||||
#define ID_EMPF3 0x708
|
||||
#define ID_SEND1 0x020
|
||||
#define ID_SEND2 0x500
|
||||
#define ID_SEND3 0x700
|
||||
#else
|
||||
#error "Define CFG"
|
||||
#endif
|
||||
#define ID_SEND_CUST 0x720
|
||||
|
||||
|
||||
|
||||
/* ===== Extern RAM variables declared elsewhere ===== */
|
||||
extern uint16_t BitStatus;
|
||||
extern float PHI_AD;
|
||||
extern float RPM;
|
||||
extern float Temp;
|
||||
extern float ME, MEPI, B_FB_KW, B_FB_NW, dFi, B_PHIAD;
|
||||
extern uint8_t cilCount, safetySHUTOFF;
|
||||
extern uint8_t inj_mode, request_syncout_activation;
|
||||
extern uint8_t memWrite;
|
||||
extern uint32_t quart_hour_counter;
|
||||
|
||||
extern float FBKW_DEMAND, FBKW_DC, FBKW_FEEDBACK, T_ein, PSG_Voltage;
|
||||
extern float actual_phi1, real_eoi, target_eoi;
|
||||
extern uint32_t sensorfail, canfails;
|
||||
extern uint8_t hasCapturedTeeth, T_ein_status;
|
||||
|
||||
/* ===== STARTUP MESSAGE (template-only) ===== */
|
||||
|
||||
|
||||
/* ===== Common scales ===== */
|
||||
static const CanScaleDef SCALE_DEG_KW = { "degKW", 3.0f/256.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_PHIAD = { "degNW", 3.0f/256.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_PHIAD_2 = { "degNW", 3.0f/64.0f, 0.0f };
|
||||
|
||||
#if defined(T06215)
|
||||
static const CanScaleDef SCALE_ME = { "mg/H", 1.0f/32.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_TEMP = { "degC", 1.0f/16.0f, -273.0f };
|
||||
static const CanScaleDef SCALE_FBKW = { "FBKW", 3.0f/256.0f, 0.0f };
|
||||
#elif defined(T06301)
|
||||
static const CanScaleDef SCALE_ME = { "mg/H", 1.0f/16.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_TEMP = { "degC", 1.0f/4.0f, -273.0f };
|
||||
static const CanScaleDef SCALE_FBKW = { "FBKW", 1.0f/16.0f, 0.0f };
|
||||
#else
|
||||
static const CanScaleDef SCALE_ME = { "mg/H", 1.0f/32.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_TEMP = { "degC", 1.0f/16.0f, -273.0f };
|
||||
static const CanScaleDef SCALE_FBKW = { "FBKW", 3.0f/256.0f, 0.0f };
|
||||
#endif
|
||||
|
||||
static const CanScaleDef SCALE_ME_RAM = { "mg/H", 1.0f/32.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_DC = { "%", 100.0f/4095.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_TEIN = { "uS", 1.0f/2.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_RPM = { "1/min", 1.0f/4.0f, 0.0f };
|
||||
static const CanScaleDef SCALE_VOLTAGE= { "V", 0.0185f, -0.05f };
|
||||
|
||||
|
||||
/* ===== TX: ID 0x114 EMPF1 ===== */
|
||||
uint8_t injectionStatus = 0b0101; //---* tein, --*- feedback, -*-- rpm,
|
||||
uint8_t QTY_valve_status = 1; //---* tein, --*- feedback, -*-- rpm,
|
||||
|
||||
static CanSymbolDef SYM_ID_EMPF1[] = {
|
||||
#if defined(T06301)
|
||||
{ "TEIN_STATUS", 8, 1, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &T_ein_status, NULL, CAN_STORE_U8, INVERTED},
|
||||
{ "QTY_VALVE_STATUS", 9, 1, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &QTY_valve_status, NULL, CAN_STORE_U8},
|
||||
{ "ANGLESENSOR_STATUS", 10, 1, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &hasCapturedTeeth, NULL, CAN_STORE_U8, INVERTED},
|
||||
|
||||
{ "CIL_COUNT", 0, 3, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &cilCount, NULL, CAN_STORE_U8},
|
||||
{ "NW_N", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &RPM, NULL, CAN_STORE_FLOAT},
|
||||
#elif defined(T06215)
|
||||
{ "STATUS", 0, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &BitStatus, NULL, CAN_STORE_U32},
|
||||
{ "PHIAD_AKT", 16, 13, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &PHI_AD, &SCALE_PHIAD, CAN_STORE_FLOAT},
|
||||
{ "CIL_COUNT", 29, 3, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &cilCount, NULL, CAN_STORE_U8},
|
||||
{ "NW_N", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &RPM, &SCALE_RPM, CAN_STORE_FLOAT},
|
||||
{ "THYBR", 48, 16, CAN_ENDIAN_INTEL, CAN_SYM_SX, 0,0, &Temp, &SCALE_TEMP, CAN_STORE_FLOAT},
|
||||
#elif defined(T15021) || defined(T31804)
|
||||
|
||||
#elif defined(T06209) || defined(T06211) || defined(T06216)
|
||||
{ "STATUS", 0, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &BitStatus, NULL, CAN_STORE_U32},
|
||||
{ "PHIAD_AKT", 16, 13, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &PHI_AD, &SCALE_PHIAD, CAN_STORE_FLOAT},
|
||||
{ "CIL_COUNT", 29, 3, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &cilCount, NULL, CAN_STORE_U8},
|
||||
{ "NW_N", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &RPM, &SCALE_RPM, CAN_STORE_FLOAT},
|
||||
{ "THYBR", 48, 16, CAN_ENDIAN_INTEL, CAN_SYM_SX, 0,0, &Temp, &SCALE_TEMP, CAN_STORE_FLOAT},
|
||||
#else
|
||||
#error "Define CFG"
|
||||
#endif
|
||||
};
|
||||
|
||||
uint16_t fbkwStatus = 0x0001; //alternative 0x0001
|
||||
|
||||
uint16_t fa02 = 0x0001;
|
||||
uint16_t status2 = 0xfffe;
|
||||
const CanAddressEntry CAN_ANSWERS[] = {
|
||||
#if defined(T15021) || defined(T31804)
|
||||
{ 0xD282, &FBKW_DC, CAN_SYM_UX, &SCALE_DC , CAN_STORE_FLOAT },
|
||||
{ 0xF882, &FBKW_FEEDBACK, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
{ 0x7A81, &fbkwStatus, CAN_SYM_UX, NULL, CAN_STORE_U16 },
|
||||
{ 0x4281, &PSG_Voltage, CAN_SYM_UX, &SCALE_VOLTAGE, CAN_STORE_FLOAT },
|
||||
#else
|
||||
{ 0x5E00, &FBKW_DEMAND, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
{ 0xD202, &FBKW_DC, CAN_SYM_UX, &SCALE_DC , CAN_STORE_FLOAT },
|
||||
//d402always 0
|
||||
{ 0xF802, &FBKW_FEEDBACK, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
{ 0xFA02, &fa02, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
|
||||
{ 0x7800, &T_ein, CAN_SYM_UX, &SCALE_TEIN , CAN_STORE_FLOAT },
|
||||
{ 0x4201, &PSG_Voltage, CAN_SYM_UX, &SCALE_VOLTAGE, CAN_STORE_FLOAT },
|
||||
{ 0x4400, &ME, CAN_SYM_UX, &SCALE_ME_RAM, CAN_STORE_FLOAT },
|
||||
{ 0x4800, &PHI_AD, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
{ 0x4C00, &actual_phi1, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
{ 0x5800, &real_eoi, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
{ 0x5A00, &target_eoi, CAN_SYM_SX, &SCALE_DEG_KW, CAN_STORE_FLOAT },
|
||||
|
||||
{ 0x7A01, &fbkwStatus, CAN_SYM_UX, NULL, CAN_STORE_U16 },
|
||||
{ 0x7C01, &status2, CAN_SYM_UX, NULL, CAN_STORE_U16 },
|
||||
|
||||
{ 0xBABA, &quart_hour_counter, CAN_SYM_UX, NULL , CAN_STORE_U32 },
|
||||
#endif
|
||||
|
||||
#if ENABLE_AUDI_IMMO
|
||||
{ 0x0404, &audi_immo_key_part_0, CAN_SYM_UX, NULL, CAN_STORE_U16 },
|
||||
{ 0xFA04, &audi_immo_key_part_1, CAN_SYM_UX, NULL, CAN_STORE_U16 },
|
||||
{ 0x0204, &audi_immo_key_part_2, CAN_SYM_UX, NULL, CAN_STORE_U16 },
|
||||
{ 0x0004, &audi_immo_key_part_3, CAN_SYM_UX, NULL, CAN_STORE_U16 },
|
||||
#endif
|
||||
{ 0x0008, &canfails, CAN_SYM_UX, NULL, CAN_STORE_U32 },
|
||||
{ 0x0108, &sensorfail, CAN_SYM_UX, NULL, CAN_STORE_U32 },
|
||||
};
|
||||
|
||||
extern volatile uint8_t EMPF2_BYTES[8];
|
||||
static CanSymbolDef SYM_ID_EMPF2[] = {
|
||||
// name, start, len, endian, raw, factor, offset, ptr, scale, storage
|
||||
{ "B0", 0, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, (void*)&EMPF2_BYTES[0], NULL, CAN_STORE_U8 },
|
||||
{ "B1", 8, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, (void*)&EMPF2_BYTES[1], NULL, CAN_STORE_U8 },
|
||||
{ "B2", 16, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, (void*)&EMPF2_BYTES[2], NULL, CAN_STORE_U8 },
|
||||
{ "B3", 24, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, (void*)&EMPF2_BYTES[3], NULL, CAN_STORE_U8 },
|
||||
{ "B4", 32, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, (void*)&EMPF2_BYTES[4], NULL, CAN_STORE_U8 },
|
||||
{ "B5", 40, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, (void*)&EMPF2_BYTES[5], NULL, CAN_STORE_U8 },
|
||||
{ "B6", 48, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, (void*)&EMPF2_BYTES[6], NULL, CAN_STORE_U8 },
|
||||
{ "B7", 56, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, (void*)&EMPF2_BYTES[7], NULL, CAN_STORE_U8 },
|
||||
};
|
||||
|
||||
const size_t CAN_ANSWERS_COUNT = sizeof(CAN_ANSWERS)/sizeof(CAN_ANSWERS[0]);
|
||||
|
||||
//static const uint8_t STARTUP_PAYLOAD[8] = {0x07, 0x0C, 0x5D, 0x1C, 0xE6, 0x7B, 0x9D, 0xD8}; //0xDC bit immo 1
|
||||
//static const uint8_t STARTUP_PAYLOAD_2[8] = {0x81, 0x7F, 0x5D, 0x1C, 0xE6, 0x7B, 0x9D, 0xD8}; //0xD8 bit immo 0
|
||||
|
||||
#if defined(T06301)
|
||||
static const uint8_t STARTUP_PAYLOAD[8] = {0x07, 0x05, 0x1C, 0x38, 0x1C, 0xFC, 0xF5, 0x71}; //0x75 immo 1 0x71 immo 0
|
||||
static const uint8_t STARTUP_PAYLOAD_2[8] = {0x81, 0x7F, 0x1C, 0x38, 0x1C, 0xFC, 0xF5, 0x71};
|
||||
#elif defined(T06211)
|
||||
static const uint8_t STARTUP_PAYLOAD[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //0x75 immo 1 0x71 immo 0
|
||||
|
||||
#elif defined(T06209) || defined(T06216)
|
||||
static const uint8_t STARTUP_PAYLOAD[8] = {0x00, 0x00, 0x21, 0xD7, 0x46, 0xBA, 0xE9, 0x5F}; //0x75 immo 1 0x71 immo 0
|
||||
#endif
|
||||
//static const uint8_t STARTUP_PAYLOAD[8] = {0x00, 0x00, 0x1C, 0x38, 0x01c, 0xFC, 0xF5, 0x71}; //0x75 immo 1 0x71 immo 0
|
||||
//static const uint8_t STARTUP_PAYLOAD_2[8] = {0x00, 0x00, 0x1C, 0x38, 0x1c, 0xFC, 0xF5, 0x71};
|
||||
uint8_t pepe = 1;
|
||||
/* ===== TX: ID 0x312 EMPF4 ===== */
|
||||
#if defined(T06301)
|
||||
static CanSymbolDef SYM_ID_EMPF4[] = {
|
||||
{ "FIEONA-PER0", 0, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &FIEONA_FIRSTWORD, NULL, CAN_STORE_U16},
|
||||
{ "FIEONA-PER1", 16, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &FIEONA_SECONDWORD, NULL, CAN_STORE_U16},
|
||||
{ "FIEONA-SHUTOFF", 16, 1, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &safetySHUTOFF, NULL, CAN_STORE_U8},
|
||||
{ "THYBR", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_SX, 0,0, &Temp, &SCALE_TEMP, CAN_STORE_FLOAT},
|
||||
|
||||
{ "STATUS", 48, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &BitStatus, NULL, CAN_STORE_U32},
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
const CanMessageDef MSG_ID_EMPF1 = {
|
||||
.can_id = ID_EMPF1,
|
||||
.dir = CAN_DIR_TX,
|
||||
.dlc = 8,
|
||||
.name = "ID_EMPF1",
|
||||
.symbols= SYM_ID_EMPF1,
|
||||
.symbol_count = (uint8_t)(sizeof(SYM_ID_EMPF1)/sizeof(SYM_ID_EMPF1[0])),
|
||||
.tx_template = NULL,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = NULL
|
||||
};
|
||||
/* ===== TX: EMPF2 — reply to addressed requests (8 bytes, 4 words) ===== */
|
||||
const CanMessageDef MSG_ID_EMPF2 = {
|
||||
.can_id = ID_EMPF2,
|
||||
.dir = CAN_DIR_TX,
|
||||
.dlc = 8,
|
||||
.name = "ID_EMPF2",
|
||||
.symbols = SYM_ID_EMPF2, // payload is built by the handler (no symbols)
|
||||
.symbol_count = (uint8_t)(sizeof(SYM_ID_EMPF2)/sizeof(SYM_ID_EMPF2[0])),
|
||||
.tx_template = NULL, // no template; handler writes all 8 bytes
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = NULL
|
||||
};
|
||||
const CanMessageDef MSG_ID_EMPF3 =
|
||||
{
|
||||
.can_id = ID_EMPF3, // you set 0x714
|
||||
.dir = CAN_DIR_TX,
|
||||
.dlc = 8,
|
||||
.name = "BOOT_TEMPLATE",
|
||||
.symbols = NULL,
|
||||
.symbol_count = 0,
|
||||
.tx_template = STARTUP_PAYLOAD,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = NULL
|
||||
};
|
||||
|
||||
#if defined(T06301)
|
||||
const CanMessageDef MSG_ID_EMPF3_MOD =
|
||||
{
|
||||
.can_id = ID_EMPF3, // you set 0x714
|
||||
.dir = CAN_DIR_TX,
|
||||
.dlc = 8,
|
||||
.name = "BOOT_TEMPLATE",
|
||||
.symbols = NULL,
|
||||
.symbol_count = 0,
|
||||
.tx_template = STARTUP_PAYLOAD_2,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = NULL
|
||||
};
|
||||
|
||||
const CanMessageDef MSG_ID_EMPF4 = {
|
||||
.can_id = ID_EMPF4,
|
||||
.dir = CAN_DIR_TX,
|
||||
.dlc = 8,
|
||||
.name = "ID_EMPF4",
|
||||
.symbols= SYM_ID_EMPF4,
|
||||
.symbol_count = (uint8_t)(sizeof(SYM_ID_EMPF4)/sizeof(SYM_ID_EMPF4[0])),
|
||||
.tx_template = NULL,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/* ===== RX: ID 0x100 SEND1 ===== */
|
||||
static CanSymbolDef SYM_ID_SEND1[] = {
|
||||
#if defined(T06301)
|
||||
{ "MESOLL", 0, 12, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &ME, &SCALE_ME, CAN_STORE_FLOAT},
|
||||
//{ "B_PHIAD", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_PHIAD, &SCALE_PHIAD, CAN_STORE_FLOAT},
|
||||
{ "FB_KW", 12, 12, CAN_ENDIAN_INTEL, CAN_SYM_SX, 0,0, &B_FB_KW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
//{ "FB_NW", 48, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_FB_NW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
#elif defined(T06215)
|
||||
{ "MESOLL", 0, 12, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &ME, &SCALE_ME, CAN_STORE_FLOAT},
|
||||
{ "B_PHIAD", 12, 24, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_PHIAD, &SCALE_PHIAD, CAN_STORE_FLOAT},
|
||||
{ "FB_KW", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_FB_KW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
{ "FB_NW", 48, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_FB_NW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
#elif defined(T15021) || defined(T31804)
|
||||
{ "MESOLL", 0, 12, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &ME, &SCALE_ME, CAN_STORE_FLOAT},
|
||||
{ "B_PHIAD", 12, 24, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_PHIAD, &SCALE_PHIAD, CAN_STORE_FLOAT},
|
||||
{ "FB_KW", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_FB_KW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
{ "FB_NW", 48, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_FB_NW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
#elif defined(T06209) || defined(T06211) || defined(T06216)
|
||||
{ "MESOLL", 0, 12, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &ME, &SCALE_ME, CAN_STORE_FLOAT},
|
||||
{ "B_PHIAD", 12, 24, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_PHIAD, &SCALE_PHIAD, CAN_STORE_FLOAT},
|
||||
{ "FB_KW", 32, 16, CAN_ENDIAN_INTEL, CAN_SYM_SX, 0,0, &B_FB_KW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
{ "FB_NW", 48, 16, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &B_FB_NW, &SCALE_FBKW, CAN_STORE_FLOAT},
|
||||
#else
|
||||
#error "Define CFG"
|
||||
#endif
|
||||
};
|
||||
#if defined(T06301)
|
||||
static CanSymbolDef SYM_ID_SEND4[] = {
|
||||
{ "FIEONA-SHUTOFF-SEND", 32, 1, CAN_ENDIAN_INTEL, CAN_SYM_UX, 0,0, &safetySHUTOFF, NULL, CAN_STORE_U8},
|
||||
};
|
||||
#elif defined(cfgejemplo)
|
||||
|
||||
#endif
|
||||
/* ===== RX: ID 0x720 SEND ===== */
|
||||
static CanSymbolDef SYM_ID_SEND_CUSTOM[] = {
|
||||
{ "PHI_OFFSET", 0, 16, CAN_ENDIAN_INTEL, CAN_SYM_SX, 0,0, &dFi, &SCALE_DEG_KW, CAN_STORE_FLOAT},
|
||||
{ "INJMODE", 16, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 1,0, &inj_mode, NULL, CAN_STORE_U8},
|
||||
{ "SYNCMODE", 24, 8, CAN_ENDIAN_INTEL, CAN_SYM_UX, 1,0, &request_syncout_activation, NULL, CAN_STORE_U8},
|
||||
|
||||
{ "memWrite", 63, 1, CAN_ENDIAN_INTEL, CAN_SYM_UX, 1,0, &memWrite, NULL, CAN_STORE_U8},
|
||||
};
|
||||
|
||||
const CanMessageDef MSG_ID_SEND1 = {
|
||||
.can_id = ID_SEND1,
|
||||
.dir = CAN_DIR_RX,
|
||||
.dlc = 8,
|
||||
.name = "ID_SEND1",
|
||||
.symbols= SYM_ID_SEND1,
|
||||
.symbol_count = (uint8_t)(sizeof(SYM_ID_SEND1)/sizeof(SYM_ID_SEND1[0])),
|
||||
.tx_template = NULL,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = SEND1_Handler
|
||||
};
|
||||
/* ===== RX: ID 0x502 SEND2 request (addressed read -> handler replies) ===== */
|
||||
const CanMessageDef MSG_ID_SEND2 = {
|
||||
.can_id = ID_SEND2,
|
||||
.dir = CAN_DIR_RX,
|
||||
.dlc = 8,
|
||||
.name = "ID_SEND2_REQ",
|
||||
.symbols = NULL, // parsed by handler
|
||||
.symbol_count = 0,
|
||||
.tx_template = NULL,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = NULL
|
||||
};
|
||||
|
||||
const CanMessageDef MSG_ID_SEND3 = {
|
||||
.can_id = ID_SEND3,
|
||||
.dir = CAN_DIR_RX,
|
||||
.dlc = 8,
|
||||
.name = "ID_SEND3",
|
||||
.symbols = NULL,
|
||||
.symbol_count = 0,
|
||||
.tx_template = NULL,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = NULL
|
||||
};
|
||||
|
||||
#if defined(T06301)
|
||||
const CanMessageDef MSG_ID_SEND4 = {
|
||||
.can_id = ID_SEND4,
|
||||
.dir = CAN_DIR_RX,
|
||||
.dlc = 8,
|
||||
.name = "ID_SEND4",
|
||||
.symbols = SYM_ID_SEND4,
|
||||
.symbol_count = (uint8_t)(sizeof(SYM_ID_SEND4)/sizeof(SYM_ID_SEND4[0])),
|
||||
.tx_template = NULL,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = Fieona_SEND4_Handler
|
||||
};
|
||||
#elif defined(cfgejemplo)
|
||||
|
||||
#endif
|
||||
|
||||
const CanMessageDef MSG_ID_SEND_CUSTOM = {
|
||||
.can_id = ID_SEND_CUST,
|
||||
.dir = CAN_DIR_RX,
|
||||
.dlc = 8,
|
||||
.name = "ID_SEND_CUSTOM",
|
||||
.symbols= SYM_ID_SEND_CUSTOM,
|
||||
.symbol_count = (uint8_t)(sizeof(SYM_ID_SEND_CUSTOM)/sizeof(SYM_ID_SEND_CUSTOM[0])),
|
||||
.tx_template = NULL,
|
||||
.send_on_boot = 0,
|
||||
.rx_handler = NULL
|
||||
};
|
||||
|
||||
/* ===== Registry ===== */
|
||||
static const CanMessageDef* const CAN_DB[] = {
|
||||
&MSG_ID_EMPF1,
|
||||
&MSG_ID_EMPF2,
|
||||
&MSG_ID_EMPF3,
|
||||
&MSG_ID_SEND1,
|
||||
&MSG_ID_SEND2,
|
||||
&MSG_ID_SEND3,
|
||||
#if defined(T06301)
|
||||
&MSG_ID_EMPF3_MOD,
|
||||
&MSG_ID_EMPF4,
|
||||
&MSG_ID_SEND4,
|
||||
#endif
|
||||
&MSG_ID_SEND_CUSTOM,
|
||||
};
|
||||
|
||||
const CanMessageDef* can_db_find(uint16_t id, CanDirection dir)
|
||||
{
|
||||
size_t n = sizeof(CAN_DB)/sizeof(CAN_DB[0]);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
if (CAN_DB[i]->can_id == id && CAN_DB[i]->dir == dir)
|
||||
return CAN_DB[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* New helper that actually returns the pointer array */
|
||||
const CanMessageDef* const* can_db_all_ptr(size_t *count) {
|
||||
if (count) *count = sizeof(CAN_DB)/sizeof(CAN_DB[0]);
|
||||
return CAN_DB;
|
||||
}
|
||||
|
||||
const CanMessageDef* can_db_all(size_t *count) {
|
||||
if (count) *count = sizeof(CAN_DB)/sizeof(CAN_DB[0]);
|
||||
return (const CanMessageDef*)CAN_DB; // manager casts back to ptr-of-ptr
|
||||
}
|
||||
35
Core/CAN_Libs/can_db_symbols.h
Normal file
35
Core/CAN_Libs/can_db_symbols.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* can_db_symbols.h
|
||||
*
|
||||
* Created on: Sep 16, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#ifndef SRC_CAN_LIBS_CAN_DB_SYMBOLS_H_
|
||||
#define SRC_CAN_LIBS_CAN_DB_SYMBOLS_H_
|
||||
|
||||
#include "can_schema.h"
|
||||
/* Exported message definitions (no hardcoded IDs anywhere else) */
|
||||
extern const CanMessageDef MSG_ID_EMPF1; // TX injection/status (was 0x114)
|
||||
extern const CanMessageDef MSG_ID_EMPF2; // TX reply to address-requests (ID = 516)
|
||||
extern const CanMessageDef MSG_ID_EMPF3; // TX boot template
|
||||
|
||||
extern const CanMessageDef MSG_ID_EMPF3_MOD; // TX boot template
|
||||
extern const CanMessageDef MSG_ID_EMPF4; // TX boot template
|
||||
|
||||
extern const CanMessageDef MSG_ID_SEND1; // RX ecu command(was 0x10E)
|
||||
extern const CanMessageDef MSG_ID_SEND2; // RX address requests handler (was 0x502)
|
||||
extern const CanMessageDef MSG_ID_SEND3; // RX dfi coding(was 0x700)
|
||||
extern const CanMessageDef MSG_ID_SEND4; // RX dfi coding(was 0x300)
|
||||
|
||||
extern const CanMessageDef MSG_ID_SEND_CUSTOM; // RX dfi coding(was 0x720)
|
||||
|
||||
extern const CanMessageDef MSG_STARTUP_TRIGGER_RX; // RX trigger (was 0x700)
|
||||
|
||||
extern const CanAddressEntry CAN_ANSWERS[];
|
||||
extern const size_t CAN_ANSWERS_COUNT;
|
||||
|
||||
/* Optional: get full registry for iteration */
|
||||
const CanMessageDef* const* can_db_all_ptr(size_t *count);
|
||||
|
||||
#endif /* SRC_CAN_LIBS_CAN_DB_SYMBOLS_H_ */
|
||||
196
Core/CAN_Libs/can_encode.c
Normal file
196
Core/CAN_Libs/can_encode.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* can_encode.c
|
||||
*
|
||||
* Created on: Sep 16, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
#include "can_encode.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
/* -------- Bit helpers (Intel) --------
|
||||
* Intel (little-endian bit numbering): bit 0 is LSB of byte 0, bit 7 is MSB of byte 0,
|
||||
* then bit 8 is LSB of byte 1, etc.
|
||||
*/
|
||||
uint64_t _can_get_bits_intel(const uint8_t data[8], uint8_t start_bit, uint8_t bit_len)
|
||||
{
|
||||
uint64_t acc = 0;
|
||||
for (uint8_t i = 0; i < bit_len; ++i) {
|
||||
uint16_t bit_index = start_bit + i;
|
||||
uint8_t byte_idx = (uint8_t)(bit_index >> 3);
|
||||
uint8_t bit_in_byte = (uint8_t)(bit_index & 7);
|
||||
uint8_t b = (data[byte_idx] >> bit_in_byte) & 1u;
|
||||
acc |= ((uint64_t)b) << i;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
void _can_set_bits_intel(uint8_t data[8], uint8_t start_bit, uint8_t bit_len, uint64_t raw)
|
||||
{
|
||||
for (uint8_t i = 0; i < bit_len; ++i) {
|
||||
uint16_t bit_index = start_bit + i;
|
||||
uint8_t byte_idx = (uint8_t)(bit_index >> 3);
|
||||
uint8_t bit_in_byte = (uint8_t)(bit_index & 7);
|
||||
uint8_t bit = (uint8_t)((raw >> i) & 1u);
|
||||
data[byte_idx] = (uint8_t)((data[byte_idx] & ~(1u << bit_in_byte)) | (bit << bit_in_byte));
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- Bit helpers (Motorola) --------
|
||||
* Motorola (big-endian) uses a different bit ordering: start_bit points to a bit index where
|
||||
* bytes count from MSB to LSB. Implementation below follows standard DBC Motorola mapping.
|
||||
* This implementation is conservative and handles the general case.
|
||||
*/
|
||||
static inline uint8_t _motorola_byte(uint8_t bit_index) { return (uint8_t)(7 - (bit_index & 7)); }
|
||||
|
||||
uint64_t _can_get_bits_motorola(const uint8_t data[8], uint8_t start_bit, uint8_t bit_len)
|
||||
{
|
||||
uint64_t acc = 0;
|
||||
uint8_t cur_bit = start_bit;
|
||||
for (uint8_t i = 0; i < bit_len; ++i) {
|
||||
uint8_t byte_idx = (uint8_t)(cur_bit >> 3);
|
||||
uint8_t bit_in_byte = _motorola_byte(cur_bit);
|
||||
uint8_t b = (data[byte_idx] >> bit_in_byte) & 1u;
|
||||
acc = (acc << 1) | b;
|
||||
// advance to next bit (Motorola decrements bit index)
|
||||
if (bit_in_byte == 0) {
|
||||
// next byte
|
||||
if (byte_idx == 0) break; // avoid underflow; malformed definition
|
||||
cur_bit = (uint8_t)(((byte_idx - 1) << 3) + 7);
|
||||
} else {
|
||||
cur_bit = (uint8_t)((byte_idx << 3) + (bit_in_byte - 1));
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
void _can_set_bits_motorola(uint8_t data[8], uint8_t start_bit, uint8_t bit_len, uint64_t raw)
|
||||
{
|
||||
uint8_t cur_bit = start_bit;
|
||||
for (uint8_t i = 0; i < bit_len; ++i) {
|
||||
uint8_t bit_val = (uint8_t)((raw >> (bit_len - 1 - i)) & 1u);
|
||||
uint8_t byte_idx = (uint8_t)(cur_bit >> 3);
|
||||
uint8_t bit_in_byte = _motorola_byte(cur_bit);
|
||||
data[byte_idx] = (uint8_t)((data[byte_idx] & ~(1u << bit_in_byte)) | (bit_val << bit_in_byte));
|
||||
// advance (Motorola)
|
||||
if (bit_in_byte == 0) {
|
||||
if (byte_idx == 0) break;
|
||||
cur_bit = (uint8_t)(((byte_idx - 1) << 3) + 7);
|
||||
} else {
|
||||
cur_bit = (uint8_t)((byte_idx << 3) + (bit_in_byte - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- Effective factor/offset for a symbol -------- */
|
||||
static inline void eff_scale(const CanSymbolDef *s, float *f, float *o)
|
||||
{
|
||||
if ((s->factor != 0.0f) || (s->offset != 0.0f)) {
|
||||
*f = s->factor; *o = s->offset;
|
||||
} else if (s->scale) {
|
||||
*f = s->scale->factor; *o = s->scale->offset;
|
||||
} else {
|
||||
*f = 1.0f; *o = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- Public encode/decode -------- */
|
||||
void can_encode_message(const CanMessageDef *msg, uint8_t out_data[8])
|
||||
{
|
||||
if (!msg || !out_data) return;
|
||||
|
||||
if (msg->tx_template) {
|
||||
memcpy(out_data, msg->tx_template, msg->dlc);
|
||||
if (msg->dlc < 8) memset(out_data + msg->dlc, 0, 8 - msg->dlc);
|
||||
} else {
|
||||
memset(out_data, 0, 8);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < msg->symbol_count; ++i) {
|
||||
const CanSymbolDef *s = &msg->symbols[i];
|
||||
if (!s->ptr || s->bit_len == 0) continue;
|
||||
|
||||
int64_t raw_q;
|
||||
if (s->storage == CAN_STORE_FLOAT) {
|
||||
float f, o; eff_scale(s, &f, &o);
|
||||
if (f == 0.0f) f = 1.0f; // guard
|
||||
float phys = *(const float*)s->ptr;
|
||||
float scaled = (phys - o) / f;
|
||||
raw_q = (int64_t)llroundf(scaled);
|
||||
} else {
|
||||
switch (s->storage) {
|
||||
case CAN_STORE_U32: raw_q = (int64_t)(*(const uint32_t*)s->ptr); break;
|
||||
case CAN_STORE_S32: raw_q = (int64_t)(*(const int32_t *)s->ptr); break;
|
||||
case CAN_STORE_U16: raw_q = (int64_t)(*(const uint16_t*)s->ptr); break;
|
||||
case CAN_STORE_S16: raw_q = (int64_t)(*(const int16_t *)s->ptr); break;
|
||||
case CAN_STORE_U8: raw_q = (int64_t)(*(const uint8_t *)s->ptr); break;
|
||||
case CAN_STORE_S8: raw_q = (int64_t)(*(const int8_t *)s->ptr); break;
|
||||
default: raw_q = 0; break;
|
||||
}
|
||||
if(s->inverted){
|
||||
raw_q = !raw_q;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->raw_type == CAN_SYM_SX) {
|
||||
int64_t minv = -(1LL << (s->bit_len - 1));
|
||||
int64_t maxv = (1LL << (s->bit_len - 1)) - 1;
|
||||
if (raw_q < minv) raw_q = minv;
|
||||
if (raw_q > maxv) raw_q = maxv;
|
||||
uint64_t raw_u = (uint64_t)((int64_t)raw_q & ((1ULL << s->bit_len) - 1ULL));
|
||||
(s->endian == CAN_ENDIAN_INTEL)
|
||||
? _can_set_bits_intel(out_data, s->start_bit, s->bit_len, raw_u)
|
||||
: _can_set_bits_motorola(out_data, s->start_bit, s->bit_len, raw_u);
|
||||
} else {
|
||||
if (raw_q < 0) raw_q = 0;
|
||||
uint64_t raw_u = (uint64_t)raw_q & ((s->bit_len == 64) ? ~0ULL : ((1ULL << s->bit_len) - 1ULL));
|
||||
(s->endian == CAN_ENDIAN_INTEL)
|
||||
? _can_set_bits_intel(out_data, s->start_bit, s->bit_len, raw_u)
|
||||
: _can_set_bits_motorola(out_data, s->start_bit, s->bit_len, raw_u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void can_decode_message(const CanMessageDef *msg, const uint8_t in_data[8])
|
||||
{
|
||||
if (!msg || !in_data) return;
|
||||
|
||||
for (uint8_t i = 0; i < msg->symbol_count; ++i) {
|
||||
const CanSymbolDef *s = &msg->symbols[i];
|
||||
if (!s->ptr || s->bit_len == 0) continue;
|
||||
|
||||
uint64_t raw = (s->endian == CAN_ENDIAN_INTEL)
|
||||
? _can_get_bits_intel(in_data, s->start_bit, s->bit_len)
|
||||
: _can_get_bits_motorola(in_data, s->start_bit, s->bit_len);
|
||||
|
||||
// 1) Sign-extend (or not) -> produce raw_s
|
||||
int64_t raw_s;
|
||||
if (s->raw_type == CAN_SYM_SX) {
|
||||
uint64_t sign_bit = 1ULL << (s->bit_len - 1);
|
||||
raw_s = (raw & sign_bit)
|
||||
? (int64_t)(raw | (~((1ULL << s->bit_len) - 1ULL))) // extend
|
||||
: (int64_t)raw;
|
||||
} else {
|
||||
raw_s = (int64_t)raw;
|
||||
}
|
||||
|
||||
// 2) Store according to 'storage'
|
||||
if (s->storage == CAN_STORE_FLOAT) {
|
||||
float f, o; eff_scale(s, &f, &o);
|
||||
// f==0 guard (shouldn't happen if scales are defined, but safe)
|
||||
if (f == 0.0f) f = 1.0f;
|
||||
*(float*)s->ptr = (float)raw_s * f + o;
|
||||
} else {
|
||||
switch (s->storage) {
|
||||
case CAN_STORE_U32: *(uint32_t*)s->ptr = (uint32_t)raw_s; break;
|
||||
case CAN_STORE_S32: *(int32_t *)s->ptr = (int32_t) raw_s; break;
|
||||
case CAN_STORE_U16: *(uint16_t*)s->ptr = (uint16_t)raw_s; break;
|
||||
case CAN_STORE_S16: *(int16_t *)s->ptr = (int16_t) raw_s; break;
|
||||
case CAN_STORE_U8: *(uint8_t *)s->ptr = (uint8_t) raw_s; break;
|
||||
case CAN_STORE_S8: *(int8_t *)s->ptr = (int8_t) raw_s; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
Core/CAN_Libs/can_encode.h
Normal file
20
Core/CAN_Libs/can_encode.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* can_encode.h
|
||||
*
|
||||
* Created on: Sep 16, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#ifndef INC_CAN_ENCODE_H_
|
||||
#define INC_CAN_ENCODE_H_
|
||||
|
||||
#include "can_schema.h"
|
||||
|
||||
/* Exposed for unit tests; most users call can_encode_message / can_decode_message */
|
||||
uint64_t _can_get_bits_intel(const uint8_t data[8], uint8_t start_bit, uint8_t bit_len);
|
||||
void _can_set_bits_intel(uint8_t data[8], uint8_t start_bit, uint8_t bit_len, uint64_t raw);
|
||||
|
||||
uint64_t _can_get_bits_motorola(const uint8_t data[8], uint8_t start_bit, uint8_t bit_len);
|
||||
void _can_set_bits_motorola(uint8_t data[8], uint8_t start_bit, uint8_t bit_len, uint64_t raw);
|
||||
|
||||
#endif /* INC_CAN_ENCODE_H_ */
|
||||
266
Core/CAN_Libs/can_manager.c
Normal file
266
Core/CAN_Libs/can_manager.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* can_manager.c
|
||||
*
|
||||
* Created on: Sep 16, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
#include "id.h"
|
||||
#include "can_manager.h"
|
||||
#include "can_db_symbols.h" // we’ll reference message defs here
|
||||
#include "can_encode.h"
|
||||
#include "timeouts.h"
|
||||
#include "ford_immo.h"
|
||||
#include <string.h>
|
||||
|
||||
static CanTxFn s_tx = NULL;
|
||||
|
||||
/* Handler registry keyed by message DEF, not by ID */
|
||||
#ifndef CAN_MANAGER_MAX_HANDLERS
|
||||
#define CAN_MANAGER_MAX_HANDLERS 8
|
||||
#endif
|
||||
typedef struct {
|
||||
const CanMessageDef *msg;
|
||||
CanRxHandler handler;
|
||||
} _HandlerEntry;
|
||||
|
||||
static _HandlerEntry s_handlers[CAN_MANAGER_MAX_HANDLERS];
|
||||
static uint8_t s_handlers_cnt = 0;
|
||||
|
||||
|
||||
/* for request */
|
||||
volatile uint16_t EMPF2_WORDS[4] = {0,0,0,0};
|
||||
|
||||
|
||||
bool can_manager_register_handler_msg(const CanMessageDef *msg, CanRxHandler handler)
|
||||
{
|
||||
if (!msg || !handler) return false;
|
||||
for (uint8_t i = 0; i < s_handlers_cnt; ++i) {
|
||||
if (s_handlers[i].msg == msg) { s_handlers[i].handler = handler; return true; }
|
||||
}
|
||||
if (s_handlers_cnt >= CAN_MANAGER_MAX_HANDLERS) return false;
|
||||
s_handlers[s_handlers_cnt++] = (_HandlerEntry){ msg, handler };
|
||||
return true;
|
||||
}
|
||||
|
||||
static CanRxHandler _find_override_by_msg(const CanMessageDef *msg)
|
||||
{
|
||||
for (uint8_t i = 0; i < s_handlers_cnt; ++i)
|
||||
if (s_handlers[i].msg == msg) return s_handlers[i].handler;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void can_manager_init(CanTxFn tx_fn) { s_tx = tx_fn; }
|
||||
|
||||
|
||||
void can_manager_boot(void)
|
||||
{
|
||||
if (!s_tx) return;
|
||||
size_t n = 0;
|
||||
const CanMessageDef* const* db = can_db_all_ptr(&n);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const CanMessageDef *m = db[i];
|
||||
if (m->dir == CAN_DIR_TX && m->send_on_boot) {
|
||||
uint8_t buf[8] = {0};
|
||||
can_encode_message(m, buf);
|
||||
s_tx(m->can_id, buf, m->dlc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void can_manager_on_rx(uint16_t can_id, const uint8_t data[8], uint8_t dlc)
|
||||
{
|
||||
(void)dlc;
|
||||
if (!s_tx) return;
|
||||
|
||||
const CanMessageDef *msg = can_db_find(can_id, CAN_DIR_RX);
|
||||
if (!msg) return;
|
||||
|
||||
if (msg->symbol_count && msg->symbols)
|
||||
can_decode_message(msg, data);
|
||||
|
||||
if(msg->can_id == MSG_ID_SEND1.can_id){ //si es el command, reseteo
|
||||
Timeout_ResetByIndex(15, TIM16->CNT);
|
||||
}
|
||||
|
||||
CanRxHandler h = msg->rx_handler ? msg->rx_handler : _find_override_by_msg(msg);
|
||||
if (h) h(msg, data, s_tx);
|
||||
}
|
||||
|
||||
bool can_manager_send_msg(const CanMessageDef *msg)
|
||||
{
|
||||
if (!s_tx || !msg || msg->dir != CAN_DIR_TX) return false;
|
||||
uint8_t buf[8] = {0};
|
||||
can_encode_message(msg, buf);
|
||||
return s_tx(msg->can_id, buf, msg->dlc);
|
||||
}
|
||||
|
||||
bool can_manager_send(uint16_t can_id)
|
||||
{
|
||||
const CanMessageDef *msg = can_db_find(can_id, CAN_DIR_TX);
|
||||
if (!msg) return false;
|
||||
return can_manager_send_msg(msg);
|
||||
}
|
||||
|
||||
/* ---------- Startup and request trigger handlers (reply by DEF) ---------- */
|
||||
static const CanMessageDef *s_startup_reply_msg = NULL; // -> MSG_ID_EMPF3
|
||||
static const CanMessageDef *s_request_reply_msg = NULL; // -> MSG_ID_EMPF2
|
||||
|
||||
extern void Timeout_ResetByIndex(uint8_t idx, uint16_t now);
|
||||
extern TIM_HandleTypeDef* htim16;
|
||||
|
||||
void can_manager_set_startup_reply_msg(const CanMessageDef *reply_msg)
|
||||
{
|
||||
s_startup_reply_msg = reply_msg;
|
||||
}
|
||||
uint8_t startup = 1;
|
||||
|
||||
/*
|
||||
void can_manager_rx_startup_trigger(const CanMessageDef *msg, const uint8_t in[8], CanTxFn tx)
|
||||
{
|
||||
(void)msg; (void)in;
|
||||
if (!tx || !s_startup_reply_msg) return;
|
||||
|
||||
if (startup) {
|
||||
//Send by DEFINITION: use reply_msg’s ID & DLC and (if present) its tx_template
|
||||
uint8_t buf[8] = {0};
|
||||
can_encode_message(s_startup_reply_msg, buf); // template + symbols
|
||||
tx(s_startup_reply_msg->can_id, buf, s_startup_reply_msg->dlc);
|
||||
|
||||
startup = (startup < 3) ? (startup + 1) : 0;
|
||||
Timeout_ResetByIndex(11, (uint16_t)htim16->Instance->CNT);
|
||||
}else{
|
||||
//register for answering next messages, on end should also reregister for the boot sequence right??
|
||||
can_manager_register_handler_msg(&MSG_STARTUP_TRIGGER_RX, can_manager_rx_boot_reply_always);
|
||||
}
|
||||
Timeout_ResetByIndex(15, (uint16_t)htim16->Instance->CNT);
|
||||
}
|
||||
*/
|
||||
// Always send the boot message (EMPF3) as a reply, regardless of 'startup'
|
||||
uint8_t count = 0;
|
||||
|
||||
uint8_t startup_finished = 0;
|
||||
#if defined(T06301)
|
||||
uint8_t startup_count = 9;
|
||||
#elif defined(T06209) || defined(T06216) || defined(T06211)
|
||||
uint8_t startup_count = 0;
|
||||
uint8_t startup_sent_count = 0;
|
||||
|
||||
#else
|
||||
#endif
|
||||
extern int watchdog_active;
|
||||
void can_manager_rx_boot_reply_always(const CanMessageDef *msg, const uint8_t in[8], CanTxFn tx)
|
||||
{
|
||||
(void)msg; (void)in;
|
||||
if (!tx || !s_startup_reply_msg) return;
|
||||
|
||||
#if defined(T06301)
|
||||
if(!watchdog_active){return;}
|
||||
|
||||
if(count < 2){
|
||||
count++;
|
||||
}
|
||||
|
||||
startup = 0;
|
||||
startup_count = 0;
|
||||
Timeout_ResetByIndex(18, TIM16->CNT); // first callback in 40 ms
|
||||
Timeout_StopByIndex(21); // first callback in 40 ms
|
||||
if(count > 1){
|
||||
Timeout_StartIfStopped(20, TIM16->CNT - 500);
|
||||
//no deberia hacer na esto pq bootea started.
|
||||
}
|
||||
#elif defined(T06209) || defined(T06216) || defined(T06211)
|
||||
if (!startup_sent_count){return;}
|
||||
|
||||
if(startup_finished){
|
||||
startup_count++; //probar esto
|
||||
startup_count %= 3;
|
||||
if (!startup_count){
|
||||
Timeout_ResetByIndex(18, TIM16->CNT); // re-arm for another 40ms
|
||||
}
|
||||
}else{
|
||||
if(startup_count){
|
||||
startup_count--;
|
||||
}else{
|
||||
startup_finished = 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
void can_manager_set_request_reply_msg(const CanMessageDef *reply_msg)
|
||||
{
|
||||
s_request_reply_msg = reply_msg; // set to &MSG_ID_EMPF2
|
||||
}
|
||||
|
||||
volatile uint8_t s_empf2_pending = 0;
|
||||
|
||||
bool can_manager_empf2_has_pending(void) { return s_empf2_pending != 0; }
|
||||
void can_manager_empf2_clear_pending(void) { s_empf2_pending = 0; }
|
||||
|
||||
void can_manager_rx_address_request(const CanMessageDef *msg, const uint8_t in[8], CanTxFn tx)
|
||||
{
|
||||
(void)msg; (void)tx;
|
||||
|
||||
// Parse 4 big-endian request words
|
||||
uint16_t req[4];
|
||||
for (int i = 0; i < 4; ++i)
|
||||
req[i] = (uint16_t)((in[2*i] << 8) | in[2*i+1]);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
uint16_t a = req[i];
|
||||
int32_t raw = 0; // signed accumulator before clamping
|
||||
int found = 0;
|
||||
|
||||
for (size_t j = 0; j < CAN_ANSWERS_COUNT; ++j) {
|
||||
const CanAddressEntry *E = &CAN_ANSWERS[j];
|
||||
if (E->addr != a) continue;
|
||||
found = 1;
|
||||
|
||||
if (E->storage == CAN_STORE_FLOAT) {
|
||||
// physical float with optional scale
|
||||
const float phys = *(const float*)E->ptr;
|
||||
const float f = E->scale ? E->scale->factor : 1.0f;
|
||||
const float o = E->scale ? E->scale->offset : 0.0f;
|
||||
float scaled = (phys - o) / f;
|
||||
//if (!isfinite(scaled)) scaled = 0.0f;
|
||||
raw = (int32_t)llroundf(scaled);
|
||||
} else {
|
||||
// integer-backed: read as-is (no scaling)
|
||||
switch (E->storage) {
|
||||
case CAN_STORE_U32: raw = (int32_t)*(const uint32_t*)E->ptr; break;
|
||||
case CAN_STORE_S32: raw = (int32_t)*(const int32_t *)E->ptr; break;
|
||||
case CAN_STORE_U16: raw = (int32_t)*(const uint16_t*)E->ptr; break;
|
||||
case CAN_STORE_S16: raw = (int32_t)*(const int16_t *)E->ptr; break;
|
||||
case CAN_STORE_U8: raw = (int32_t)*(const uint8_t *)E->ptr; break;
|
||||
case CAN_STORE_S8: raw = (int32_t)*(const int8_t *)E->ptr; break;
|
||||
default: raw = 0; break;
|
||||
}
|
||||
}
|
||||
|
||||
// Clamp to 16-bit range according to raw_type
|
||||
if (E->raw_type == CAN_SYM_SX) {
|
||||
if (raw < -32768) raw = -32768;
|
||||
if (raw > 32767) raw = 32767;
|
||||
} else {
|
||||
if (raw < 0) raw = 0;
|
||||
if (raw > 65535) raw = 65535;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t raw16 = (uint16_t)raw; // two's complement for signed values
|
||||
// Pack little-endian into EMPF2_BYTES (shared TX buffer for MSG_ID_EMPF2)
|
||||
EMPF2_BYTES[2*i + 0] = (uint8_t)(raw16 & 0xFF);
|
||||
EMPF2_BYTES[2*i + 1] = (uint8_t)(raw16 >> 8);
|
||||
}
|
||||
|
||||
// Mark pending and start 60ms window only if not already running
|
||||
s_empf2_pending = 1;
|
||||
Timeout_StartIfStopped(17, (uint16_t)TIM16->CNT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
56
Core/CAN_Libs/can_manager.h
Normal file
56
Core/CAN_Libs/can_manager.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* can_manager.h
|
||||
*
|
||||
* Created on: Sep 16, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#ifndef SRC_CAN_LIBS_CAN_MANAGER_H_
|
||||
#define SRC_CAN_LIBS_CAN_MANAGER_H_
|
||||
|
||||
#include "can_schema.h"
|
||||
|
||||
extern uint8_t startup;
|
||||
|
||||
extern volatile uint8_t EMPF2_BYTES[8];
|
||||
extern volatile uint8_t s_empf2_pending;
|
||||
|
||||
|
||||
/* Provide your HAL-backed TX function when initializing the manager. */
|
||||
void can_manager_init(CanTxFn tx_fn);
|
||||
|
||||
/* Send all TX messages flagged with send_on_boot==1 (templates first, then symbols). */
|
||||
void can_manager_boot(void);
|
||||
|
||||
/* RX entrypoint: call from your FDCAN Rx FIFO callback. */
|
||||
void can_manager_on_rx(uint16_t can_id, const uint8_t data[8], uint8_t dlc);
|
||||
|
||||
/* TX by ID (packs symbols; starts from tx_template if present). Returns false if ID not found. */
|
||||
bool can_manager_send(uint16_t can_id);
|
||||
|
||||
/* Utility: direct send of a message definition (useful if you already called can_db_find) */
|
||||
bool can_manager_send_msg(const CanMessageDef *msg);
|
||||
|
||||
/* NEW: runtime registration of message handlers (keeps can_db.c pure-data) */
|
||||
bool can_manager_register_handler(uint16_t can_id, CanDirection dir, CanRxHandler handler);
|
||||
|
||||
/* Register a handler for a specific message DEFINITION (no IDs in app code) */
|
||||
bool can_manager_register_handler_msg(const CanMessageDef *msg, CanRxHandler handler);
|
||||
|
||||
// STARTUP MANAGER FUNCTIONS //
|
||||
void can_manager_set_startup_reply_msg(const CanMessageDef *reply_msg); // use MSG_ID_EMPF3
|
||||
/* Optional: we expose a ready-made startup-trigger handler you can register. */
|
||||
void can_manager_rx_startup_trigger(const CanMessageDef *msg, const uint8_t in[8], CanTxFn tx);
|
||||
|
||||
void can_manager_rx_boot_reply_always(const CanMessageDef *msg, const uint8_t in[8], CanTxFn tx);
|
||||
|
||||
// REQUEST MANAGER FUNCTIONS //
|
||||
/* Address-request handler (uses EMPF2 as the reply message def) */
|
||||
void can_manager_set_request_reply_msg(const CanMessageDef *reply_msg); // use MSG_ID_EMPF2
|
||||
void can_manager_rx_address_request(const CanMessageDef *msg, const uint8_t in[8], CanTxFn tx);
|
||||
|
||||
// Request/Reply control for EMPF2
|
||||
bool can_manager_empf2_has_pending(void);
|
||||
void can_manager_empf2_clear_pending(void);
|
||||
|
||||
#endif /* SRC_CAN_LIBS_CAN_MANAGER_H_ */
|
||||
256
Core/CAN_Libs/can_port.c
Normal file
256
Core/CAN_Libs/can_port.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* can_port.c
|
||||
*
|
||||
* Created on: Sep 16, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
#include "can_port.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef CAN_TXQ_CAP
|
||||
#define CAN_TXQ_CAP 16u
|
||||
#endif
|
||||
|
||||
|
||||
/* ===== Static state ===== */
|
||||
static FDCAN_HandleTypeDef *s_hcan = NULL;
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
uint8_t dlc;
|
||||
uint8_t data[8];
|
||||
} _CanQueuedMsg;
|
||||
|
||||
/* Map 0..8 payload length to FDCAN DLC enum for classic CAN. */
|
||||
static inline uint32_t _dlc_from_len(uint8_t len)
|
||||
{
|
||||
switch (len) {
|
||||
case 0: return FDCAN_DLC_BYTES_0;
|
||||
case 1: return FDCAN_DLC_BYTES_1;
|
||||
case 2: return FDCAN_DLC_BYTES_2;
|
||||
case 3: return FDCAN_DLC_BYTES_3;
|
||||
case 4: return FDCAN_DLC_BYTES_4;
|
||||
case 5: return FDCAN_DLC_BYTES_5;
|
||||
case 6: return FDCAN_DLC_BYTES_6;
|
||||
case 7: return FDCAN_DLC_BYTES_7;
|
||||
default: return FDCAN_DLC_BYTES_8;
|
||||
}
|
||||
}
|
||||
static inline bool _try_tx_now(FDCAN_HandleTypeDef *h, uint16_t id, const uint8_t data[8], uint8_t dlc)
|
||||
{
|
||||
FDCAN_TxHeaderTypeDef th = {0};
|
||||
th.Identifier = id;
|
||||
th.IdType = FDCAN_STANDARD_ID;
|
||||
th.TxFrameType = FDCAN_DATA_FRAME;
|
||||
th.DataLength = _dlc_from_len(dlc);
|
||||
th.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
|
||||
th.BitRateSwitch = FDCAN_BRS_OFF;
|
||||
th.FDFormat = FDCAN_CLASSIC_CAN;
|
||||
th.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
|
||||
th.MessageMarker = 0;
|
||||
|
||||
return (HAL_FDCAN_AddMessageToTxFifoQ(h, &th, (uint8_t*)data) == HAL_OK);
|
||||
}
|
||||
|
||||
static volatile uint16_t _txq_head = 0; // push
|
||||
static volatile uint16_t _txq_tail = 0; // pop
|
||||
static _CanQueuedMsg _txq_buf[CAN_TXQ_CAP];
|
||||
|
||||
static inline bool _txq_full(void) { return (uint16_t)((_txq_head + 1u) % CAN_TXQ_CAP) == _txq_tail; }
|
||||
static inline bool _txq_empty(void) { return _txq_head == _txq_tail; }
|
||||
|
||||
static bool _txq_push(const _CanQueuedMsg *m)
|
||||
{
|
||||
if (_txq_full()) return false;
|
||||
uint16_t h = _txq_head;
|
||||
_txq_buf[h] = *m;
|
||||
__DMB(); // ensure data visible before advancing head
|
||||
_txq_head = (uint16_t)((h + 1u) % CAN_TXQ_CAP);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _txq_pop(_CanQueuedMsg *m)
|
||||
{
|
||||
if (_txq_empty()) return false;
|
||||
uint16_t t = _txq_tail;
|
||||
*m = _txq_buf[t];
|
||||
__DMB();
|
||||
_txq_tail = (uint16_t)((t + 1u) % CAN_TXQ_CAP);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t CAN_TxQueueDepth(void)
|
||||
{
|
||||
int16_t d = (int16_t)_txq_head - (int16_t)_txq_tail;
|
||||
if (d < 0) d += (int16_t)CAN_TXQ_CAP;
|
||||
return (size_t)d;
|
||||
}
|
||||
bool CAN_Service(void)
|
||||
{
|
||||
if (!s_hcan) return false;
|
||||
|
||||
bool sent_any = false;
|
||||
for (;;) {
|
||||
_CanQueuedMsg m;
|
||||
if (!_txq_pop(&m)) break;
|
||||
|
||||
if (!_try_tx_now(s_hcan, (uint16_t)m.id, m.data, m.dlc)) {
|
||||
// HW still full -> put back and stop to preserve order
|
||||
(void)_txq_push(&m);
|
||||
break;
|
||||
}
|
||||
sent_any = true;
|
||||
}
|
||||
return sent_any;
|
||||
}
|
||||
|
||||
|
||||
/* Adapter used by can_manager to actually TX via HAL */
|
||||
static bool _tx_adapter(uint16_t id, const uint8_t data[8], uint8_t dlc)
|
||||
{
|
||||
if (!s_hcan) return false;
|
||||
|
||||
// 1) Try to send immediately
|
||||
if (_try_tx_now(s_hcan, id, data, dlc)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2) HW busy -> enqueue and report success if queued
|
||||
_CanQueuedMsg m;
|
||||
m.id = id;
|
||||
m.dlc = dlc;
|
||||
memcpy(m.data, data, 8);
|
||||
|
||||
return _txq_push(&m);
|
||||
}
|
||||
|
||||
|
||||
/* ===== Public API ===== */
|
||||
|
||||
void can_port_init(FDCAN_HandleTypeDef *hfdcan)
|
||||
{
|
||||
s_hcan = hfdcan;
|
||||
can_manager_init(_tx_adapter);
|
||||
//falta el register handler
|
||||
|
||||
}
|
||||
|
||||
void can_port_boot(void)
|
||||
{
|
||||
can_manager_boot();
|
||||
|
||||
// Send the first EMPF3 immediately
|
||||
//can_port_send_msg_def(&MSG_ID_EMPF3);
|
||||
|
||||
// Schedule the remaining two, 40 ms apart, via timeout index 18
|
||||
//Timeout_ResetByIndex(18, TIM16->CNT); // first callback in 40 ms
|
||||
}
|
||||
|
||||
void can_port_handle_rx_fifo(uint32_t fifo_index)
|
||||
{
|
||||
if (!s_hcan) return;
|
||||
|
||||
const uint32_t fifo = (fifo_index == 1) ? FDCAN_RX_FIFO1 : FDCAN_RX_FIFO0;
|
||||
|
||||
while (HAL_FDCAN_GetRxFifoFillLevel(s_hcan, fifo) > 0U) {
|
||||
FDCAN_RxHeaderTypeDef rh;
|
||||
uint8_t data[8];
|
||||
if (HAL_FDCAN_GetRxMessage(s_hcan, fifo, &rh, data) != HAL_OK) {
|
||||
/* If needed: handle error or break */
|
||||
break;
|
||||
}
|
||||
/* Pass to the generic manager; it will decode symbols and/or call handlers. */
|
||||
can_manager_on_rx((uint16_t)rh.Identifier, data, 8);
|
||||
}
|
||||
}
|
||||
|
||||
bool can_port_send_msg(uint16_t can_id)
|
||||
{
|
||||
return can_manager_send(can_id);
|
||||
}
|
||||
|
||||
bool can_port_send_raw(uint16_t id, const uint8_t data[8], uint8_t dlc)
|
||||
{
|
||||
return _tx_adapter(id, data, dlc);
|
||||
}
|
||||
|
||||
static int _is_std_id(uint32_t id) { return (id <= 0x7FFu); }
|
||||
|
||||
size_t can_port_required_std_filters(void)
|
||||
{
|
||||
size_t count = 0, n = 0;
|
||||
const CanMessageDef* const* all = can_db_all_ptr(&n);
|
||||
if (!all) return 0;
|
||||
|
||||
// simple dedup set (tiny nets) — 64 IDs buffer; grow if you need more
|
||||
uint16_t seen[64];
|
||||
size_t seen_n = 0;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const CanMessageDef *m = all[i];
|
||||
if (!m || m->dir != CAN_DIR_RX) continue;
|
||||
if (!_is_std_id(m->can_id)) continue;
|
||||
|
||||
uint16_t id = (uint16_t)m->can_id;
|
||||
int dup = 0;
|
||||
for (size_t k = 0; k < seen_n; ++k) { if (seen[k] == id) { dup = 1; break; } }
|
||||
if (!dup) {
|
||||
if (seen_n < (sizeof(seen)/sizeof(seen[0]))) seen[seen_n++] = id;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef can_port_apply_rx_filters(FDCAN_HandleTypeDef *hfdcan)
|
||||
{
|
||||
if (!hfdcan) return HAL_ERROR;
|
||||
|
||||
// 1) Reject everything by default (we’ll explicitly allow only DB RX IDs)
|
||||
HAL_StatusTypeDef st =
|
||||
HAL_FDCAN_ConfigGlobalFilter(hfdcan,
|
||||
FDCAN_REJECT, // non-matching STD
|
||||
FDCAN_REJECT, // non-matching EXT
|
||||
FDCAN_REJECT_REMOTE, // STD remote
|
||||
FDCAN_REJECT_REMOTE);// EXT remote
|
||||
if (st != HAL_OK) return st;
|
||||
|
||||
// 2) Build exact-match STANDARD filters to FIFO0
|
||||
size_t n=0, idx=0;
|
||||
const CanMessageDef* const* all = can_db_all_ptr(&n);
|
||||
if (!all) return HAL_OK;
|
||||
|
||||
// Dedup pass (same as above, but we’ll store all unique IDs)
|
||||
uint16_t ids[64];
|
||||
size_t ids_n = 0;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const CanMessageDef *m = all[i];
|
||||
if (!m || m->dir != CAN_DIR_RX) continue;
|
||||
if (!_is_std_id(m->can_id)) continue;
|
||||
|
||||
uint16_t id = (uint16_t)m->can_id;
|
||||
int dup = 0;
|
||||
for (size_t k = 0; k < ids_n; ++k) { if (ids[k] == id) { dup = 1; break; } }
|
||||
if (!dup && ids_n < (sizeof(ids)/sizeof(ids[0]))) ids[ids_n++] = id;
|
||||
}
|
||||
|
||||
// Guard: hardware must have enough filter elements (StdFiltersNbr >= ids_n)
|
||||
// If not, we still program as many as possible.
|
||||
for (idx = 0; idx < ids_n; ++idx) {
|
||||
FDCAN_FilterTypeDef f = {0};
|
||||
f.IdType = FDCAN_STANDARD_ID;
|
||||
f.FilterIndex = (uint32_t)idx;
|
||||
f.FilterType = FDCAN_FILTER_MASK; // mask-based exact match
|
||||
f.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; // route to FIFO0
|
||||
f.FilterID1 = ids[idx]; // ID to match
|
||||
f.FilterID2 = 0x7FF; // mask: all 11 bits must match
|
||||
|
||||
st = HAL_FDCAN_ConfigFilter(hfdcan, &f);
|
||||
if (st != HAL_OK) return st;
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
45
Core/CAN_Libs/can_port.h
Normal file
45
Core/CAN_Libs/can_port.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* can_port.h
|
||||
*
|
||||
* Created on: Sep 16, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#ifndef SRC_CAN_LIBS_CAN_PORT_H_
|
||||
#define SRC_CAN_LIBS_CAN_PORT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "stm32g4xx_hal.h" // adjust family include if needed
|
||||
#include "can_manager.h" // uses the generic CAN manager API
|
||||
#include "can_db_symbols.h"
|
||||
|
||||
/* Initialize the CAN port glue (provide your HAL handle).
|
||||
* You can call this before or after HAL_FDCAN_Start(), but call can_port_boot()
|
||||
* only after the CAN is started and bus-active.
|
||||
*/
|
||||
void can_port_init(FDCAN_HandleTypeDef *hfdcan);
|
||||
|
||||
/* Sends all TX messages flagged with send_on_boot == 1 in can_db.c */
|
||||
void can_port_boot(void);
|
||||
|
||||
/* Drain and process all frames from a FIFO (0 or 1). Call from your HAL Rx callbacks. */
|
||||
void can_port_handle_rx_fifo(uint32_t fifo_index);
|
||||
|
||||
size_t can_port_required_std_filters(void);
|
||||
|
||||
HAL_StatusTypeDef can_port_apply_rx_filters(FDCAN_HandleTypeDef *hfdcan);
|
||||
|
||||
/* New: send by message DEF */
|
||||
static inline bool can_port_send_msg_def(const CanMessageDef *msg) {
|
||||
return can_manager_send_msg(msg);
|
||||
}
|
||||
|
||||
/* Raw (rarely needed) */
|
||||
bool can_port_send_raw(uint16_t id, const uint8_t data[8], uint8_t dlc);
|
||||
|
||||
bool CAN_Service(void); // drain queue; returns true if any sent
|
||||
size_t CAN_TxQueueDepth(void); // how many frames waiting
|
||||
|
||||
|
||||
#endif /* SRC_CAN_LIBS_CAN_PORT_H_ */
|
||||
138
Core/CAN_Libs/can_read_pump_data.c
Normal file
138
Core/CAN_Libs/can_read_pump_data.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
29
Core/CAN_Libs/can_read_pump_data.h
Normal file
29
Core/CAN_Libs/can_read_pump_data.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* can_read_pump_data.h
|
||||
*
|
||||
* Created on: Sep 18, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#ifndef IMMOBILISERS_CAN_READ_PUMP_DATA_H_
|
||||
#define IMMOBILISERS_CAN_READ_PUMP_DATA_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* Configure the 4 logical pieces (optional; defaults are compiled in) */
|
||||
void can_read_pump_data_set_client_model(const char *ascii); // e.g. "059 130 106L"
|
||||
void can_read_pump_data_set_serial(const char *ascii); // e.g. "142974"
|
||||
void can_read_pump_data_set_sw(const char *ascii); // e.g. "C150_1.V79"
|
||||
void can_read_pump_data_set_pin(const char *ascii); // e.g. "482"
|
||||
|
||||
/* Build the full ASCII payload from the 4 pieces. Call at boot (or after setters). */
|
||||
void can_read_pump_data_init(void);
|
||||
|
||||
/* Register the wrapper handler on 0x502 (MSG_ID_SEND2).
|
||||
* - Pump data pattern (FFFF A5..AB) -> handled here and reply is queued via the 60 ms path.
|
||||
* - Otherwise -> forwarded to the normal 0x502 address→value handler.
|
||||
*/
|
||||
void can_read_pump_data_register(void);
|
||||
|
||||
#endif /* IMMOBILISERS_CAN_READ_PUMP_DATA_H_ */
|
||||
119
Core/CAN_Libs/can_schema.h
Normal file
119
Core/CAN_Libs/can_schema.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* can_schema.h
|
||||
*
|
||||
* Created on: Sep 16, 2025
|
||||
* Author: herli
|
||||
*/
|
||||
|
||||
#ifndef INC_CAN_SCHEMA_H_
|
||||
#define INC_CAN_SCHEMA_H_
|
||||
|
||||
#ifndef CAN_SCHEMA_H
|
||||
#define CAN_SCHEMA_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
CAN_DIR_RX = 0, // incoming from bus -> decode into RAM
|
||||
CAN_DIR_TX = 1 // outgoing to bus -> encode from RAM
|
||||
} CanDirection;
|
||||
|
||||
typedef enum {
|
||||
CAN_ENDIAN_INTEL = 0, // DBC "Intel" (little-endian bit numbering): bit 0 = LSB of byte 0
|
||||
CAN_ENDIAN_MOTOROLA = 1 // DBC "Motorola" (big-endian bit numbering)
|
||||
} CanEndian;
|
||||
|
||||
typedef enum {
|
||||
CAN_SYM_UX = 0, // unsigned raw
|
||||
CAN_SYM_SX = 1, // signed two's complement raw
|
||||
CAN_SYM_FLOAT = 2 // (kept for future use)
|
||||
} CanRawType;
|
||||
|
||||
typedef enum {
|
||||
NOMINAL = 0,
|
||||
INVERTED = 1
|
||||
} CanInversion;
|
||||
|
||||
/* Shared scale (optional): if a symbol sets factor==0 && offset==0 and scale!=NULL,
|
||||
* the effective factor/offset comes from this struct. If symbol.factor/offset is non-zero,
|
||||
* it overrides the scale.
|
||||
*/
|
||||
typedef struct CanScaleDef {
|
||||
const char *unit; // informational, may be NULL
|
||||
float factor;
|
||||
float offset;
|
||||
} CanScaleDef;
|
||||
|
||||
typedef enum {
|
||||
CAN_STORE_FLOAT = 0, // ptr -> float (uses factor/offset)
|
||||
CAN_STORE_U32, // ptr -> uint32_t (raw integer)
|
||||
CAN_STORE_S32, // ptr -> int32_t (raw integer)
|
||||
CAN_STORE_U16, // ptr -> uint16_t (raw integer)
|
||||
CAN_STORE_S16, // ptr -> int16_t (raw integer)
|
||||
CAN_STORE_U8, // ptr -> uint8_t (raw integer)
|
||||
CAN_STORE_S8 // ptr -> int8_t (raw integer)
|
||||
} CanStorage;
|
||||
|
||||
struct CanMessageDef; // fwd
|
||||
|
||||
// User-provided TX function that actually hands frames to HAL
|
||||
typedef bool (*CanTxFn)(uint16_t id, const uint8_t data[8], uint8_t dlc);
|
||||
|
||||
// Optional per-message RX handler (called AFTER any symbol decode)
|
||||
typedef void (*CanRxHandler)(
|
||||
const struct CanMessageDef *msg,
|
||||
const uint8_t in_data[8],
|
||||
CanTxFn tx
|
||||
);
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
uint8_t start_bit, bit_len;
|
||||
CanEndian endian;
|
||||
CanRawType raw_type; // UX / SX (bit interpretation)
|
||||
float factor, offset;
|
||||
void *ptr;
|
||||
const CanScaleDef *scale;
|
||||
CanStorage storage; // NEW: how to read/write *ptr
|
||||
CanInversion inverted;
|
||||
|
||||
} CanSymbolDef;
|
||||
|
||||
typedef struct CanMessageDef {
|
||||
uint16_t can_id; // 11-bit standard ID
|
||||
CanDirection dir; // RX or TX
|
||||
uint8_t dlc; // 0..8
|
||||
const char *name; // message name
|
||||
const CanSymbolDef *symbols; // array of symbols (NULL if template-only)
|
||||
uint8_t symbol_count; // number of symbols
|
||||
|
||||
// Optional template payload (used for TX): copied first, then symbols packed on top.
|
||||
const uint8_t *tx_template; // 0..8 bytes in flash (NULL if none)
|
||||
uint8_t send_on_boot; // if 1 and TX, manager will send at init
|
||||
|
||||
// Optional RX handler (for custom behaviors like address-based replies)
|
||||
CanRxHandler rx_handler;
|
||||
} CanMessageDef;
|
||||
|
||||
typedef struct {
|
||||
uint16_t addr; // request address
|
||||
void *ptr; // pointer to physical value (usually float*)
|
||||
CanRawType raw_type; // how to quantize (unsigned/signed)
|
||||
const CanScaleDef *scale; // scaling used for inverse transform
|
||||
CanStorage storage; // NEW: how to read ptr (FLOAT/U16/U32/…)
|
||||
} CanAddressEntry;
|
||||
|
||||
/* Registry access (implemented in can_db.c) */
|
||||
const CanMessageDef* can_db_find(uint16_t can_id, CanDirection dir);
|
||||
const CanMessageDef* can_db_all(size_t *count);
|
||||
|
||||
/* Bit-pack engine (implemented in can_encode.c) */
|
||||
void can_encode_message(const CanMessageDef *msg, uint8_t out_data[8]);
|
||||
void can_decode_message(const CanMessageDef *msg, const uint8_t in_data[8]);
|
||||
|
||||
#endif /* CAN_SCHEMA_H */
|
||||
|
||||
#endif /* INC_CAN_SCHEMA_H_ */
|
||||
Reference in New Issue
Block a user