22// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
33
44#include " isolation_monitorImpl.hpp"
5+ #include " everest/logging.hpp"
56#include < chrono>
67#include < fmt/core.h>
78#include < thread>
@@ -16,6 +17,13 @@ void isolation_monitorImpl::init() {
1617void isolation_monitorImpl::configure_device () {
1718 // Query device name and version
1819 bool successful = true ;
20+ int selftest_enable_at_start_value = config.selftest_enable_at_start ? 1 : 0 ;
21+ if (config.disable_device_on_stop and config.selftest_enable_at_start ) {
22+ EVLOG_warning << " disable_device_on_stop configuration option and "
23+ " selftest_enable_at_start are incompatible. Self test at "
24+ " start will be disabled." ;
25+ selftest_enable_at_start_value = 0 ;
26+ }
1927 do {
2028 successful = true ;
2129 successful &= send_to_imd (3000 , (config.voltage_to_earth_monitoring_alarm_enable ? 1 : 0 ));
@@ -48,14 +56,16 @@ void isolation_monitorImpl::configure_device() {
4856 std::this_thread::sleep_for (std::chrono::milliseconds (20 ));
4957 successful &= send_to_imd (3024 , (config.selftest_enable_gridconnection ? 1 : 0 ));
5058 std::this_thread::sleep_for (std::chrono::milliseconds (20 ));
51- successful &= send_to_imd (3025 , (config. selftest_enable_at_start ? 1 : 0 ) );
59+ successful &= send_to_imd (3025 , selftest_enable_at_start_value );
5260 std::this_thread::sleep_for (std::chrono::milliseconds (20 ));
5361 successful &= send_to_imd (3027 , config.relay_k1_alarm_assignment );
5462 std::this_thread::sleep_for (std::chrono::milliseconds (20 ));
5563 successful &= send_to_imd (3028 , config.relay_k2_alarm_assignment );
5664 std::this_thread::sleep_for (std::chrono::milliseconds (20 ));
57- // start up
58- successful &= send_to_imd (3026 , 1 );
65+ // start up enable the device if the configuration option is not set
66+ if (!config.disable_device_on_stop ) {
67+ successful &= send_to_imd (3026 , 1 );
68+ }
5969 // Give device time to process startup command
6070 std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
6171
@@ -68,9 +78,10 @@ void isolation_monitorImpl::configure_device() {
6878 enable_faster_cable_check_mode ();
6979 std::this_thread::sleep_for (std::chrono::milliseconds (20 ));
7080 } else {
71- EVLOG_info
72- << " Does not support faster cable check method, falling back to long self test. This may create "
73- " timeouts with certain cars in CableCheck. Consider upgrading to at least firmware 5.00" ;
81+ EVLOG_info << " Does not support faster cable check method, falling "
82+ " back to long self test. This may create "
83+ " timeouts with certain cars in CableCheck. Consider "
84+ " upgrading to at least firmware 5.00" ;
7485 disable_faster_cable_check_mode ();
7586 std::this_thread::sleep_for (std::chrono::milliseconds (20 ));
7687 }
@@ -83,8 +94,8 @@ void isolation_monitorImpl::configure_device() {
8394
8495void isolation_monitorImpl::start_self_test () {
8596 if (last_test != TestType::ExternalTest) {
86- // Wait a bit to ensure device is ready (not processing previous read operations)
87- // This prevents conflicts with the regular reading loop
97+ // Wait a bit to ensure device is ready (not processing previous read
98+ // operations) This prevents conflicts with the regular reading loop
8899 std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
89100
90101 if (mod->r_serial_comm_hub ->call_modbus_write_multiple_registers (
@@ -139,6 +150,8 @@ bool isolation_monitorImpl::send_to_imd(const uint16_t& command, const uint16_t&
139150void isolation_monitorImpl::ready () {
140151 this ->configure_device ();
141152 bool self_test_running = false ;
153+ bool need_to_disable_device = false ;
154+ int device_disabled_timeout_s = 10 ;
142155
143156 while (true ) {
144157 read_imd_values ();
@@ -148,6 +161,7 @@ void isolation_monitorImpl::ready() {
148161 if (self_test_timeout <= 0 ) {
149162 // a time out happend
150163 self_test_started = false ;
164+ need_to_disable_device = true ;
151165 // publish failed result
152166 EVLOG_warning << " Self test timed out" ;
153167 publish_self_test_result (false );
@@ -157,6 +171,7 @@ void isolation_monitorImpl::ready() {
157171 // Self test is done
158172 self_test_running = false ;
159173 self_test_started = false ;
174+ need_to_disable_device = true ;
160175 // was it successfull? If there is no error, it was...
161176 bool result = true ;
162177 if (last_alarm == AlarmType::DeviceError) {
@@ -173,6 +188,23 @@ void isolation_monitorImpl::ready() {
173188 }
174189 if (not error_state_monitor->is_error_active (" isolation_monitor/DeviceFault" , " " )) {
175190 std::this_thread::sleep_for (std::chrono::seconds (1 ));
191+ if (need_to_disable_device) {
192+ device_disabled_timeout_s--;
193+ if (device_disabled_timeout_s <= 0 ) {
194+ need_to_disable_device = false ;
195+ device_disabled_timeout_s = 10 ;
196+ // disable the device if the configuration option is set and we are not publishing
197+ // aka we are in a measuring cycle (start called)
198+ if (not enable_publishing && config.disable_device_on_stop ) {
199+ if (not send_to_imd (3026 , 0 )) {
200+ EVLOG_error << " Can't disable the device: " << read_device_name ();
201+ } else {
202+ EVLOG_info << " Device disabled after self test since we didn't start measuring cycle "
203+ " (timeout 10s)" ;
204+ }
205+ }
206+ }
207+ }
176208 } else {
177209 std::this_thread::sleep_for (std::chrono::seconds (10 ));
178210 }
@@ -181,14 +213,36 @@ void isolation_monitorImpl::ready() {
181213
182214void isolation_monitorImpl::handle_start () {
183215 enable_publishing = true ;
216+ if (config.disable_device_on_stop ) {
217+ if (not send_to_imd (3026 , 1 )) {
218+ EVLOG_error << " Can't enable the device: " << read_device_name ();
219+ } else {
220+ EVLOG_info << " Device enabled for measurements" ;
221+ }
222+ }
184223}
185224
186225void isolation_monitorImpl::handle_stop () {
187226 enable_publishing = false ;
227+ if (config.disable_device_on_stop ) {
228+ if (not send_to_imd (3026 , 0 )) {
229+ EVLOG_error << " Can't disable the device: " << read_device_name ();
230+ } else {
231+ EVLOG_info << " Device disabled after measurements" ;
232+ }
233+ }
188234}
189235
190236void isolation_monitorImpl::handle_start_self_test (double & test_voltage_V) {
191237 EVLOG_info << " IMD Starting self-test..." ;
238+ // make sure that the device is on
239+ if (config.disable_device_on_stop ) {
240+ if (not send_to_imd (3026 , 1 )) {
241+ EVLOG_error << " Can't enable the device: " << read_device_name ();
242+ } else {
243+ EVLOG_info << " Device enabled for self test" ;
244+ }
245+ }
192246 start_self_test ();
193247}
194248
@@ -209,11 +263,13 @@ void isolation_monitorImpl::read_imd_values() {
209263
210264 isolation_monitorImpl::MeasurementValue voltage_to_earth_l1e;
211265 isolation_monitorImpl::MeasurementValue voltage_to_earth_l2e;
212- // Read Voltage to Earth L1E and L2E only if the device is not in self test mode and only it
213- // we are in a measuring cycle. We have seen that Bender sometimes is overwhelmed
266+ // Read Voltage to Earth L1E and L2E only if the device is not in self test
267+ // mode and only it we are in a measuring cycle. We have seen that Bender
268+ // sometimes is overwhelmed
214269 if ((last_test == TestType::NoTest) and (enable_publishing or config.always_publish_measurements )) {
215- // VOLTAGE_U_L1E_V (1016) and VOLTAGE_U_L2E_V (1020) are consecutive (4 registers apart)
216- // Read 8 registers starting from 1016 to get both measurements in a single operation
270+ // VOLTAGE_U_L1E_V (1016) and VOLTAGE_U_L2E_V (1020) are consecutive (4
271+ // registers apart) Read 8 registers starting from 1016 to get both
272+ // measurements in a single operation
217273 types::serial_comm_hub_requests::Result register_response =
218274 mod->r_serial_comm_hub ->call_modbus_read_holding_registers (
219275 config.imd_device_id , static_cast <int >(ImdRegisters::VOLTAGE_U_L1E_V), 8 );
@@ -271,7 +327,8 @@ void isolation_monitorImpl::read_imd_values() {
271327 valid_readings = false ;
272328 }
273329
274- // do not publish values if in error state or the device is in self test mode
330+ // do not publish values if in error state or the device is in self test
331+ // mode
275332 if (last_test == TestType::NoTest) {
276333 if (not error_state_monitor->is_error_active (" isolation_monitor/DeviceFault" , " " )) {
277334 publish_isolation_measurement (m);
0 commit comments