diff --git a/Makefile b/Makefile index 29837d74..bf608b37 100644 --- a/Makefile +++ b/Makefile @@ -44,8 +44,8 @@ OBJSL = $(BINARY).o hwinit.o stm32scheduler.o params.o terminal.o terminal_prj. chademo.o amperaheater.o amperacharger.o subaruvehicle.o iomatrix.o bmw_sbox.o NissanPDM.o teslaCharger.o extCharger.o vag_sbox.o \ daisychainbms.o simpbms.o outlanderCharger.o Can_OBD2.o cansdo.o TeslaDCDC.o BMW_E31.o F30_Lever.o \ CPC.o ElconCharger.o RearOutlanderinverter.o linbus.o VWCoolantHeater.o JLR_G1.o JLR_G2.o Foccci.o digipot.o\ - OutlanderHeartBeat.o E65_Lever.o leafbms.o V_Classic.o kangoobms.o OutlanderCanHeater.o VWAirHeater.o\ - MGCoolantHeater.o NissLeafMng.o preheater.o MGgen2V2Lcharger.o + OutlanderHeartBeat.o E65_Lever.o leafbms.o V_Classic.o kangoobms.o OutlanderCanHeater.o VWAirHeater.o\ + MGCoolantHeater.o NissLeafMng.o preheater.o MGgen2V2Lcharger.o Gear_9x1.o vw_mlb_charger.o vag_utils.o\ OBJS = $(patsubst %.o,$(OUT_DIR)/%.o, $(OBJSL)) diff --git a/include/Gear_9x1.h b/include/Gear_9x1.h new file mode 100644 index 00000000..5cd4bc1f --- /dev/null +++ b/include/Gear_9x1.h @@ -0,0 +1,42 @@ +/* + * This file is part of the Zombieverter project. + * + * Copyright (C) 2024 Mitch Elliott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef Gear_9x1_h +#define Gear_9x1_h + +#include "shifter.h" + +class Gear_9x1: public Shifter +{ +public: + + void Task10Ms(); + void Task100Ms(); + void DecodeCAN(int, uint32_t*); + bool GetGear(Shifter::Sgear& outGear);//if shifter class knows gear return true and set dir + void SetCanInterface(CanHardware* c); + +private: + Shifter::Sgear gear; +}; + + +#endif // Gear_9x1_INCLUDED + + diff --git a/include/param_prj.h b/include/param_prj.h index d68b7a8e..11311202 100644 --- a/include/param_prj.h +++ b/include/param_prj.h @@ -32,10 +32,10 @@ #define PARAM_LIST \ PARAM_ENTRY(CAT_SETUP, Inverter, INVMODES, 0, 8, 0, 5 ) \ PARAM_ENTRY(CAT_SETUP, Vehicle, VEHMODES, 0, 8, 0, 6 ) \ - PARAM_ENTRY(CAT_SETUP, GearLvr, SHIFTERS, 0, 4, 0, 108 ) \ + PARAM_ENTRY(CAT_SETUP, GearLvr, SHIFTERS, 0, 5, 0, 108 ) \ PARAM_ENTRY(CAT_SETUP, Transmission, TRNMODES, 0, 1, 0, 78 ) \ PARAM_ENTRY(CAT_SETUP, interface, CHGINT, 0, 4, 0, 39 ) \ - PARAM_ENTRY(CAT_SETUP, chargemodes, CHGMODS, 0, 7, 0, 37 ) \ + PARAM_ENTRY(CAT_SETUP, chargemodes, CHGMODS, 0, 8, 0, 37 ) \ PARAM_ENTRY(CAT_SETUP, BMS_Mode, BMSMODES, 0, 5, 0, 90 ) \ PARAM_ENTRY(CAT_SETUP, ShuntType, SHNTYPE, 0, 4, 0, 88 ) \ PARAM_ENTRY(CAT_SETUP, InverterCan, CAN_DEV, 0, 1, 0, 70 ) \ @@ -270,7 +270,7 @@ "12=DCFCRequest, 13=BrakeVacPump, 14=CoolingFan, 15=HvActive, 16=ShiftLockNO, 17=PreHeatOut, 18=PwmTim3, 19=CpSpoof,"\ "20=GS450pump, 21=PwmTempGauge, 22=PwmSocGauge" #define APINFUNCS "0=None, 1=ProxPilot, 2=BrakeVacSensor, 3=HeaterPot" -#define SHIFTERS "0=None, 1=BMW_F30, 2=JLR_G1, 3=JLR_G2, 4=BMW_E65" +#define SHIFTERS "0=None, 1=BMW_F30, 2=JLR_G1, 3=JLR_G2, 4=BMW_E65, 5=Porsche_PDK" #define SHNTYPE "0=None, 1=ISA, 2=SBOX, 3=VAG. 4=ISA_udcsw" #define DMODES "0=CLOSED, 1=OPEN, 2=ERROR, 3=INVALID" #define POTMODES "0=SingleChannel, 1=DualChannel" @@ -298,7 +298,7 @@ #define CDMSTAT "1=Charging, 2=Malfunction, 4=ConnLock, 8=BatIncomp, 16=SystemMalfunction, 32=Stop" #define HTTYPE "0=None, 1=Ampera, 2=VWCoolant, 3=VWAir, 4=OutlanderCan, 5=MGCoolant" #define HTCTRL "0=Disable, 1=Enable, 2=Timer" -#define CHGMODS "0=Off, 1=EXT_DIGI, 2=Volt_Ampera, 3=Leaf_PDM, 4=TeslaOI, 5=Out_lander, 6=Elcon, 7=MGgen2" +#define CHGMODS "0=Off, 1=EXT_DIGI, 2=Volt_Ampera, 3=Leaf_PDM, 4=TeslaOI, 5=Out_lander, 6=Elcon, 7=MGgen2, 8=MLBEvo" #define CHGCTRL "0=Enable, 1=Disable, 2=Timer" #define CHGINT "0=Unused, 1=i3LIM, 2=Chademo, 3=CPC, 4=Foccci" #define CAN3SPD "0=k33.3, 1=k500, 2=k100" @@ -388,7 +388,8 @@ enum ChargeModes TeslaOI = 4, Out_lander = 5, Elcon = 6, - MGgen2=7 + MGgen2 = 7, + MLBevo = 8 }; enum ChargeInterfaces @@ -433,7 +434,8 @@ enum ShifterModes BMWF30 = 1, JLRG1 = 2, JLRG2 =3, - BMWE65 =4 + BMWE65 =4, + PorschePDK =5 }; diff --git a/include/vag_utils.h b/include/vag_utils.h new file mode 100644 index 00000000..4407d9f5 --- /dev/null +++ b/include/vag_utils.h @@ -0,0 +1,36 @@ +/* + * This file is part of the ZombieVeter project. + * + * Copyright (C) 2020 Johannes Huebner + * 2021-2022 Damien Maguire + * 2024 Mitch Elliott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + #ifndef VAG_UTILS_H + #define VAG_UTILS_H + + #include + #include "my_fp.h" + #include "my_math.h" + + namespace vag_utils + { + uint8_t vw_crc_calc(uint8_t* inputBytes, uint8_t length, uint16_t address); + uint8_t vw_crc_calc_MQB(uint8_t* inputBytes, uint8_t length, uint16_t address); + } + + #endif + \ No newline at end of file diff --git a/include/vw_mlb_charger.h b/include/vw_mlb_charger.h new file mode 100644 index 00000000..e61fb245 --- /dev/null +++ b/include/vw_mlb_charger.h @@ -0,0 +1,151 @@ + +/* + * This file is part of the ZombieVerter project. + * + * Copyright (C) 2024 Mitch Elliott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef vw_mlb_charger_h +#define vw_mlb_charger_h + +#include "chargerhw.h" +#include "chargerint.h" +#include "canhardware.h" +#include +#include "my_fp.h" +#include "params.h" +#include "my_math.h" +#include "stm32_can.h" +#include "CANSPI.h" +#include "vag_utils.h" + +class VWMLBClass: public Chargerhw +{ +public: + bool ControlCharge(bool RunCh, bool ACReq); + void SetCanInterface(CanHardware*); + void DecodeCAN(int id, uint32_t data[2]); + void Task1Ms(); + void Task10Ms(); + void Task100Ms(); + void Task200Ms(); + + +private: + //void CommandStates(); + void Simulate(); + void TagParams(); + void CalcValues100ms(); + void msg3C0(); + void msg1A1(); // BMS_02 0x1A1 + void msg2B1(); // MSG_TME_02 0x2B1 + void msg39D(); // BMS_03 0x39D + void msg485(); // NavData_02 0x485 + void msg509(); // BMS_10 0x509 + void msg552(); // HVEM_05 0x552 + void msg583(); // ZV_02 0x583 + void msg59E(); // BMS_06 0x59E + void msg5AC(); // HVEM_02 0x5AC + void msg64F(); // BCM1_04 0x64F + void msg663(); // NVEM_02 0x663 + void msg1A555548(); // ORU_01 0x1A555548 + void msg1A5555AD(); // Authentic_Time_01 0x1A5555AD + void msg96A955EB(); // BMS_09 0x96A955EB + void msg96A954A6(); // BMS_11 0x96A954A6 + void msg9A555539(); // BMS_16 0x9A555539 + void msg9A555552(); // BMS_27 0x9A555552 + void msg040(); // Airbag_01 0x40 + void msg184(); // ZV_01 0x184 + void msg191(); // BMS_01 0x191 + void msg1A2(); // ESP_15 0x1A2 + void msg2AE(); // DCDC_01 0x2AE + void msg37C(); // EM1_HYB_11 0x37C + void msg503(); // HVK_01 0x503 + void msg578(); // BMS_DC_01 0x578 + void msg5A2(); // BMS_04 0x5A2 + void msg5CA(); // BMS_07 0x5CA + void msg5CD(); // DCDC_03 0x5CD + uint8_t Airbag_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t Authentic_Time_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BCM1_04[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_02[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_03[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_04[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_06[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_07[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_09[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_10[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_11[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_16[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_27[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t BMS_DC_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t EM_HYB_11[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t ESP_15[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t Dimmung_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t DCDC_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t DCDC_02[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t DCDC_03[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVK_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVEM_02[8] = {0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVEM_05[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t Klemmen_Status_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t MSG_TME_02[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t NVEM_02[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t ORU_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t ZV_02[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVLM_06[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVLM_04[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t LAD_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVLM_03[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t LAD_02[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVLM_10[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVLM_11[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVLM_08[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t HVLM_15[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t LAD_06[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t ZV_01[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t vag_cnt3C0 = 0x00; + uint8_t vag_cnt040 = 0x00; + uint8_t vag_cnt184 = 0x00; + uint8_t vag_cnt191 = 0x00; + uint8_t vag_cnt1A2 = 0x00; + uint8_t vag_cnt37C = 0x00; + uint8_t vag_cnt2AE = 0x00; + uint8_t vag_cnt503 = 0x00; + uint8_t vag_cnt578 = 0x00; + uint8_t vag_cnt5A2 = 0x00; + uint8_t vag_cnt5CA = 0x00; + uint8_t vag_cnt5CD = 0x00; +}; + +class VWMLBintClass: public Chargerint +{ +public: + // void SetCanInterface(CanHardware* c); + // void DecodeCAN(int id, uint32_t data[2]); + // void Task10Ms(); + // void Task100Ms(); + // void Task200Ms(); + // bool DCFCRequest(bool RunCh); + // bool ACRequest(bool RunCh); + + +protected: + // CanHardware* can; + +}; + +#endif /* vw_mlb_charger_h */ diff --git a/src/Gear_9x1.cpp b/src/Gear_9x1.cpp new file mode 100644 index 00000000..8105e28f --- /dev/null +++ b/src/Gear_9x1.cpp @@ -0,0 +1,89 @@ +/* + * This file is part of the Zombieverter project. + * + * Copyright (C) 2024 Mitch Elliott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Gear_9x1.h" + +uint8_t Gear9x1LeverPos = 0x78; // Gear Lever Position on Init +uint8_t Gear9x1TipSport = 0; // Tip +/- Sport Postion +uint8_t Gear9x1Checksum = 0; // Checksum Value for Plausibilty +uint8_t Gear9x1Counter = 0; // Counter Value + +void Gear_9x1::SetCanInterface(CanHardware* c) +{ + can = c; + can->RegisterUserMessage(0x133);// 9x1 based shifter CAN message: WHL_01 +} + + +void Gear_9x1::DecodeCAN(int id, uint32_t* data) +{ + uint8_t *bytes = (uint8_t *)data; + if (id == 0x133) + { + Gear9x1LeverPos = bytes[0]; + Gear9x1Counter = (bytes[1] >> 4); // Mapping for later to determine signal validity + Gear9x1TipSport = (bytes[1] & (0x0FU)); // +/- sport movement + Gear9x1Checksum = bytes[6]; // Mapping for later to determine signal validity + + switch (Gear9x1LeverPos) + { + case 0x78: // Park + { + this->gear = PARK; + } + break; + case 0x87: // Reverse + { + this->gear = REVERSE; + } + break; + case 0x96: // Neutral + { + this->gear = NEUTRAL; + } + break; + case 0xA5: // Drive + { + this->gear = DRIVE; + } + break; + case 0x1E: // Manual/ Tip + { + this->gear = DRIVE; + } + break; + } + } +} + + void Gear_9x1::Task10Ms() + { + + } + + void Gear_9x1::Task100Ms() + { + + } + + bool Gear_9x1::GetGear(Shifter::Sgear& outGear) +{ + outGear = gear; //send the shifter pos + return true; //Let caller know we set a valid gear +} diff --git a/src/stm32_vcu.cpp b/src/stm32_vcu.cpp index 5065c46d..e9191ea2 100644 --- a/src/stm32_vcu.cpp +++ b/src/stm32_vcu.cpp @@ -91,8 +91,10 @@ #include "JLR_G1.h" #include "JLR_G2.h" #include "no_Lever.h" +#include "Gear_9x1.h" #include "CPC.h" #include "Foccci.h" +#include "vw_mlb_charger.h" #include "NoInverter.h" #include "linbus.h" #include "VWCoolantHeater.h" @@ -168,6 +170,7 @@ static FCChademo chademoFC; static i3LIMClass LIMFC; static CPCClass CPCcan; static FoccciClass Focccican; +static VWMLBClass MLBcharger; static Can_OI openInv; static NoInverterClass NoInverter; static OutlanderInverter outlanderInv; @@ -179,6 +182,7 @@ static F30_Lever F30GearLever; static E65_Lever E65GearLever; static JLR_G1 JLRG1shift; static JLR_G2 JLRG2shift; +static Gear_9x1 PorschePDKshift; static vwCoolantHeater heaterCoolantVW; static mgCoolantHeater heaterCoolantMG; static vwAirHeater heaterAirVW; @@ -959,6 +963,9 @@ static void UpdateCharger() case ChargeModes::MGgen2: selectedCharger = &MGgen2v2l; break; + case ChargeModes::MLBevo: + selectedCharger = &MLBcharger; + break; } @@ -1101,6 +1108,10 @@ static void UpdateShifter() case ShifterModes::BMWE65: selectedShifter = &E65GearLever; break; + + case ShifterModes::PorschePDK: + selectedShifter = &PorschePDKshift; + break; default: // Default to no shifter diff --git a/src/vag_utils.cpp b/src/vag_utils.cpp new file mode 100644 index 00000000..57b0bd7d --- /dev/null +++ b/src/vag_utils.cpp @@ -0,0 +1,278 @@ +/* + * This file is part of the ZombieVeter project. + * + * Copyright (C) 2020 Johannes Huebner + * 2021-2022 Damien Maguire + * 2024 Mitch Elliott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "vag_utils.h" + +namespace vag_utils { + +uint8_t vw_crc_calc(uint8_t* inputBytes, uint8_t length, uint16_t address) +{ + const uint8_t poly = 0x2F; + const uint8_t xor_output = 0xFF; + // VAG Magic Bytes + const uint8_t MB0040[16] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 }; + const uint8_t MB0073[16] = { 0xdb, 0x71, 0x31, 0xf9, 0x26, 0x43, 0x6d, 0x22, 0x52, 0xe4, 0xe8, 0xa9, 0x73, 0x1c, 0xc5, 0x67 }; + const uint8_t MB0074[16] = { 0xb7, 0x6e, 0x93, 0xf5, 0xdc, 0x38, 0xe2, 0x40, 0x06, 0xfb, 0x80, 0x1c, 0x0e, 0xe3, 0xd5, 0xe5 }; + const uint8_t MB0075[16] = { 0x63, 0x04, 0xb4, 0x32, 0x56, 0xc1, 0xfa, 0x97, 0x1f, 0xa6, 0xae, 0xd7, 0x64, 0xc3, 0xbe, 0x42 }; + const uint8_t MB0080[16] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; + const uint8_t MB0081[16] = { 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81 }; + const uint8_t MB0082[16] = { 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82 }; + const uint8_t MB0083[16] = { 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83 }; + const uint8_t MB0087[16] = { 0x14, 0x40, 0x8b, 0x7a, 0x78, 0x23, 0xc6, 0x13, 0x1c, 0x03, 0xed, 0xf4, 0xcb, 0xf8, 0xf0, 0xe5 }; + const uint8_t MB0097[16] = { 0x3C, 0x54, 0xCF, 0xA3, 0x81, 0x93, 0x0B, 0xC7, 0x3E, 0xDF, 0x1C, 0xB0, 0xA7, 0x25, 0xD3, 0xD8 }; + const uint8_t MB009D[16] = { 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D }; + const uint8_t MB00A0[16] = { 0x4a, 0xb4, 0xe8, 0x24, 0x99, 0x5a, 0x59, 0x8b, 0x1e, 0xaa, 0x94, 0xb6, 0x09, 0xd5, 0xaf, 0x97 }; + const uint8_t MB00A8[16] = { 0x52, 0x8c, 0x50, 0xee, 0x4f, 0xa6, 0xcc, 0xcf, 0x7d, 0x2f, 0x98, 0x6b, 0x27, 0x41, 0x9f, 0x93 }; + const uint8_t MB00AA[16] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA }; + const uint8_t MB00AB[16] = { 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB }; + const uint8_t MB00B1[16] = { 0xe1, 0x9e, 0xc2, 0xe9, 0x48, 0x98, 0xf5, 0xb6, 0x47, 0x83, 0x26, 0x45, 0x9a, 0x10, 0x7b, 0x1c }; + const uint8_t MB00B3[16] = { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }; + const uint8_t MB0102[16] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; + const uint8_t MB0105[16] = { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; + const uint8_t MB0108[16] = { 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09 }; + const uint8_t MB010E[16] = { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; + const uint8_t MB0111[16] = { 0xb3, 0xeb, 0xe1, 0xf7, 0xba, 0x9e, 0x5f, 0xd9, 0xc2, 0xec, 0xf6, 0xe9, 0x24, 0x18, 0x48, 0xed }; + const uint8_t MB0114[16] = { 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15 }; + const uint8_t MB0116[16] = { 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac }; + const uint8_t MB0121[16] = { 0xe9, 0x65, 0xae, 0x6b, 0x7b, 0x35, 0xe5, 0x5f, 0x4e, 0xc7, 0x86, 0xa2, 0xbb, 0xdd, 0xeb, 0xb4 }; + const uint8_t MB0124[16] = { 0x12, 0x7E, 0x34, 0x16, 0x25, 0x8F, 0x8E, 0x35, 0xBA, 0x7F, 0xEA, 0x59, 0x4C, 0xF0, 0x88, 0x15 }; + const uint8_t MB0136[16] = { 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37 }; + const uint8_t MB0153[16] = { 0x03, 0x13, 0x23, 0x7a, 0x40, 0x51, 0x68, 0xba, 0xa8, 0xbe, 0x55, 0x02, 0x11, 0x31, 0x76, 0xec }; + const uint8_t MB0154[16] = { 0x21, 0x93, 0x4a, 0x04, 0x5c, 0x18, 0xe0, 0x69, 0x14, 0xce, 0x26, 0x8f, 0x5e, 0xb1, 0xdf, 0x53 }; + const uint8_t MB0184[16] = { 0xe3, 0xe8, 0xc4, 0x7f, 0xf1, 0x95, 0xd8, 0xb0, 0xc7, 0xa3, 0xf4, 0x6c, 0xe7, 0xc3, 0x5a, 0xf7 }; + const uint8_t MB0187[16] = { 0x7F, 0xED, 0x17, 0xC2, 0x7C, 0xEB, 0x44, 0x21, 0x01, 0xFA, 0xDB, 0x15, 0x4A, 0x6B, 0x23, 0x05 }; + const uint8_t MB018D[16] = { 0x9c, 0xcc, 0xe1, 0x4c, 0xc9, 0x39, 0xe3, 0x53, 0x78, 0x33, 0x15, 0x49, 0x55, 0x0a, 0x62, 0x83 }; + const uint8_t MB0191[16] = { 0x7d, 0x0e, 0xaf, 0x0b, 0x24, 0x58, 0x88, 0x9e, 0x89, 0x3a, 0x81, 0x61, 0x4e, 0xe3, 0x04, 0x1f }; + const uint8_t MB01A2[16] = { 0xcb, 0x47, 0xd7, 0xd2, 0x56, 0x3e, 0x20, 0xea, 0x6e, 0x6d, 0x8c, 0x1b, 0xdf, 0x49, 0xaa, 0xab }; + const uint8_t MB01A3[16] = { 0x4a, 0x06, 0x0a, 0x36, 0xf8, 0xd3, 0x60, 0x79, 0xaa, 0xd2, 0x2e, 0x89, 0xa3, 0x76, 0x5f, 0x45 }; + const uint8_t MB01F3[16] = { 0xc4, 0x1e, 0x9c, 0xae, 0x59, 0xcc, 0x66, 0x99, 0xe1, 0x87, 0xe8, 0x4c, 0x65, 0x4a, 0xc9, 0xde }; + const uint8_t MB01F9[16] = { 0x14, 0xf8, 0xf6, 0x94, 0x2a, 0x12, 0x39, 0x3d, 0x98, 0x3f, 0xfb, 0x9d, 0x36, 0xca, 0x1d, 0xe0 }; + const uint8_t MB020F[16] = { 0xd4, 0x22, 0xad, 0x3f, 0x25, 0xaa, 0x62, 0x5b, 0xdc, 0x73, 0xed, 0xc3, 0x9a, 0x14, 0x2f, 0x3e }; + const uint8_t MB02AD[16] = { 0x7b, 0xed, 0xa6, 0xd1, 0x57, 0x4b, 0x69, 0x9f, 0x13, 0x82, 0x9e, 0x19, 0x3e, 0x08, 0x5e, 0x78 }; + const uint8_t MB02AE[16] = { 0x83, 0x50, 0xbf, 0x5d, 0x67, 0x68, 0x2f, 0x4b, 0x32, 0x4e, 0x1a, 0xba, 0xc4, 0x39, 0xf5, 0xdb }; + const uint8_t MB030E[16] = { 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D }; + const uint8_t MB0312[16] = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 }; + const uint8_t MB031B[16] = { 0x67, 0x8a, 0xae, 0x22, 0x4d, 0xd0, 0x51, 0x80, 0x5c, 0xb9, 0xce, 0x1e, 0xdf, 0x02, 0x2d, 0xd4 }; + const uint8_t MB0365[16] = { 0xe3, 0x0a, 0x29, 0xd3, 0x96, 0xaa, 0xeb, 0x89, 0xe6, 0x5f, 0x14, 0xc4, 0xe9, 0x27, 0x0b, 0x2d }; + const uint8_t MB0367[16] = { 0xa1, 0xb0, 0xdb, 0x69, 0x9c, 0xef, 0xbd, 0x08, 0xdd, 0xcc, 0x1b, 0x05, 0xce, 0x20, 0xe1, 0x48 }; + const uint8_t MB037C[16] = { 0xed, 0x03, 0x1c, 0x13, 0xc6, 0x23, 0x78, 0x7a, 0x8b, 0x40, 0x14, 0x51, 0xbf, 0x68, 0x32, 0xba }; + const uint8_t MB0393[16] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; + const uint8_t MB0394[16] = { 0x47, 0x94, 0x92, 0x6a, 0x67, 0xb5, 0x0d, 0x38, 0xe3, 0x8a, 0x5d, 0xb4, 0x54, 0xab, 0xae, 0x27 }; + const uint8_t MB03A6[16] = { 0xB6, 0x1C, 0xC1, 0x23, 0x6D, 0x8B, 0x0C, 0x51, 0x38, 0x32, 0x24, 0xA8, 0x3F, 0x3A, 0xA4, 0x02 }; + const uint8_t MB03AF[16] = { 0x94, 0x6A, 0xB5, 0x38, 0x8A, 0xB4, 0xAB, 0x27, 0xCB, 0x22, 0x88, 0xEF, 0xA3, 0xE1, 0xD0, 0xBB }; + const uint8_t MB03BE[16] = { 0x1f, 0x28, 0xc6, 0x85, 0xe6, 0xf8, 0xb0, 0x19, 0x5b, 0x64, 0x35, 0x21, 0xe4, 0xf7, 0x9c, 0x24 }; + const uint8_t MB03C0[16] = { 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3 }; + const uint8_t MB03F4[16] = { 0x26, 0xe4, 0xc5, 0x16, 0xcf, 0x20, 0x65, 0xad, 0xed, 0x6a, 0xa3, 0x49, 0x02, 0x6b, 0xb2, 0xbd }; + const uint8_t MB03FA[16] = { 0x26, 0xe3, 0x43, 0x0a, 0x6d, 0x29, 0x22, 0xd3, 0x52, 0x96, 0xe4, 0xaa, 0xe8, 0xeb, 0xa9, 0x89 }; + const uint8_t MB0450[16] = { 0x30, 0x25, 0xc2, 0x1f, 0x02, 0xb1, 0x9e, 0xe0, 0x73, 0x51, 0xe1, 0xa5, 0xab, 0x0d, 0xf4, 0x2f }; + const uint8_t MB0451[16] = { 0x19, 0xc1, 0x1a, 0xf6, 0x7d, 0x28, 0x7b, 0x12, 0xcb, 0x29, 0x59, 0x98, 0xd2, 0xbf, 0x53, 0x9d }; + const uint8_t MB0452[16] = { 0x74, 0x4a, 0x84, 0x18, 0xb9, 0x14, 0x9e, 0x8f, 0x0c, 0xdf, 0x29, 0x40, 0x63, 0x1f, 0xd4, 0xca }; + const uint8_t MB0457[16] = { 0x82, 0x79, 0xee, 0xb9, 0xf9, 0x67, 0x97, 0xad, 0xb1, 0xd5, 0xcb, 0xf7, 0xb6, 0x70, 0x13, 0xaa }; + const uint8_t MB0489[16] = { 0x7A, 0x13, 0xF4, 0xE5, 0xC9, 0x07, 0x21, 0xDD, 0x6F, 0x94, 0x63, 0x9B, 0xD2, 0x93, 0x42, 0x33 }; + const uint8_t MB0503[16] = { 0xed, 0xd6, 0x96, 0x63, 0xa5, 0x12, 0xd5, 0x9a, 0x1e, 0x0d, 0x24, 0xcd, 0x8c, 0xa6, 0x2f, 0x41 }; + const uint8_t MB0504[16] = { 0x03, 0x63, 0x3e, 0x04, 0xf9, 0xb4, 0x4f, 0x32, 0x25, 0x56, 0x1e, 0xc1, 0x83, 0xfa, 0x31, 0x97 }; + const uint8_t MB053C[16] = { 0x8e, 0xf9, 0xe1, 0x2e, 0x83, 0x34, 0xd0, 0xf1, 0xaa, 0x2c, 0xbb, 0x81, 0x17, 0x60, 0x11, 0x37 }; + const uint8_t MB0560[16] = { 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65 }; + const uint8_t MB0564[16] = { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 }; + const uint8_t MB0578[16] = { 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48 }; + const uint8_t MB05A2[16] = { 0xeb, 0x4c, 0x44, 0xaf, 0x21, 0x8d, 0x01, 0x58, 0xfa, 0x93, 0xdb, 0x89, 0x15, 0x10, 0x4a, 0x61 }; + const uint8_t MB05A3[16] = { 0x0a, 0xd3, 0xaa, 0x89, 0x5f, 0xc4, 0x27, 0x2d, 0xfb, 0xa0, 0x47, 0x1e, 0x28, 0xa8, 0x44, 0x5c }; + const uint8_t MB05CA[16] = { 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43 }; + const uint8_t MB05CC[16] = { 0x92, 0x9d, 0xb8, 0x71, 0xc4, 0x40, 0x3d, 0x49, 0x5b, 0x4d, 0xfa, 0x94, 0x6d, 0x72, 0xb3, 0x46 }; + const uint8_t MB05CD[16] = { 0x93, 0x04, 0x18, 0x69, 0xce, 0x8f, 0xb1, 0x53, 0x40, 0x2d, 0xe4, 0xca, 0x90, 0x25, 0x79, 0x8c }; + const uint8_t MB0641[16] = { 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47 }; + const uint8_t MB065D[16] = { 0xac, 0xb3, 0xab, 0xeb, 0x7a, 0xe1, 0x3b, 0xf7, 0x73, 0xba, 0x7c, 0x9e, 0x06, 0x5f, 0x02, 0xd9 }; + const uint8_t MB067E[16] = { 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25 }; + const uint8_t MB06A3[16] = { 0xC1, 0x8B, 0x38, 0xA8, 0xA4, 0x27, 0xEB, 0xC8, 0xEF, 0x05, 0x9A, 0xBB, 0x39, 0xF7, 0x80, 0xA7 }; + const uint8_t MB06A4[16] = { 0xC7, 0xD8, 0xF1, 0xC4, 0xE3, 0x5E, 0x9A, 0xE2, 0xA1, 0xCB, 0x02, 0x4F, 0x57, 0x4E, 0x8E, 0xE4 }; + const uint8_t MB092DD5477[16] = { 0x41, 0x5e, 0x7f, 0xc7, 0xc3, 0x04, 0x0a, 0x11, 0x34, 0x4d, 0x9b, 0x27, 0xaf, 0x0d, 0x0f, 0x31 }; + const uint8_t MB092DD5478[16] = { 0xe0, 0x2f, 0x8d, 0x3c, 0x70, 0x22, 0x03, 0x60, 0x0e, 0x18, 0xd9, 0xeb, 0x95, 0x63, 0xcb, 0x76 }; + const uint8_t MB092DD5490[16] = { 0x48, 0x52, 0xa7, 0xe6, 0x83, 0x2b, 0x8c, 0xfb, 0x7b, 0x64, 0x58, 0x50, 0xbc, 0xb3, 0x0f, 0x9c }; + const uint8_t MB092DD5491[16] = { 0xb1, 0x44, 0x37, 0xca, 0xb5, 0xd6, 0x0e, 0xa3, 0x3b, 0x16, 0xa6, 0x1a, 0x23, 0x1d, 0x91, 0x9c }; + const uint8_t MB092DD5493[16] = { 0x74, 0x7e, 0x45, 0xe8, 0x3c, 0xd0, 0x13, 0x1f, 0x4e, 0x3a, 0x88, 0x0b, 0x7d, 0xd2, 0x6d, 0xab }; + const uint8_t MB092DD54AB[16] = { 0xab, 0xe1, 0x73, 0x9e, 0x02, 0xc2, 0x30, 0xe9, 0x75, 0x48, 0x2e, 0x98, 0x7f, 0xf5, 0xa7, 0xb6 }; + const uint8_t MB092DD54AD[16] = { 0x02, 0xf4, 0x6f, 0x42, 0x4a, 0x62, 0xcd, 0x1b, 0xb4, 0xa0, 0x16, 0x14, 0xe8, 0x0a, 0x71, 0xef }; + const uint8_t MB092DD54E0[16] = { 0xd0, 0x4d, 0x22, 0xae, 0x8a, 0x67, 0xf4, 0x35, 0x15, 0x2a, 0xb8, 0x4e, 0xcc, 0x07, 0xad, 0xa2 }; + const uint8_t MB092DD550B[16] = { 0x67, 0xf7, 0x44, 0xdc, 0xd2, 0xca, 0xe7, 0x2b, 0xd6, 0x5c, 0xc6, 0xa3, 0xbe, 0x0d, 0x16, 0x58 }; + const uint8_t MB096A95414[16] = { 0xa3, 0xed, 0x65, 0xcf, 0xc5, 0x26, 0x54, 0x1a, 0x99, 0x3c, 0x01, 0x84, 0xf4, 0x46, 0x9c, 0x28 }; + const uint8_t MB096A95415[16] = { 0x01, 0x40, 0xf0, 0x21, 0x22, 0x92, 0x44, 0x1a, 0x85, 0xeb, 0x7b, 0xcd, 0x7c, 0x59, 0xc5, 0xc2 }; + const uint8_t MB096A954A6[16] = { 0x79, 0xb9, 0x67, 0xad, 0xd5, 0xf7, 0x70, 0xaa, 0x44, 0x61, 0x5a, 0xdc, 0x26, 0xb4, 0xd2, 0xc3 }; + const uint8_t MB09A555517[16] = { 0xfb, 0xee, 0x5d, 0x2d, 0xfa, 0x85, 0x27, 0xd4, 0xc9, 0xc4, 0xa5, 0x45, 0x5f, 0x76, 0xa3, 0x89 }; + const uint8_t MB09A555545[16] = { 0xc2, 0xe1, 0xd3, 0x20, 0x42, 0xce, 0x68, 0x05, 0xa9, 0x1b, 0xa3, 0xcc, 0xe2, 0xdd, 0x14, 0x08 }; + + uint8_t crc = 0xFF; + uint8_t magicByte = 0x00; + uint8_t counter = inputBytes[1] & 0x0F; // only the low byte of the counter is relevant + + switch (address) + { + case 0x03C0: // ?? + magicByte = MB03C0[counter]; + break; + case 0x0040: // ?? + magicByte = MB0040[counter]; + break; + case 0x0184: // ?? + magicByte = MB0184[counter]; + break; + case 0x0191: // ?? + magicByte = MB0191[counter]; + break; + case 0x01A2: // ?? + magicByte = MB01A2[counter]; + break; + case 0x02AE: // ?? + magicByte = MB02AE[counter]; + break; + case 0x037C: // ?? + magicByte = MB037C[counter]; + break; + case 0x0503: // ?? + magicByte = MB0503[counter]; + break; + case 0x0578: // ?? + magicByte = MB0578[counter]; + break; + case 0x05A2: // ?? + magicByte = MB05A2[counter]; + break; + case 0x05CA: // ?? + magicByte = MB05CA[counter]; + break; + case 0x05CD: // ?? + magicByte = MB05CD[counter]; + break; + default: // this won't lead to correct CRC checksums + magicByte = 0x00; + break; + } + + for (uint8_t i = 1; i < length + 1; i++) + { + // We skip the empty CRC position and start at the timer + // The last element is the VAG magic byte for address 0x187 depending on the counter value. + if (i < length) + crc ^= inputBytes[i]; + else + crc ^= magicByte; + + for (uint8_t j = 0; j < 8; j++) + { + if (crc & 0x80) + crc = (crc << 1) ^ poly; + else + crc = (crc << 1); + } + } + + crc ^= xor_output; + + inputBytes[0] = crc; // set the CRC checksum directly in the output bytes + return crc; +} + +uint8_t vw_crc_calc_MQB(uint8_t* inputBytes, uint8_t length, uint16_t address) +{ + + // const uint8_t poly = 0x2F; + const uint8_t xor_output = 0xFF; + + uint8_t crc = 0xFF; + uint8_t magicByte = 0x00; + uint8_t counter = inputBytes[1] & 0x0F; // only the low byte of the counter is relevant + + switch (address) + { + case 0x0080: // Motor1 + magicByte = 0x80; + break; + case 0x0081: // Motor2 + magicByte = 0x81; + break; + case 0x0082: // Gearbox1 + magicByte = 0x82; + break; + case 0x0083: // Gearbox2 + magicByte = 0x83; + break; + case 0x00AA: // Motor13 + magicByte = 0xAA; + break; + case 0x00AB: // Gearbox7 + magicByte = 0xAB; + break; + case 0x0102: // Gearbox3 + magicByte = 0x03; + break; + case 0x0105: // Motor3 + magicByte = 0x04; + break; + case 0x010E: // TSK4 + magicByte = 0x0F; + break; + case 0x0111: // TSK5 + magicByte = 0x10; + break; + case 0x0114: // Motor10 + magicByte = 0x15; + break; + case 0x030E: // Motor5 + magicByte = 0x0D; + break; + case 0x0312: // TSK3 + magicByte = 0x11; + break; + case 0x0393: // WBA2 + magicByte = 0x90; + break; + case 0x0641: // Motorcode + magicByte = 0x47; + break; + default: // this won't lead to correct CRC checksums + magicByte = 0x00; + break; + } + + for (uint8_t i = 1; i < length + 1; i++) + { + // We skip the empty CRC position and start at the timer + // The last element is the VAG magic byte for address 0x187 depending on the counter value. + if (i < length) + crc ^= inputBytes[i]; + else + crc ^= magicByte; + + for (uint8_t j = 0; j < 8; j++) + { + // if (crc & 0x80) + // crc = (crc << 1) ^ poly; + // else + // crc = (crc << 1); + } + } + + crc ^= xor_output; + + inputBytes[0] = crc; // set the CRC checksum directly in the output bytes + return crc; +} +} \ No newline at end of file diff --git a/src/vw_mlb_charger.cpp b/src/vw_mlb_charger.cpp new file mode 100644 index 00000000..bb5ba933 --- /dev/null +++ b/src/vw_mlb_charger.cpp @@ -0,0 +1,1002 @@ +/* + * This file is part of the ZombieVerter project. + * + * Copyright (C) 2024 Mitch Elliott + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + + +#include + +uCAN_MSG txMsg; +uint8_t CanMsgBuf[8]; + +struct VehicleStatus{ + bool locked = false; + bool CANQuiet = false; +} vehicle_status; + +struct ChargerStatus { + uint16_t ACvoltage ; + uint16_t HVVoltage ; + int8_t temperature ; + uint8_t mode; + uint16_t current; + uint8_t MaxACAmps; + uint8_t PPLim; + uint32_t HVLM_MaxDC_ChargePower; // maximum DC charging power + uint16_t HVLM_Max_DC_Voltage_DCLS; // maximum DC charging voltage + uint16_t HVLM_Actual_DC_Current_DCLS; // actual DC charging current + uint16_t HVLM_Max_DC_Current_DCLS; // maximum DC charging current + uint16_t HVLM_Min_DC_Voltage_DCLS; // minimum DC charging voltage + uint16_t HVLM_Min_DC_Current_DCLS; // minimum DC charging current + uint8_t HVLM_Status_Grid; // Information as to whether the vehicle is connected to a power grid. + uint8_t HVLM_EnergyFlowType; // Display of whether electricity flows into the vehicle and what it is used for. + uint8_t HVLM_OperationalMode; // Current Mode: 0=Inactive, 1=Active, 2=Init, 3=Error + uint8_t HVLM_HV_ActivationRequest; // HV activation request and reason for the request: 0=No Request, 1=Charging, 2=Battery Balancing, 3=AC/Climate + uint8_t HVLM_ChargerErrorStatus; // Current error status of the charger: 0=No Error, 1=DC-NotOK, 2=AC-NotOK, 3=Interlock, 4=Reserved, 5=Reserved, 6=No Component Function, 7=Init + uint8_t HVLM_Park_Request; // Request to lock the drive train + uint8_t HVLM_Park_Request_Maintain; // Request to keep the drive train locked + uint8_t HVLM_Plug_Status; // Plug detection status independent of charging mode (AC or DC): 0=Init, 1=No Plug Inserted, 2=Connector Inserted, Not Locked, 3=Connector Inserted & Locked + uint8_t HVLM_LoadRequest; // Charger Status: 0=No Request, 1=AC Charge, 2=DC Charge, 3=Recharge 12V, 4=AC AWC Charge, 5=Reserved, 6=Init, 7=Error + uint8_t HVLM_MaxBattChargeCurrent; // Recommended HV battery charging current for a planned charge + uint8_t LAD_Mode; // Operating mode of the charger + uint16_t LAD_AC_Volt_RMS; // Actual value AC grid voltage (RMS) + uint16_t LAD_VoltageOut_HV; // Output voltage of the charger + uint16_t LAD_CurrentOut_HV; // Output current charger + uint8_t LAD_Status_Voltage; // + uint16_t LAD_Temperature; // Instantaneous value: Charger temperature + uint16_t LAD_PowerLossVal; // Instantaneous value: power loss charger + uint16_t HVLM_HV_StaleTime; // Period between HV deactivated and HV activated + uint8_t HVLM_ChargeSystemState; // Displaying status about the charging system. 0=No issue, 1=System Defective, 2=System Incompatable 3=DC Charge not possible + uint8_t HVLM_Status_LED; // Status of the charging LED: 0=Colour1-off, 1=Colour2-White, 2=Colour3-Yellow, 3=Colour4-Green, 4=Colour5-Red, 5=Yellow Pulsing, 6=Green Pulsing, 7=Red Pulsing, 8=Green/Red Pulsing, 9=Green Flashing, 14=Init, 15=Error + uint8_t HVLM_MaxCurrent_AC; // Maximum permissible current on the primary side (AC) + bool HVLM_LG_ChargerTargetMode; // AC charger target mode: 0=Standby, 1=Mains Charging + uint8_t HVLM_TankCapReleaseRequest; // Fuel Cap Release: 0=No Release, 1=Release, 2=Init, 3=Error + uint8_t HVLM_RequestConnectorLock; // Request connector lock: 0=Unlock, 1=lock, 2=Init, 3=No Request + uint8_t HVLM_Start_VoltageMeasure_DCLS; // Message to the BMS that a measurement voltage is being applied to the DC charging station: 0=Inactive, 1=DCLS With Diode, 2=DCLS without Diode, 3=Reserve + uint8_t HVLM_ChargeReadyStatus; // Display whether AC or DC charging is not possible: 0=No Error, 1=AC Charge Not Possible, 2=DC Charge Not Possible, 3=AC & DC Charge Not Possible + uint16_t HVLM_Output_Voltage_HV; // Output voltage of the charger and DC voltage of the charging station. Measurement between the DC HV lines. + bool LAD_Reduction_ChargerTemp; // Reduction due to internal overtemperature in the charger + bool LAD_Reduction_Current; // Regulation due to current or voltage at the input or output + bool LAD_Reduction_SocketTemp; // Reduction due to excessive charging socket temperature + uint16_t LAD_MaxChargerPower_HV; // Maximum power charger in relation to the maximum power infrastructure (cable, charging station) and taking into account the charger efficiency + uint8_t LAD_PRX_CableCurrentLimit; // AC current limit due to PRX cable coding + bool LAD_ControlPilotStatus; // Status control pilot monitoring (detection of the control pilot duty cycle) + bool LAD_LockFeedback; // Status of connector lock (feedback contact of the locking actuator) + uint8_t LAD_ChargerCoolingDemand; // Cooling demand of the charger + bool LAD_ChargerWarning; // Collective warning charger: 0=Normal, 1=Warning + bool LAD_ChargerFault; // Collective error charger: 0=Normal, 1=No Charging Possible +} charger_status; + +struct ChargerControl { + uint16_t HVDCSetpnt; + uint16_t IDCSetpnt; + uint16_t HVpwr=0; + uint16_t HVcur=0; + uint16_t calcpwr=0; + uint8_t modeSet; + bool activate; +} charger_params; + +struct BatteryStatus { + uint16_t SOCx10; // SOC of battery, With implied decimal place + uint16_t SOC_Targetx10; // Target SOC of battery, With implied decimal place + uint16_t CapkWhx10; // Usable energy content of the HV battery + uint16_t BattkWhx10; // Current energy content of the HV battery + uint16_t BMSVoltx10; // BMS Voltage of battery + uint16_t BMSCurrx10; // BMS Current of battery, With implied decimal place + uint16_t BMSMaxVolt; // BMS Max Voltage of Battery + uint16_t BMSMinVolt; // BMS Min Voltage of Battery + uint16_t BMSMaxChargeCurr; // BMS Max Charge Curr + uint16_t BMSBattCellSumx10; + uint16_t BMSCellAhx10 = 1080; + uint8_t HV_Status; // 0=Init (no function), 1=BMS intermediate circuit voltage-free (U_Zwkr < 20V), 2=BMS intermediate circuit not free of voltage (U_Zwkr >/= 25V, hysteresis), 3=Error (e.g. error in the sensors) + uint8_t BMS_Status; // 0 "Component_OK" 1 "Limited_CompFct_Isoerror_I" 2 "Limited_CompFct_Isoerror_II" 3 "Limited_CompFct_Interlock" 4 "Limited_CompFct_SD" 5 "Limited_CompFct_Powerred" 6 "No_component_function" 7 "Init" ; + uint8_t BMS_Mode; //0 "HV_Off" 1 "Driving HV Active" 2 "Balancing" 3 "External Charger" 4 "AC Charging" 5 "Battery Fault" 6 "DC Charging" 7 "Init" ; + uint16_t BMS_Battery_Tempx10 = 242; + uint16_t BMS_Coolant_Tempx10 = 201; + uint16_t BMS_Cell_H_Tempx10 = 290; + uint16_t BMS_Cell_L_Tempx10 = 220; + uint16_t BMS_Cell_H_mV = 3850; + uint16_t BMS_Cell_L_mV = 3750; + bool HVIL_Open = false; + +} battery_status; + +uint32_t UnixTime; + +//BMS CAN Messages + uint16_t BMS_Batt_Curr; + uint16_t BMS_Batt_Volt; + uint16_t BMS_Batt_Volt_HVterm; + uint16_t BMS_SOC_HiRes; + uint16_t BMS_MaxDischarge_Curr; + uint16_t BMS_Min_Batt_Volt; + uint16_t BMS_Min_Batt_Volt_Discharge; + uint16_t BMS_MaxCharge_Curr; + uint16_t BMS_MaxCharge_Curr_Offset; + uint16_t BMS_Batt_Max_Volt; + uint16_t BMS_Min_Batt_Volt_Charge; + uint16_t BMS_OpenCircuit_Volts; + bool BMS_Status_ServiceDisconnect; + uint8_t BMS_HV_Status; + bool BMS_Faultstatus; + uint8_t BMS_IstModus; + uint16_t BMS_Batt_Ah; + uint16_t BMS_Target_SOC_HiRes; + uint16_t BMS_Batt_Temp; + uint16_t BMS_CurrBatt_Temp; + uint16_t BMS_CoolantTemp_Act; + uint16_t BMS_Batt_Energy; + uint16_t BMS_Max_Wh; + uint16_t BMS_BattEnergy_Wh_HiRes; + uint16_t BMS_MaxBattEnergy_Wh_HiRes; + uint16_t BMS_SOC; + uint16_t BMS_ResidualEnergy_Wh; + uint16_t BMS_SOC_ChargeLim; + uint16_t BMS_EnergyCount; + uint16_t BMS_EnergyReq_Full; + uint16_t BMS_ChargePowerMax; + uint16_t BMS_ChargeEnergyCount; + uint16_t BMS_BattCell_Temp_Max; + uint16_t BMS_BattCell_Temp_Min; + uint16_t BMS_BattCell_MV_Max; + uint16_t BMS_BattCell_MV_Min; + bool HVEM_Nachladen_Anf; + uint16_t HVEM_SollStrom_HV; + uint16_t HVEM_MaxSpannung_HV; + uint8_t HMS_Systemstatus; + uint8_t HMS_aktives_System; + bool HMS_Fehlerstatus; + uint8_t HVK_HVLM_Sollmodus; // Requested target mode of the charging manager: 0=Not Enabled, 1=Enabled + bool HV_Bordnetz_aktiv; // Indicates an active high-voltage vehicle electrical system: 0 = Not Active, 1 = Active + uint8_t HVK_MO_EmSollzustand; // 0 "HvOff" 1 "HvStbyReq" 2 "HvStbyWait" 3 "HvBattOnReq" 4 "HvBattOnWait" 10 "HvOnIdle" 20 "HvOnDrvRdy" 46 "HvAcChPreReq" 47 "HvAcChPreWait" 48 "HvAcChReq" 49 "HvAcChWait" 50 "HvAcCh" 56 "HvDcChPreReq" 57 "HvDcChPreWait" 58 "HvDcChReq" 59 "HvDcChWait" 60 "HvDcCh" 67 "HvChOffReq" 68 "HvChOffWait" 69 "HvOnIdleReq" 70 "HvOnIdleWait" 96 "HvCpntOffReq" 97 "HvCpntOffWait" 98 "HvBattOffReq" 99 "HvBattOffWait" 119 "HvElmOffReq" 120 "HvElmOff" + uint8_t HVK_BMS_Sollmodus; // 0 "HV_Off" 1 "HV_On" 3 "AC_Charging_ext" 4 "AC_Charging" 6 "DC_Charging" 7 "Init" ; + uint8_t HVK_DCDC_Sollmodus; //0 "Standby" 1 "HV_On_Precharging" 2 "Step down" 3 "Step up" 4 "Test pulse_12V" 7 "Initialization" ; + bool ZV_FT_verriegeln; + bool ZV_FT_entriegeln; + bool ZV_BT_verriegeln; + bool ZV_BT_entriegeln; + bool ZV_entriegeln_Anf; + bool ZV_verriegelt_intern_ist; + bool ZV_verriegelt_extern_ist; + bool ZV_verriegelt_intern_soll; + bool ZV_verriegelt_extern_soll; + uint8_t ZV_verriegelt_soll; + bool BMS_Charger_Active; + uint16_t BMS_RIso_Ext = 4090; + uint8_t HVK_Gesamtst_Spgfreiheit; + uint8_t BMS_Balancing_Active=2; + uint8_t BMS_Freig_max_Perf =1; + uint8_t BMS_Battdiag =1; // Battery Display Diagnostics: 1 = Display Battery, 4 = Display Battery OK, 5 = Charging, 6 = Check Battery + uint8_t DC_IstModus_02 = 2; + uint8_t BMS_HV_Auszeit_Status = 1; // Status HV timeout. + uint16_t BMS_HV_Auszeit = 25; // Time since last HV Activity + uint16_t BMS_Kapazitaet = 1000; // Total Energy Capacity (aged) + uint16_t BMS_SOC_Kaltstart = 0; // SOC Cold + uint8_t BMS_max_Grenz_SOC = 30; // Upper limit of SOC operating strategy (70 offset, so 30 = 100) + uint8_t BMS_min_Grenz_SOC = 15; // Lower limit of SOC Operating strategy + uint8_t EM1_Istmodus2; // EM1 Status, 0=standby + uint8_t EM1_Status_Spgfreiheit; // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + bool ZAS_Kl_S; // KeySwitch Inserted + bool ZAS_Kl_15; // Acc position + bool ZAS_Kl_X; // Run position + bool ZAS_Kl_50_Startanforderung; // Start + uint8_t HVActiveDelayOff; + uint8_t HVEM_NVNachladen_Energie = 200; + uint8_t LockState; + +void VWMLBClass::SetCanInterface(CanHardware* c) +{ + can = c; + can->RegisterUserMessage(0x488); // HVLM_06 + can->RegisterUserMessage(0x53C); // HVLM_04 + can->RegisterUserMessage(0x564); // LAD_01 + can->RegisterUserMessage(0x565); // HVLM_03 + can->RegisterUserMessage(0x67E); // LAD_02 +} + +bool VWMLBClass::ControlCharge(bool RunCh, bool ACReq) +{ + if (charger_status.HVLM_Plug_Status > 1 && RunCh) + { + charger_params.activate = 1; + return true; + } + else + { + charger_params.activate = 0; + return false; + } +} + +void VWMLBClass::Simulate() +{ +} + +void VWMLBClass::Task1Ms() +{ static uint8_t counter1ms = 0; + counter1ms++; // Increments every 10ms + if(vehicle_status.CANQuiet == 1){ counter1ms = 0; } // Quick way of silencing the canbus -- NOT IMPLEMENTED +// - Do 10ms Tasks: + if (counter1ms % 10 == 0) { // Every 100ms (10ms * 1) + msg191(); // BMS_01 0x191 CRC + } +// - Do 20ms, 40ms, 50ms tasks: + if (counter1ms % 20 == 0) { // Every 20ms (10ms * 2) + } + if (counter1ms % 40 == 0) { // Every 40ms (10ms * 4) + //msg040(); // Airbag_01 - 0x40 CRC + can->Send(0x2B1, MSG_TME_02, 8); // MSG_TME_02 0x2B1 + } + if (counter1ms % 50 == 0) { // Every 50ms (10ms * 5) + msg2AE(); // DCDC_01 0x2AE CRC + counter1ms = 1; + } +} + +void VWMLBClass::Task10Ms() +{ + +} + +void VWMLBClass::Task100Ms() +{ +//Simulate(); +static uint8_t counter100ms = 0; +TagParams(); +CalcValues100ms(); +counter100ms++; // Increments every 100ms +if(vehicle_status.CANQuiet == 1){ counter100ms = 0; } // Quick way of silencing the canbus -- NOT IMPLEMENTED +// - Do 100ms Tasks: +if (counter100ms % 1 == 0) { // Every 100ms (100ms * 2) + msg3C0(); // Klemmen_Status_01 CRC + msg503(); // HVK_01 0x503 CRC + msg184(); // ZV_01 0x184 CRC + msg578(); // BMS_DC_01 0x578 CRC + can->Send(0x1A1, BMS_02, 8); // BMS_02 0x1A1 + can->Send(0x39D, BMS_03, 8); // BMS_03 0x39D + can->Send(0x509, BMS_10, 8); // BMS_10 0x509 + can->Send(0x552, HVEM_05, 8); // HVEM_05 0x552 Fun items relating to Max Voltage and Plug Release + can->Send(0x5AC, HVEM_02, 8); // HVEM_02 0x5AC +} +// - Do 200ms, 500ms, 1000ms and 2000ms tasks: +if (counter100ms % 2 == 0) { // Every 200ms (100ms * 2) + msg1A2(); // ESP_15 0x1A2 CRC + can->Send(0x583, ZV_02, 8); // ZV_02 - 0x583 +} +if (counter100ms % 5 == 0) { // Every 500ms (100ms * 5) + msg5A2(); // BMS_04 0x5A2 CRC + msg5CA(); // BMS_07 0x5CA CRC + msg5CD(); // DCDC_03 0x5CD CRC + can->Send(0x59E, BMS_06, 8); // BMS_06 0x59E +} +if (counter100ms % 10 == 0) { // Every 1000ms (100ms * 10) + can->Send(0x485, Authentic_Time_01, 8); // NavData_02 - 0x485 + can->Send(0x1A555548, ORU_01, 8); // ORU_01 0x1A555548 + can->Send(0x1A5555AD, Authentic_Time_01, 8); // Authentic_Time_01 0x1A5555AD + can->Send(0x96A955EB, BMS_09, 8); // BMS_09 0x96A955EB + can->Send(0x9A555539, BMS_16, 8); // BMS_16 0x9A555539 Just contains IDs for cells with low/high charge or temps + can->Send(0x9A555552, BMS_27, 8); // BMS_27 0x9A555552 +} +if (counter100ms % 20 == 0) { // Every 2000ms (100ms * 20) + can->Send(0x96A954A6, BMS_11, 8); // BMS_11 0x96A954A6 + counter100ms = 1; +} +} + +void VWMLBClass::Task200Ms() +{ +} + +// Msgs with CRC & Counters: + +void VWMLBClass::msg040() // Airbag_01 - 0x40 +{ + // CanMsgBuf[0] = 0x00 ; + // CanMsgBuf[1] = (0x00 | vag_cnt040) ; + // CanMsgBuf[2] = 0x00 ; + // CanMsgBuf[3] = 0x00 ; + // CanMsgBuf[4] = 0x00 ; + // CanMsgBuf[5] = 0x00 ; + // CanMsgBuf[6] = 0x00 ; + // CanMsgBuf[7] = 0x00 ; + // CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x40); + // can->Send(0x040, CanMsgBuf, 8); + // vag_cnt040++; + // if(vag_cnt040>0x0f) vag_cnt040=0x00; +} + +void VWMLBClass::msg184() // ZV_01 0x184 +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (ZV_01[1]|vag_cnt184) ; + CanMsgBuf[2] = ZV_01[2] ; + CanMsgBuf[3] = ZV_01[3] ; + CanMsgBuf[4] = ZV_01[4] ; + CanMsgBuf[5] = ZV_01[5] ; + CanMsgBuf[6] = ZV_01[6] ; + CanMsgBuf[7] = ZV_01[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x184); + can->Send(0x184, CanMsgBuf, 8); + vag_cnt184++; + if(vag_cnt184>0x0f) vag_cnt184=0x00; +} + +void VWMLBClass::msg191() // BMS_01 0x191 +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (BMS_01[1]|vag_cnt191) ; + CanMsgBuf[2] = BMS_01[2] ; + CanMsgBuf[3] = BMS_01[3] ; + CanMsgBuf[4] = BMS_01[4] ; + CanMsgBuf[5] = BMS_01[5] ; + CanMsgBuf[6] = BMS_01[6] ; + CanMsgBuf[7] = BMS_01[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x191); + can->Send(0x191, CanMsgBuf, 8); + vag_cnt191++; + if(vag_cnt191>0x0f) vag_cnt191=0x00; +} + +void VWMLBClass::msg1A2() // ESP_15 0x1A2 +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (ESP_15[1]|vag_cnt1A2) ; + CanMsgBuf[2] = ESP_15[2] ; + CanMsgBuf[3] = ESP_15[3] ; + CanMsgBuf[4] = ESP_15[4] ; + CanMsgBuf[5] = ESP_15[5] ; + CanMsgBuf[6] = ESP_15[6] ; + CanMsgBuf[7] = ESP_15[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x1A2); + can->Send(0x1A2, CanMsgBuf, 8); + vag_cnt1A2++; + if(vag_cnt1A2>0x0f) vag_cnt1A2=0x00; +} + +void VWMLBClass::msg2AE() // DCDC_01 0x2AE +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (DCDC_01[1]|vag_cnt2AE) ; + CanMsgBuf[2] = DCDC_01[2] ; + CanMsgBuf[3] = DCDC_01[3] ; + CanMsgBuf[4] = DCDC_01[4] ; + CanMsgBuf[5] = DCDC_01[5] ; + CanMsgBuf[6] = DCDC_01[6] ; + CanMsgBuf[7] = 0xA8 ; // Sets static 13.8V as DC output voltage + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x2AE); + can->Send(0x2AE, CanMsgBuf, 8); + vag_cnt2AE++; + if(vag_cnt2AE>0x0f) vag_cnt2AE=0x00; +} + +void VWMLBClass::msg503() // HVK_01 0x503 +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (HVK_01[1]|vag_cnt503) ; + CanMsgBuf[2] = HVK_01[2] ; + CanMsgBuf[3] = HVK_01[3] ; + CanMsgBuf[4] = HVK_01[4] ; + CanMsgBuf[5] = HVK_01[5] ; + CanMsgBuf[6] = HVK_01[6] ; + CanMsgBuf[7] = HVK_01[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x503); + can->Send(0x503, CanMsgBuf, 8); + vag_cnt503++; + if(vag_cnt503>0x0f) vag_cnt503=0x00; +} + +void VWMLBClass::msg578() // BMS_DC_01 0x578 +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (BMS_DC_01[1]|vag_cnt578) ; + CanMsgBuf[2] = BMS_DC_01[2] ; + CanMsgBuf[3] = BMS_DC_01[3] ; + CanMsgBuf[4] = BMS_DC_01[4] ; + CanMsgBuf[5] = BMS_DC_01[5] ; + CanMsgBuf[6] = BMS_DC_01[6] ; + CanMsgBuf[7] = BMS_DC_01[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x578); + can->Send(0x578, CanMsgBuf, 8); + vag_cnt578++; + if(vag_cnt578>0x0f) vag_cnt578=0x00; +} +void VWMLBClass::msg5A2() // BMS_04 0x5A2 +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (BMS_04[1]|vag_cnt5A2) ; + CanMsgBuf[2] = BMS_04[2] ; + CanMsgBuf[3] = BMS_04[3] ; + CanMsgBuf[4] = BMS_04[4] ; + CanMsgBuf[5] = BMS_04[5] ; + CanMsgBuf[6] = BMS_04[6] ; + CanMsgBuf[7] = BMS_04[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x5A2); + can->Send(0x5A2, CanMsgBuf, 8); + vag_cnt5A2++; + if(vag_cnt5A2>0x0f) vag_cnt5A2=0x00; +} +void VWMLBClass::msg5CA() // BMS_07 0x5CA +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (BMS_07[1]|vag_cnt5CA) ; + CanMsgBuf[2] = BMS_07[2] ; + CanMsgBuf[3] = BMS_07[3] ; + CanMsgBuf[4] = BMS_07[4] ; + CanMsgBuf[5] = BMS_07[5] ; + CanMsgBuf[6] = BMS_07[6] ; + CanMsgBuf[7] = BMS_07[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x5CA); + can->Send(0x5CA, CanMsgBuf, 8); + vag_cnt5CA++; + if(vag_cnt5CA>0x0f) vag_cnt5CA=0x00; +} +void VWMLBClass::msg5CD() // DCDC_03 0x5CD +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (DCDC_03[1]|vag_cnt5CD) ; + CanMsgBuf[2] = DCDC_03[2] ; + CanMsgBuf[3] = DCDC_03[3] ; + CanMsgBuf[4] = DCDC_03[4] ; + CanMsgBuf[5] = DCDC_03[5] ; + CanMsgBuf[6] = DCDC_03[6] ; + CanMsgBuf[7] = DCDC_03[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x5CD); + can->Send(0x5CD, CanMsgBuf, 8); + vag_cnt5CD++; + if(vag_cnt5CD>0x0f) vag_cnt5CD=0x00; +} + +void VWMLBClass::msg3C0() // Klemmen_Status_01 +{ + CanMsgBuf[0] = 0x00 ; + CanMsgBuf[1] = (Klemmen_Status_01[1] |vag_cnt3C0) ; + CanMsgBuf[2] = Klemmen_Status_01[2] ; + CanMsgBuf[3] = Klemmen_Status_01[3] ; + CanMsgBuf[4] = Klemmen_Status_01[4] ; + CanMsgBuf[5] = Klemmen_Status_01[5] ; + CanMsgBuf[6] = Klemmen_Status_01[6] ; + CanMsgBuf[7] = Klemmen_Status_01[7] ; + CanMsgBuf[0] = vag_utils::vw_crc_calc(CanMsgBuf, 8, 0x3C0); + can->Send(0x3C0, CanMsgBuf, 8); + vag_cnt3C0++; + if(vag_cnt3C0>0x0f) vag_cnt3C0=0x00; +} + +void VWMLBClass::DecodeCAN(int id, uint32_t data[2]) +{ +uint8_t* bytes = (uint8_t*)data;// arrgghhh this converts the two 32bit array into bytes. See comments are useful:) ... Stolen from Zombie, Left comments as they're now famous. +switch (id) +{ + case 0x488: // HVLM_06 + charger_status.HVLM_MaxDC_ChargePower = (((bytes[2] & (0x3FU)) << 4) | ((bytes[1] >> 4) & (0x0FU)))*250; + charger_status.HVLM_Max_DC_Voltage_DCLS = ((bytes[3] & (0xFFU)) << 2) | ((bytes[2] >> 6) & (0x03U)); + charger_status.HVLM_Actual_DC_Current_DCLS = ((bytes[5] & (0x01U)) << 8) | (bytes[4] & (0xFFU)); + charger_status.HVLM_Max_DC_Current_DCLS = ((bytes[6] & (0x03U)) << 7) | ((bytes[5] >> 1) & (0x7FU)); + charger_status.HVLM_Min_DC_Voltage_DCLS = ((bytes[7] & (0x07U)) << 6) | ((bytes[6] >> 2) & (0x3FU)); + charger_status.HVLM_Min_DC_Current_DCLS = ((bytes[7] >> 3) & (0x1FU)); + break; + + + case 0x53C: // HVLM_04 + // HVLM_ParkingHeater_Mode = ((HVLM_04[1] >> 4) & (0x07U)); + // HVLM_StationaryClimat_Timer_Stat = ((HVLM_04[1] >> 7) & (0x01U)); + // HVLM_HVEM_MaxPower = ((HVLM_04[3] & (0x01U)) << 8) | (HVLM_04[2] & (0xFFU)); + charger_status.HVLM_Status_Grid = ((bytes[3] >> 1) & (0x01U)); + // HVLM_BEV_LoadingScreen = ((HVLM_04[3] >> 2) & (0x01U)); + charger_status.HVLM_EnergyFlowType = ((bytes[3] >> 3) & (0x03U)); + // HVLM_VK_ParkingHeaterStatus = ((HVLM_04[3] >> 5) & (0x07U)); + // HVLM_VK_ClimateConditioningStat = (HVLM_04[4] & (0x03U)); + charger_status.HVLM_OperationalMode = ((bytes[4] >> 2) & (0x03U)); + charger_status.HVLM_HV_ActivationRequest = ((bytes[4] >> 4) & (0x03U)); + charger_status.HVLM_ChargerErrorStatus = ((bytes[5] & (0x01U)) << 2) | ((bytes[4] >> 6) & (0x03U)); + charger_status.HVLM_Park_Request = ((bytes[5] >> 1) & (0x07U)); + charger_status.HVLM_Park_Request_Maintain = ((bytes[5] >> 4) & (0x03U)); + // HVLM_AWC_Mode = (HVLM_04[6] & (0x07U)); + charger_status.HVLM_Plug_Status = ((bytes[6] >> 3) & (0x03U)); + charger_status.HVLM_LoadRequest = ((bytes[6] >> 5) & (0x07U)); + charger_status.HVLM_MaxBattChargeCurrent = (bytes[7] & (0xFFU)); + break; + + case 0X564: // LAD_01 + charger_status.mode = ((bytes[1] >> 4) & (0x07U)); + charger_status.ACvoltage = ((bytes[2] & (0xFFU)) << 1) | ((bytes[1] >> 7) & (0x01U)); + charger_status.HVVoltage = (((bytes[4] & (0x03U)) << 8) | (bytes[3] & (0xFFU))); + charger_status.current = ((((bytes[5] & (0x0FU)) << 6) | ((bytes[4] >> 2) & (0x3FU))) * 0.2) - 102; + charger_status.LAD_Status_Voltage = ((bytes[5] >> 4) & (0x03U)); + charger_status.temperature = bytes[6] - 40; + charger_status.LAD_PowerLossVal = ((bytes[7] & (0xFFU)))*20; + break; + + case 0x565: // HVLM_03 + charger_status.HVLM_HV_StaleTime = ((bytes[0] & (0xFFU)))*4; + charger_status.HVLM_ChargeSystemState = (bytes[1] & (0x03U)); + // HVLM_KESSY_KeySearch = ((HVLM_03[1] >> 2) & (0x03U)); + charger_status.HVLM_Status_LED = ((bytes[1] >> 4) & (0x0FU)); + charger_status.MaxACAmps = ((bytes[3] & (0x7FU)))/2; + charger_status.HVLM_LG_ChargerTargetMode = ((bytes[3] >> 7) & (0x01U)); + charger_status.HVLM_TankCapReleaseRequest = (bytes[4] & (0x03U)); + charger_status.HVLM_RequestConnectorLock = ((bytes[4] >> 2) & (0x03U)); + charger_status.HVLM_Start_VoltageMeasure_DCLS = ((bytes[4] >> 4) & (0x03U)); + // PnC_Trigger_OBC_cGW = ((HVLM_03[5] & (0x03U)) << 2) | ((HVLM_03[4] >> 6) & (0x03U)); + // HVLM_ReleaseAirConditioning = ((HVLM_03[5] >> 2) & (0x03U)); + charger_status.HVLM_ChargeReadyStatus = ((bytes[6] >> 1) & (0x07U)); + // HVLM_IsolationRequest = ((HVLM_03[6] >> 5) & (0x01U)); + charger_status.HVLM_Output_Voltage_HV = ((bytes[7] & (0xFFU)) << 2) | ((bytes[6] >> 6) & (0x03U)); + break; + + case 0x67E: // LAD_02 + charger_status.LAD_Reduction_ChargerTemp = ((bytes[1] >> 4) & (0x01U)); + charger_status.LAD_Reduction_Current = ((bytes[1] >> 5) & (0x01U)); + charger_status.LAD_Reduction_SocketTemp = ((bytes[1] >> 6) & (0x01U)); + charger_status.LAD_MaxChargerPower_HV = (((bytes[3] & (0x01U)) << 8) | (bytes[2] & (0xFFU)))*100; + charger_status.PPLim = (bytes[4] & (0x07U)); + charger_status.LAD_ControlPilotStatus = ((bytes[4] >> 3) & (0x01U)); + charger_status.LAD_LockFeedback = ((bytes[4] >> 4) & (0x01U)); + charger_status.LAD_ChargerCoolingDemand = ((bytes[4] >> 6) & (0x03U)); + // LAD_MaxLadLeistung_HV_Offset = ((LAD_02[7] >> 1) & (0x03U)); + charger_status.LAD_ChargerWarning = ((bytes[7] >> 6) & (0x01U)); + charger_status.LAD_ChargerFault = ((bytes[7] >> 7) & (0x01U)); + break; +} +} + + +void VWMLBClass::TagParams() // To make code portable between standalone (more params) vs Zombie (basic params) - This code executed 100ms, uncomment or delete un-needed params +{ + //Common Params (Shared same param names as zombie vs standalone) + + battery_status.SOCx10 = int(Param::GetFloat(Param::SOC)*10); + battery_status.SOC_Targetx10 = 1000; //Param::GetInt(Param::VCU_SOC_Limit); + battery_status.CapkWhx10 = int(Param::GetFloat(Param::BattCap)*10); + battery_status.BMSMinVolt = Param::GetInt(Param::udcmin); + charger_params.HVpwr=Param::GetInt(Param::Pwrspnt); + charger_params.HVcur = Param::GetInt(Param::BMS_ChargeLim); + charger_params.HVDCSetpnt = Param::GetInt(Param::Voltspnt); + battery_status.BMSVoltx10 = Param::GetInt(Param::udc); + battery_status.BMSBattCellSumx10 = Param::GetInt(Param::udc2); + battery_status.BMSMaxVolt = Param::GetInt(Param::udclim); + battery_status.BMS_Cell_H_Tempx10 = int(Param::GetFloat(Param::BMS_Tmax)*10); + battery_status.BMS_Cell_L_Tempx10 = int(Param::GetFloat(Param::BMS_Tmin)*10); + battery_status.BMS_Cell_H_mV = int(Param::GetFloat(Param::BMS_Vmax)*100); + battery_status.BMS_Cell_L_mV = int(Param::GetFloat(Param::BMS_Vmin)*100); + vehicle_status.locked = Param::GetInt(Param::VehLockSt); + + Param::SetInt(Param::CableLim,charger_status.MaxACAmps); + Param::SetInt(Param::AC_Volts,charger_status.ACvoltage); + Param::SetInt(Param::ChgTemp,charger_status.temperature); + switch (charger_status.HVLM_Plug_Status) + { + case 0: + Param::SetInt(Param::PlugDet,0); + break; + case 1: + Param::SetInt(Param::PlugDet,0); + break; + case 2: + Param::SetInt(Param::PlugDet,1); + break; + case 3: + Param::SetInt(Param::PlugDet,1); + break; + } + + switch (charger_status.PPLim) + { + case 0: + Param::SetInt(Param::PilotLim,13); + break; + case 1: + Param::SetInt(Param::PilotLim,20); + break; + case 2: + Param::SetInt(Param::PilotLim,32); + break; + case 3: + Param::SetInt(Param::PilotLim,63); + break; + } + // Standalone additional params: + + // Param::SetInt(Param::DC_Max_ChargePower,charger_status.HVLM_MaxDC_ChargePower); + // Param::SetInt(Param::DC_Max_ChargeVoltage,charger_status.HVLM_Max_DC_Voltage_DCLS); + // Param::SetInt(Param::DC_Actual_Current,charger_status.HVLM_Actual_DC_Current_DCLS); + // Param::SetInt(Param::DC_Max_ChargeCurrent,charger_status.HVLM_Max_DC_Current_DCLS); + // Param::SetInt(Param::DC_Min_ChargeVoltage,charger_status.HVLM_Min_DC_Voltage_DCLS); + // Param::SetInt(Param::DC_Min_ChargeCurrent,charger_status.HVLM_Min_DC_Current_DCLS); + // Param::SetInt(Param::Status_Grid,charger_status.HVLM_EnergyFlowType); + // Param::SetInt(Param::ChargeManagerMode,charger_status.HVLM_OperationalMode); + // Param::SetInt(Param::ChargerRequestingHV,charger_status.HVLM_HV_ActivationRequest); + // Param::SetInt(Param::ChargerErrorStatus,charger_status.HVLM_ChargerErrorStatus); + // Param::SetInt(Param::PlugStatus,charger_status.HVLM_Plug_Status); + // Param::SetInt(Param::LoadRequest,charger_status.HVLM_LoadRequest); + // Param::SetInt(Param::ChargerState,charger_status.mode); + // Param::SetInt(Param::Charger_AC_Volt_RMS,charger_status.ACvoltage); + // Param::SetInt(Param::Charger_VoltageOut_HV,charger_status.HVVoltage); + // Param::SetInt(Param::Charger_CurrentOut_HV,charger_status.current); + // Param::SetInt(Param::Charger_Temperature,charger_status.temperature); + // Param::SetInt(Param::ChargerSystemState,charger_status.HVLM_ChargeSystemState); + // Param::SetInt(Param::Status_LED,charger_status.HVLM_Status_LED); + // Param::SetInt(Param::MaxCurrent_AC,charger_status.MaxACAmps); + // Param::SetInt(Param::LockRequest,charger_status.HVLM_RequestConnectorLock); + // Param::SetInt(Param::Charger_Ready,charger_status.HVLM_ChargeReadyStatus); + // Param::SetInt(Param::ChargerTemp_Reduction,charger_status.LAD_Reduction_ChargerTemp); + // Param::SetInt(Param::ChargerCurrent_Reduction,charger_status.LAD_Reduction_Current); + // Param::SetInt(Param::SocketTemp_Reduction,charger_status.LAD_Reduction_SocketTemp); + // Param::SetInt(Param::MaxChargerOutput,charger_status.LAD_MaxChargerPower_HV); + // Param::SetInt(Param::CableCurrentLimit,charger_status.PPLim); + // Param::SetInt(Param::ControlPilotStatus,charger_status.LAD_ControlPilotStatus); + // Param::SetInt(Param::LockState,charger_status.LAD_LockFeedback); + // Param::SetInt(Param::ChargerWarning,charger_status.LAD_ChargerWarning); + // Param::SetInt(Param::ChargerFault,charger_status.LAD_ChargerFault); + // Param::SetInt(Param::OutputVolts,charger_status.HVLM_Output_Voltage_HV); + + // Param::SetFloat(Param::VCU_SOC, (Param::GetInt(Param::SOCx10))); + // Param::SetFloat(Param::VCU_SOC_Limit, Param::GetInt(Param::SOC_Targetx10)); + // Param::SetInt(Param::VCU_UDCmin, Param::GetInt(Param::BMSMinVolt)); + // Param::SetInt(Param::VCU_Current_SP, Param::GetInt(Param::IDCSetpnt)); + // Param::SetInt(Param::VCU_Volt_SP, Param::GetInt(Param::HVDCSetpnt)); + // Param::SetFloat(Param::BMS_Pack_Voltage, (Param::GetInt(Param::BMSBattCellSumx10)/10)); + // Param::SetInt(Param::VCU_UDCmax, Param::GetInt(Param::BMSMaxVolt)); + // Param::SetFloat(Param::BMS_Highest_Cell_Temp, (Param::GetInt(Param::BMS_Cell_H_Tempx10))/10); + // Param::SetFloat(Param::BMS_Lowest_Cell_Temp, (Param::GetInt(Param::BMS_Cell_L_Tempx10))/10); + // Param::SetInt(Param::BMS_Highest_Cell_Volt, Param::GetInt(Param::BMS_Cell_H_mV)); + // Param::SetInt(Param::BMS_Lowest_Cell_Volt, Param::GetInt(Param::BMS_Cell_L_mV)); + // Param::SetInt(Param::VCUChargeRequest, Param::Ge|tInt(Param::Activation_Crg)); + // Param::SetInt(Param::VehicleLockState, Param::GetInt(Param::LockSim)); + + // battery_status.SOCx10 = (Param::GetInt(Param::VCU_SOC)); + // battery_status.SOC_Targetx10 = Param::GetInt(Param::VCU_SOC_Limit); + // battery_status.BMSMinVolt = Param::GetInt(Param::VCU_UDCmin); + // charger_params.IDCSetpnt = Param::GetInt(Param::VCU_Current_SP); + // charger_params.HVDCSetpnt = Param::GetInt(Param::VCU_Volt_SP); + // battery_status.BMSBattCellSumx10 = Param::GetInt(Param::BMS_Pack_Voltage); + // battery_status.BMSMaxVolt = Param::GetInt(Param::VCU_UDCmax); + // battery_status.BMS_Cell_H_Tempx10 = Param::GetInt(Param::BMS_Highest_Cell_Temp)*10; + // battery_status.BMS_Cell_L_Tempx10 = Param::GetInt(Param::BMS_Lowest_Cell_Temp)*10; + // battery_status.BMS_Cell_H_mV = Param::GetInt(Param::BMS_Highest_Cell_Volt); + // battery_status.BMS_Cell_L_mV = Param::GetInt(Param::BMS_Lowest_Cell_Volt); + // ZV_verriegelt_extern_ist = Param::GetInt(Param::VehicleLockState); + +} + +void VWMLBClass::CalcValues100ms() // Run to calculate values every 100 ms +{ +// Static Set Values - TODO: Roll these up into the CAN msg and eliminate useless variables + BMS_MaxDischarge_Curr = 1500; + BMS_MaxCharge_Curr_Offset = 0; + BMS_Status_ServiceDisconnect = 0; + BMS_Battdiag = 0; + BMS_BattEnergy_Wh_HiRes = 0; + BMS_MaxBattEnergy_Wh_HiRes = 0; + BMS_ResidualEnergy_Wh = 0; + BMS_ChargePowerMax = 625; + BMS_ChargeEnergyCount = 0; + BMS_EnergyCount = 0; + +//BMS charge current limit but needs to be power for most AC charger types. + if(charger_params.HVcur > 1000) + { + charger_params.calcpwr = 12000; + } + else + { + charger_params.calcpwr = charger_params.HVcur*(battery_status.BMSVoltx10/10); + } + + charger_params.HVpwr=MIN(charger_params.HVpwr,charger_params.calcpwr); + + charger_params.IDCSetpnt = charger_params.HVpwr / (battery_status.BMSVoltx10/10); + +// BMS SOC: + BMS_Batt_Curr = charger_status.current + 2047; + BMS_SOC = battery_status.SOCx10 * .05; + BMS_SOC_HiRes = battery_status.SOCx10 * 2; + BMS_SOC_Kaltstart = battery_status.SOCx10 * 2; + BMS_Batt_Energy = battery_status.CapkWhx10 * 2; + + +// BMS Current: + +// BMS Voltages: + BMS_Batt_Volt = battery_status.BMSVoltx10 * 4; + BMS_Batt_Volt_HVterm = battery_status.BMSVoltx10 * 2; + BMS_BattCell_MV_Max = battery_status.BMS_Cell_H_mV - 1000; + BMS_BattCell_MV_Min = battery_status.BMS_Cell_L_mV - 1000; + +// BMS Temps: + BMS_Batt_Temp = (battery_status.BMS_Battery_Tempx10 + 400) / 5; + BMS_CurrBatt_Temp = (battery_status.BMS_Battery_Tempx10 + 400) / 5; + BMS_CoolantTemp_Act = (battery_status.BMS_Coolant_Tempx10 + 400) / 5; + BMS_BattCell_Temp_Max = (battery_status.BMS_Cell_H_Tempx10 + 400) / 5; + BMS_BattCell_Temp_Min = (battery_status.BMS_Cell_L_Tempx10 + 400) / 5; + +// BMS SOC Limits: + BMS_Max_Wh = battery_status.CapkWhx10*2; + BMS_SOC_ChargeLim = battery_status.SOC_Targetx10/10; + BMS_max_Grenz_SOC = (battery_status.SOC_Targetx10 - 700)/10; + BMS_EnergyReq_Full =((battery_status.SOC_Targetx10 - battery_status.SOCx10)*battery_status.CapkWhx10)/2500; + +// BMS Limits Discharge: + BMS_Min_Batt_Volt = battery_status.BMSMinVolt; + BMS_Min_Batt_Volt_Discharge = battery_status.BMSMinVolt; + +// BMS Limits Charge: + BMS_MaxCharge_Curr = 1500; + HVEM_SollStrom_HV = (charger_params.IDCSetpnt+205)*5; + BMS_Batt_Max_Volt = charger_params.HVDCSetpnt; + BMS_Min_Batt_Volt_Charge = battery_status.BMSMinVolt;; + BMS_OpenCircuit_Volts = battery_status.BMSBattCellSumx10; + HVEM_MaxSpannung_HV = battery_status.BMSMaxVolt; + BMS_Faultstatus = battery_status.BMS_Status; + BMS_Batt_Ah = (battery_status.CapkWhx10*100)/350; + BMS_Target_SOC_HiRes = battery_status.SOC_Targetx10*2; + + // ESP15 + HMS_Systemstatus = 3 ; //0 "No_function_active" 1 "Hold_active" 2 "Parking_requested" 3 "Parking_active" 4 "Keep parking_active" 5 "Start_active" 6 "Release_request_active" 7 "Release_request_by_driver" 8 "Slipping_detected" 9 "Hold_standby_active" 10 "Start_standby_active" 14 "Init" 15 "Error " ; + HMS_aktives_System = 6; //0 "No_System__Init_Error" 1 "Driver request_active" 2 "HMS_internal_active" 3 "ACC_active" 4 "Autohold_active" 5 "HHC_active" 6 "HVLM_active" 7 "Getriebe_aktiv" 8 "EBKV_aktiv" 9 "ParkAssist_aktiv" 10 "ARA_aktiv" 12 "Autonomous_Hold_aktiv" 13 "STA_aktiv " 14 "Motor_aktiv" 15 "EA_aktiv" 16 "VLK_aktiv" ; + + // Lock Status: + if (vehicle_status.locked == 0) + { + ZV_verriegelt_soll = 1; + } + if (vehicle_status.locked == 1) + { + ZV_verriegelt_soll = 2; + } + + + // Charger Activation State Logic: + if( charger_status.HVLM_HV_ActivationRequest == 1) + { + HV_Bordnetz_aktiv = true; // Indicates an active high-voltage vehicle electrical system: 0 = Not Active, 1 = Active + //HVK_BMS_Sollmodus = 4; + BMS_IstModus = 4; // 0=Standby, 1=HV Active (Driving) 2=Balancing 4=AC charge, 6=DC charge, 7=init + BMS_HV_Status = 2; // HV System Voltage Detected // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + HVK_MO_EmSollzustand = 50; + BMS_Charger_Active = 1; + HVActiveDelayOff = 20; + } + + if( charger_status.HVLM_HV_ActivationRequest == 0) + { + BMS_Charger_Active = 0; + if (HVActiveDelayOff >= 1) + { + BMS_HV_Status = 2; // HV No Voltage // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + BMS_IstModus = 1; // 0=Standby, 1=HV Active (Driving) 2=Balancing 4=AC charge, 6=DC charge, 7=init + HVK_BMS_Sollmodus = 1; + HVK_MO_EmSollzustand = 67; + HVActiveDelayOff = HVActiveDelayOff - 1; + } + + if (HVActiveDelayOff == 0) + { + // HV_Bordnetz_aktiv = false; // Indicates an active high-voltage vehicle electrical system: 0 = Not Active, 1 = Active + // BMS_HV_Status = 1; // HV No Voltage // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + // BMS_IstModus = 0; // 0=Standby, 1=HV Active (Driving) 2=Balancing 4=AC charge, 6=DC charge, 7=init + // HVK_BMS_Sollmodus = 0; + // HVK_MO_EmSollzustand = 0; + // BMS_Batt_Volt = charger_status.HVVoltage*4; // Modify after testing to actual values from BMS/VCU + // BMS_Batt_Volt_HVterm = charger_status.HVVoltage*2; // Modify after testing to actual values from BMS/VCU + + BMS_HV_Status = 2; // Voltage Applied // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + BMS_IstModus = 1; // 0=Standby, 1=HV Active (Driving) 2=Balancing 4=AC charge, 6=DC charge, 7=init + HVK_BMS_Sollmodus = 1; + HVK_MO_EmSollzustand = 67; + } + } + + if(BMS_HV_Status == 2) + { + HVK_DCDC_Sollmodus = 2; // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + EM1_Status_Spgfreiheit = 2; // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + HVK_Gesamtst_Spgfreiheit = 2; // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + } + if(BMS_HV_Status == 1) + { + HVK_DCDC_Sollmodus = 1; // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + EM1_Status_Spgfreiheit = 1; // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + HVK_Gesamtst_Spgfreiheit = 1; // Voltage Status: 0=Init, 1=NoVoltage, 2=Voltage, 3=Fault & Voltage + } + + switch (charger_params.activate) + { + case 0: // Charger Standby + HVK_HVLM_Sollmodus = false; // Requested target mode of the charging manager: 0=Not Enabled, 1=Enabled + HVEM_Nachladen_Anf = false; // Request for HV charging with plugged in connector and deactivated charging request + BMS_Charger_Active = 0; + break; + + case 1: // HV Active - Charger Active + HVEM_Nachladen_Anf = true; // Request for HV charging with plugged in connector and deactivated charging request + HVK_HVLM_Sollmodus = true; // Requested target mode of the charging manager: 0=Not Enabled, 1=Enabled + BMS_Charger_Active = 1; + HVK_BMS_Sollmodus = 4; + + break; + } + + // BMS_01 + BMS_01[0] = 0x00; + BMS_01[1] = (0x00 & (0x0FU)) | ((BMS_Batt_Curr & (0x0FU)) << 4); + BMS_01[2] = ((BMS_Batt_Curr >> 4) & (0xFFU)); + BMS_01[3] = (BMS_Batt_Volt& (0xFFU)); + BMS_01[4] = ((BMS_Batt_Volt >> 8) & (0x0FU)) | ((BMS_Batt_Volt_HVterm & (0x0FU)) << 4); + BMS_01[5] = ((BMS_Batt_Volt_HVterm >> 4) & (0x7FU)) | ((BMS_SOC_HiRes & (0x01U)) << 7); + BMS_01[6] = ((BMS_SOC_HiRes >> 1) & (0xFFU)); + BMS_01[7] = ((BMS_SOC_HiRes >> 9) & (0x03U)) | ((0x00 & (0x01U)) << 2) | ((0x00 & (0x0FU)) << 4); + + // BMS_02 + BMS_02[0] = 0x00; + BMS_02[1] = (BMS_MaxCharge_Curr_Offset & (0x0FU)) | ((BMS_MaxDischarge_Curr & (0x0FU)) << 4); + BMS_02[2] = ((BMS_MaxDischarge_Curr >> 4) & (0x7FU)) | ((BMS_MaxCharge_Curr & (0x01U)) << 7); + BMS_02[3] = ((BMS_MaxCharge_Curr >> 1) & (0xFFU)); + BMS_02[4] = ((BMS_MaxCharge_Curr >> 9) & (0x03U)) | ((BMS_Min_Batt_Volt & (0x3FU)) << 2); + BMS_02[5] = ((BMS_Min_Batt_Volt >> 6) & (0x0FU)) | ((BMS_Min_Batt_Volt_Discharge & (0x0FU)) << 4); + BMS_02[6] = ((BMS_Min_Batt_Volt_Discharge >> 4) & (0x3FU)) | ((BMS_Min_Batt_Volt_Charge & (0x03U)) << 6); + BMS_02[7] = ((BMS_Min_Batt_Volt_Charge >> 2) & (0xFFU)); + + // BMS_03 + BMS_03[0] = (BMS_OpenCircuit_Volts & (0xFFU)); + BMS_03[1] = ((BMS_OpenCircuit_Volts >> 8) & (0x03U)) | ((BMS_Batt_Max_Volt & (0x0FU)) << 4); + BMS_03[2] = ((BMS_Batt_Max_Volt >> 4) & (0x3FU)) | ((BMS_MaxDischarge_Curr & (0x03U)) << 6); + BMS_03[3] = ((BMS_MaxDischarge_Curr >> 2) & (0xFFU)); + BMS_03[4] = ((BMS_MaxDischarge_Curr >> 10) & (0x01U)) | ((BMS_MaxCharge_Curr & (0x7FU)) << 1); + BMS_03[5] = ((BMS_MaxCharge_Curr >> 7) & (0x0FU)) | ((BMS_Min_Batt_Volt_Discharge & (0x0FU)) << 4); + BMS_03[6] = ((BMS_Min_Batt_Volt_Discharge >> 4) & (0x3FU)) | ((BMS_Min_Batt_Volt_Charge & (0x03U)) << 6); + BMS_03[7] = ((BMS_Min_Batt_Volt_Charge >> 2) & (0xFFU)); + + // BMS_04 + BMS_04[0] = 0x00; + BMS_04[1] = (0x00 & (0x0FU)) | ((BMS_Status_ServiceDisconnect & (0x01U)) << 5) | ((BMS_HV_Status & (0x03U)) << 6); + BMS_04[2] = 0x00 | ((BMS_IstModus & (0x07U)) << 1) | ((BMS_Faultstatus & (0x07U)) << 4) | ((BMS_Batt_Ah & (0x01U)) << 7); + BMS_04[3] = ((BMS_Batt_Ah >> 1) & (0xFFU)); + BMS_04[4] = ((BMS_Batt_Ah >> 9) & (0x03U)); + BMS_04[6] = ((BMS_Target_SOC_HiRes & (0x07U)) << 5); + BMS_04[7] = ((BMS_Target_SOC_HiRes >> 3) & (0xFFU)); + + // BMS_06 + BMS_06[2] = (BMS_Batt_Temp & (0xFFU)); + BMS_06[3] = (BMS_CurrBatt_Temp & (0xFFU)); + BMS_06[7] = (BMS_CoolantTemp_Act & (0xFFU)); + // BMS_07 + BMS_07[0] = 0x00; + BMS_07[1] = (0x00 & (0x0FU)) | ((BMS_Batt_Energy & (0x0FU)) << 4); + BMS_07[2] = ((BMS_Batt_Energy >> 4) & (0x7FU)) | ((BMS_Charger_Active & (0x01U)) << 7); //BMS_07[2] = ((BMS_Batt_Energy >> 4) & (0x7FU)) | ((BMS_Charger_Active & (0x01U)) << 7); + BMS_07[3] = (BMS_Battdiag & (0x07U)) | ((BMS_Freig_max_Perf & (0x03U)) << 3) | ((BMS_Balancing_Active & (0x03U)) << 6); + BMS_07[4] = (BMS_Max_Wh & (0xFFU)); + BMS_07[5] = ((BMS_Max_Wh >> 8) & (0x07U)) | ((0x0 & (0x01U)) << 3) | ((0x00 & (0x03U)) << 4) | ((0x00& (0x03U)) << 6); //BMS_07[5] = ((BMS_Max_Wh >> 8) & (0x07U)) | ((0x0 & (0x01U)) << 3) | ((BMS_Gesamtst_Spgfreiheit & (0x03U)) << 4) | ((BMS_RIso_Ext & (0x03U)) << 6); + BMS_07[6] = ((BMS_RIso_Ext >> 2) & (0xFFU)); + BMS_07[7] = ((BMS_RIso_Ext >> 10) & (0x03U)) | ((0x00 & (0x03U)) << 2) | ((0x00 & (0x03U)) << 4); + // BMS_09 + BMS_09[2] = ((BMS_HV_Auszeit_Status & (0x03U)) << 5) | ((BMS_HV_Auszeit & (0x01U)) << 7); + BMS_09[3] = ((BMS_HV_Auszeit >> 1) & (0xFFU)); + BMS_09[4] = (BMS_Kapazitaet & (0xFFU)); + BMS_09[5] = ((BMS_Kapazitaet >> 8) & (0x07U)) | ((BMS_SOC_Kaltstart & (0x1FU)) << 3); + BMS_09[6] = ((BMS_SOC_Kaltstart >> 5) & (0x3FU)) | ((BMS_max_Grenz_SOC & (0x03U)) << 6); + BMS_09[7] = ((BMS_max_Grenz_SOC >> 2) & (0x07U)) | ((BMS_min_Grenz_SOC & (0x1FU)) << 3); + // BMS_10 + BMS_10[0] = (BMS_BattEnergy_Wh_HiRes & (0xFFU)); + BMS_10[1] = ((BMS_BattEnergy_Wh_HiRes >> 8) & (0x7FU)) | ((BMS_MaxBattEnergy_Wh_HiRes & (0x01U)) << 7); + BMS_10[2] = ((BMS_MaxBattEnergy_Wh_HiRes >> 1) & (0xFFU)); + BMS_10[3] = ((BMS_MaxBattEnergy_Wh_HiRes >> 9) & (0x3FU)) | ((BMS_SOC & (0x03U)) << 6); + BMS_10[4] = ((BMS_SOC >> 2) & (0x3FU)) | ((BMS_ResidualEnergy_Wh & (0x03U)) << 6); + BMS_10[5] = ((BMS_ResidualEnergy_Wh >> 2) & (0xFFU)); + BMS_10[6] = ((BMS_ResidualEnergy_Wh >> 10) & (0x03U)) | ((0x64 & (0x3FU)) << 2); + BMS_10[7] = ((0x64 >> 6) & (0x01U)) | ((0x64 & (0x7FU)) << 1); + // BMS_11 + BMS_11[0] = 0x00; + BMS_11[1] = 0x00; + BMS_11[2] = ((0x02 & (0x0FU)) << 1) | ((0x01 & (0x07U)) << 5); + BMS_11[3] = (BMS_BattCell_Temp_Max & (0xFFU)); + BMS_11[4] = (BMS_BattCell_Temp_Min & (0xFFU)); + BMS_11[5] = (BMS_BattCell_MV_Max & (0xFFU)); + BMS_11[6] = ((BMS_BattCell_MV_Max >> 8) & (0x0FU)) | ((BMS_BattCell_MV_Min & (0x0FU)) << 4); + BMS_11[7] = ((BMS_BattCell_MV_Min >> 4) & (0xFFU)); + // BMS_27 + BMS_27[0] = 0x00; + BMS_27[1] = 0x00; + BMS_27[2] = 0x00; + BMS_27[3] = ((BMS_SOC_ChargeLim & (0x3FU)) << 2); + BMS_27[4] = ((BMS_SOC_ChargeLim >> 6) & (0x01U)) | ((BMS_EnergyCount & (0x0FU)) << 1) | ((BMS_EnergyReq_Full & (0x07U)) << 5); + BMS_27[5] = ((BMS_EnergyReq_Full >> 3) & (0xFFU)); + BMS_27[6] = (BMS_ChargePowerMax & (0xFFU)); + BMS_27[7] = ((BMS_ChargePowerMax >> 8) & (0x0FU)) | ((BMS_ChargeEnergyCount & (0x0FU)) << 4); + // BMS_DC_01 + + // BMS_Status_DCLS = Status of the voltage monitoring at the DC charging interface | 0=inactive, 1= i.O, 2= n.i.O, 3= Active + // BMS_DCLS_Spannung = DC voltage of the charging station. Measurement between the DC HV lines. + // BMS_DCLS_MaxLadeStrom = maximum permissible DC charging current + + // BMS_DC_01[0] = (BMS_DC_01_CRC & (0xFFU)); + // BMS_DC_01[1] = (BMS_DC_01_BZ & (0x0FU)) | ((BMS_Status_DCLS & (0x03U)) << 4) | ((BMS_DCLS_Spannung & (0x03U)) << 6); + // BMS_DC_01[2] = ((BMS_DCLS_Spannung >> 2) & (0xFFU)); + // BMS_DC_01[3] = (BMS_DCLS_MaxLadeStrom & (0xFFU)); + // BMS_DC_01[4] = ((BMS_DCLS_MaxLadeStrom >> 8) & (0x01U)); + // BMS_DC_01[5] = 0x00; + // BMS_DC_01[6] = 0x00; + // BMS_DC_01[7] = 0x00; + + // DCDC_01 - For DC/DC 12V Converter + // Intend to mirror HV voltage from main bus (unless found elsewhere) + // Charger only seems interested in the 12V output Current & Voltage from module? + // DCDC_01[0] = 0x00; + // DCDC_01[1] = (0x00 & (0x0FU)) | ((DC_IstSpannung_HV & (0x0FU)) << 4); + // DCDC_01[2] = ((DC_IstSpannung_HV >> 4) & (0xFFU)); + // DCDC_01[3] = (DC_IstStrom_HV_02 & (0xFFU)); + // DCDC_01[4] = ((DC_IstStrom_HV_02 >> 8) & (0x03U)) | ((DC_IstStrom_NV & (0x3FU)) << 2); + // DCDC_01[5] = ((DC_IstStrom_NV >> 6) & (0x0FU)); + // DCDC_01[7] = (DC_IstSpannung_NV & (0xFFU)); + + // DCDC_03 - For DC/DC 12V Converter + DCDC_03[2] = (0x00 & (0x07U)) | ((0x00 & (0x01U)) << 3) | ((0x00 & (0x01U)) << 4) | ((DC_IstModus_02 & (0x07U)) << 5); + + + // Dimmung_01 + // Dimmung_01[0] = (DI_KL_58xd & (0xFFU)); + // Dimmung_01[1] = (DI_KL_58xs & (0x7FU)) | ((DI_Display_Nachtdesign & (0x01U)) << 7); + // Dimmung_01[2] = (DI_KL_58xt & (0x7FU)); + // Dimmung_01[3] = (DI_Fotosensor & (0xFFU)); + // Dimmung_01[4] = ((DI_Fotosensor >> 8) & (0xFFU)); + // Dimmung_01[5] = (BCM1_Stellgroesse_Kl_58s & (0x7FU)); + // Dimmung_01[6] = 0x00; + // Dimmung_01[7] = 0x00; + + // HVEM_05 + HVEM_05[0] = 0x00; + HVEM_05[1] = ((HVEM_NVNachladen_Energie & (0x0FU)) << 4); + HVEM_05[2] = (HVEM_NVNachladen_Energie >> 4) & (0x0FU); + HVEM_05[3] = 0x00; + HVEM_05[4] = (HVEM_Nachladen_Anf & (0x01U)) | ((HVEM_SollStrom_HV & (0x7FU)) << 1); + HVEM_05[5] = ((HVEM_SollStrom_HV >> 7) & (0x0FU)) | ((HVEM_MaxSpannung_HV & (0x0FU)) << 4); + HVEM_05[6] = ((HVEM_MaxSpannung_HV >> 4) & (0x3FU)) | ((0x00& (0x03U)) << 6); + HVEM_05[7] = 0x00; + + // Authentic_Time_01 & NavData_02 + Authentic_Time_01[4] = (UnixTime & (0xFFU)); + Authentic_Time_01[5] = ((UnixTime >> 8) & (0xFFU)); + Authentic_Time_01[6] = ((UnixTime >> 16) & (0xFFU)); + Authentic_Time_01[7] = ((UnixTime >> 24) & (0xFFU)); + + ESP_15[4] = (0x00 & (0x01U)) | ((0x00 & (0x07U)) << 1) | ((HMS_Systemstatus & (0x0FU)) << 4); + ESP_15[5] = (0x00 & (0x07U)) | ((HMS_aktives_System & (0x1FU)) << 3); + ESP_15[6] = (0x00 & (0x01U)) | ((0x00 & (0x01U)) << 1) | ((HMS_Fehlerstatus & (0x07U)) << 2) | ((0x00 & (0x01U)) << 5) | ((0x00 & (0x03U)) << 6); + + Klemmen_Status_01[2] = (ZAS_Kl_S & (0x01U)) | ((ZAS_Kl_15 & (0x01U)) << 1) | ((ZAS_Kl_X & (0x01U)) << 2) | ((ZAS_Kl_50_Startanforderung & (0x01U)) << 3) | ((0x00 & (0x01U)) << 4) | ((0x00 & (0x01U)) << 5) | ((0x00 & (0x01U)) << 6) | ((0x00 & (0x01U)) << 7); + + HVK_01[1] = (0x00 & (0x0FU)) | ((0x00 & (0x01U)) << 4) | ((0x00 & (0x03U)) << 5); + HVK_01[2] = (HVK_MO_EmSollzustand & (0xFFU)); + HVK_01[3] = (HVK_BMS_Sollmodus & (0x07U)) | ((HVK_DCDC_Sollmodus & (0x07U)) << 3) | ((0x00 & (0x03U)) << 6); + HVK_01[4] = ((0x00 >> 2) & (0x01U)) | ((0x00 & (0x07U)) << 1) | ((HVK_HVLM_Sollmodus & (0x07U)) << 4) | ((0x00 & (0x01U)) << 7); + HVK_01[5] = ((0x00 >> 1) & (0x01U)) | ((HV_Bordnetz_aktiv & (0x01U)) << 1) | ((0x00 & (0x01U)) << 2) | ((HVK_Gesamtst_Spgfreiheit & (0x03U)) << 3) | ((0x00 & (0x01U)) << 5); + + + ZV_01[1] = (0x00 & (0x0FU)) | ((ZV_FT_verriegeln & (0x01U)) << 4) | ((ZV_FT_entriegeln & (0x01U)) << 5) | ((ZV_BT_verriegeln & (0x01U)) << 6) | ((ZV_BT_entriegeln & (0x01U)) << 7); + ZV_01[7] = ((0x00 >> 5) & (0x3FU)) | ((ZV_entriegeln_Anf & (0x01U)) << 6) | ((0x00 & (0x01U)) << 7); + + ZV_02[2] = (ZV_verriegelt_intern_ist & (0x01U)) | ((ZV_verriegelt_extern_ist & (0x01U)) << 1) | ((ZV_verriegelt_intern_soll & (0x01U)) << 2) | ((ZV_verriegelt_extern_soll & (0x01U)) << 3) | ((0x00 & (0x01U)) << 4) | ((0x00 & (0x01U)) << 5) | ((0x00 & (0x01U)) << 6) | ((0x00 & (0x01U)) << 7); + ZV_02[7] = (0x00 & (0x01U)) | ((0x00 & (0x01U)) << 1) | ((0x00 & (0x01U)) << 2) | ((0x00 & (0x01U)) << 3) | ((0x00 & (0x01U)) << 4) | ((0x00 & (0x01U)) << 5) | ((ZV_verriegelt_soll & (0x03U)) << 6); + + + + EM_HYB_11[1] = (0x00 & (0x0FU)) | ((EM1_Istmodus2 & (0x0FU)) << 4); + EM_HYB_11[2] = (0x00 & (0x07U)) | ((EM1_Status_Spgfreiheit & (0x03U)) << 3) | ((0x00 & (0x01U)) << 5); + +}