diff --git a/hardware/ParaTNC-HW-RevCplus-gerber-schematic-partlist.zip b/hardware/ParaTNC-HW-RevCplus-gerber-schematic-partlist.zip index a09771a..15b65d4 100644 Binary files a/hardware/ParaTNC-HW-RevCplus-gerber-schematic-partlist.zip and b/hardware/ParaTNC-HW-RevCplus-gerber-schematic-partlist.zip differ diff --git a/src/packet_tx_handler.c b/src/packet_tx_handler.c index 0111f55..a6fcc65 100644 --- a/src/packet_tx_handler.c +++ b/src/packet_tx_handler.c @@ -13,6 +13,7 @@ #include "./umb_master/umb_master.h" #include "main.h" +#include "delay.h" #define _TELEM_DESCR_INTERVAL 150 @@ -39,6 +40,29 @@ uint8_t packet_tx_telemetry_descr_counter = 145; const uint8_t packet_tx_modbus_raw_values = (uint8_t)(_TELEM_DESCR_INTERVAL - _WX_INTERVAL * (uint8_t)(_TELEM_DESCR_INTERVAL / 28)); const uint8_t packet_tx_modbus_status = (uint8_t)(_TELEM_DESCR_INTERVAL - _WX_INTERVAL * (uint8_t)(_TELEM_DESCR_INTERVAL / 8)); +uint8_t packet_tx_more_than_one = 0; + +/** + * This function is called from the inside of 'packet_rx_handler' to put an extra wait + * if more than one packet is sent from the single call to that function. This is required + * to protect against jamming own frames when any path is configured. + * + */ +inline void packet_tx_multi_per_call_handler(void) { + // if this consecutive frame sent from one call to this function + if (packet_tx_more_than_one > 0) { + // wait for previous transmission to complete + main_wait_for_tx_complete(); + + // wait for any possible retransmission to kick in + delay_fixed(1000); + + } + else { + packet_tx_more_than_one = 1; + } +} + // this shall be called in 60 seconds periods void packet_tx_handler(void) { dallas_qf_t dallas_qf = DALLAS_QF_UNKNOWN; @@ -49,6 +73,9 @@ void packet_tx_handler(void) { int ln = 0; + // set to one if more than one packet will be send from this function at once (like beacon + telemetry) + packet_tx_more_than_one = 0; + packet_tx_beacon_counter++; packet_tx_error_status_counter++; packet_tx_telemetry_counter++; @@ -62,13 +89,7 @@ void packet_tx_handler(void) { #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(ln, main_own_aprs_msg); - - main_wait_for_tx_complete(); - - } + packet_tx_multi_per_call_handler(); #endif packet_tx_error_status_counter = 0; @@ -76,16 +97,20 @@ void packet_tx_handler(void) { if (packet_tx_beacon_counter >= packet_tx_beacon_interval) { + packet_tx_multi_per_call_handler(); + beacon_send_own(); - main_wait_for_tx_complete(); - packet_tx_beacon_counter = 0; + + } #ifdef _METEO if (packet_tx_meteo_counter >= packet_tx_meteo_interval) { + packet_tx_multi_per_call_handler(); + #if defined _DALLAS_AS_TELEM // _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); @@ -94,8 +119,6 @@ void packet_tx_handler(void) { SendWXFrame(rte_wx_average_windspeed, rte_wx_max_windspeed, rte_wx_average_winddirection, rte_wx_temperature_average_dallas_valid, rte_wx_pressure_valid, rte_wx_humidity_valid); #endif - main_wait_for_tx_complete(); - #ifdef EXTERNAL_WATCHDOG GPIOA->ODR ^= GPIO_Pin_12; #endif @@ -111,6 +134,8 @@ void packet_tx_handler(void) { packet_tx_telemetry_descr_counter >= packet_tx_modbus_raw_values) { + packet_tx_multi_per_call_handler(); + telemetry_send_status_raw_values_modbus(); } @@ -120,6 +145,8 @@ void packet_tx_handler(void) { packet_tx_telemetry_descr_counter <= packet_tx_modbus_status * 2) { + packet_tx_multi_per_call_handler(); + rte_main_trigger_modbus_status = 1; } #endif @@ -131,13 +158,14 @@ void packet_tx_handler(void) { srl_start_tx(main_kiss_srl_ctx_ptr, ln); - packet_tx_meteo_kiss_counter = 0; } #endif // #ifdef _METEO if (packet_tx_telemetry_counter >= packet_tx_telemetry_interval) { + packet_tx_multi_per_call_handler(); + // if there weren't any erros related to communication with DS12B20 from previous function call if (rte_wx_error_dallas_qf == DALLAS_QF_UNKNOWN) { dallas_qf = rte_wx_current_dallas_qf; // it might be DEGRADATED so we need to copy a value directly @@ -250,8 +278,6 @@ void packet_tx_handler(void) { #endif // #endif - main_wait_for_tx_complete(); - packet_tx_telemetry_counter = 0; rx10m = 0, tx10m = 0, digi10m = 0, kiss10m = 0; @@ -261,6 +287,8 @@ void packet_tx_handler(void) { } if (packet_tx_telemetry_descr_counter >= packet_tx_telemetry_descr_interval) { + packet_tx_multi_per_call_handler(); + #ifdef _VICTRON telemetry_send_chns_description_pv(); @@ -268,13 +296,11 @@ void packet_tx_handler(void) { telemetry_send_status(&rte_pv_average, &rte_pv_last_error, rte_pv_struct.system_state); - main_wait_for_tx_complete(); #else telemetry_send_chns_description(); telemetry_send_status(); - main_wait_for_tx_complete(); #endif #if defined _UMB_MASTER umb_clear_error_history(&rte_wx_umb_context); diff --git a/system/include/modbus_rtu/rtu_configuration.h b/system/include/modbus_rtu/rtu_configuration.h index a40fc1d..5ea0df5 100644 --- a/system/include/modbus_rtu/rtu_configuration.h +++ b/system/include/modbus_rtu/rtu_configuration.h @@ -10,7 +10,7 @@ #include "station_config.h" -#ifdef _UMB_MASTER +#ifdef _MODBUS_RTU #define RTU_GETTERS_F1_NAME rte_wx_modbus_rtu_f1 #define RTU_GETTERS_F2_NAME rte_wx_modbus_rtu_f2 diff --git a/system/src/aprs/beacon.c b/system/src/aprs/beacon.c index 3fd4a64..39c2858 100644 --- a/system/src/aprs/beacon.c +++ b/system/src/aprs/beacon.c @@ -15,6 +15,7 @@ #include void beacon_send_own(void) { + main_wait_for_tx_complete(); main_own_aprs_msg_len = sprintf(main_own_aprs_msg, "=%07.2f%c%c%08.2f%c%c %s", (float)_LAT, _LATNS, _SYMBOL_F, (float)_LON, _LONWE, _SYMBOL_S, _COMMENT); main_own_aprs_msg[main_own_aprs_msg_len] = 0; ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len); @@ -31,7 +32,7 @@ void beacon_send_on_startup(void) { } void beacon_send_from_user_content(uint16_t content_ln, char* content_ptr) { - + main_wait_for_tx_complete(); ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, content_ptr, content_ln); after_tx_lock = 1; afsk_txStart(&main_afsk); diff --git a/system/src/aprs/telemetry.c b/system/src/aprs/telemetry.c index cac10a6..09c349b 100644 --- a/system/src/aprs/telemetry.c +++ b/system/src/aprs/telemetry.c @@ -150,12 +150,10 @@ void telemetry_send_values_pv ( uint8_t rx_pkts, main_own_aprs_msg[main_own_aprs_msg_len] = 0; ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len); after_tx_lock = 1; -// while(ax25.dcd == true); - + while(ax25.dcd == true); afsk_txStart(&main_afsk); - } void telemetry_send_status(ve_direct_average_struct* avg, ve_direct_error_reason* last_error, ve_direct_system_state state) { @@ -168,6 +166,8 @@ void telemetry_send_status(ve_direct_average_struct* avg, ve_direct_error_reason ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len); afsk_txStart(&main_afsk); + main_wait_for_tx_complete(); + avg->max_battery_current = 0; avg->min_battery_current = 0; *last_error = ERR_UNINITIALIZED; @@ -175,11 +175,17 @@ void telemetry_send_status(ve_direct_average_struct* avg, ve_direct_error_reason #else +/** + * Sends four frames with telemetry description + */ void telemetry_send_chns_description(void) { - while (main_afsk.sending == 1); + // wait for any RF transmission to finish + main_wait_for_tx_complete(); + // clear the output frame buffer memset(main_own_aprs_msg, 0x00, sizeof(main_own_aprs_msg)); + // prepare a frame with channel names depending on SSID #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,QNH_QF_NAVBLE,HUM_QF_NAVBLE,WIND_QF_DEGR,WIND_QF_NAVB", _CALL); #endif @@ -189,14 +195,20 @@ void telemetry_send_chns_description(void) { #if (_SSID > 9 && _SSID <= 15) main_own_aprs_msg_len = sprintf(main_own_aprs_msg, ":%s-%d:PARM.Rx10min,Tx10min,Digi10min,HostTx10m,Tempre,DS_QF_FULL,DS_QF_DEGRAD,DS_QF_NAVBLE,QNH_QF_NAVBLE,HUM_QF_NAVBLE,WIND_QF_DEGR,WIND_QF_NAVB", _CALL, _SSID); #endif + + // place a null terminator at the end main_own_aprs_msg[main_own_aprs_msg_len] = 0; + + // prepare transmission ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len); after_tx_lock = 1; + + // key up the transmitter and afsk_txStart(&main_afsk); - while (main_afsk.sending == 1); + main_wait_for_tx_complete(); - delay_fixed(1200); + delay_fixed(1500); while (main_ax25.dcd == 1); @@ -214,9 +226,9 @@ main_own_aprs_msg_len = sprintf(main_own_aprs_msg, ":%s-%d:PARM.Rx10min,Tx10min, after_tx_lock = 1; afsk_txStart(&main_afsk); - while (main_afsk.sending == 1); + main_wait_for_tx_complete(); - delay_fixed(1200); + delay_fixed(1500); while (main_ax25.dcd == 1); @@ -233,15 +245,18 @@ main_own_aprs_msg_len = sprintf(main_own_aprs_msg, ":%s-%d:PARM.Rx10min,Tx10min, ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len); after_tx_lock = 1; afsk_txStart(&main_afsk); - - while (main_afsk.sending == 1); - - delay_fixed(1200); - - while (main_ax25.dcd == 1); +// +// main_wait_for_tx_complete(); +// +// delay_fixed(1500); +// +// while (main_ax25.dcd == 1); } +/** + * This function sends telemetry values in 'typical configuration' when VICTRON VE.direct protocol parser is not enabled. + */ void telemetry_send_values( uint8_t rx_pkts, uint8_t tx_pkts, uint8_t digi_pkts, @@ -260,8 +275,13 @@ void telemetry_send_values( uint8_t rx_pkts, char anemometer_degradated = '0'; char anemometer_navble = '0'; + // temperature scaled to 0x00-0xFF range for fifth telemetry channel. + // if _METEO mode is enabled this channel sends the temperaure measure by + // internal MS5611 or BME280. If _METEO is not enabled this channel + // could send Dallas DS18B20 masurements if this is enabled in station_config.h uint8_t scaled_temperature = 0; + // get the quality factor for wind measurements if (anemometer_qf == WIND_QF_DEGRADATED) { anemometer_degradated = '1'; anemometer_navble = '0'; @@ -275,6 +295,8 @@ void telemetry_send_values( uint8_t rx_pkts, anemometer_navble = '1'; } + // scale the physical temperature and limit upper and lower boundary if + // it is required if (temperature < -50.0f) { scaled_temperature = (uint8_t)0; } @@ -285,6 +307,7 @@ void telemetry_send_values( uint8_t rx_pkts, scaled_temperature = (uint8_t)((temperature + 50.0f) * 2.0f); } + // set the quality factor for dallas DS18B20 switch (dallas_qf) { case DALLAS_QF_FULL: qf = '1', degr = '0', nav = '0'; @@ -302,6 +325,7 @@ void telemetry_send_values( uint8_t rx_pkts, break; } + // set the quality factor for pressure switch (press_qf) { case PRESSURE_QF_NOT_AVALIABLE: case PRESSURE_QF_UNKNOWN: @@ -321,32 +345,46 @@ void telemetry_send_values( uint8_t rx_pkts, humidity_qf_navaliable = '0'; } + // reset the buffer where the frame will be contructed and stored for transmission memset(main_own_aprs_msg, 0x00, sizeof(main_own_aprs_msg)); + // generate the telemetry frame from values #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, pressure_qf_navaliable, humidity_qf_navaliable, anemometer_degradated, anemometer_navble); #else 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, pressure_qf_navaliable, humidity_qf_navaliable, anemometer_degradated, anemometer_navble); #endif + // reset the frame counter if it overflowed if (telemetry_counter > 999) telemetry_counter = 0; + + // put a null terminator at the end of frame (but it should be placed there anyway) main_own_aprs_msg[main_own_aprs_msg_len] = 0; + + // wait for completing any previous transmission (afsk_txStart will exit with failure if the modem is transmitting) + main_wait_for_tx_complete(); + + // prepare transmission of the frame ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len); + + // ?? after_tx_lock = 1; + // check if RF channel is free from other transmissions and wait for the clearance if it is needed + while (main_ax25.dcd == 1); + // key up a transmitter and start transmission afsk_txStart(&main_afsk); - while (main_afsk.sending == 1); } 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); + while (main_ax25.dcd == 1); afsk_txStart(&main_afsk); - while (main_afsk.sending == 1); } @@ -359,8 +397,9 @@ void telemetry_send_status_raw_values_modbus(void) { rtu_get_raw_values_string(main_own_aprs_msg, OWN_APRS_MSG_LN, &status_ln); ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, status_ln); + while (main_ax25.dcd == 1); afsk_txStart(&main_afsk); - while (main_afsk.sending == 1); + main_wait_for_tx_complete(); #endif } diff --git a/system/src/modbus_rtu/rtu_getters.c b/system/src/modbus_rtu/rtu_getters.c index e999ed9..f6fa7c5 100644 --- a/system/src/modbus_rtu/rtu_getters.c +++ b/system/src/modbus_rtu/rtu_getters.c @@ -607,7 +607,7 @@ void rtu_get_raw_values_string(char* out, uint16_t out_buffer_ln, uint8_t* gener uint16_t f6_value = 0; int string_ln = 0; - +#ifdef _MODBUS_RTU #if defined(_RTU_SLAVE_ID_1) f1_value = RTU_GETTERS_F1_NAME.registers_values[0]; #endif @@ -631,7 +631,7 @@ void rtu_get_raw_values_string(char* out, uint16_t out_buffer_ln, uint8_t* gener #if defined(_RTU_SLAVE_ID_6) f6_value = RTU_GETTERS_F6_NAME.registers_values[0]; #endif - +#endif string_ln = snprintf(out, out_buffer_ln, ">F1V %X, F2V %X, F3V %X, F4V %X, F5V %X, F6V %X", (int) f1_value, (int) f2_value,