Compare commits

...

3 commits

Author SHA1 Message Date
Daniel Öster
ff71cadcb2 Further improve sending 2025-09-29 19:01:56 +03:00
Daniel Öster
657656b1f5 Improve CAN message sending routine towards battery 2025-09-29 18:25:47 +03:00
Daniel Öster
5cbfe92de9 Add more CAN message sending towards battery 2025-09-29 17:59:17 +03:00
3 changed files with 236 additions and 9 deletions

View file

@ -68,6 +68,8 @@ const char* name_for_battery_type(BatteryType type) {
return ChademoBattery::Name;
case BatteryType::CmfaEv:
return CmfaEvBattery::Name;
case BatteryType::FordMachE:
return FordMachEBattery::Name;
case BatteryType::Foxess:
return FoxessBattery::Name;
case BatteryType::GeelyGeometryC:

View file

@ -167,10 +167,85 @@ void FordMachEBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
}
void FordMachEBattery::transmit_can(unsigned long currentMillis) {
// Send 10ms CAN Message
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
previousMillis10 = currentMillis;
transmit_can_frame(&FORD_217);
transmit_can_frame(&FORD_442);
}
// Send 30ms CAN Message
if (currentMillis - previousMillis30 >= INTERVAL_30_MS) {
previousMillis30 = currentMillis;
counter_30ms = (counter_30ms + 1) % 16; // cycles 0-15
// Byte 2: upper nibble = 0xF, lower nibble = (0xF - counter_10ms) % 16
FORD_7D.data.u8[2] = 0xF0 | ((0xF - counter_30ms) & 0x0F);
// Byte 3: upper nibble = counter_10ms, lower nibble = 0x0
FORD_7D.data.u8[3] = (counter_30ms << 4) & 0xF0;
// Byte 0: starts at 0xC0 and increments by 4 each step, wraps every 16 steps
FORD_204.data.u8[0] = 0xC0 + (counter_30ms * 4);
// Byte 5: starts at 0xFC and decrements by 1 each step, wraps every 16 steps
FORD_204.data.u8[5] = 0xFC - counter_30ms;
// Byte 4: upper nibble = counter_10ms, lower nibble = 0x0
FORD_4B0.data.u8[4] = (counter_30ms << 4) & 0xF0;
// Byte 7: upper nibble = 0xF, lower nibble = (0xF - counter_10ms) % 16
FORD_4B0.data.u8[7] = 0xF0 | ((0xF - counter_30ms) & 0x0F);
// Byte 2: starts at 0xC0 and increments by 4 each step, wraps every 16 steps
FORD_415.data.u8[2] = 0xC0 + (counter_30ms * 4);
// Byte 3: starts at 0xFC and decrements by 1 each step, wraps every 16 steps
FORD_415.data.u8[3] = 0xFC - counter_30ms;
//TODO: handle FORD_4C properly very odd looping
transmit_can_frame(&FORD_77);
transmit_can_frame(&FORD_7D);
transmit_can_frame(&FORD_167);
transmit_can_frame(&FORD_48F); //Only sent in AC charging logs!
transmit_can_frame(&FORD_204);
transmit_can_frame(&FORD_4B0);
transmit_can_frame(&FORD_47);
transmit_can_frame(&FORD_230);
transmit_can_frame(&FORD_415);
transmit_can_frame(&FORD_4C);
transmit_can_frame(&FORD_7E);
transmit_can_frame(&FORD_48);
transmit_can_frame(&FORD_165);
}
// Send 50ms CAN Message
if (currentMillis - previousMillis50 >= INTERVAL_50_MS) {
previousMillis50 = currentMillis;
transmit_can_frame(&FORD_42C);
transmit_can_frame(&FORD_42F);
transmit_can_frame(&FORD_43D);
}
// Send 100ms CAN Message
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis;
//transmit_can_frame(&TEST);
transmit_can_frame(
&FORD_12F); //This message actually has checksum/counter, but it seems to close contactors without those
transmit_can_frame(&FORD_332);
transmit_can_frame(&FORD_333);
transmit_can_frame(&FORD_42B);
transmit_can_frame(&FORD_2EC);
transmit_can_frame(&FORD_156);
transmit_can_frame(
&FORD_5A); //This message actually has checksum/counter, but it seems to close contactors without those
transmit_can_frame(&FORD_166);
transmit_can_frame(&FORD_175);
}
// Send 1s CAN Message
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
previousMillis1000 = currentMillis;
transmit_can_frame(&FORD_3C3);
transmit_can_frame(&FORD_581);
}
}

View file

@ -18,9 +18,12 @@ class FordMachEBattery : public CanBattery {
static const int MAX_CELL_VOLTAGE_MV = 4250;
static const int MIN_CELL_VOLTAGE_MV = 2900;
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
unsigned long previousMillis10s = 0; // will store last time a 1s CAN Message was send
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
unsigned long previousMillis30 = 0; // will store last time a 10ms CAN Message was send
unsigned long previousMillis50 = 0; // will store last time a 100ms CAN Message was send
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was send
unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send
int16_t cell_temperature[6] = {0};
int16_t maximum_temperature = 0;
@ -30,11 +33,158 @@ class FordMachEBattery : public CanBattery {
uint16_t maximum_cellvoltage_mV = 3700;
uint16_t minimum_cellvoltage_mV = 3700;
CAN_frame TEST = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x123,
.data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}};
uint8_t counter_30ms = 0;
CAN_frame FORD_47 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x047,
.data = {0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame FORD_48 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x048,
.data = {0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame FORD_4C = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x04C,
.data = {0x70, 0xAA, 0xBF, 0xDE, 0xCC, 0xEC, 0x00, 0x00}};
CAN_frame FORD_5A = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x05A,
.data = {0x00, 0x00, 0x00, 0x0B, 0xF2, 0x90, 0x10, 0x00}};
CAN_frame FORD_77 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x077,
.data = {0x00, 0x00, 0x0F, 0xFE, 0xFF, 0xFF, 0xFB, 0xFE}};
CAN_frame FORD_7D = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x07D,
.data = {0x00, 0x00, 0xF0, 0xF0, 0x00, 0x3F, 0xEF, 0xFE}};
CAN_frame FORD_7E = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x07E,
.data = {0x00, 0x00, 0x3E, 0x80, 0x00, 0x04, 0x00, 0x00}};
CAN_frame FORD_156 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x156,
.data = {0x4B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}};
CAN_frame FORD_165 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x165,
.data = {0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame FORD_166 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x166,
.data = {0x00, 0x00, 0x00, 0x01, 0x5C, 0x89, 0x00, 0x00}};
CAN_frame FORD_167 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x167,
.data = {0x00, 0x80, 0x00, 0x11, 0xFF, 0xE0, 0x00, 0x00}};
CAN_frame FORD_175 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x175,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame FORD_12F = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x12F,
.data = {0x0A, 0xF8, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
CAN_frame FORD_204 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x204,
.data = {0xD4, 0x00, 0x7D, 0x00, 0x00, 0xF7, 0x00, 0x00}};
CAN_frame FORD_217 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x217,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame FORD_230 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x230,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}};
CAN_frame FORD_25B = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x25B,
.data = {0x01, 0xF4, 0x09, 0xF4, 0xE0, 0x00, 0x80, 0x00}};
CAN_frame FORD_2EC = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x2EC,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}};
CAN_frame FORD_332 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x332,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame FORD_333 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x333,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame FORD_3C3 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x3C3,
.data = {0x5C, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}};
CAN_frame FORD_415 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x415,
.data = {0x00, 0x00, 0xC0, 0xFC, 0x0F, 0xFE, 0xEF, 0xFE}};
CAN_frame FORD_42B = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x42B,
.data = {0xCB, 0xBE, 0x00, 0x02, 0x00, 0x00, 0xCE, 0x00}};
CAN_frame FORD_42C = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x42C,
.data = {0x80, 0x02, 0x00, 0x00, 0x19, 0xA0, 0x00, 0x00}};
CAN_frame FORD_42F = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x42F,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
CAN_frame FORD_43D = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x43D,
.data = {0x00, 0x00, 0xDC, 0x00, 0x00, 0x77, 0x00, 0x00}};
CAN_frame FORD_442 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x442,
.data = {0x4E, 0x20, 0x78, 0x7E, 0x7C, 0x00, 0x00, 0x40}};
CAN_frame FORD_48F = {.FD = false, //Only sent in active charging logs (OBC?)
.ext_ID = false,
.DLC = 8,
.ID = 0x48F,
.data = {0x30, 0x4E, 0x20, 0x80, 0x00, 0x00, 0x80, 0x00}};
CAN_frame FORD_4B0 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x4B0,
.data = {0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xF0}};
CAN_frame FORD_581 = {.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x4B0,
.data = {0x81, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
};
#endif