From 3ba4f26b436c18de375134e20f6a6dfbd5c6dce9 Mon Sep 17 00:00:00 2001 From: Janosch Date: Fri, 14 Oct 2022 13:24:43 +0100 Subject: [PATCH] move to charger.cpp complete, stubs & TODOs for missing tests --- Makefile | 1 + include/charger.h | 6 ++ libopeninv/libopeninv.a | Bin 49702 -> 58174 bytes src/charger.cpp | 164 +++++++++++++++++++++++++++++++++++++++ src/main.cpp | 165 +--------------------------------------- test/test.out | Bin 58352 -> 60840 bytes test/test_common.h | 2 + test/test_logic.h | 5 +- 8 files changed, 178 insertions(+), 165 deletions(-) diff --git a/Makefile b/Makefile index 67d1481..90d16ea 100644 --- a/Makefile +++ b/Makefile @@ -125,6 +125,7 @@ Test: g++ -c -Ilibopeninv/include/ -Iinclude -o params.o libopeninv/src/params.cpp g++ -c -Ilibopeninv/include/ -Iinclude -o errormessage.o libopeninv/src/errormessage.cpp g++ -c -Ilibopeninv/include/ -Iinclude -o printf.o libopeninv/src/printf.cpp + g++ -c -Ilibopeninv/include/ -Iinclude -o picontroller.o libopeninv/src/picontroller.cpp g++ -c -Ilibopeninv/include/ -Iinclude -o charger.o src/charger.cpp -D TEST_COMMON_H g++ -c -Ilibopeninv/include/ -Iinclude -o digio_mock.o test/digio_mock.cpp g++ -c -Ilibopeninv/include/ -Iinclude -o timer_mock.o test/timer_mock.cpp diff --git a/include/charger.h b/include/charger.h index e921599..81de23a 100644 --- a/include/charger.h +++ b/include/charger.h @@ -1,7 +1,9 @@ #ifndef CHARGER_H #define CHARGER_H +#include "../libopeninv/include/picontroller.h" #include "../libopeninv/include/params.h" extern uint32_t startTime; +extern PiController dcCurController; bool IsEvseInput(); bool CheckUnplugged(); bool CheckTimeout(); @@ -13,4 +15,8 @@ bool CheckStartCondition(); bool CheckVoltage(); void ResetValuesInOffMode(); void CalcEnable(); +bool CheckChargerFaults(); +void ChargerStateMachine(); +void CalcAcCurrentLimit(); +void ChargerStateMachine(); #endif diff --git a/libopeninv/libopeninv.a b/libopeninv/libopeninv.a index e7fc1de5b2142f33aee1d1361dd30755e98c40e9..fa7118d896ed11a3c4a61dfd2fd4cfb83e421580 100644 GIT binary patch delta 9506 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 delta 3021 zcmb`JZERCj7{||Tw~lqAYscE#6=+M>O;}-V=Rh!E$BS{}!!|K-gpdpjzHDOV7qdt( zjSB(sg9H8qAraOrNRSWg&4@BW$H2-511=CXDsE9@G?~FKMo2L8oO_;2PH!~9mnS** z-~0bP&)GTm+&sG%bM{kv><3n*mp_~c8?nvF80%onS@Z9QXA@)pY@}sD^$Nz+k?3OV zLB^V=8T(Ho%_r!N{6FL9w~U!1^A%$cGFpaYOYynUEhRr3DO}mG zq9KgzV~M2;_#sg=8rsMz*gU53-*fm7T1@I3JvXq%;ozsq4SYAa7~!FSBfPf%Ol=Bf zx8nGt?Qyt<{n~0gG#t{l;(31EjeY$34!(XeWV^s{bvS7IhT*5-h{jMd64JtmjZ|qH z(8_=BKsUecLElKoc2dL8NYHjg!)GG_e12;M?mgu{w6Y1?dTT>-jTIH~tBeBDC0sS; zfTzlfQ~m(Pd&}{%rvR?^>oM;4BlG&Y?N9KWh_N?W{5$z_ohqO?`fu%lMKuS_dvy^R8dZfH1 z|#M$ zJIdPqa1G4C`tyyLJEo5|j797*nN&`>;@EUP?#;?*QhYC3vpQW-X znvm|K;_`DOw}f6gxwiC#u0`?oM31%vWta6z^*z`_nL=uj;#9O0bB`C4d31DhTC31% z{$7d@Nz2gBsc02u?P{W84RyGFS#ORjv|Xtc-PNpm$>MWl#6D%V1maip$|U#AssV-S z=-^b{V>XZWS!!n$nncz@V`BL{gd}m>LZ8i}p^x)dbx5H)S}pXlLX${a==XVa&_eCh z2}Dv7Q=F>%U7JVCa`H{-B3GPN15!ENC3=JT1bYh+-s;1yT&ZXTwu|!iOfIVFxSq@3 z*Ii})<(SRsS`zvv9sD}AO2>1PP1x00iu04D4)M2A4AY&ywAu5gxg|m%G0fgwKrgcC zo83BU@y%}CWbw^z{es1({=A;OVF6}?K5g;M?t9hZw-h4r;!5niF$cLD3vlPgA_Q;l zFZ_`2!GrCdc{t&AFZA#`@mT5f?(6-mWoF|Q-x?xBg=n&WTj4eT|ELueNF9thH;V~) zJnBGWJczD{-+Nlj$73^Pi`xQZ55{bV9T;-^5U6tFT7RWRcV8@a9_1f6BD@Tl>0m^B zE{LrghbMfBvy|qOX&v1DtF$YWR$-)Rub?BL+rD%l#5?LAD@>0TC)D{7+y5?d@o>R8O{rjHpn hy`bVG%8@=6bB0~Arq^yfsoENUaoc=pWs!=9{shr$twaC- diff --git a/src/charger.cpp b/src/charger.cpp index ade0736..afa2300 100644 --- a/src/charger.cpp +++ b/src/charger.cpp @@ -208,3 +208,167 @@ void CalcEnable() Param::SetInt(Param::enable, enable); } +// TODO: no unit tests below here (see test_logic.h and implement there) + +bool CheckChargerFaults() +{ + const int acPresentThresh = 70; + const int timeout = 20; + static int counters[3] = { timeout, timeout, timeout }; + int configuredChargers = Param::GetInt(Param::chargerena); + bool timeouts[3]; + bool active1 = (configuredChargers & 1) && (Param::GetInt(Param::c1uac) > acPresentThresh); + bool active2 = (configuredChargers & 2) && (Param::GetInt(Param::c2uac) > acPresentThresh); + bool active3 = (configuredChargers & 4) && (Param::GetInt(Param::c3uac) > acPresentThresh); + + timeouts[0] = (Param::GetInt(Param::c1flag) & FLAG_CHECK) != 0; + timeouts[1] = (Param::GetInt(Param::c2flag) & FLAG_CHECK) != 0; + timeouts[2] = (Param::GetInt(Param::c3flag) & FLAG_CHECK) != 0; + + for (int i = 0; i < 3; i++) + { + if (timeouts[i]) + { + if (counters[i] > 0) + { + counters[i]--; + timeouts[i] = false; + } + else + { + ErrorMessage::Post(ERR_CHARGERCAN); + } + } + else + { + counters[i] = timeout; + } + } + + //Set check flag. By the next call this should be deleted by the CAN module + Param::SetInt(Param::c1flag, Param::GetInt(Param::c1flag) | FLAG_CHECK); + Param::SetInt(Param::c2flag, Param::GetInt(Param::c2flag) | FLAG_CHECK); + Param::SetInt(Param::c3flag, Param::GetInt(Param::c3flag) | FLAG_CHECK); + + return (active1 && ((Param::GetInt(Param::c1flag) & FLAG_FAULT) || timeouts[0])) || + (active2 && ((Param::GetInt(Param::c2flag) & FLAG_FAULT) || timeouts[1])) || + (active3 && ((Param::GetInt(Param::c3flag) & FLAG_FAULT) || timeouts[2])); +} + +void CalcAcCurrentLimit() +{ + int configuredChargers = Param::GetInt(Param::chargerena); + float iacLim = Param::GetFloat(Param::iaclim); + float hwaclim = Param::GetFloat(Param::hwaclim); + float evseLim = Param::GetFloat(Param::evselim); + float cableLim = Param::GetFloat(Param::cablelim); + int activeModules = ((configuredChargers & 1) > 0) + ((configuredChargers & 2) > 0) + ((configuredChargers & 4) > 0); + + if (IsEvseInput()) + { + iacLim = MIN(iacLim, MIN(evseLim, cableLim)); + } + + if (Param::GetInt(Param::opmode) == 0) + { + dcCurController.ResetIntegrator(); + iacLim = 0; + } + else + { + dcCurController.SetMinMaxY(0, iacLim); + iacLim = dcCurController.Run(Param::Get(Param::idc)); + } + + if (Param::GetInt(Param::inputype) == INP_MANUAL || + Param::GetInt(Param::inputype) == INP_TYPE1 || + Param::GetInt(Param::inputype) == INP_TYPE2 || + (Param::GetInt(Param::inputype) == INP_TYPE2_AUTO && !DigIo::threep_in.Get())) + { + iacLim /= (float)activeModules; + } + + iacLim = MIN(iacLim, hwaclim); + + Param::SetFloat(Param::aclim, iacLim); +} + +void ChargerStateMachine() +{ + static states state = OFF; + int configuredChargers = Param::GetInt(Param::chargerena); + + if (!Param::GetBool(Param::enable)) + { + state = OFF; + } + + switch (state) + { + default: + case OFF: + Param::SetInt(Param::opmode, 0); + DisableAll(); + + if (CheckStartCondition()) + { + startTime = rtc_get_counter_val(); + state = WAITSTART; + } + break; + case WAITSTART: + if (CheckDelay()) + state = ENABLE; + break; + case ENABLE: + DigIo::hvena_out.Set(); + if (configuredChargers & 1) + DigIo::ch1ena_out.Set(); + if (configuredChargers & 2) + DigIo::ch2ena_out.Set(); + if (configuredChargers & 4) + DigIo::ch3ena_out.Set(); + state = ACTIVATE; + break; + case ACTIVATE: + Param::SetInt(Param::opmode, 1); + + if (configuredChargers & 1) + DigIo::ch1act_out.Set(); + if (configuredChargers & 2) + DigIo::ch2act_out.Set(); + if (configuredChargers & 4) + DigIo::ch3act_out.Set(); + + startTime = rtc_get_counter_val(); + state = EVSEACTIVATE; + break; + case EVSEACTIVATE: + DigIo::evseact_out.Set(); + DigIo::acpres_out.Set(); + + if (CheckVoltage() || CheckTimeout()) + state = STOP; + if (CheckUnplugged()) + { + DigIo::acpres_out.Clear(); + DigIo::evseact_out.Clear(); + state = OFF; + } + if (CheckChargerFaults()) + { + DigIo::acpres_out.Clear(); + state = OFF; + } + break; + case STOP: + DisableAll(); + Param::SetInt(Param::opmode, 0); + + if (CheckUnplugged()) + state = OFF; + break; + } + + Param::SetInt(Param::state, state); +} diff --git a/src/main.cpp b/src/main.cpp index 2e45c9a..3dcec61 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,172 +45,9 @@ static Stm32Scheduler* scheduler; static Can* can; -static PiController dcCurController; +PiController dcCurController; uint32_t startTime; -static bool CheckChargerFaults() -{ - const int acPresentThresh = 70; - const int timeout = 20; - static int counters[3] = { timeout, timeout, timeout }; - int configuredChargers = Param::GetInt(Param::chargerena); - bool timeouts[3]; - bool active1 = (configuredChargers & 1) && (Param::GetInt(Param::c1uac) > acPresentThresh); - bool active2 = (configuredChargers & 2) && (Param::GetInt(Param::c2uac) > acPresentThresh); - bool active3 = (configuredChargers & 4) && (Param::GetInt(Param::c3uac) > acPresentThresh); - - timeouts[0] = (Param::GetInt(Param::c1flag) & FLAG_CHECK) != 0; - timeouts[1] = (Param::GetInt(Param::c2flag) & FLAG_CHECK) != 0; - timeouts[2] = (Param::GetInt(Param::c3flag) & FLAG_CHECK) != 0; - - for (int i = 0; i < 3; i++) - { - if (timeouts[i]) - { - if (counters[i] > 0) - { - counters[i]--; - timeouts[i] = false; - } - else - { - ErrorMessage::Post(ERR_CHARGERCAN); - } - } - else - { - counters[i] = timeout; - } - } - - //Set check flag. By the next call this should be deleted by the CAN module - Param::SetInt(Param::c1flag, Param::GetInt(Param::c1flag) | FLAG_CHECK); - Param::SetInt(Param::c2flag, Param::GetInt(Param::c2flag) | FLAG_CHECK); - Param::SetInt(Param::c3flag, Param::GetInt(Param::c3flag) | FLAG_CHECK); - - return (active1 && ((Param::GetInt(Param::c1flag) & FLAG_FAULT) || timeouts[0])) || - (active2 && ((Param::GetInt(Param::c2flag) & FLAG_FAULT) || timeouts[1])) || - (active3 && ((Param::GetInt(Param::c3flag) & FLAG_FAULT) || timeouts[2])); -} - -static void CalcAcCurrentLimit() -{ - int configuredChargers = Param::GetInt(Param::chargerena); - float iacLim = Param::GetFloat(Param::iaclim); - float hwaclim = Param::GetFloat(Param::hwaclim); - float evseLim = Param::GetFloat(Param::evselim); - float cableLim = Param::GetFloat(Param::cablelim); - int activeModules = ((configuredChargers & 1) > 0) + ((configuredChargers & 2) > 0) + ((configuredChargers & 4) > 0); - - if (IsEvseInput()) - { - iacLim = MIN(iacLim, MIN(evseLim, cableLim)); - } - - if (Param::GetInt(Param::opmode) == 0) - { - dcCurController.ResetIntegrator(); - iacLim = 0; - } - else - { - dcCurController.SetMinMaxY(0, iacLim); - iacLim = dcCurController.Run(Param::Get(Param::idc)); - } - - if (Param::GetInt(Param::inputype) == INP_MANUAL || - Param::GetInt(Param::inputype) == INP_TYPE1 || - Param::GetInt(Param::inputype) == INP_TYPE2 || - (Param::GetInt(Param::inputype) == INP_TYPE2_AUTO && !DigIo::threep_in.Get())) - { - iacLim /= (float)activeModules; - } - - iacLim = MIN(iacLim, hwaclim); - - Param::SetFloat(Param::aclim, iacLim); -} - -static void ChargerStateMachine() -{ - static states state = OFF; - int configuredChargers = Param::GetInt(Param::chargerena); - - if (!Param::GetBool(Param::enable)) - { - state = OFF; - } - - switch (state) - { - default: - case OFF: - Param::SetInt(Param::opmode, 0); - DisableAll(); - - if (CheckStartCondition()) - { - startTime = rtc_get_counter_val(); - state = WAITSTART; - } - break; - case WAITSTART: - if (CheckDelay()) - state = ENABLE; - break; - case ENABLE: - DigIo::hvena_out.Set(); - if (configuredChargers & 1) - DigIo::ch1ena_out.Set(); - if (configuredChargers & 2) - DigIo::ch2ena_out.Set(); - if (configuredChargers & 4) - DigIo::ch3ena_out.Set(); - state = ACTIVATE; - break; - case ACTIVATE: - Param::SetInt(Param::opmode, 1); - - if (configuredChargers & 1) - DigIo::ch1act_out.Set(); - if (configuredChargers & 2) - DigIo::ch2act_out.Set(); - if (configuredChargers & 4) - DigIo::ch3act_out.Set(); - - startTime = rtc_get_counter_val(); - state = EVSEACTIVATE; - break; - case EVSEACTIVATE: - DigIo::evseact_out.Set(); - DigIo::acpres_out.Set(); - - if (CheckVoltage() || CheckTimeout()) - state = STOP; - if (CheckUnplugged()) - { - DigIo::acpres_out.Clear(); - DigIo::evseact_out.Clear(); - state = OFF; - } - if (CheckChargerFaults()) - { - DigIo::acpres_out.Clear(); - state = OFF; - } - break; - case STOP: - DisableAll(); - Param::SetInt(Param::opmode, 0); - - if (CheckUnplugged()) - state = OFF; - break; - } - - Param::SetInt(Param::state, state); -} - //sample 100ms task static void Ms100Task(void) { diff --git a/test/test.out b/test/test.out index baf48312681cf85f51e0aa53b9d751cd3385d248..6594a494584e9898ba04c2d552eb516e2d85bd7c 100755 GIT binary patch delta 21440 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ℜjyZF7d%&qnRI4+1g?wr#$b# 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 diff --git a/test/test_common.h b/test/test_common.h index 41f96cf..e67bbd5 100644 --- a/test/test_common.h +++ b/test/test_common.h @@ -3,4 +3,6 @@ #include "timer_mock.h" #include "digio_mock.h" #include "charger.h" +uint32_t startTime; +PiController dcCurController; #endif diff --git a/test/test_logic.h b/test/test_logic.h index 3ad5e5b..175e2ec 100644 --- a/test/test_logic.h +++ b/test/test_logic.h @@ -3,7 +3,6 @@ #endif #include #include "test_common.h" -uint32_t startTime; void test_calc_totals() { @@ -238,3 +237,7 @@ void test_calc_enable(){ //} //assert(3 == canenable); } + +// TODO: test_charger_state_machine(){} +// TODO: test_calc_ac_current_limit(){} +// TODO: test_check_charger_faults(){}