diff --git a/Firmware/firmwareLiBCM/config.h b/Firmware/firmwareLiBCM/config.h index 785aab2..442277f 100644 --- a/Firmware/firmwareLiBCM/config.h +++ b/Firmware/firmwareLiBCM/config.h @@ -7,8 +7,8 @@ #define config_h #include "src/libcm.h" - #define FW_VERSION "0.9.5m" - #define BUILD_DATE "2025JUN25" + #define FW_VERSION "0.9.5n" + #define BUILD_DATE "2025JUL07" ////////////////////////////////////////////////////////////////// @@ -24,20 +24,20 @@ //there are no default options because this firmware works with all LiBCM variants... you need to specify which hardware you have installed //choose your battery type: - #define BATTERY_TYPE_5AhG3 //if you're not sure, you probably have this battery + //#define BATTERY_TYPE_5AhG3 //if you're not sure, you probably have this battery //#define BATTERY_TYPE_47Ah //aka FoMoCo //aka Samsung SDI modules //choose how many cells are in series: - #define STACK_IS_48S //All 5AhG3 Kits & 47Ah Kits with QTY4 modules + //#define STACK_IS_48S //All 5AhG3 Kits & 47Ah Kits with QTY4 modules //#define STACK_IS_60S //47Ah Kits with QTY5 modules //choose which grid charger is installed - #define GRIDCHARGER_IS_NOT_1500W //All 5AhG3 Kits & 'standard' 47Ah Kits + //#define GRIDCHARGER_IS_NOT_1500W //All 5AhG3 Kits & 'standard' 47Ah Kits //#define GRIDCHARGER_IS_1500W //47Ah Kits with 'fast' 6.5A charger //choose ONE of the following //must match actual "current hack" hardware configuration: - #define SET_CURRENT_HACK_40 //actually +45.8% //most LiBCM users installed this hardware option + //#define SET_CURRENT_HACK_40 //actually +45.8% //most LiBCM users installed this hardware option //#define SET_CURRENT_HACK_20 //actually +25.0% //#define SET_CURRENT_HACK_00 //OEM configuration (no current hack installed inside MCM) diff --git a/Firmware/firmwareLiBCM/src/LTC68042cell.cpp b/Firmware/firmwareLiBCM/src/LTC68042cell.cpp index e040030..2bb699e 100644 --- a/Firmware/firmwareLiBCM/src/LTC68042cell.cpp +++ b/Firmware/firmwareLiBCM/src/LTC68042cell.cpp @@ -113,7 +113,7 @@ void validateAndStoreNextCVR(uint8_t chipAddress, char cellVoltageRegister) uint8_t cellX=0; //1st cell in returnedData (LTC cell 1, 4, 7, or 10) uint8_t cellY=0; //2nd cell in returnedData (LTC cell 2, 5, 8, or 11) uint8_t cellZ=0; //3rd cell in returnedData (LTC cell 3, 6, 9, or 12) - switch (cellVoltageRegister) //LUT to prevent QTY3 multiplies & QTY12 adds per call + switch (cellVoltageRegister) //LUT prevents QTY3 multiplies & QTY12 adds per call { case 'A': cellX=0; cellY=1; cellZ=2 ; break; //LTC cells 1/ 2/ 3 (LTC 1-indexed, array 0-indexed) case 'B': cellX=3; cellY=4; cellZ=5 ; break; //LTC cells 4/ 5/ 6 diff --git a/Firmware/firmwareLiBCM/src/SoC.h b/Firmware/firmwareLiBCM/src/SoC.h index c374724..2600d58 100644 --- a/Firmware/firmwareLiBCM/src/SoC.h +++ b/Firmware/firmwareLiBCM/src/SoC.h @@ -11,7 +11,7 @@ void SoC_setBatteryStateNow_percent(uint8_t newSoC); uint8_t SoC_getBatteryStateNow_percent(void); - uint16_t SoC_getBatteryStateNow_deciPercent(void); //JTS2doNow: Use this in Battsci, etc. + uint16_t SoC_getBatteryStateNow_deciPercent(void); //JTS2doLater: Use this in Battsci, etc. uint8_t SoC_estimateFromRestingCellVoltage_percent(void); diff --git a/Firmware/firmwareLiBCM/src/USB_userInterface.cpp b/Firmware/firmwareLiBCM/src/USB_userInterface.cpp index ddfed81..c582a0f 100644 --- a/Firmware/firmwareLiBCM/src/USB_userInterface.cpp +++ b/Firmware/firmwareLiBCM/src/USB_userInterface.cpp @@ -182,12 +182,8 @@ void printHelp(void) "\n -'$FAN' display fan status. '$FAN=OFF'/LOW/HI to set." "\n -'$IHACK' display current hack setting. '$IHACK=00'/20/40/60 to set." "\n -'$VHACK' display voltage hack setting. '$VHACK=OEM'/ASSISTONLY_VAR/ASSISTONLY_BIN/ALWAYS." - "\n -'$ASSIST_OFF' disable assist until LiBCM resets." - "\n -'$ASSIST_ON' enable assist until LiBCM resets." - "\n -'$REGEN_OFF' disable regen until LiBCM resets." - "\n -'$REGEN_ON' enable regen until LiBCM resets." - "\n -'SoC_MAX' display max allowed SoC. 'SoC_MAX=__' to set." - "\n -'SoC_MIN' display min allowed SoC. 'SoC_MIN=__' to set." + "\n -'$AST=ON/OFF'" + "\n -'$RGN=ON/OFF'" */ )); //When adding new commands, make sure to add cases to the following functions: @@ -198,28 +194,24 @@ void printHelp(void) ///////////////////////////////////////////////////////////////////////////////////////// -//JTS2doNow: Add '$SPOOF' code -//JTS2doNow: Finish this function void printVspoofInstructions(void) { Serial.print(F("\n\nVoltage Spoofing Commands:" - "\n -'$BVO=_ : +/-/0: increase/decrease/reset OBDIIC&C parameter 0x0A" - "\n -'$MDV=_ : +/-/0: increase/decrease/reset OBDIIC&C parameter 0x05" + "\n -'$BVO=_ : +/-/0: adjust OBDIIC&C parameter 0x0A" + "\n -'$MDV=_ : +/-/0: adjust OBDIIC&C parameter 0x05" + "\n -'$SPF=_ : +/-/0: adjust max allowed spoofed pack voltage" "\n" - "\nInstructions:" - "\n 1: KeyON, engine not running, no IMA CELs" - "\n 2: Display above parameters on OBDIIC&C" - "\n 3: Compare LiBCM's spoofed pack voltage to the above parameters." - "\n 4: Adjust above parameters as needed to make all voltages equal." - "\n For example, if OBDII BVO is 169 volts & Vspoof is 175 volts," - "\n type $BVO=+ to increase BVO. Repeat as needed." - "\n Goal: All three parameters within 5 volts." - + "\nCalibration instructions:" + "\n 0: KeyON, engine off, IMA light must remain off throughout test" + "\n 1: Configure OBDIIC&C to display BVO parameter 0x0A" + "\n 2: Configure OBDIIC&C to display MDV parameter 0x05" + "\n 4: Adjust BVO (on OBDIIC&C) until equal to SPF (on LiBCM LCD)" + "\n Example: BVO is 169 volts & SPF is 175 volts. Type '$BVO=+' repeatedly until BVO=SPF" + "\n Note: If '$BVO=+' doesn't increase BVO, type '$SPF=-' to reduce SPF" + "\n 5: Adjust MDV until equal to SPF" + "\n Example: MDV is 171 volts & SPF is 168 volts. Type '$MDV=-' repeatedly until MDV=SPF" + "\n 6: Verify SPF & BVO & MDV are within 5 volts (ideally 0 volts)" )); - //When adding new commands, make sure to add cases to the following functions: - //USB_userInterface_executeUserInput() - //eeprom_resetDebugValues() //if debug data is stored in EEPROM - //eeprom_verifyDataValid() //if data is stored in EEPROM } ///////////////////////////////////////////////////////////////////////////////////////// @@ -419,9 +411,9 @@ void USB_userInterface_executeUserInput(void) Serial.print(' '); if ( (line[4]=='=') && ((line[5]=='+') || (line[5]=='-') || (line[5]=='0')) && - (line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetBVO_adjust(line[5]); } + (line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetBVO_adjust(line[5]); } else if (line[4]==STRING_TERMINATION_CHARACTER) { Serial.print(vPackSpoof_offsetBVO_get()); } - else { printText_invalidEntry(); } + else { printText_invalidEntry(); } } //$MDV @@ -431,9 +423,21 @@ void USB_userInterface_executeUserInput(void) Serial.print(' '); if ( (line[4]=='=') && ((line[5]=='+') || (line[5]=='-') || (line[5]=='0')) && - (line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetMDV_adjust(line[5]); } + (line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetMDV_adjust(line[5]); } else if (line[4]==STRING_TERMINATION_CHARACTER) { Serial.print(vPackSpoof_offsetMDV_get()); } - else { printText_invalidEntry(); } + else { printText_invalidEntry(); } + } + + //$SPF + else if ((line[1]=='S') && (line[2]=='P') && (line[3]=='F')) + { + //MDV affects VPIN output + Serial.print(' '); + if ( (line[4]=='=') && + ((line[5]=='+') || (line[5]=='-') || (line[5]=='0')) && + (line[6]==STRING_TERMINATION_CHARACTER) ) { vPackSpoof_offsetSPF_adjust(line[5]); } + else if (line[4]==STRING_TERMINATION_CHARACTER) { Serial.print(vPackSpoof_offsetSPF_get()); } + else { printText_invalidEntry(); } } //$SPOOF diff --git a/Firmware/firmwareLiBCM/src/battsci.cpp b/Firmware/firmwareLiBCM/src/battsci.cpp index 5943265..f8aeba0 100755 --- a/Firmware/firmwareLiBCM/src/battsci.cpp +++ b/Firmware/firmwareLiBCM/src/battsci.cpp @@ -192,7 +192,7 @@ uint8_t BATTSCI_calculateRegenAssistFlags(void) if ((BATTSCI_isPackFull() == YES) || //pack is full ((temperature_battery_getLatest() < TEMP_FREEZING_DEGC + 2) && (BATTSCI_isPackEmpty() == NO)) ) //pack too cold to charge; DCDC still powered //JTS2doLater: Allow minimal regen when pack below freezing (e.g. using LiControl to limit max regen) - //JTS2doNow: Disable assist and regen if pack too hot + //JTS2doLater: Disable assist and regen if pack too hot #endif { flags |= BATTSCI_DISABLE_REGEN_FLAG; //when this flag is set, MCM draws zero power from IMA motor @@ -219,7 +219,7 @@ uint8_t BATTSCI_calculateRegenAssistFlags(void) // 0x32 = 50d = 0b0011 0010: pack empty // 0x52 = 82d = 0b0101 0010: pack full (usually... see "Day1-1" for case where pack is empty) -//JTS2doNow: Allow regen at lower temperatures (see calculations in LiBCM Support Thread post#3637) +//JTS2doLater: Allow regen at lower temperatures (see calculations in LiBCM Support Thread post#3637) //kindly request regen and/or no regen from MCM uint8_t BATTSCI_calculateChargeRequestByte(void) { diff --git a/Firmware/firmwareLiBCM/src/eepromAccess.cpp b/Firmware/firmwareLiBCM/src/eepromAccess.cpp index fac5b67..60433b9 100755 --- a/Firmware/firmwareLiBCM/src/eepromAccess.cpp +++ b/Firmware/firmwareLiBCM/src/eepromAccess.cpp @@ -28,6 +28,7 @@ const uint16_t EEPROM_ADDRESS_COMPILE_TIME = 0x013; //EEPROM range is 0x0 const uint16_t EEPROM_ADDRESS_MAX_VCELL_DELTA = 0x01C; //EEPROM range is 0x01C:0x01D ( 2B) const uint16_t EEPROM_ADDRESS_BVO_OFFSET = 0x01E; //EEPROM range is 0x01E ( 1B) const uint16_t EEPROM_ADDRESS_MDV_OFFSET = 0x01F; //EEPROM range is 0x01F ( 1B) +const uint16_t EEPROM_ADDRESS_SPF_OFFSET = 0x020; //EEPROM range is 0x020 ( 1B) //this EEPROM space still available //The following addresses start from end of EEPROM space and work backwards to beginning const uint16_t EEPROM_ADDRESS_BATT_HISTORY = EEPROM_LAST_USABLE_ADDRESS - NUM_BYTES_BATTERY_HISTORY; //0xA57:0xF9F (1536B) @@ -203,10 +204,13 @@ void eeprom_delayKeyON_ms_set(uint8_t delay_ms) { EEPROM.upd ///////////////////////////////////////////////////////////////////////////////////////// -int8_t eeprom_getVspoofOffset_BVO(void) { return EEPROM.read (EEPROM_ADDRESS_BVO_OFFSET); } -void eeprom_setVspoofOffset_BVO(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_BVO_OFFSET, newOffset_counts); } -int8_t eeprom_getVspoofOffset_MDV(void) { return EEPROM.read (EEPROM_ADDRESS_MDV_OFFSET); } -void eeprom_setVspoofOffset_MDV(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_MDV_OFFSET, newOffset_counts); } +int8_t eeprom_getVspoofOffset_BVO(void) { return EEPROM.read (EEPROM_ADDRESS_BVO_OFFSET); } +int8_t eeprom_getVspoofOffset_MDV(void) { return EEPROM.read (EEPROM_ADDRESS_MDV_OFFSET); } +int8_t eeprom_getVspoofOffset_SPF(void) { return EEPROM.read (EEPROM_ADDRESS_SPF_OFFSET); } + +void eeprom_setVspoofOffset_BVO(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_BVO_OFFSET, newOffset_counts); } +void eeprom_setVspoofOffset_MDV(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_MDV_OFFSET, newOffset_counts); } +void eeprom_setVspoofOffset_SPF(int8_t newOffset_counts) { EEPROM.update(EEPROM_ADDRESS_SPF_OFFSET, newOffset_counts); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -256,16 +260,15 @@ void eeprom_verifyDataValid(void) EEPROM.update(EEPROM_ADDRESS_NEXT_Wh_RECORD, EEPROM_ADDRESS_FORMATTED_VALUE); } - if (EEPROM.read(EEPROM_ADDRESS_BVO_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b) + if ((EEPROM.read(EEPROM_ADDRESS_BVO_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b) && + (EEPROM.read(EEPROM_ADDRESS_MDV_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b) && + (EEPROM.read(EEPROM_ADDRESS_SPF_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b) ) { - printMessage_RestoringEEPROM(); Serial.print(F("BVO_OFFSET")); + //JTS2doLater: fix int8_t issue where EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b = 0xFF = -1 + printMessage_RestoringEEPROM(); Serial.print(F("VPACKSPOOF_OFFSETS")); EEPROM.update(EEPROM_ADDRESS_BVO_OFFSET, EEPROM_ADDRESS_FORMATTED_VALUE); - } - - if (EEPROM.read(EEPROM_ADDRESS_MDV_OFFSET) == EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b) - { - printMessage_RestoringEEPROM(); Serial.print(F("MDV_OFFSET")); EEPROM.update(EEPROM_ADDRESS_MDV_OFFSET, EEPROM_ADDRESS_FORMATTED_VALUE); + EEPROM.update(EEPROM_ADDRESS_SPF_OFFSET, EEPROM_ADDRESS_FORMATTED_VALUE); } } diff --git a/Firmware/firmwareLiBCM/src/eepromAccess.h b/Firmware/firmwareLiBCM/src/eepromAccess.h index 6031fbc..977bc1f 100755 --- a/Firmware/firmwareLiBCM/src/eepromAccess.h +++ b/Firmware/firmwareLiBCM/src/eepromAccess.h @@ -13,8 +13,8 @@ #define EEPROM_ADDRESS_FACTORY_DEFAULT_VALUE_8b 0xFF #define EEPROM_ADDRESS_FORMATTED_VALUE 0x00 - #define BYTES_IN_DATE 12 //JTS2doLater: Is date 11 bytes or 12? - #define BYTES_IN_TIME 9 //JTS2doLater: Is time 9 bytes or 8? + #define BYTES_IN_DATE 12 + #define BYTES_IN_TIME 9 #define REQUIRED_FIRMWARE_UPDATE_PERIOD_DAYS 120 #define REQUIRED_FIRMWARE_UPDATE_PERIOD_HOURS (REQUIRED_FIRMWARE_UPDATE_PERIOD_DAYS * 24) @@ -47,9 +47,12 @@ void eeprom_delayKeyON_ms_set(uint8_t); int8_t eeprom_getVspoofOffset_BVO(void); - void eeprom_setVspoofOffset_BVO(int8_t); int8_t eeprom_getVspoofOffset_MDV(void); - void eeprom_setVspoofOffset_MDV(int8_t); + int8_t eeprom_getVspoofOffset_SPF(void); + + void eeprom_setVspoofOffset_BVO(int8_t); + void eeprom_setVspoofOffset_MDV(int8_t); + void eeprom_setVspoofOffset_SPF(int8_t); void eeprom_resetDebugValues(void); diff --git a/Firmware/firmwareLiBCM/src/gridCharger.cpp b/Firmware/firmwareLiBCM/src/gridCharger.cpp index 7365863..705ee22 100644 --- a/Firmware/firmwareLiBCM/src/gridCharger.cpp +++ b/Firmware/firmwareLiBCM/src/gridCharger.cpp @@ -117,6 +117,7 @@ void processChargerDisableReason(uint8_t canWeCharge) ///////////////////////////////////////////////////////////////////////////////////////// +//JTS2doLater: add current feedback to 1500 charger, so LiBCM can cycle charger if no output current detected //JTS2doLater: add timer/current logic to detect if grid charger isn't working void chargerControlSignals_handler(void) { diff --git a/Firmware/firmwareLiBCM/src/key.cpp b/Firmware/firmwareLiBCM/src/key.cpp index a676ef9..3021efc 100755 --- a/Firmware/firmwareLiBCM/src/key.cpp +++ b/Firmware/firmwareLiBCM/src/key.cpp @@ -22,7 +22,7 @@ void key_handleKeyEvent_off(void) METSCI_disable(); LTC68042cell_acquireAllCellVoltages(); SoC_updateUsingLatestOpenCircuitVoltage(); //JTS2doLater: Add ten minute delay before VoC->SoC LUT - adc_calibrateBatteryCurrentSensorOffset(DEBUG_TEXT_ENABLED); + adc_calibrateBatteryCurrentSensorOffset(DEBUG_TEXT_ENABLED); //JTS2doNext: move to keyON gpio_turnPowerSensors_off(); LTC68042configure_handleKeyStateChange(); vPackSpoof_handleKeyOFF(); @@ -127,7 +127,7 @@ void keyOn_coldBootTasks(void) vPackSpoof_setVoltage(); SoC_setBatteryStateNow_percent(SoC_estimateFromRestingCellVoltage_percent()); BATTSCI_enable(); //must occur after we have valid Vcell data - adc_calibrateBatteryCurrentSensorOffset(DEBUG_TEXT_DISABLED); //current sensor settles almost immediately + adc_calibrateBatteryCurrentSensorOffset(DEBUG_TEXT_DISABLED); //current sensor settles almost immediately //JTS2doLater: Can we detect true keyON from USB reset? } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/Firmware/firmwareLiBCM/src/lcdTransmit.cpp b/Firmware/firmwareLiBCM/src/lcdTransmit.cpp index 74665b3..57b8f44 100755 --- a/Firmware/firmwareLiBCM/src/lcdTransmit.cpp +++ b/Firmware/firmwareLiBCM/src/lcdTransmit.cpp @@ -98,7 +98,7 @@ bool lcd_flashBacklight(void) ///////////////////////////////////////////////////////////////////////////////////////// -//JTS2doNow: Build string in RAM, then send all at once to display (much faster). +//JTS2doLater: Build string in RAM, then send all at once to display (much faster). //alternates between: //time since last keyON, and; //"tuuuuu" in seconds diff --git a/Firmware/firmwareLiBCM/src/temperature.cpp b/Firmware/firmwareLiBCM/src/temperature.cpp index f2e1174..27d6d8b 100644 --- a/Firmware/firmwareLiBCM/src/temperature.cpp +++ b/Firmware/firmwareLiBCM/src/temperature.cpp @@ -242,7 +242,7 @@ void temperature_handler(void) uint8_t keyState_Now = key_getSampledState(); //prevent mid-loop key state change - keyState_Now = turnSensorsOff_whenKeyStateChanges(keyState_Now); //JTS2doNow: function returns value meant for tempSensorState //writing to wrong variable? + keyState_Now = turnSensorsOff_whenKeyStateChanges(keyState_Now); //JTS2doNext: function returns value meant for tempSensorState //writing to wrong variable? static uint32_t latestTempMeasurement_ms = 0; static uint32_t latestSensorTurnon_ms = 0; diff --git a/Firmware/firmwareLiBCM/src/vPackSpoof.cpp b/Firmware/firmwareLiBCM/src/vPackSpoof.cpp index 834cc40..4d55d42 100755 --- a/Firmware/firmwareLiBCM/src/vPackSpoof.cpp +++ b/Firmware/firmwareLiBCM/src/vPackSpoof.cpp @@ -38,6 +38,7 @@ void vPackSpoof_handleKeyOFF(void) int8_t vPackSpoof_offsetBVO_get(void) { return eeprom_getVspoofOffset_BVO(); } int8_t vPackSpoof_offsetMDV_get(void) { return eeprom_getVspoofOffset_MDV(); } +int8_t vPackSpoof_offsetSPF_get(void) { return eeprom_getVspoofOffset_SPF(); } void vPackSpoof_offsetBVO_adjust(uint8_t action) { @@ -53,6 +54,14 @@ void vPackSpoof_offsetMDV_adjust(uint8_t action) else if (action == '0') { eeprom_setVspoofOffset_MDV(0); } } + +void vPackSpoof_offsetSPF_adjust(uint8_t action) +{ + if (action == '+') { eeprom_setVspoofOffset_SPF(eeprom_getVspoofOffset_SPF() + 1); } + else if (action == '-') { eeprom_setVspoofOffset_SPF(eeprom_getVspoofOffset_SPF() - 1); } + else if (action == '0') { eeprom_setVspoofOffset_SPF(0); } +} + ///////////////////////////////////////////////////////////////////////////////////////// void spoofVoltageMCMe(void) @@ -106,8 +115,6 @@ uint8_t calculate_Vspoof_maxPossible(void) //The max allowed voltage is a function of the actual pack voltage //Derivation: ~/Electronics/PCB (KiCAD)/RevD/V&V/VPIN-MCMe Calibration.ods - //JTS2doNow: Decide if adding more headroom here is easier than changing existing calibration method - uint8_t actualPackVoltage = LTC68042result_packVoltage_get(); uint8_t maxAllowedVspoof = 0; @@ -128,6 +135,8 @@ uint8_t calculate_Vspoof_maxPossible(void) else if (actualPackVoltage < 245) { maxAllowedVspoof = actualPackVoltage - 20; } else { maxAllowedVspoof = actualPackVoltage - 21; } + maxAllowedVspoof += eeprom_getVspoofOffset_SPF(); + return maxAllowedVspoof; } diff --git a/Firmware/firmwareLiBCM/src/vPackSpoof.h b/Firmware/firmwareLiBCM/src/vPackSpoof.h index ef560ac..0918a0e 100644 --- a/Firmware/firmwareLiBCM/src/vPackSpoof.h +++ b/Firmware/firmwareLiBCM/src/vPackSpoof.h @@ -23,9 +23,12 @@ void vPackSpoof_handleKeyON(void); int8_t vPackSpoof_offsetBVO_get(void); - void vPackSpoof_offsetBVO_adjust(uint8_t action); int8_t vPackSpoof_offsetMDV_get(void); - void vPackSpoof_offsetMDV_adjust(uint8_t action); + int8_t vPackSpoof_offsetSPF_get(void); + + void vPackSpoof_offsetBVO_adjust(uint8_t action); + void vPackSpoof_offsetMDV_adjust(uint8_t action); + void vPackSpoof_offsetSPF_adjust(uint8_t action); uint8_t vPackSpoof_getSpoofedPackVoltage(void);