kopia lustrzana https://github.com/SP8EBC/ParaTNC
Porównaj commity
3 Commity
d5614dbf53
...
428f6a2360
Autor | SHA1 | Data |
---|---|---|
Mateusz Lubecki | 428f6a2360 | |
Mateusz Lubecki | 15829704be | |
Mateusz Lubecki | 9b52612eec |
|
@ -12,6 +12,7 @@ C_SRCS += \
|
|||
../system/src/aprs/crc.c \
|
||||
../system/src/aprs/dac.c \
|
||||
../system/src/aprs/digi.c \
|
||||
../system/src/aprs/message.c \
|
||||
../system/src/aprs/status.c \
|
||||
../system/src/aprs/telemetry.c \
|
||||
../system/src/aprs/wx.c
|
||||
|
@ -25,6 +26,7 @@ OBJS += \
|
|||
./system/src/aprs/crc.o \
|
||||
./system/src/aprs/dac.o \
|
||||
./system/src/aprs/digi.o \
|
||||
./system/src/aprs/message.o \
|
||||
./system/src/aprs/status.o \
|
||||
./system/src/aprs/telemetry.o \
|
||||
./system/src/aprs/wx.o
|
||||
|
@ -38,6 +40,7 @@ C_DEPS += \
|
|||
./system/src/aprs/crc.d \
|
||||
./system/src/aprs/dac.d \
|
||||
./system/src/aprs/digi.d \
|
||||
./system/src/aprs/message.d \
|
||||
./system/src/aprs/status.d \
|
||||
./system/src/aprs/telemetry.d \
|
||||
./system/src/aprs/wx.d
|
||||
|
|
|
@ -58,6 +58,6 @@
|
|||
<listEntry value="4"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <memoryBlockExpressionList context="Context string"/> "/>
|
||||
<stringAttribute key="org.eclipse.embedcdt.debug.gdbjtag.core.PERIPHERALS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <peripherals> <peripheral name="IWDG"/> <peripheral name="DBGMCU"/> <peripheral name="USART3"/> </peripherals> "/>
|
||||
<stringAttribute key="org.eclipse.embedcdt.debug.gdbjtag.core.PERIPHERALS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <peripherals> <peripheral name="IWDG"/> <peripheral name="DBGMCU"/> <peripheral name="RTC"/> </peripherals> "/>
|
||||
<stringAttribute key="process_factory_id" value="org.eclipse.cdt.dsf.gdb.GdbProcessFactory"/>
|
||||
</launchConfiguration>
|
||||
|
|
Plik binarny nie jest wyświetlany.
|
@ -50,7 +50,7 @@ void aprsis_init(
|
|||
aprsis_return_t aprsis_connect_and_login(const char * address, uint8_t address_ln, uint16_t port, uint8_t auto_send_beacon);
|
||||
aprsis_return_t aprsis_connect_and_login_default(uint8_t auto_send_beacon);
|
||||
sim800_return_t aprsis_disconnect(void);
|
||||
void aprsis_receive_callback(srl_context_t* srl_context);
|
||||
//void aprsis_receive_callback(srl_context_t* srl_context);
|
||||
void aprsis_check_alive(void);
|
||||
int aprsis_check_connection_attempt_alive(void);
|
||||
|
||||
|
|
|
@ -81,6 +81,11 @@ void backup_reg_set_telemetry(uint16_t);
|
|||
void backup_reg_get_packet_counters(uint8_t * beacon_counter, uint8_t * meteo_counter, uint8_t * meteo_gsm_counter);
|
||||
void backup_reg_set_packet_counters(uint8_t beacon_counter, uint8_t meteo_counter, uint8_t meteo_gsm_counter);
|
||||
|
||||
void backup_reg_increment_aprsis_check_reset(void);
|
||||
void backup_reg_increment_weather_measurements_check_reset(void);
|
||||
void backup_reg_increment_dallas_degraded_reset(void);
|
||||
void backup_reg_increment_is_rtc_ok_check_reset(void);
|
||||
|
||||
|
||||
|
||||
#endif /* BACKUP_REGISTERS_H_ */
|
||||
|
|
|
@ -25,10 +25,6 @@
|
|||
* $WIZ$ type = "int"
|
||||
* $WIZ$ min = 1
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
//extern uint8_t kiss_txdelay;
|
||||
//#define CONFIG_AFSK_PREAMBLE_LEN (kiss_txdelay*10UL)
|
||||
#define CONFIG_AFSK_PREAMBLE_LEN 400UL /// 300
|
||||
|
||||
/**
|
||||
|
@ -36,8 +32,6 @@
|
|||
* $WIZ$ type = "int"
|
||||
* $WIZ$ min = 1
|
||||
*/
|
||||
//extern uint8_t kiss_txtail;
|
||||
//#define CONFIG_AFSK_TRAILER_LEN (kiss_txtail*10UL)
|
||||
#define CONFIG_AFSK_TRAILER_LEN 50UL
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* misc_config.h
|
||||
* Misc configuration which doesn't match to any other place
|
||||
*
|
||||
*
|
||||
* Created on: Apr 15, 2024
|
||||
* Author: mateusz
|
||||
*/
|
||||
|
||||
#ifndef ETC_MISC_CONFIG_H_
|
||||
#define ETC_MISC_CONFIG_H_
|
||||
|
||||
#define RTE_WX_PROBLEMS_MAX_THRESHOLD 10
|
||||
|
||||
|
||||
|
||||
#endif /* ETC_MISC_CONFIG_H_ */
|
|
@ -45,7 +45,7 @@
|
|||
/**
|
||||
* Do not uncomment this on production devices
|
||||
*/
|
||||
//#define INHIBIT_CUTOFF
|
||||
#define INHIBIT_CUTOFF
|
||||
|
||||
/**
|
||||
* Intermediate STOP2 cycle lenght within L7 or L6 mode.
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#define SYSTICK_TICKS_PER_SECONDS 100
|
||||
#define SYSTICK_TICKS_PERIOD 10
|
||||
|
||||
#define INTERNAL_WATCHDOG
|
||||
#define EXTERNAL_WATCHDOG
|
||||
//#define INTERNAL_WATCHDOG
|
||||
//#define EXTERNAL_WATCHDOG
|
||||
|
||||
#define PWR_SWITCH_BOTH
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ extern "C"
|
|||
void rte_wx_init(void);
|
||||
void rte_wx_update_last_measuremenet_timers(uint16_t measurement_type);
|
||||
void rte_wx_reset_last_measuremenet_timers(uint16_t measurement_type);
|
||||
int8_t rte_wx_check_weather_measurements(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#ifndef SOFTWARE_VERSION_H_
|
||||
#define SOFTWARE_VERSION_H_
|
||||
|
||||
#define SW_VER "EB04"
|
||||
#define SW_DATE "10042024"
|
||||
#define SW_VER "EB05"
|
||||
#define SW_DATE "18042024"
|
||||
#define SW_KISS_PROTO "B"
|
||||
|
||||
extern const char software_version_str[5];
|
||||
|
|
|
@ -56,7 +56,7 @@ ENTRY(Reset_Handler)
|
|||
_estack = 0x20018000; /* end of RAM */
|
||||
/* Generate a link error if heap and stack don't fit into RAM */
|
||||
_Min_Heap_Size = 0x200; /* required amount of heap */
|
||||
_Min_Stack_Size = 0x400; /* required amount of stack */
|
||||
_Min_Stack_Size = 0x800; /* required amount of stack */
|
||||
|
||||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
|
|
96
src/aprsis.c
96
src/aprsis.c
|
@ -9,6 +9,7 @@
|
|||
#include "etc/aprsis_config.h"
|
||||
#include "text.h"
|
||||
#include "aprs/status.h"
|
||||
#include "aprs/message.h"
|
||||
|
||||
#include "gsm/sim800c.h"
|
||||
#include "gsm/sim800c_poolers.h"
|
||||
|
@ -19,6 +20,12 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
#define STATIC
|
||||
#else
|
||||
#define STATIC static
|
||||
#endif
|
||||
|
||||
srl_context_t * aprsis_serial_port;
|
||||
|
||||
/**
|
||||
|
@ -180,6 +187,72 @@ char aprsis_login_string_reveived[APRSIS_LOGIN_STRING_RECEIVED_LN];
|
|||
*/
|
||||
#define MAXIMUM_CALL_SSID_DASH_LN 10
|
||||
|
||||
/**
|
||||
* Checks if data in a buffer contains APRS message
|
||||
* @param message
|
||||
* @param message_ln
|
||||
* @return position at which content of message starts
|
||||
*/
|
||||
STATIC int aprsis_check_is_message(const uint8_t * const message, const uint16_t message_ln) {
|
||||
// example message
|
||||
// Details:"SP8EBC>APX216,TCPIP*,qAC,NINTH::SR9WXZ :tedt{0s}\r\n", '\0' <repeats 715 times>
|
||||
|
||||
// go through a buffer and look for double ':'
|
||||
|
||||
int message_start_position = 0;
|
||||
|
||||
for (int i = 0; i < message_ln; i++) {
|
||||
const uint8_t * this_character = message + i;
|
||||
|
||||
const uint8_t * next_character = message + i + 1;
|
||||
|
||||
if (*this_character == 0x00) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*this_character == ':') && (*next_character == ':')) {
|
||||
message_start_position = i + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return message_start_position;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param srl_context
|
||||
*/
|
||||
STATIC void aprsis_receive_callback(srl_context_t* srl_context) {
|
||||
|
||||
const uint8_t * buffer = srl_get_rx_buffer(srl_context);
|
||||
|
||||
const uint16_t message_ln = srl_context->srl_rx_bytes_counter;
|
||||
|
||||
// if something was actually received
|
||||
if (srl_context->srl_rx_state == SRL_RX_DONE) {
|
||||
// check if this is keepalive message
|
||||
if (*buffer == '#') {
|
||||
aprsis_last_keepalive_ts = main_get_master_time();
|
||||
|
||||
aprsis_last_keepalive_long_ts = main_get_master_time();
|
||||
|
||||
aprsis_keepalive_received_counter++;
|
||||
|
||||
gsm_sim800_tcpip_async_receive(aprsis_serial_port, aprsis_gsm_modem_state, 0, 61000, aprsis_receive_callback);
|
||||
}
|
||||
else if (aprsis_check_is_message(buffer, message_ln) == 1) {
|
||||
|
||||
}
|
||||
else {
|
||||
aprsis_another_received_counter++;
|
||||
|
||||
gsm_sim800_tcpip_async_receive(aprsis_serial_port, aprsis_gsm_modem_state, 0, 61000, aprsis_receive_callback);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void aprsis_init(
|
||||
srl_context_t * context,
|
||||
gsm_sim800_state_t * gsm_modem_state,
|
||||
|
@ -394,29 +467,6 @@ sim800_return_t aprsis_disconnect(void) {
|
|||
return out;
|
||||
}
|
||||
|
||||
void aprsis_receive_callback(srl_context_t* srl_context) {
|
||||
|
||||
// if something was actually received
|
||||
if (srl_context->srl_rx_state == SRL_RX_DONE) {
|
||||
// check if this is keepalive message
|
||||
if (*(srl_get_rx_buffer(srl_context)) == '#') {
|
||||
aprsis_last_keepalive_ts = main_get_master_time();
|
||||
|
||||
aprsis_last_keepalive_long_ts = main_get_master_time();
|
||||
|
||||
aprsis_keepalive_received_counter++;
|
||||
|
||||
gsm_sim800_tcpip_async_receive(aprsis_serial_port, aprsis_gsm_modem_state, 0, 61000, aprsis_receive_callback);
|
||||
}
|
||||
else {
|
||||
aprsis_another_received_counter++;
|
||||
|
||||
gsm_sim800_tcpip_async_receive(aprsis_serial_port, aprsis_gsm_modem_state, 0, 61000, aprsis_receive_callback);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pooler function which check periodically if APRS-IS connection is alive.
|
||||
*/
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define REGISTER_COUNTERS RTC->BKP4R
|
||||
#define REGISTER_LAST_SLTIM RTC->BKP6R
|
||||
#define REGISTER_PACKET_COUNTERS RTC->BKP7R
|
||||
#define REGISTER_RESET_CHECK_FAIL RTC->BKP8R
|
||||
#endif
|
||||
|
||||
#define BACKUP_REG_INHIBIT_PWR_SWITCH_PERIODIC_H 1u
|
||||
|
@ -39,6 +40,7 @@
|
|||
// 5 -> monitor
|
||||
// 6 -> last sleep time
|
||||
// 7 -> weather and telemetry timers & counters
|
||||
// 8 -> counters of resets caused by validation checks failures
|
||||
|
||||
// 7th register map
|
||||
// xxxxyyAA - telemetry frames counter
|
||||
|
@ -47,6 +49,12 @@
|
|||
// xxAAyyyy - value of packet_tx_beacon_counter
|
||||
// Axxxyyyy - checksum
|
||||
|
||||
// 8th register map
|
||||
// xxxxyyAA - resets caused by 'aprsis_check_connection_attempt_alive()'
|
||||
// xxxxAAyy - resets caused by 'rte_wx_check_weather_measurements()'
|
||||
// xxAAyyyy - resets caused by value of 'rte_wx_dallas_degraded_counter'
|
||||
// AAxxyyyy - resets caused by 'system_is_rtc_ok()'
|
||||
|
||||
static void backup_reg_unclock(void) {
|
||||
// enable access to backup domain
|
||||
PWR->CR1 |= PWR_CR1_DBP;
|
||||
|
@ -421,7 +429,10 @@ uint32_t backup_reg_get_last_sleep_duration(void) {
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param in
|
||||
*/
|
||||
void backup_reg_set_last_sleep_duration(uint32_t in) {
|
||||
#ifdef PARAMETEO
|
||||
backup_reg_unclock();
|
||||
|
@ -512,6 +523,12 @@ void backup_reg_set_telemetry(uint16_t in) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param beacon_counter
|
||||
* @param meteo_counter
|
||||
* @param meteo_gsm_counter
|
||||
*/
|
||||
void backup_reg_get_packet_counters(uint8_t * beacon_counter, uint8_t * meteo_counter, uint8_t * meteo_gsm_counter) {
|
||||
#ifdef PARAMETEO
|
||||
uint32_t reg_value = REGISTER_PACKET_COUNTERS;
|
||||
|
@ -539,6 +556,12 @@ void backup_reg_get_packet_counters(uint8_t * beacon_counter, uint8_t * meteo_co
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param beacon_counter
|
||||
* @param meteo_counter
|
||||
* @param meteo_gsm_counter
|
||||
*/
|
||||
void backup_reg_set_packet_counters(uint8_t beacon_counter, uint8_t meteo_counter, uint8_t meteo_gsm_counter) {
|
||||
#ifdef PARAMETEO
|
||||
volatile uint32_t reg_value = REGISTER_PACKET_COUNTERS;
|
||||
|
@ -572,3 +595,95 @@ void backup_reg_set_packet_counters(uint8_t beacon_counter, uint8_t meteo_counte
|
|||
|
||||
#endif
|
||||
}
|
||||
|
||||
void backup_reg_increment_aprsis_check_reset(void) {
|
||||
// REGISTER_RESET_CHECK_FAIL
|
||||
volatile uint32_t reg_value = REGISTER_RESET_CHECK_FAIL;
|
||||
|
||||
// get existing value
|
||||
uint8_t counter = (uint8_t)(reg_value & 0xFFU);
|
||||
|
||||
// increment it
|
||||
counter++;
|
||||
|
||||
// clear existing value from register
|
||||
reg_value &= 0xFFFFFF00U;
|
||||
|
||||
// add incremented counter value
|
||||
reg_value |= counter;
|
||||
|
||||
backup_reg_unclock();
|
||||
|
||||
REGISTER_RESET_CHECK_FAIL = reg_value;
|
||||
|
||||
backup_reg_lock();
|
||||
}
|
||||
|
||||
void backup_reg_increment_weather_measurements_check_reset(void) {
|
||||
// REGISTER_RESET_CHECK_FAIL
|
||||
volatile uint32_t reg_value = REGISTER_RESET_CHECK_FAIL;
|
||||
|
||||
// get existing value
|
||||
uint8_t counter = (uint8_t)((reg_value & 0xFF00U) >> 8U);
|
||||
|
||||
// increment it
|
||||
counter++;
|
||||
|
||||
// clear existing value from register
|
||||
reg_value &= 0xFFFF00FFU;
|
||||
|
||||
// add incremented counter value
|
||||
reg_value |= ((uint32_t)counter << 8U);
|
||||
|
||||
backup_reg_unclock();
|
||||
|
||||
REGISTER_RESET_CHECK_FAIL = reg_value;
|
||||
|
||||
backup_reg_lock();
|
||||
}
|
||||
|
||||
void backup_reg_increment_dallas_degraded_reset(void) {
|
||||
// REGISTER_RESET_CHECK_FAIL
|
||||
volatile uint32_t reg_value = REGISTER_RESET_CHECK_FAIL;
|
||||
|
||||
// get existing value
|
||||
uint8_t counter = (uint8_t)((reg_value & 0xFF0000U) >> 16U);
|
||||
|
||||
// increment it
|
||||
counter++;
|
||||
|
||||
// clear existing value from register
|
||||
reg_value &= 0xFF00FFFFU;
|
||||
|
||||
// add incremented counter value
|
||||
reg_value |= ((uint32_t)counter << 16U);
|
||||
|
||||
backup_reg_unclock();
|
||||
|
||||
REGISTER_RESET_CHECK_FAIL = reg_value;
|
||||
|
||||
backup_reg_lock();
|
||||
}
|
||||
|
||||
void backup_reg_increment_is_rtc_ok_check_reset(void) {
|
||||
// REGISTER_RESET_CHECK_FAIL
|
||||
volatile uint32_t reg_value = REGISTER_RESET_CHECK_FAIL;
|
||||
|
||||
// get existing value
|
||||
uint8_t counter = (uint8_t)((reg_value & 0xFF000000U) >> 24U);
|
||||
|
||||
// increment it
|
||||
counter++;
|
||||
|
||||
// clear existing value from register
|
||||
reg_value &= 0x00FFFFFFU;
|
||||
|
||||
// add incremented counter value
|
||||
reg_value |= ((uint32_t)counter << 24U);
|
||||
|
||||
backup_reg_unclock();
|
||||
|
||||
REGISTER_RESET_CHECK_FAIL = reg_value;
|
||||
|
||||
backup_reg_lock();
|
||||
}
|
||||
|
|
23
src/main.c
23
src/main.c
|
@ -122,8 +122,8 @@
|
|||
// 3 -> controller configuration status
|
||||
// 4 -> wakeup events MSB, sleep events LSB
|
||||
// 5 -> monitor
|
||||
// 6 -> weather and telemetry timers & counters
|
||||
|
||||
// 6 -> last sleep time
|
||||
// 7 -> weather and telemetry timers & counters
|
||||
|
||||
#define CONFIG_FIRST_RESTORED (1)
|
||||
#define CONFIG_FIRST_FAIL_RESTORING (1 << 1)
|
||||
|
@ -1485,16 +1485,31 @@ int main(int argc, char* argv[]){
|
|||
if ((main_config_data_gsm->aprsis_enable != 0) && (main_config_data_mode->gsm == 1)) {
|
||||
|
||||
if (pwr_save_is_currently_cutoff() == 0) {
|
||||
// this checks when APRS-IS was alive last time and when any packet
|
||||
// has been sent to the server.
|
||||
const int i_am_ok_with_aprsis = aprsis_check_connection_attempt_alive();
|
||||
|
||||
if (i_am_ok_with_aprsis != 0) {
|
||||
|
||||
// increase counter stored in RTC backup register
|
||||
backup_reg_increment_aprsis_check_reset();
|
||||
|
||||
// trigger a restart
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rte_wx_check_weather_measurements() == 0) {
|
||||
backup_reg_increment_weather_measurements_check_reset();
|
||||
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
if (rte_wx_dallas_degraded_counter > DALLAS_MAX_LIMIT_OF_DEGRADED) {
|
||||
backup_reg_increment_dallas_degraded_reset();
|
||||
|
||||
rte_main_reboot_req = 1;
|
||||
}
|
||||
|
||||
|
@ -1504,7 +1519,11 @@ int main(int argc, char* argv[]){
|
|||
if (--main_one_hour_pool_timer < 0) {
|
||||
main_one_hour_pool_timer = 60;
|
||||
|
||||
// check if RTC is working correctly
|
||||
if (system_is_rtc_ok() == 0) {
|
||||
|
||||
backup_reg_increment_is_rtc_ok_check_reset();
|
||||
|
||||
rte_main_reboot_req = 1;
|
||||
}
|
||||
|
||||
|
|
85
src/rte_wx.c
85
src/rte_wx.c
|
@ -9,6 +9,11 @@
|
|||
#include <rte_wx.h>
|
||||
#include <wx_handler.h>
|
||||
#include "main.h"
|
||||
#include "misc_config.h"
|
||||
|
||||
#ifndef RTE_WX_PROBLEMS_MAX_THRESHOLD
|
||||
#define RTE_WX_PROBLEMS_MAX_THRESHOLD 20
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A little word of explanataion:
|
||||
|
@ -21,7 +26,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
//float rte_wx_temperature_average_external = 0.0f; //<! This name should be refactored
|
||||
float rte_wx_temperature_average_external_valid = 0.0f; //<! This name should be refactored
|
||||
float rte_wx_temperature_internal = 0.0f, rte_wx_temperature_internal_valid = 0.0f;
|
||||
float rte_wx_pressure = 0.0f, rte_wx_pressure_valid = 0.0f;
|
||||
|
@ -81,9 +85,15 @@ uint8_t rte_wx_davis_station_avaliable = 0;
|
|||
uint8_t rte_wx_davis_loop_packet_avaliable = 0;
|
||||
davis_loop_t rte_wx_davis_loop_content;
|
||||
|
||||
uint8_t rte_wx_problems_wind_buffers = 0; //!< Problems detected with buffers content
|
||||
uint8_t rte_wx_problems_wind_values = 0; //!< Problems with values calculated from buffers content
|
||||
|
||||
void rte_wx_init(void) {
|
||||
int i = 0;
|
||||
|
||||
rte_wx_problems_wind_buffers = 0;
|
||||
rte_wx_problems_wind_values = 0;
|
||||
|
||||
for (; i < WIND_AVERAGE_LEN; i++) {
|
||||
rte_wx_windspeed[i] = 0;
|
||||
rte_wx_winddirection[i] = 0;
|
||||
|
@ -116,3 +126,76 @@ void rte_wx_reset_last_measuremenet_timers(uint16_t parameter_type) {
|
|||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function checks if weather measurements looks to be valid and if they
|
||||
* are changing over time. The function shall be called in one minute interval.
|
||||
* @return
|
||||
*/
|
||||
int8_t rte_wx_check_weather_measurements(void) {
|
||||
int8_t looks_good = 1;
|
||||
|
||||
uint8_t i = 0; // loop iterator
|
||||
|
||||
// go through wind direction buffer and checks if it contains the same value
|
||||
for (i = 0; i < WIND_AVERAGE_LEN - 1; i++) {
|
||||
if (rte_wx_winddirection[i] != rte_wx_winddirection[i + 1]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if an end of the buffer has been reached
|
||||
if (i >= WIND_AVERAGE_LEN - 1) {
|
||||
rte_wx_problems_wind_buffers++;
|
||||
}
|
||||
|
||||
// go through wind speed buffer and checks if it contains the same value
|
||||
for (i = 0; i < WIND_AVERAGE_LEN - 1; i++) {
|
||||
if (rte_wx_windspeed[i] != rte_wx_windspeed[i + 1]) {
|
||||
break;
|
||||
}
|
||||
|
||||
// break the loop if the windspeed is zero anywhere, not to reset
|
||||
// periodically if wind sensor is not connected.
|
||||
if (rte_wx_windspeed[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if an end of the buffer has been reached
|
||||
if (i >= WIND_AVERAGE_LEN - 1) {
|
||||
rte_wx_problems_wind_buffers++;
|
||||
}
|
||||
|
||||
// check if average wind speed is different from zero and the same than gusts
|
||||
if (rte_wx_average_windspeed != 0 &&
|
||||
(rte_wx_average_windspeed == rte_wx_max_windspeed))
|
||||
{
|
||||
// if so a wind sensor had been blocked by icing very rapidly
|
||||
// before next DMA interrupt so rte_wx_windspeed is also
|
||||
// not updated at all
|
||||
rte_wx_problems_wind_values++;
|
||||
}
|
||||
|
||||
// check if wind direction equals exactly north (zero degrees)
|
||||
if (rte_wx_average_winddirection == 0) {
|
||||
// open wind direction input (anemometer disconnected) gives
|
||||
// a reading of about 6 do 8 degrees. If it is stuck on zero
|
||||
// the U->f converted or its reference clock generator
|
||||
// might not work at all
|
||||
rte_wx_problems_wind_values++;
|
||||
}
|
||||
else {
|
||||
rte_wx_problems_wind_values = 0;
|
||||
}
|
||||
|
||||
if (rte_wx_problems_wind_values > RTE_WX_PROBLEMS_MAX_THRESHOLD) {
|
||||
looks_good = 0;
|
||||
}
|
||||
|
||||
if (rte_wx_problems_wind_buffers > RTE_WX_PROBLEMS_MAX_THRESHOLD * 3) {
|
||||
looks_good = 0;
|
||||
}
|
||||
|
||||
return looks_good;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,9 @@ const uint32_t * const config_section_first_start = (const uint32_t *)CONFIG_S
|
|||
const uint32_t * const config_section_second_start = (const uint32_t *)CONFIG_SECTION_SECOND_START;
|
||||
const uint32_t * const config_section_default_start = (const uint32_t *)CONFIG_SECTION_DEFAULT_START;
|
||||
|
||||
uint8_t config_engineering_1 = 0xFFU;
|
||||
uint8_t config_engineering_2 = 0xFFU;
|
||||
|
||||
#ifdef PARAMETEO
|
||||
#define STRUCT_COUNT 6
|
||||
#endif
|
||||
|
@ -638,6 +641,9 @@ void configuration_handler_load_configuration(configuration_handler_region_t reg
|
|||
|
||||
configuration_handler_loaded = region;
|
||||
|
||||
config_engineering_1 = main_config_data_basic->engineering1;
|
||||
config_engineering_2 = main_config_data_basic->engineering2;
|
||||
|
||||
}
|
||||
|
||||
kiss_communication_nrc_t configuration_handler_erase_startup(void) {
|
||||
|
|
|
@ -180,7 +180,7 @@ void wx_pool_anemometer(const config_data_wx_sources_t * const config_sources, c
|
|||
short i = 0;
|
||||
uint8_t average_ln;
|
||||
|
||||
int32_t modbus_retval;
|
||||
int32_t modbus_retval = MODBUS_RET_UNINITIALIZED;
|
||||
uint16_t scaled_windspeed = 0;
|
||||
|
||||
//#ifdef STM32L471xx
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "main_master_time.h"
|
||||
|
||||
#include "ax25_t.h"
|
||||
#include "cfifo.h"
|
||||
#include "afsk.h"
|
||||
|
||||
|
@ -50,15 +51,15 @@
|
|||
|
||||
struct AX25Msg; // fwd declaration
|
||||
|
||||
/**
|
||||
* Type for AX25 messages callback.
|
||||
*/
|
||||
typedef void (*ax25_callback_t)(struct AX25Msg *ax25_rxed_frame);
|
||||
|
||||
/**
|
||||
* Type for channel free wait timeout callback
|
||||
* Create an AX25Call structure on the fly.
|
||||
* \param str callsign, can be 6 characters or shorter.
|
||||
* \param id ssid associated with the callsign.
|
||||
*/
|
||||
typedef void (*ax25_ch_free_timeout_callback_t)(void);
|
||||
#define AX25_CALL(str, id) {.call = (str), .ssid = (id) }
|
||||
#define AX25_PATH(dst, src, ...) { dst, src, ## __VA_ARGS__ }
|
||||
|
||||
|
||||
typedef struct AX25Ctx
|
||||
{
|
||||
|
@ -81,54 +82,6 @@ typedef struct AX25Ctx
|
|||
|
||||
} AX25Ctx;
|
||||
|
||||
|
||||
/**
|
||||
* AX25 Call sign.
|
||||
*/
|
||||
typedef struct AX25Call
|
||||
{
|
||||
char call[6]; ///< Call string, max 6 character
|
||||
uint8_t ssid; ///< SSID (secondary station ID) for the call
|
||||
} AX25Call;
|
||||
|
||||
|
||||
/**
|
||||
* Create an AX25Call structure on the fly.
|
||||
* \param str callsign, can be 6 characters or shorter.
|
||||
* \param id ssid associated with the callsign.
|
||||
*/
|
||||
#define AX25_CALL(str, id) {.call = (str), .ssid = (id) }
|
||||
#define AX25_PATH(dst, src, ...) { dst, src, ## __VA_ARGS__ }
|
||||
|
||||
|
||||
/**
|
||||
* Maximum number of Repeaters in a AX25 message.
|
||||
*/
|
||||
#define AX25_MAX_RPT 8
|
||||
|
||||
|
||||
/**
|
||||
* AX25 Message.
|
||||
* Used to handle AX25 sent/received messages.
|
||||
*/
|
||||
typedef struct AX25Msg
|
||||
{
|
||||
|
||||
AX25Call src; ///< Source adress
|
||||
AX25Call dst; ///< Destination address
|
||||
AX25Call rpt_lst[AX25_MAX_RPT]; ///< List of repeaters
|
||||
uint8_t rpt_cnt; ///< Number of repeaters in this message
|
||||
uint8_t rpt_flags; ///< Has-been-repeated flags for each repeater (bit-mapped)
|
||||
#define AX25_REPEATED(msg, idx) ((msg)->rpt_flags & BV(idx))
|
||||
uint16_t ctrl; ///< AX25 control field
|
||||
uint8_t pid; ///< AX25 PID field
|
||||
const uint8_t *info; ///< Pointer to the info field (payload) of the message
|
||||
uint16_t len; ///< Payload length
|
||||
uint8_t raw_data[CONFIG_AX25_FRAME_BUF_LEN]; /// Surowa zawarto<74><6F> ramki przekopiowana z Ctx->buff
|
||||
short int raw_msg_len; // wielkosc surowej ramki
|
||||
|
||||
} AX25Msg;
|
||||
|
||||
extern AX25Msg ax25_rxed_frame;
|
||||
extern char ax25_new_msg_rx_flag;
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* ax25_t.h
|
||||
*
|
||||
* Created on: Apr 20, 2024
|
||||
* Author: mateusz
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_APRS_AX25_T_H_
|
||||
#define INCLUDE_APRS_AX25_T_H_
|
||||
|
||||
#include "stdint.h"
|
||||
#include "ax25_config.h"
|
||||
|
||||
/**
|
||||
* Maximum number of Repeaters in a AX25 message.
|
||||
*/
|
||||
#define AX25_MAX_RPT 8
|
||||
|
||||
/**
|
||||
* AX25 Call sign.
|
||||
*/
|
||||
typedef struct AX25Call
|
||||
{
|
||||
char call[6]; ///< Call string, max 6 character
|
||||
uint8_t ssid; ///< SSID (secondary station ID) for the call
|
||||
} AX25Call;
|
||||
|
||||
/**
|
||||
* AX25 Message.
|
||||
* Used to handle AX25 sent/received messages.
|
||||
*/
|
||||
typedef struct AX25Msg
|
||||
{
|
||||
|
||||
AX25Call src; ///< Source adress
|
||||
AX25Call dst; ///< Destination address
|
||||
AX25Call rpt_lst[AX25_MAX_RPT]; ///< List of repeaters
|
||||
uint8_t rpt_cnt; ///< Number of repeaters in this message
|
||||
uint8_t rpt_flags; ///< Has-been-repeated flags for each repeater (bit-mapped)
|
||||
#define AX25_REPEATED(msg, idx) ((msg)->rpt_flags & BV(idx))
|
||||
uint16_t ctrl; ///< AX25 control field
|
||||
uint8_t pid; ///< AX25 PID field
|
||||
const uint8_t *info; ///< Pointer to the info field (payload) of the message
|
||||
uint16_t len; ///< Payload length
|
||||
uint8_t raw_data[CONFIG_AX25_FRAME_BUF_LEN]; /// Surowa zawarto<74><6F> ramki przekopiowana z Ctx->buff
|
||||
short int raw_msg_len; // wielkosc surowej ramki
|
||||
|
||||
} AX25Msg;
|
||||
|
||||
/**
|
||||
* Type for AX25 messages callback.
|
||||
*/
|
||||
typedef void (*ax25_callback_t)(struct AX25Msg *ax25_rxed_frame);
|
||||
|
||||
/**
|
||||
* Type for channel free wait timeout callback
|
||||
*/
|
||||
typedef void (*ax25_ch_free_timeout_callback_t)(void);
|
||||
|
||||
|
||||
#endif /* INCLUDE_APRS_AX25_T_H_ */
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* message.h
|
||||
*
|
||||
* Created on: Apr 20, 2024
|
||||
* Author: mateusz
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_APRS_MESSAGE_H_
|
||||
#define INCLUDE_APRS_MESSAGE_H_
|
||||
|
||||
#include "ax25_t.h"
|
||||
#include "stdint.h"
|
||||
#include "./stored_configuration_nvm/config_data.h"
|
||||
|
||||
#define MESSAGE_MAX_LENGHT 67
|
||||
|
||||
typedef struct message_t {
|
||||
AX25Call from;
|
||||
AX25Call to;
|
||||
uint8_t content[MESSAGE_MAX_LENGHT];
|
||||
uint8_t number;
|
||||
}message_t;
|
||||
|
||||
typedef enum message_source_t {
|
||||
MESSAGE_SOURCE_APRSIS,
|
||||
MESSAGE_SOURCE_RADIO
|
||||
|
||||
}message_source_t;
|
||||
|
||||
/**
|
||||
* Decode received data to look for an APRS message and put it into a structure
|
||||
* @param message pointer to data received from APRS-IS
|
||||
* @param message_ln lenght of a buffer content
|
||||
* @param content_position optional position of an APRS message content (recipient callsign). if set to zero function will look for it
|
||||
* @param src
|
||||
* @param output parsed APRS message content
|
||||
* @return zero if message has been found and decoded, non zero if parsing failed
|
||||
*/
|
||||
uint8_t message_decode_from_aprsis(const uint8_t * const message, const uint16_t message_ln, uint16_t content_position, message_source_t src, message_t * output);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param config_data
|
||||
* @param message
|
||||
* @return zero if this is a message to us, non zero otherwise
|
||||
*/
|
||||
uint8_t message_is_for_me(config_data_basic_t * config_data, const message_t * const message);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param out_buffer
|
||||
* @param out_buffer_ln
|
||||
* @param message
|
||||
* @param src how this message has been received
|
||||
*/
|
||||
void message_create_ack_for(uint8_t * out_buffer, const uint16_t out_buffer_ln, const message_t * const message, const message_source_t src);
|
||||
|
||||
#endif /* INCLUDE_APRS_MESSAGE_H_ */
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* message.c
|
||||
*
|
||||
* Created on: Apr 20, 2024
|
||||
* Author: mateusz
|
||||
*/
|
||||
|
||||
#include "message.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#define MESSAGE_RECIPIENT_FIELD_SIZE 9
|
||||
|
||||
#define MESSAGE_SSID_CHARS_LN 2
|
||||
|
||||
#define MESSAGE_ATOI_BUFFER 5 ///!< include room of null terminator
|
||||
|
||||
#define MESSAGE_SENDER_CALL_SSID_MAXLEN 9
|
||||
|
||||
#define MESSAGE_CURRENT_CHAR *(message + content_position + i)
|
||||
|
||||
#define MESSAGE_CURRENT_SENDER_CHAR *(message + i)
|
||||
|
||||
#define MESSAGE_IS_DIGIT(c) (c >= '0' && c <= '9')
|
||||
|
||||
#define MESSAGE_ACK_REMAINING_BUF (out_buffer_ln - current_pos)
|
||||
|
||||
#define MESSAGE_ACK_CURRENT_POS (char*)(out_buffer + current_pos)
|
||||
|
||||
static char message_atoi_buffer[MESSAGE_ATOI_BUFFER];
|
||||
|
||||
/**
|
||||
* Decode received data to look for an APRS message and put it into a structure
|
||||
* @param message pointer to data received from APRS-IS
|
||||
* @param message_ln lenght of a buffer content
|
||||
* @param content_position optional position of an APRS message content (recipient callsign). if set to zero function will look for it
|
||||
* @param output parsed APRS message content
|
||||
* @return zero if message has been found and decoded, non zero if parsing failed
|
||||
*/
|
||||
uint8_t message_decode_from_aprsis(const uint8_t * const message, const uint16_t message_ln, uint16_t content_position, message_source_t src, message_t * output) {
|
||||
|
||||
// example message:: SP8EBC>APX216,TCPIP*,qAC,NINTH::SR9WXZ :tedt{0s}\r\n
|
||||
|
||||
// result returned by the function, although shamesly it is also used as local aux variable
|
||||
// in few places of this function :( this is what You sometimes do to save some stack.
|
||||
uint8_t result = 0xFF;
|
||||
|
||||
uint16_t i = 0;
|
||||
|
||||
if (output == 0x00) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (message_ln < (MESSAGE_SENDER_CALL_SSID_MAXLEN + MESSAGE_RECIPIENT_FIELD_SIZE)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
memset(message_atoi_buffer, 0x00, MESSAGE_ATOI_BUFFER);
|
||||
|
||||
// if start position of APRS message (position of recipient callsign) has not been provided
|
||||
if ((src == MESSAGE_SOURCE_APRSIS) && (content_position == 0)) {
|
||||
|
||||
// look for it
|
||||
for (i = 0; i < message_ln; i++) {
|
||||
const uint8_t * this_character = message + i;
|
||||
|
||||
const uint8_t * next_character = message + i + 1;
|
||||
|
||||
// break on an end of input string
|
||||
if (*this_character == 0x00) {
|
||||
break;
|
||||
}
|
||||
|
||||
// check if double semicolon has been found
|
||||
if ((*this_character == ':') && (*next_character == ':')) {
|
||||
// APRS message starts after second semicolong
|
||||
content_position = i + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear the iterator, it will be used across this function
|
||||
i = 0;
|
||||
|
||||
// check content position one more time to verify
|
||||
// if input data contains APRS message at all
|
||||
if (
|
||||
((src == MESSAGE_SOURCE_APRSIS) && (content_position != 0)) ||
|
||||
(src == MESSAGE_SOURCE_RADIO)
|
||||
) {
|
||||
|
||||
// set this variable to zero as now it will be used as a local
|
||||
result = 0;
|
||||
|
||||
// clear output structure to make room for new data
|
||||
memset(output, 0x00, sizeof(message_t));
|
||||
|
||||
//extract sender call and SSID only if this message has been received from APRS-IS in pure text form
|
||||
if (src == MESSAGE_SOURCE_APRSIS) {
|
||||
// fast forward any potential whitespace at the begining
|
||||
while (MESSAGE_CURRENT_SENDER_CHAR == ' ') {
|
||||
i++;
|
||||
|
||||
if (i >= message_ln) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// extract sender callsign
|
||||
for (; i < MESSAGE_SENDER_CALL_SSID_MAXLEN; i++) {
|
||||
|
||||
// if SSID separator or sender end character ('>') has been reached
|
||||
if (MESSAGE_CURRENT_SENDER_CHAR == '-' || MESSAGE_CURRENT_SENDER_CHAR == '>') {
|
||||
break;
|
||||
}
|
||||
|
||||
output->from.call[result++] = MESSAGE_CURRENT_SENDER_CHAR;
|
||||
}
|
||||
|
||||
// check if sender has SSID
|
||||
if (MESSAGE_CURRENT_SENDER_CHAR == '-') {
|
||||
// jumps to next character. otherwise separating '-'
|
||||
// will be interpreted as a minus/negitive sign
|
||||
i++;
|
||||
|
||||
result = 0; // here used as a local iterator
|
||||
|
||||
// extract SSID
|
||||
for (; i < MESSAGE_RECIPIENT_FIELD_SIZE; i++) {
|
||||
// copy characters to aux buffer
|
||||
message_atoi_buffer[result++] = MESSAGE_CURRENT_SENDER_CHAR;
|
||||
|
||||
// check if there isn't enough characters
|
||||
if (result == MESSAGE_ATOI_BUFFER) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert SSID to int
|
||||
output->from.ssid = atoi(message_atoi_buffer);
|
||||
}
|
||||
|
||||
// clear the iterator, it will be used across this function
|
||||
i = 0;
|
||||
}
|
||||
else {
|
||||
// clear content_position iterator
|
||||
content_position = 0;
|
||||
|
||||
// find a begining of the message in data from radio channel
|
||||
while (MESSAGE_CURRENT_CHAR != ':') {
|
||||
content_position++;
|
||||
|
||||
if (content_position >= message_ln) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// jump over ':'
|
||||
content_position++;
|
||||
}
|
||||
|
||||
// extract recipient
|
||||
for (; i < MESSAGE_RECIPIENT_FIELD_SIZE; i++) {
|
||||
|
||||
// look if end of callsign or separating '-' has been found
|
||||
if (MESSAGE_CURRENT_CHAR == ' ' || MESSAGE_CURRENT_CHAR == '-') {
|
||||
break; // and go for SSID reading
|
||||
}
|
||||
|
||||
// copy recipient callsign character per character
|
||||
output->to.call[i] = MESSAGE_CURRENT_CHAR;
|
||||
}
|
||||
|
||||
// check if callsign has SSID set
|
||||
if (MESSAGE_CURRENT_CHAR == '-') {
|
||||
// jumps to next character. otherwise separating '-'
|
||||
// will be interpreted as a minus/negitive sign
|
||||
i++;
|
||||
|
||||
result = 0; // here used as a local iterator
|
||||
|
||||
// extract SSID
|
||||
for (; i < MESSAGE_RECIPIENT_FIELD_SIZE; i++) {
|
||||
// copy characters to aux buffer
|
||||
message_atoi_buffer[result++] = MESSAGE_CURRENT_CHAR;
|
||||
|
||||
// check if there isn't enough characters
|
||||
if (result == MESSAGE_ATOI_BUFFER) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert SSID to int
|
||||
output->to.ssid = atoi(message_atoi_buffer);
|
||||
}
|
||||
|
||||
if (result != MESSAGE_ATOI_BUFFER && /* if SSID extraction was OK and end of a buffer hasn't been reached */
|
||||
(
|
||||
(i < MESSAGE_RECIPIENT_FIELD_SIZE) || /* if recipient and callsign has been read before ':' separating from message content */
|
||||
((i == MESSAGE_RECIPIENT_FIELD_SIZE) && (MESSAGE_CURRENT_CHAR == ':')) /* if a position of separating ':' was reached and ':' is there */
|
||||
)
|
||||
) {
|
||||
|
||||
// reinitialize buffer before next usage
|
||||
memset(message_atoi_buffer, 0x00, MESSAGE_ATOI_BUFFER);
|
||||
|
||||
// check if the iterator is set now to position of ':' separating
|
||||
// recipient an the message itself
|
||||
while(MESSAGE_CURRENT_CHAR != ':' && i <= MESSAGE_RECIPIENT_FIELD_SIZE) {
|
||||
i++;
|
||||
}
|
||||
|
||||
// one more incrementation to jump over ':' and land on the first character of the message
|
||||
i++;
|
||||
|
||||
result = 0;
|
||||
|
||||
// then copy message, which ends on a counter, something like '{1'
|
||||
while(MESSAGE_CURRENT_CHAR != ':' && i + content_position < message_ln) {
|
||||
output->content[result++] = MESSAGE_CURRENT_CHAR;
|
||||
i++;
|
||||
|
||||
// break on message counter separator
|
||||
if (MESSAGE_CURRENT_CHAR == '{') {
|
||||
i++; // move to first digit of a counter
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check which condition has ended previous 'while' loop and if an end of the buffer has been reached
|
||||
if (i + content_position < message_ln) {
|
||||
result = 0;
|
||||
|
||||
// now iterator is set (should be set) on a first digit of message counter
|
||||
// copy everything until first non digit character is found
|
||||
while (MESSAGE_IS_DIGIT(MESSAGE_CURRENT_CHAR)) {
|
||||
message_atoi_buffer[result++] = MESSAGE_CURRENT_CHAR;
|
||||
|
||||
i++;
|
||||
|
||||
// check if there isn't enough characters
|
||||
if (result == MESSAGE_ATOI_BUFFER) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert message counter from string to int
|
||||
output->number = atoi(message_atoi_buffer);
|
||||
|
||||
if (result < MESSAGE_ATOI_BUFFER) {
|
||||
// new we are done (??)
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = 0xFF;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param config_data
|
||||
* @param message
|
||||
* @return zero if this is a message to us, non zero otherwise
|
||||
*/
|
||||
uint8_t message_is_for_me(config_data_basic_t * config_data, const message_t * const message)
|
||||
{
|
||||
const int callsign = strncmp(config_data->callsign, message->to.call, 6);
|
||||
|
||||
if (callsign == 0 && (config_data->ssid == message->to.ssid)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param out_buffer
|
||||
* @param out_buffer_ln
|
||||
* @param message
|
||||
* @param src how this message has been received
|
||||
*/
|
||||
void message_create_ack_for(uint8_t * out_buffer, const uint16_t out_buffer_ln, const message_t * const message, const message_source_t src)
|
||||
{
|
||||
int current_pos = 0;
|
||||
|
||||
uint8_t call_position = 0;
|
||||
|
||||
// clear output buffer
|
||||
memset(out_buffer, 0x00, out_buffer_ln);
|
||||
|
||||
if (src == MESSAGE_SOURCE_APRSIS) {
|
||||
|
||||
// put my callsign
|
||||
for (; call_position < 6; call_position++) {
|
||||
// break on null character
|
||||
if (message->to.call[call_position] == 0x00) {
|
||||
break;
|
||||
}
|
||||
|
||||
// copy callsign data
|
||||
out_buffer[current_pos + call_position] = message->to.call[call_position];
|
||||
}
|
||||
|
||||
current_pos += call_position;
|
||||
|
||||
call_position = 0;
|
||||
|
||||
// check if I have a SSID
|
||||
if (message->to.ssid != 0) {
|
||||
current_pos += snprintf(MESSAGE_ACK_CURRENT_POS, MESSAGE_ACK_REMAINING_BUF, "-%d", message->to.ssid);
|
||||
}
|
||||
|
||||
// constant part
|
||||
current_pos += snprintf(MESSAGE_ACK_CURRENT_POS, MESSAGE_ACK_REMAINING_BUF, ">AKLPRZ::");
|
||||
|
||||
// put sender callsign, station I received this message from
|
||||
for (; call_position < 6; call_position++) {
|
||||
// break on null character
|
||||
if (message->from.call[call_position] == 0x00) {
|
||||
break;
|
||||
}
|
||||
|
||||
// copy callsign data
|
||||
out_buffer[current_pos + call_position] = message->from.call[call_position];
|
||||
}
|
||||
|
||||
// put sender SSID, station I received this message from
|
||||
if (message->from.ssid != 0) {
|
||||
call_position += snprintf(MESSAGE_ACK_CURRENT_POS + call_position, MESSAGE_ACK_REMAINING_BUF, "-%d", message->from.ssid);
|
||||
}
|
||||
|
||||
// check if callsign was shorter than 6 characters
|
||||
while (call_position < 9) {
|
||||
// copy callsign data
|
||||
out_buffer[current_pos + call_position] = ' ';
|
||||
|
||||
call_position++;
|
||||
}
|
||||
|
||||
// callsign + ssid + padding must be exactly 9 characters long
|
||||
current_pos += 9;
|
||||
|
||||
// then put 'ackXX' where X is message number
|
||||
current_pos += snprintf(MESSAGE_ACK_CURRENT_POS, MESSAGE_ACK_REMAINING_BUF, ":ack%d", message->number);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue