From 6d2416d307c61331c496cad88f12db9be88fbb78 Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Thu, 12 Aug 2021 09:48:56 +0300 Subject: [PATCH] Improve configuration and its documentation --- README.md | 10 +++- src/config.c | 46 +++++++-------- src/config.h | 110 ++++++++++++++++++++++++++---------- src/config_internal.h | 20 +++++++ src/drivers/si4032/si4032.c | 5 ++ src/radio.c | 70 +++++++++++++++-------- src/radio_internal.h | 2 - 7 files changed, 178 insertions(+), 85 deletions(-) create mode 100644 src/config_internal.h diff --git a/README.md b/README.md index e15e69f..8ae99a8 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,12 @@ The main features this firmware aims to implement are: * Support for more I²C sensors * Configurable transmission frequencies and schedules based on location / altitude +## Configuring the firmware + +1. Configure your amateur radio call sign, transmission schedule (time sync), + transmit frequencies and transmission mode parameters in `config.h` +2. Set up transmitted message templates in `config.c`, depending on the modes you use + ## Building the firmware Software requirements: @@ -63,9 +69,7 @@ dnf install arm-none-eabi-gcc-cs arm-none-eabi-gcc-cs-c++ arm-none-eabi-binutils ### Steps to build the firmware 1. Install the required software dependencies listed above -2. Configure your amateur radio call sign, transmit frequencies and transmission mode parameters in `config.h` -3. Configure scheduling of transmissions in `radio.c` by editing array `radio_transmit_schedule` -4. Build the firmware using the following commands +2. Build the firmware using the following commands ``` mkdir build cd build diff --git a/src/config.c b/src/config.c index d873bea..6648079 100644 --- a/src/config.c +++ b/src/config.c @@ -1,30 +1,7 @@ /** - * The tracker firmware will transmit each of the message templates - * defined here one by one, starting again from the beginning once the last message is transmitted. - */ - -#include -#include "config.h" - -bool leds_enabled = LEDS_ENABLE; -bool bmp280_enabled = SENSOR_BMP280_ENABLE; -bool si5351_enabled = RADIO_SI5351_ENABLE; - -volatile bool system_initialized = false; - -/** - * Allowed message lengths: + * The tracker firmware will transmit each of the message templates defined here in rotation, one by one, + * starting again from the beginning once the last message for a particular mode is transmitted. * - * APRS comment - Free text up to 127 chars - * FT8 - Free text up to 13 chars (Type 0.0 free text message, Type 0.5 telemetry message) - * JT65 - Free text up to 13 chars (Plaintext Type 6 message) - * JT9 - Free text up to 13 chars (Plaintext Type 6 message) - * JT4 - Free text up to 13 chars (Plaintext Type 6 message) - * FSQ - Call sign up to 20 chars, free text up to 130 chars - * WSPR - Call sign up to 6 chars, locator 4 chars, output power in dBm - */ - -/** * Supported variable references in templates: * * $cs - Call sign @@ -48,8 +25,27 @@ volatile bool system_initialized = false; * $gs - Ground speed in km/h (up to 3 chars) * $cl - Climb in m/s (up to 2 chars) * $he - Heading in degrees (up to 3 chars) + * + * Allowed message lengths: + * + * APRS comment - Free text up to 127 chars + * FT8 - Free text up to 13 chars (Type 0.0 free text message, Type 0.5 telemetry message) + * JT65 - Free text up to 13 chars (Plaintext Type 6 message) + * JT9 - Free text up to 13 chars (Plaintext Type 6 message) + * JT4 - Free text up to 13 chars (Plaintext Type 6 message) + * FSQ - Call sign up to 20 chars, free text up to 130 chars + * WSPR - Call sign up to 6 chars, locator 4 chars, output power in dBm */ +#include +#include "config.h" + +bool leds_enabled = LEDS_ENABLE; +bool bmp280_enabled = SENSOR_BMP280_ENABLE; +bool si5351_enabled = RADIO_SI5351_ENABLE; + +volatile bool system_initialized = false; + /** * APRS mode comment messages. * Maximum length: depends on the packet contents, but keeping this under 100 characters is usually safe. diff --git a/src/config.h b/src/config.h index 7f49a9b..cb4518c 100644 --- a/src/config.h +++ b/src/config.h @@ -6,22 +6,39 @@ //#define SEMIHOSTING_ENABLE //#define LOGGING_ENABLE -#include +/** + * Global configuration + */ // Set the tracker amateur radio call sign here #define CALLSIGN "MYCALL" +// Disabling LEDs will save power +// Red LED: Lit during initialization and transmit. +// Green LED: Blinking fast when there is no GPS fix. Blinking slowly when the GPS has a fix. #define LEDS_ENABLE true + +// Enable use of an externally connected I²C BMP280 atmospheric sensor #define SENSOR_BMP280_ENABLE false + +// Enable use of an externally connected I²C Si5351 clock generator chip for HF radio transmissions #define RADIO_SI5351_ENABLE false +// Number of character pairs to include in locator +#define LOCATOR_PAIR_COUNT_FULL 6 // max. 6 (12 characters WWL) + +// Delay after transmission for modes that do not use time synchronization #define RADIO_POST_TRANSMIT_DELAY_MS 5000 + +// Threshold for time-synchronized modes regarding how far from scheduled transmission time the transmission is still allowed #define RADIO_TIME_SYNC_THRESHOLD_MS 2000 /** - * Si4032 transmit power: 0..7 - * 0 = -1dBm, 1 = 2dBm, 2 = 5dBm, 3 = 8dBm, 4 = 11dBm, 5 = 14dBm, 6 = 17dBm, 7 = 20dBm + * Built-in Si4032 radio chip transmission configuration */ + +// Si4032 transmit power: 0..7 +// 0 = -1dBm, 1 = 2dBm, 2 = 5dBm, 3 = 8dBm, 4 = 11dBm, 5 = 14dBm, 6 = 17dBm, 7 = 20dBm #define RADIO_SI4032_TX_POWER 7 // Which modes to transmit using the built-in Si4032 transmitter chip @@ -38,9 +55,11 @@ #define RADIO_SI4032_TX_FREQUENCY_HORUS_V1 432501000 /** - * Si5351 transmit power: 0..3 - * Si5351 drive strength: 0 = 2mA, 1 = 4mA, 2 = 6mA, 3 = 8mA + * External Si5351 radio chip transmission configuration */ + +// Si5351 transmit power: 0..3 +// Si5351 drive strength: 0 = 2mA, 1 = 4mA, 2 = 6mA, 3 = 8mA #define RADIO_SI5351_TX_POWER 3 // Which modes to transmit using an externally connected Si5351 chip in the I²C bus @@ -59,19 +78,9 @@ #define RADIO_SI5351_TX_FREQUENCY_FSQ 14085000UL // Was: 7105350UL // Base freq is 1350 Hz higher than dial freq in USB #define RADIO_SI5351_TX_FREQUENCY_FT8 14085000UL // Was: 14075000UL -#define LOCATOR_PAIR_COUNT_FULL 6 // max. 6 (12 characters WWL) - -// WSPR settings -#define WSPR_CALLSIGN CALLSIGN -#define WSPR_LOCATOR_FIXED_ENABLED false -#define WSPR_LOCATOR_FIXED "AA00" -#define WSPR_DBM 10 - -// FSQ settings -#define FSQ_CALLSIGN_FROM CALLSIGN -#define FSQ_COMMENT "RS41ng radiosonde firmware test" - /** + * APRS mode settings + * * APRS SSID: * * '0' = (-0) Your primary station usually fixed and message capable @@ -102,31 +111,72 @@ #define APRS_DESTINATION "APZ41N" #define APRS_DESTINATION_SSID '0' +// Schedule transmission every N seconds, counting from beginning of an hour (based on GPS time). Set to zero to disable time sync. +#define APRS_TIME_SYNC_SECONDS 1 +// Delay transmission for an N second offset after the scheduled time. +#define APRS_TIME_SYNC_OFFSET_SECONDS 0 + +/** + * Horus V1 4FSK mode settings + */ + // Use Horus payload ID 0 for tests (4FSKTEST) #define HORUS_V1_PAYLOAD_ID 0 #define HORUS_V1_BAUD_RATE 100 #define HORUS_V1_FREQUENCY_OFFSET 0 #define HORUS_V1_PREAMBLE_LENGTH 16 -// TODO: RTTY and CW settings (once modes are implemented) +// Schedule transmission every N seconds, counting from beginning of an hour (based on GPS time). Set to zero to disable time sync. +#define HORUS_V1_TIME_SYNC_SECONDS 1 +// Delay transmission for an N second offset after the scheduled time. +#define HORUS_V1_TIME_SYNC_OFFSET_SECONDS 0 -#define RTTY_LOCATOR_PAIR_COUNT 4 // max. 6 (12 characters WWL) -#define RTTY_7BIT 1 // if 0 --> 5 bits +/** + * TODO: CW settings (once implemented) + */ #define CW_LOCATOR_PAIR_COUNT 4 // max. 6 (12 characters WWL) -#define RADIO_PAYLOAD_MAX_LENGTH 256 -#define RADIO_SYMBOL_DATA_MAX_LENGTH 512 -#define RADIO_PAYLOAD_MESSAGE_MAX_LENGTH 128 +/** + * WSPR settings + */ +#define WSPR_CALLSIGN CALLSIGN +#define WSPR_LOCATOR_FIXED_ENABLED false +#define WSPR_LOCATOR_FIXED "AA00" +#define WSPR_DBM 10 -extern bool leds_enabled; -extern bool bmp280_enabled; -extern bool si5351_enabled; +#define WSPR_TIME_SYNC_SECONDS 120 +#define WSPR_TIME_SYNC_OFFSET_SECONDS 1 -extern volatile bool system_initialized; +/** + * FSQ settings + */ +#define FSQ_CALLSIGN_FROM CALLSIGN +#define FSQ_COMMENT "RS41ng radiosonde firmware test" -extern char *aprs_comment_templates[]; -extern char *fsq_comment_templates[]; -extern char *ftjt_message_templates[]; +#define FSQ_SUBMODE RADIO_DATA_MODE_FSQ_6 + +#define FSQ_TIME_SYNC_SECONDS 0 +#define FSQ_TIME_SYNC_OFFSET_SECONDS 0 + +/** + * FT/JT mode settings + */ + +// Schedule transmission every 15 seconds, counting from beginning of an hour (based on GPS time). Set to zero to disable time sync. +#define FT8_TIME_SYNC_SECONDS 15 +// Delay transmission for 1 second after the scheduled time. +#define FT8_TIME_SYNC_OFFSET_SECONDS 1 + +#define JT9_TIME_SYNC_SECONDS 60 +#define JT9_TIME_SYNC_OFFSET_SECONDS 1 + +#define JT4_TIME_SYNC_SECONDS 60 +#define JT4_TIME_SYNC_OFFSET_SECONDS 1 + +#define JT65_TIME_SYNC_SECONDS 60 +#define JT65_TIME_SYNC_OFFSET_SECONDS 1 + +#include "config_internal.h" #endif diff --git a/src/config_internal.h b/src/config_internal.h new file mode 100644 index 0000000..b4cc6b2 --- /dev/null +++ b/src/config_internal.h @@ -0,0 +1,20 @@ +#ifndef __CONFIG_INTERNAL_H +#define __CONFIG_INTERNAL_H + +#define RADIO_PAYLOAD_MAX_LENGTH 256 +#define RADIO_SYMBOL_DATA_MAX_LENGTH 512 +#define RADIO_PAYLOAD_MESSAGE_MAX_LENGTH 128 + +#include + +extern bool leds_enabled; +extern bool bmp280_enabled; +extern bool si5351_enabled; + +extern volatile bool system_initialized; + +extern char *aprs_comment_templates[]; +extern char *fsq_comment_templates[]; +extern char *ftjt_message_templates[]; + +#endif diff --git a/src/drivers/si4032/si4032.c b/src/drivers/si4032/si4032.c index b0ea6e9..0e69ea3 100644 --- a/src/drivers/si4032/si4032.c +++ b/src/drivers/si4032/si4032.c @@ -10,6 +10,11 @@ #define GPIO_SI_4032_CS GPIOC #define GPIO_PIN_SI4032_CS GPIO_Pin_13 +// TODO: For CW support: +// TODO: static const uint16_t radioSDIpin = GPIO_Pin_15; // @ GPIOB! +// TODO: Add methods to init SDI pin GPIO and to set SDI pin state -> Verify it can be used for OOK (CW), NSEL (CS) must be high +// TODO: Call uninitialization of PWM timer after use so that SDI pin is free to use + static inline uint8_t si4032_write(uint8_t reg, uint8_t value) { return spi_send_and_receive(GPIO_SI_4032_CS, GPIO_PIN_SI4032_CS, ((reg | SPI_WRITE_FLAG) << 8U) | value); diff --git a/src/radio.c b/src/radio.c index 9a6d4c8..bc0be68 100644 --- a/src/radio.c +++ b/src/radio.c @@ -24,8 +24,8 @@ radio_transmit_entry radio_transmit_schedule[] = { .enabled = RADIO_SI4032_TX_APRS, .radio_type = RADIO_TYPE_SI4032, .data_mode = RADIO_DATA_MODE_APRS_1200, - .time_sync_seconds = 1, - .time_sync_seconds_offset = 0, + .time_sync_seconds = APRS_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = APRS_TIME_SYNC_OFFSET_SECONDS, .frequency = RADIO_SI4032_TX_FREQUENCY_APRS_1200, .tx_power = RADIO_SI4032_TX_POWER, .symbol_rate = 1200, @@ -36,8 +36,8 @@ radio_transmit_entry radio_transmit_schedule[] = { .enabled = RADIO_SI4032_TX_HORUS_V1, .radio_type = RADIO_TYPE_SI4032, .data_mode = RADIO_DATA_MODE_HORUS_V1, - .time_sync_seconds = 1, - .time_sync_seconds_offset = 0, + .time_sync_seconds = HORUS_V1_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = HORUS_V1_TIME_SYNC_OFFSET_SECONDS, .frequency = RADIO_SI4032_TX_FREQUENCY_HORUS_V1, .tx_power = RADIO_SI4032_TX_POWER, .symbol_rate = HORUS_V1_BAUD_RATE, @@ -47,74 +47,68 @@ radio_transmit_entry radio_transmit_schedule[] = { { .enabled = RADIO_SI5351_TX_WSPR, .radio_type = RADIO_TYPE_SI5351, - .time_sync_seconds = 120, - .time_sync_seconds_offset = 1, + .time_sync_seconds = WSPR_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = WSPR_TIME_SYNC_OFFSET_SECONDS, .data_mode = RADIO_DATA_MODE_WSPR, .frequency = RADIO_SI5351_TX_FREQUENCY_WSPR, .tx_power = RADIO_SI5351_TX_POWER, .payload_encoder = &radio_wspr_payload_encoder, .fsk_encoder_api = &jtencode_fsk_encoder_api, - .jtencode_mode_type = JTENCODE_MODE_WSPR, }, { .enabled = RADIO_SI5351_TX_FT8, .radio_type = RADIO_TYPE_SI5351, .data_mode = RADIO_DATA_MODE_FT8, - .time_sync_seconds = 15, - .time_sync_seconds_offset = 0, + .time_sync_seconds = FT8_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = FT8_TIME_SYNC_OFFSET_SECONDS, .frequency = RADIO_SI5351_TX_FREQUENCY_FT8, .tx_power = RADIO_SI5351_TX_POWER, .payload_encoder = &radio_ft8_payload_encoder, .fsk_encoder_api = &jtencode_fsk_encoder_api, - .jtencode_mode_type = JTENCODE_MODE_FT8, }, { .enabled = RADIO_SI5351_TX_JT9, .radio_type = RADIO_TYPE_SI5351, .data_mode = RADIO_DATA_MODE_JT9, - .time_sync_seconds = 60, - .time_sync_seconds_offset = 1, + .time_sync_seconds = JT9_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = JT9_TIME_SYNC_OFFSET_SECONDS, .frequency = RADIO_SI5351_TX_FREQUENCY_JT9, .tx_power = RADIO_SI5351_TX_POWER, .payload_encoder = &radio_jt9_payload_encoder, .fsk_encoder_api = &jtencode_fsk_encoder_api, - .jtencode_mode_type = JTENCODE_MODE_JT9, }, { .enabled = RADIO_SI5351_TX_JT4, .radio_type = RADIO_TYPE_SI5351, .data_mode = RADIO_DATA_MODE_JT4, - .time_sync_seconds = 60, - .time_sync_seconds_offset = 1, + .time_sync_seconds = JT4_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = JT4_TIME_SYNC_OFFSET_SECONDS, .frequency = RADIO_SI5351_TX_FREQUENCY_JT4, .tx_power = RADIO_SI5351_TX_POWER, .payload_encoder = &radio_jt4_payload_encoder, .fsk_encoder_api = &jtencode_fsk_encoder_api, - .jtencode_mode_type = JTENCODE_MODE_JT4, }, { .enabled = RADIO_SI5351_TX_JT65, .radio_type = RADIO_TYPE_SI5351, .data_mode = RADIO_DATA_MODE_JT65, - .time_sync_seconds = 60, - .time_sync_seconds_offset = 1, + .time_sync_seconds = JT65_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = JT65_TIME_SYNC_OFFSET_SECONDS, .frequency = RADIO_SI5351_TX_FREQUENCY_JT65, .tx_power = RADIO_SI5351_TX_POWER, .payload_encoder = &radio_jt65_payload_encoder, .fsk_encoder_api = &jtencode_fsk_encoder_api, - .jtencode_mode_type = JTENCODE_MODE_JT65, }, { .enabled = RADIO_SI5351_TX_FSQ, .radio_type = RADIO_TYPE_SI5351, - .data_mode = RADIO_DATA_MODE_FSQ_6, - .time_sync_seconds = 0, - .time_sync_seconds_offset = 0, + .data_mode = FSQ_SUBMODE, + .time_sync_seconds = FSQ_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = FSQ_TIME_SYNC_OFFSET_SECONDS, .frequency = RADIO_SI5351_TX_FREQUENCY_FSQ, .tx_power = RADIO_SI5351_TX_POWER, .payload_encoder = &radio_fsq_payload_encoder, .fsk_encoder_api = &jtencode_fsk_encoder_api, - .jtencode_mode_type = JTENCODE_MODE_FSQ_6, }, { .end = true, @@ -165,6 +159,32 @@ radio_module_state radio_shared_state = { .radio_current_symbol_delay_ms_100 = 0 }; +static jtencode_mode_type radio_jtencode_mode_type_for(radio_data_mode mode) +{ + switch (mode) { + case RADIO_DATA_MODE_WSPR: + return JTENCODE_MODE_WSPR; + case RADIO_DATA_MODE_FT8: + return JTENCODE_MODE_FT8; + case RADIO_DATA_MODE_JT9: + return JTENCODE_MODE_JT9; + case RADIO_DATA_MODE_JT65: + return JTENCODE_MODE_JT65; + case RADIO_DATA_MODE_JT4: + return JTENCODE_MODE_JT4; + case RADIO_DATA_MODE_FSQ_6: + return JTENCODE_MODE_FSQ_6; + case RADIO_DATA_MODE_FSQ_4_5: + return JTENCODE_MODE_FSQ_4_5; + case RADIO_DATA_MODE_FSQ_3: + return JTENCODE_MODE_FSQ_3; + case RADIO_DATA_MODE_FSQ_2: + return JTENCODE_MODE_FSQ_2; + default: + return 0; + } +} + static inline void radio_reset_next_symbol_counter() { if (radio_shared_state.radio_current_symbol_rate > 0) { @@ -241,6 +261,7 @@ static bool radio_start_transmit(radio_transmit_entry *entry) case RADIO_DATA_MODE_FSQ_4_5: case RADIO_DATA_MODE_FSQ_6: { char locator[5]; + jtencode_mode_type jtencode_mode = radio_jtencode_mode_type_for(entry->data_mode); if (wspr_locator_fixed_enabled) { strlcpy(locator, WSPR_LOCATOR_FIXED, 4 + 1); @@ -249,8 +270,7 @@ static bool radio_start_transmit(radio_transmit_entry *entry) } success = jtencode_encoder_new(&entry->fsk_encoder, sizeof(radio_current_symbol_data), - radio_current_symbol_data, - entry->jtencode_mode_type, WSPR_CALLSIGN, locator, WSPR_DBM, FSQ_CALLSIGN_FROM); + radio_current_symbol_data, jtencode_mode, WSPR_CALLSIGN, locator, WSPR_DBM, FSQ_CALLSIGN_FROM); if (!success) { return false; } diff --git a/src/radio_internal.h b/src/radio_internal.h index 57d717a..72207ca 100644 --- a/src/radio_internal.h +++ b/src/radio_internal.h @@ -49,8 +49,6 @@ typedef struct _radio_transmit_entry { payload_encoder *payload_encoder; fsk_encoder_api *fsk_encoder_api; - jtencode_mode_type jtencode_mode_type; - fsk_encoder fsk_encoder; } radio_transmit_entry;