From 13796f63f6e82440b0760278abc1163902eef266 Mon Sep 17 00:00:00 2001 From: Mateusz Lubecki Date: Sat, 11 Apr 2020 21:37:01 +0200 Subject: [PATCH] - Storing an error code from a response on UMB offline request - Sending status on any UMB errors detected --- .cproject | 70 +++++++++-------- .gitignore | 1 + HARDWARE-README | 78 +++++++++++++++---- README | 42 +++++++--- include/main.h | 6 +- src/main.c | 3 +- src/packet_tx_handler.c | 25 ++++-- system/include/umb_master/umb_context_t.h | 2 + system/include/umb_master/umb_master.h | 1 + system/src/aprs/telemetry.c | 5 ++ system/src/aprs/wx.c | 2 + system/src/umb_master/umb_0x23_offline_data.c | 22 +++++- system/src/umb_master/umb_0x26_status.c | 2 +- system/src/umb_master/umb_channel_pool.c | 4 +- system/src/umb_master/umb_master.c | 17 +++- 15 files changed, 204 insertions(+), 76 deletions(-) diff --git a/.cproject b/.cproject index b3f2b2a..e0673bf 100644 --- a/.cproject +++ b/.cproject @@ -234,42 +234,42 @@ - diff --git a/.gitignore b/.gitignore index 8322d23..71fb9a9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ *.map station_config.h Debug/ +Release/ *.hex *.elf diff --git a/HARDWARE-README b/HARDWARE-README index 5529bf4..7c9255f 100644 --- a/HARDWARE-README +++ b/HARDWARE-README @@ -1,5 +1,9 @@ -ParaTNC Hardware Revision A -=========================== +This documentation covers few different hardware revisions. Each secion which is +specific to certain Hw Rev is marked by a letter. + +If section or point is universal across all revision it doesn't have any explicit +marking. + 1. INTRODUCTION ParaTNC is not only a software which runs on the STM32VLDISCOVERY board. Let's @@ -44,24 +48,70 @@ the controler. Then the application provided by STMicroelectronics could be used to download the HEX file into the micro. -4. CONNECTORS PINOUT (BACK EDGE) + +4. CONNECTORS PINOUT (BACK EDGE) - HW-RevA ------------------------------------------------------------------------------- -|RS485B , RS485A| |+5Vis, OneWire, AGND| |TX20, AGND, +5Vis, DTR| \r\n +|RS485B , RS485A| |+5Vsw, OneWire, AGND| |TX20, AGND, +5Vsw, DTR| \r\n |+12V, +5V, +5Vi, +3V3, AGND, GND| +Where: + RS485A and RS485B -> RS485 bus, protected by TVS (Clamping diodes) + OneWire -> Isolated one wire bus + TX20 -> Isolated data bus from LaCrosse TX20 anemometer + DTR -> Enable pin for TX20 anemometer. Permamently pulled down do AGND + +5Vi -> Isolated +5V generated by internal DC-DC converter + +5Vsw -> Switched and Isolated +5V. This line could be power cycled by + the micro if no communication will be received from either the + anemometer or one wire thermometer + +3V3 -> Main uC supply voltage regulated internally by LDO + +12V -> Main supply voltage, hooked in paralel to DC jack + AGND -> Analog GND for radio and sensors + GND -> Main ParaTNC common with DC jack + +4. CONNECTORS PINOUT (BACK EDGE) - HW-RevB +------------------------------------------------------------------------------- +|RS485B , RS485A| |+12V, AGND, +5Vi, +5Vsw, +5V, GND| |+5Vsw, OneWire, AGND| + |AGND, TX20-SPD, DIRECTION, +5Vsw| + + +Where: + RS485A and RS485B -> RS485 bus, protected by TVS (Clamping diodes) + OneWire -> Isolated one wire bus + TX20-SPD -> Isolated data bus from LaCrosse TX20 anemometer or + an windspeed input (pulse out) from mechanical anemometer + DIRECTION -> Wind direction input (pot wiper) from mechanical anemometer + + DTR -> Enable pin for TX20 anemometer. Permamently pulled down do AGND + +5Vi -> Isolated +5V generated by internal DC-DC converter + +5Vsw -> Switched and Isolated +5V. This line could be power cycled by + the micro if no communication will be received from either the + anemometer or one wire thermometer + +12V -> Main supply voltage, hooked in paralel to DC jack + AGND -> Analog GND for radio and sensors + GND -> Main ParaTNC common with DC jack + +4. CONNECTORS PINOUT (BACK EDGE) - HW-RevC +------------------------------------------------------------------------------- +|+12V, AGND, +5Vi, +5sw, OC-OUT, GND| |RS485B , RS485A| |+5Vsw, OneWire, AGND| + |AGND, TX20-SPD, DIRECTION, +5Vsw| + + Where: RS485A and RS485B -> RS485 bus, protected by TVS (Clamping diodes) OneWire -> Isolated one wire bus - TX20 -> Isolated data bus from LaCrosse TX20 anemometer - DTR -> Enable pin for TX20 anemometer. Permamently pulled down do AGND - +5Vi -> Isolated +5V generated by internal DC-DC converter - +5Vis -> Switched and Isolated +5V. This line could be power cycled by - the micro if no communication will be received from either the - anemometer or one wire thermometer - +3V3 -> Main uC supply voltage regulated internally by LDO - +12V -> Main supply voltage, hooked in paralel to DC jack - AGND -> Analog GND for radio and sensors - GND -> Main ParaTNC common with DC jack + TX20-SPD -> Isolated data bus from LaCrosse TX20 anemometer or + an windspeed input (pulse out) from mechanical anemometer + DIRECTION -> Wind direction input (pot wiper) from mechanical anemometer + +5Vi -> Isolated +5V generated by internal DC-DC converter + +5Vsw -> Switched and Isolated +5V. This line could be power cycled by + the micro if no communication will be received from either the + anemometer or one wire thermometer + OC-OUT -> Additional isolated open-collector output + +12V -> Main supply voltage, hooked in paralel to DC jack + AGND -> Analog GND for sensors (BUT NOT RADIO!!) + GND -> Main ParaTNC common with DC jack + + 5. RJ45 (RS232) pinout The RJ45 jack on the front of the PCB is NOT THE ETHERNET! Please don't plug diff --git a/README b/README index 1fce163..3107403 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -ParaTNC version DE07, March 22th 2020 +ParaTNC version DE07, April 11th 2020 ----------------------------------------- 1. INTRODUCTION @@ -12,6 +12,7 @@ ParaAPRS supports key elements of what good APRS device should have: -> Weather station with support for various meteo sensors. Full list od supported devices in point 5. -> Extensive telemetry with an information about the count of receved, transmitted and digipeated frames plus status of weather sensors. -> Support for VE.Direct serial protocol used in Victron PV charging controllers. The data about currents and voltages in the PV system are transmitted using APRS telemetry. + -> Support for UMB Binary porotocol as a mater. ParaAPRS can be used as a standalone weather station controller w/o using the radio transmission. The sw by default sends the measuremenets values @@ -20,10 +21,13 @@ by default sends the measuremenets values The ParaTNC software can run on STM32VLDISCOVERY board but it really shows it full potential od it's own dedicated hardware. This not only rub out all bodge wires required with prototype board. It gives few features which are hardly not possible without dedicated PCB - a) Three different grounds separated one from the another + a) Two different grounds separated one from the another (HW Revision A and B) + -> Controller + -> DB9 connector used to interface with a radio and Wind & Temperature sensor + aa) ONLY IN HW REVISION C: Three different grounds separated one from the another -> Controller -> DB9 connector used to interface with a radio - -> Wind and temperature sensor + -> Wind and temperature sensor including RS485 bus b) Isolated DC-DC coverter to supply sensors with an option to connect another external power supply itself c) A relay used as a watchdog to reset wind & temperature sensor in case that no communication will be received. d) RS232 serial port avaliable on Cisco style RJ45 connector. @@ -39,7 +43,7 @@ parts, separately for software and hardware. Firstly in case of software an end WITH THE NEWEST TAG marked as non-beta (like DE07). ParaTNC repository is used for daily development, so the last commit can even sometimes don't compile at all, or consist some major bugs.  -Hardware workarounds in HW Revision A, now fixed in Revision B: +Hardware workarounds in HW Revision A: -> Missing resistor in series with base of transistor T2. External 1k must be added in series with TX line -> Foortprint location of R7 (RX_LVL) and R8 (TX_LVL) helipots are 'not optimal'. If 'normal' pots are to be used the vertical version must be chosen as flat one won't fit due to neighbouring components location. @@ -49,12 +53,15 @@ Hardware workarounds in HW Revision A, now fixed in Revision B: pulse output for windspeed and potentiometer (resistance output) for direction is ongoing and should be avaliable in HW-Revision B and further SW releases. +Hardware workarounds in HW Revision B: +-> Few missing traces in micro supply. Few bodge wired needs to be added. Please look at hardware-revision-b-errata.jpg in 'hardware' + 4. LICENSING ParaTNC software and hardware are licensed under terms included to the source code in 'LICENSE' file 5. SUPPORTED METEO SENSORS a) Wind sensors: - - TX20 (not in production) + - TX20 (not in manufacturing anymore) - Davis 6410 or any another analogue anemometer with resisntance as a direction output and impulses as a windspeed WARNING: Currently support on software testing phase. Not avaliable in Hardware Revision A due to lack of circuitry - Lufft V200A/Ventus or any other UMB compatible device. @@ -74,7 +81,7 @@ Most of Victron devices have a support both for binary and text serial protocol. always enabled and a device will send from its own telegrams each couple of seconds. The communication via VE.Direct is avaliable through dedicated socket on the charging controller which is just 3.3V TTL levels UART, so no external ICs is required to connect the PV controller to an evaluation board. In the MPPT series the comm socket is located on the bottom -side of the chargin controller below the fuse holder. +side of the charging controller below the fuse holder. Exact pinout of the VE.Direct comm socket is as follows, assuming that terminal screws are facing down: -> Ground @@ -107,7 +114,8 @@ DS_QF_DEGRAD - Quality Factor for One Wire temperature sensor is DEGRADATED DS_QF_NAVBLE - Quality Factor for One Wire temperature sensor is NOT AVALIABLE MS_QF_NAVBLE - Quality Factor for MS5611 pressure sensor ins NOT AVALIABLE DHT_QF_NAVBLE - Quality Factor for DHT22 humidity & temperature is NOT AVALIABLE -TX20_SLEW - LaCrosse TX20 anemometer driver dropped at least one measuremenet due to excesive slew rate. +WIND_QF_DEGR - LaCrosse TX20 anemometer driver dropped at least one measuremenet due to excesive slew rate. +WIND_QF_NAVB - Explantion of Quality Factors: Each measuremenets signal is kept along with the Quality Factor which represents the sensor condition and value validity. If the QF is set to FULL it means that no communication problems happened between one telemetry cycle and another @@ -122,14 +130,27 @@ difference between two consecutive measuremenets excedes hardcoded limit (9m/s) At this point ParaTNC is delivered in form of source code which needs to be manually compiled by the user. Most options are configured by #define in './include/station_config.h' and then hard-coded by the C preprocessor during compilation. An example file consist a lot of comments which explains what is what, but generally an user can choose there which mode should be enabled: + + Hardware Revision A: -> KISS TNC -> KISS TNC + DIGI -> KISS TNC + DIGI + METEO -> VICTRON + DIGI + METEO -> VICTRON + DIGI -As You see there is no option to use a KISS modem and the VE.Direct protocol in the same time as the software support only -one UART in the micro. The KISS modem runs on default speed of 9600 bps. Telemetry is enabled by default and it will + Hardware Revision B & C: + -> KISS TNC + -> KISS TNC + DIGI + -> KISS TNC + DIGI + METEO + -> KISS TNC + VICTRON + DIGI + METEO + -> KISS TNC + VICTRON + DIGI + -> KISS TNC + UMB-MASTER + DIGI + METEO + +In Hardware Revision A there is no option to use a KISS modem and the VE.Direct protocol in the same time as only +one UART in the micro is used and handled by software. In hardware revisions B and C two UARTS are used and handled by +the software. The KISS modem is always enabled and avaliable on RJ45 Cisco style jack. + +The KISS modem runs on default speed of 9600 bps. Telemetry is enabled by default and it will trasmit channels values each 10 minutes and full channel descriptions each 70 minutes. @@ -150,7 +171,8 @@ When everything is installed the reporistory can be cloned to local harddrive by The example config file is named 'station_config_example.h' and should be edited and then renamed to 'station_config.h'. When everything is configured it is a time to go to 'Debug' directory and invoke command 'make' there. The source should be automatically compiled and new hex file 'ParaTNC.hex' -should appear in the same directory. +should appear in the same directory. Please do not use Release configuration!! It is screwed and produces an +application which doesn't works exactly as it should because of optimalization configuration. Finished building target: ParaTNC.elf diff --git a/include/main.h b/include/main.h index 231cf3b..c82ea52 100644 --- a/include/main.h +++ b/include/main.h @@ -4,7 +4,7 @@ #include "aprs/ax25.h" #define SW_VER "DE07" -#define SW_DATE "10042020" +#define SW_DATE "11042020" #define SYSTICK_TICKS_PER_SECONDS 100 #define SYSTICK_TICKS_PERIOD 10 @@ -31,6 +31,10 @@ extern unsigned short rx10m, tx10m, digi10m, kiss10m; uint16_t main_get_adc_sample(void); +inline uint32_t main_get_master_time(void) { + return master_time; +} + inline void main_wait_for_tx_complete(void) { while(main_afsk.sending == 1); } diff --git a/src/main.c b/src/main.c index 461699c..02b136c 100644 --- a/src/main.c +++ b/src/main.c @@ -131,8 +131,7 @@ static void message_callback(struct AX25Msg *msg) { } int -main(int argc, char* argv[]) -{ +main(int argc, char* argv[]){ // Send a greeting to the trace device (skipped on Release). // trace_puts("Hello ARM World!"); diff --git a/src/packet_tx_handler.c b/src/packet_tx_handler.c index c3aa46c..dd00159 100644 --- a/src/packet_tx_handler.c +++ b/src/packet_tx_handler.c @@ -17,6 +17,9 @@ uint8_t packet_tx_beacon_interval = _BCN_INTERVAL; uint8_t packet_tx_beacon_counter = 0; +uint8_t packet_tx_error_status_interval = 2; +uint8_t packet_tx_error_status_counter = 0; + #ifdef _METEO uint8_t packet_tx_meteo_interval = _WX_INTERVAL; uint8_t packet_tx_meteo_counter = 0; @@ -38,6 +41,7 @@ void packet_tx_handler(void) { uint16_t ln = 0; packet_tx_beacon_counter++; + packet_tx_error_status_counter++; packet_tx_telemetry_counter++; packet_tx_telemetry_descr_counter++; #ifdef _METEO @@ -45,17 +49,21 @@ void packet_tx_handler(void) { packet_tx_meteo_kiss_counter++; #endif -#if defined(_UMB_MASTER) - umb_construct_status_str(&rte_wx_umb_context, main_own_aprs_msg, sizeof(main_own_aprs_msg), &ln, master_time); + if (packet_tx_error_status_counter >= packet_tx_error_status_interval) { + #if defined(_UMB_MASTER) + umb_construct_status_str(&rte_wx_umb_context, main_own_aprs_msg, sizeof(main_own_aprs_msg), &ln, master_time); - // if there is anything to send - if (ln > 0) { - beacon_send_from_user_content(sizeof(main_own_aprs_msg), main_own_aprs_msg); + // if there is anything to send + if (ln > 0) { + beacon_send_from_user_content(ln, main_own_aprs_msg); - main_wait_for_tx_complete(); + main_wait_for_tx_complete(); + } + #endif + + packet_tx_error_status_counter = 0; } -#endif if (packet_tx_beacon_counter >= packet_tx_beacon_interval) { @@ -73,7 +81,7 @@ void packet_tx_handler(void) { // _DALLAS_AS_TELEM wil be set during compilation wx packets will be filled by temperature from MS5611 sensor SendWXFrame(&VNAME, rte_wx_temperature_valid, rte_wx_pressure_valid); #else - SendWXFrame(rte_wx_average_windspeed, rte_wx_max_windspeed, rte_wx_average_winddirection, rte_wx_temperature_average_dallas_valid, rte_wx_pressure_valid); + SendWXFrame(rte_wx_average_windspeed, rte_wx_max_windspeed, rte_wx_average_winddirection, rte_wx_temperature_average_dallas_valid, rte_wx_pressure_valid); #endif @@ -174,6 +182,7 @@ void packet_tx_handler(void) { main_wait_for_tx_complete(); #endif + umb_clear_error_history(&rte_wx_umb_context); packet_tx_telemetry_descr_counter = 0; } diff --git a/system/include/umb_master/umb_context_t.h b/system/include/umb_master/umb_context_t.h index dd15b72..f392ef0 100644 --- a/system/include/umb_master/umb_context_t.h +++ b/system/include/umb_master/umb_context_t.h @@ -22,6 +22,8 @@ typedef struct umb_context_t { uint8_t nok_error_it; + uint16_t last_fault_channel; + uint32_t time_of_last_nok; uint32_t time_of_last_comms_timeout; diff --git a/system/include/umb_master/umb_master.h b/system/include/umb_master/umb_master.h index d90b6ab..ff81a3e 100644 --- a/system/include/umb_master/umb_master.h +++ b/system/include/umb_master/umb_master.h @@ -26,6 +26,7 @@ umb_retval_t umb_pooling_handler(umb_context_t* ctx, umb_call_reason_t r, uint32 umb_retval_t umb_master_callback(umb_frame_t* frame, umb_context_t* ctx); umb_qf_t umb_get_current_qf(umb_context_t* ctx, uint32_t master_time); void umb_construct_status_str(umb_context_t* ctx, char* out_buffer, uint16_t buffer_size, uint16_t* status_string_ln, uint32_t master_time); +void umb_clear_error_history(umb_context_t* ctx); uint16_t umb_get_windspeed(void); uint16_t umb_get_windgusts(void); diff --git a/system/src/aprs/telemetry.c b/system/src/aprs/telemetry.c index 9f85c47..42fc5bd 100644 --- a/system/src/aprs/telemetry.c +++ b/system/src/aprs/telemetry.c @@ -176,6 +176,8 @@ void telemetry_send_status(ve_direct_average_struct* avg, ve_direct_error_reason void telemetry_send_chns_description(void) { while (main_afsk.sending == 1); + memset(main_own_aprs_msg, 0x00, sizeof(main_own_aprs_msg)); + #if (_SSID == 0) main_own_aprs_msg_len = sprintf(main_own_aprs_msg, ":%s :PARM.Rx10min,Tx10min,Digi10min,HostTx10m,Tempre,DS_QF_FULL,DS_QF_DEGRAD,DS_QF_NAVBLE,MS_QF_NAVBLE,DHT_QF_NAVBLE,WIND_QF_DEGR,WIND_QF_NAVB", _CALL); #endif @@ -309,6 +311,8 @@ void telemetry_send_values( uint8_t rx_pkts, dht_qf_navaliable = '0'; } + memset(main_own_aprs_msg, 0x00, sizeof(main_own_aprs_msg)); + #ifdef _DALLAS_AS_TELEM main_own_aprs_msg_len = sprintf(main_own_aprs_msg, "T#%03d,%03d,%03d,%03d,%03d,%03d,%c%c%c%c%c%c%c0", telemetry_counter++, rx_pkts, tx_pkts, digi_pkts, kiss_pkts, scaled_temperature, qf, degr, nav, ms_qf_navaliable, dht_qf_navaliable, anemometer_degradated, anemometer_navble); #else @@ -327,6 +331,7 @@ void telemetry_send_values( uint8_t rx_pkts, } void telemetry_send_status(void) { + memset(main_own_aprs_msg, 0x00, sizeof(main_own_aprs_msg)); main_own_aprs_msg_len = sprintf(main_own_aprs_msg, ">ParaTNC firmware %s-%s by SP8EBC", SW_VER, SW_DATE); ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len); afsk_txStart(&main_afsk); diff --git a/system/src/aprs/wx.c b/system/src/aprs/wx.c index 553055d..fc96d30 100644 --- a/system/src/aprs/wx.c +++ b/system/src/aprs/wx.c @@ -13,6 +13,8 @@ #include "station_config.h" +#include + void SendWXFrame(uint16_t windspeed, uint16_t windgusts, uint16_t winddirection, float temperatura, float cisnienie) { diff --git a/system/src/umb_master/umb_0x23_offline_data.c b/system/src/umb_master/umb_0x23_offline_data.c index ea7ff5c..830a6f5 100644 --- a/system/src/umb_master/umb_0x23_offline_data.c +++ b/system/src/umb_master/umb_0x23_offline_data.c @@ -9,6 +9,7 @@ #include "../umb_master/umb_0x23_offline_data.h" #include "station_config.h" #include "rte_wx.h" +#include "main.h" #define UNSIGNED_CHAR 0x10 #define SIGNED_CHAR 0x11 @@ -72,10 +73,11 @@ umb_retval_t umb_0x23_offline_data_callback(umb_frame_t* frame, umb_context_t* c // temporary float point buffer to handle this type float temp = 0.0f; + // fetch the channel number + channel = frame->payload[1] | (frame->payload[2] << 8); + // check if status is OK if (status == 0x00) { - // fetch the channel number - channel = frame->payload[1] | (frame->payload[2] << 8); // fetch the value type type = frame->payload[3]; @@ -168,6 +170,22 @@ umb_retval_t umb_0x23_offline_data_callback(umb_frame_t* frame, umb_context_t* c // if not stop further processing ctx->state = UMB_STATUS_ERROR; + ctx->last_fault_channel = channel; + + // copy current error code to the buffer + ctx->nok_error_codes[ctx->nok_error_it] = status; + + // move the iterator through the buffer + ctx->nok_error_it++; + + // check if and end of the buffer is reach here + ctx->nok_error_it %= UMB_CONTEXT_ERR_HISTORY_LN; + + // trigger the status frame + ctx->trigger_status_msg = 1; + + ctx->time_of_last_nok = main_get_master_time(); + output = UMB_NOK_STATUS_GOT_WITH_RESP; } diff --git a/system/src/umb_master/umb_0x26_status.c b/system/src/umb_master/umb_0x26_status.c index 924cdb8..a0c8e16 100644 --- a/system/src/umb_master/umb_0x26_status.c +++ b/system/src/umb_master/umb_0x26_status.c @@ -64,7 +64,7 @@ umb_retval_t umb_0x26_status_callback(umb_frame_t* frame, umb_context_t* ctx) { } // storing the time when last error code will be stored - ctx->time_of_last_nok = master_time; + ctx->time_of_last_nok = main_get_master_time(); // trigger the status message with a content of fault store ctx->trigger_status_msg = 1; diff --git a/system/src/umb_master/umb_channel_pool.c b/system/src/umb_master/umb_channel_pool.c index 78c0f56..ed2e439 100644 --- a/system/src/umb_master/umb_channel_pool.c +++ b/system/src/umb_master/umb_channel_pool.c @@ -11,13 +11,13 @@ void umb_channel_pool(umb_frame_t *frame, umb_context_t *ctx) { #if defined(_UMB_MASTER) - if (ctx->channel_number_it > UMB_CHANNELS_STORAGE_CAPAC) + if (ctx->channel_number_it >= UMB_CHANNELS_STORAGE_CAPAC) ctx->channel_number_it = 0; uint16_t curr_chn = ctx->channel_numbers[ctx->channel_number_it]; ctx->current_channel = curr_chn; - if (curr_chn != 0xFFFFu) { + if (curr_chn != 0xFFFFu && curr_chn != 0x0u) { umb_0x23_offline_data_request(frame, ctx, curr_chn); } diff --git a/system/src/umb_master/umb_master.c b/system/src/umb_master/umb_master.c index 4a94d1b..4b593a3 100644 --- a/system/src/umb_master/umb_master.c +++ b/system/src/umb_master/umb_master.c @@ -39,6 +39,8 @@ void umb_master_init(umb_context_t* ctx) { ctx->time_of_last_successful_comms = 0; + ctx->last_fault_channel = 0; + for (int i = 0; i < UMB_CONTEXT_ERR_HISTORY_LN; i++) { ctx->nok_error_codes[i] = 0; } @@ -394,10 +396,11 @@ void umb_construct_status_str(umb_context_t* ctx, char* out_buffer, uint16_t buf for (int i = 0; i < buffer_size; i++) out_buffer[i] = '\0'; - string_ln = snprintf(out_buffer, buffer_size, ">UMB Status: [TIME= 0x%x, TLN= 0x%x, TLCT= 0x%x, ERRS= [", + string_ln = snprintf(out_buffer, buffer_size, ">UMB Status: [TIME= 0x%x, TLN= 0x%x, TLCT= 0x%x, LFC= %d ERRS= [", (int)master_time, (int)local_tln, - (int)local_tlct); + (int)local_tlct, + (int)ctx->last_fault_channel); for (int i = 0; i < UMB_CONTEXT_ERR_HISTORY_LN; i++ ) { // print the string representation of the error code into the buffer sprintf_out = snprintf(local, 11, "0x%02x, ", ctx->nok_error_codes[i]); @@ -417,6 +420,16 @@ void umb_construct_status_str(umb_context_t* ctx, char* out_buffer, uint16_t buf *status_string_ln = string_ln; } +void umb_clear_error_history(umb_context_t* ctx) { + ctx->last_fault_channel = 0; + + for (int i = 0; i < UMB_CONTEXT_ERR_HISTORY_LN; i++) { + ctx->nok_error_codes[i] = 0; + } + + ctx->trigger_status_msg = 0; +} + uint16_t umb_get_windspeed(void) {