diff --git a/CMakeLists.txt b/CMakeLists.txt index d62b15d..8297bfd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.6) +project(RS41ng_top) SET(CMAKE_SYSTEM_NAME "Generic") SET(CMAKE_SYSTEM_VERSION 1) diff --git a/README.md b/README.md index 21b12f0..11b7372 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ The main features the RS41ng firmware are: * There is an option to use continuous transmit mode (for either V1 or V2 mode), which helps with receiver frequency synchronization and improves reception. * Morse code (CW) * JT65/JT9/JT4/FT8/WSPR/FSQ digital modes on HF/VHF amateur radio bands using an external Si5351 clock generator connected to the external I²C bus + * "Pip" mode, which transmits a short beep generated using CW to indicate presence of the transmitter * Support for transmitting multiple modes consecutively with custom, rotating comment messages (see `config.c`) * Support for GPS-based scheduling is available for transmission modes that require specific timing for transmissions * Support for custom sensors via the external I²C bus @@ -78,6 +79,7 @@ On the internal Si4032 transmitter: * APRS (1200 baud) * Horus 4FSK v1 and v2 (100 baud) * Morse code (CW) +* "Pip" - a short beep to indicate presence of the transmitter On an external Si5351 clock generator connected to the external I²C bus of the RS41 radiosonde: @@ -85,6 +87,7 @@ On an external Si5351 clock generator connected to the external I²C bus of the * JT65/JT9/JT4/FT8/WSPR/FSQ mode beacon transmissions using the JTEncode library. I've decoded FT8, WSPR and FSQ modes successfully. * GPS-based scheduling is available for modes that require specific timing for transmissions * Morse code (CW) +* "Pip" #### Notes about APRS diff --git a/src/config.c b/src/config.c index 39f5fac..9e0516b 100644 --- a/src/config.c +++ b/src/config.c @@ -52,7 +52,16 @@ volatile bool system_initialized = false; * Maximum length: 64 characters. */ char *cw_message_templates[] = { - "$cs TEST $loc6 $altm $tiC", + "$cs $loc6 $altm $gs km/h $tiC", + NULL +}; + +/** + * "Pip" mode messages. Transmitted as CW, because a single "pip" can be represented as the 'E' character. + * Maximum length: 64 characters. + */ +char *pip_message_templates[] = { + "E", // An 'E' character in CW represents a single "pip". NULL }; diff --git a/src/config.h b/src/config.h index 39945e8..e43e86f 100644 --- a/src/config.h +++ b/src/config.h @@ -59,8 +59,10 @@ #define RADIO_SI4032_TX_POWER 7 // Which modes to transmit using the built-in Si4032 transmitter chip -#define RADIO_SI4032_TX_CW true +#define RADIO_SI4032_TX_CW false #define RADIO_SI4032_TX_CW_COUNT 1 +#define RADIO_SI4032_TX_PIP false +#define RADIO_SI4032_TX_PIP_COUNT 6 #define RADIO_SI4032_TX_APRS true #define RADIO_SI4032_TX_APRS_COUNT 2 #define RADIO_SI4032_TX_HORUS_V1 false @@ -76,6 +78,7 @@ // Transmit frequencies for the Si4032 transmitter modes #define RADIO_SI4032_TX_FREQUENCY_CW 432500000 +#define RADIO_SI4032_TX_FREQUENCY_PIP 432500000 #define RADIO_SI4032_TX_FREQUENCY_APRS_1200 432500000 // Use a frequency offset to place FSK tones slightly above the defined frequency for SSB reception #define RADIO_SI4032_TX_FREQUENCY_HORUS_V1 432501000 @@ -92,6 +95,8 @@ // Which modes to transmit using an externally connected Si5351 chip in the I²C bus #define RADIO_SI5351_TX_CW true #define RADIO_SI5351_TX_CW_COUNT 1 +#define RADIO_SI5351_TX_PIP false +#define RADIO_SI5351_TX_PIP_COUNT 6 #define RADIO_SI5351_TX_HORUS_V1 false #define RADIO_SI5351_TX_HORUS_V1_COUNT 1 #define RADIO_SI5351_TX_HORUS_V2 true @@ -111,6 +116,7 @@ // Transmit frequencies for the Si5351 transmitter modes #define RADIO_SI5351_TX_FREQUENCY_CW 3595000UL +#define RADIO_SI5351_TX_FREQUENCY_PIP 3595000UL #define RADIO_SI5351_TX_FREQUENCY_HORUS_V1 3608000UL #define RADIO_SI5351_TX_FREQUENCY_HORUS_V2 3608000UL #define RADIO_SI5351_TX_FREQUENCY_JT9 14085000UL // Was: 14078700UL @@ -212,6 +218,18 @@ // Delay transmission for an N second offset after the scheduled time. #define CW_TIME_SYNC_OFFSET_SECONDS 0 +/** + * Pip settings (short beep generated using CW to indicate presence of the transmitter) + */ + +// Pip speed is defined as CW WPM, range 5 - 40 +#define PIP_SPEED_WPM 18 + +// Schedule transmission every N seconds, counting from beginning of an hour (based on GPS time). Set to zero to disable time sync. +#define PIP_TIME_SYNC_SECONDS 0 +// Delay transmission for an N second offset after the scheduled time. +#define PIP_TIME_SYNC_OFFSET_SECONDS 0 + /** * WSPR settings */ diff --git a/src/config_internal.h b/src/config_internal.h index 2ff46a0..60c5539 100644 --- a/src/config_internal.h +++ b/src/config_internal.h @@ -23,6 +23,7 @@ extern bool si5351_enabled; extern volatile bool system_initialized; extern char *cw_message_templates[]; +extern char *pip_message_templates[]; extern char *aprs_comment_templates[]; extern char *fsq_comment_templates[]; extern char *ftjt_message_templates[]; diff --git a/src/radio.c b/src/radio.c index d8daefa..9a1f691 100644 --- a/src/radio.c +++ b/src/radio.c @@ -75,6 +75,19 @@ radio_transmit_entry radio_transmit_schedule[] = { .fsk_encoder_api = &mfsk_fsk_encoder_api, }, #else + { + .enabled = RADIO_SI4032_TX_PIP, + .radio_type = RADIO_TYPE_SI4032, + .data_mode = RADIO_DATA_MODE_PIP, + .transmit_count = RADIO_SI4032_TX_PIP_COUNT, + .time_sync_seconds = PIP_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = PIP_TIME_SYNC_OFFSET_SECONDS, + .frequency = RADIO_SI4032_TX_FREQUENCY_PIP, + .tx_power = RADIO_SI4032_TX_POWER, + .symbol_rate = MORSE_WPM_TO_SYMBOL_RATE(PIP_SPEED_WPM), + .payload_encoder = &radio_cw_payload_encoder, + .fsk_encoder_api = &morse_fsk_encoder_api, + }, { .enabled = RADIO_SI4032_TX_CW, .radio_type = RADIO_TYPE_SI4032, @@ -132,6 +145,21 @@ radio_transmit_entry radio_transmit_schedule[] = { .fsk_encoder_api = &mfsk_fsk_encoder_api, }, #if RADIO_SI5351_ENABLE +#if RADIO_SI5351_TX_PIP + { + .enabled = RADIO_SI5351_TX_PIP, + .radio_type = RADIO_TYPE_SI5351, + .data_mode = RADIO_DATA_MODE_PIP, + .transmit_count = RADIO_SI5351_TX_PIP_COUNT, + .time_sync_seconds = PIP_TIME_SYNC_SECONDS, + .time_sync_seconds_offset = PIP_TIME_SYNC_OFFSET_SECONDS, + .frequency = RADIO_SI5351_TX_FREQUENCY_PIP, + .tx_power = RADIO_SI5351_TX_POWER, + .symbol_rate = MORSE_WPM_TO_SYMBOL_RATE(PIP_SPEED_WPM), + .payload_encoder = &radio_cw_payload_encoder, + .fsk_encoder_api = &morse_fsk_encoder_api, + }, +#endif #if RADIO_SI5351_TX_CW { .enabled = RADIO_SI5351_TX_CW, @@ -389,6 +417,7 @@ static bool radio_start_transmit(radio_transmit_entry *entry) switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: // CW timing is not as critical enable_gps_during_transmit = true; @@ -540,6 +569,7 @@ static bool radio_stop_transmit(radio_transmit_entry *entry) switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: morse_encoder_destroy(&entry->fsk_encoder); break; case RADIO_DATA_MODE_RTTY: @@ -815,6 +845,9 @@ void radio_init() case RADIO_DATA_MODE_CW: entry->messages = cw_message_templates; break; + case RADIO_DATA_MODE_PIP: + entry->messages = pip_message_templates; + break; case RADIO_DATA_MODE_APRS_1200: entry->messages = aprs_comment_templates; break; diff --git a/src/radio_internal.h b/src/radio_internal.h index 004a2c6..df134b8 100644 --- a/src/radio_internal.h +++ b/src/radio_internal.h @@ -14,6 +14,7 @@ typedef enum _radio_type { typedef enum _radio_data_mode { RADIO_DATA_MODE_CW = 1, + RADIO_DATA_MODE_PIP, RADIO_DATA_MODE_RTTY, RADIO_DATA_MODE_APRS_1200, RADIO_DATA_MODE_HORUS_V1, diff --git a/src/radio_si4032.c b/src/radio_si4032.c index b50e531..2939d9b 100644 --- a/src/radio_si4032.c +++ b/src/radio_si4032.c @@ -45,6 +45,7 @@ bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: frequency_offset = 1; modulation_type = SI4032_MODULATION_TYPE_OOK; use_direct_mode = false; @@ -96,6 +97,7 @@ bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: spi_uninit(); system_disable_tick(); si4032_use_sdi_pin(true); @@ -127,6 +129,7 @@ static uint32_t radio_next_symbol_si4032(radio_transmit_entry *entry, radio_modu { switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: return 0; case RADIO_DATA_MODE_RTTY: return 0; @@ -216,7 +219,8 @@ inline void radio_handle_data_timer_si4032() } switch (radio_current_transmit_entry->data_mode) { - case RADIO_DATA_MODE_CW: { + case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: { cw_symbol_rate_multiplier--; if (cw_symbol_rate_multiplier > 0) { break; @@ -274,6 +278,7 @@ bool radio_stop_transmit_si4032(radio_transmit_entry *entry, radio_module_state switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: si4032_use_sdi_pin(false); data_timer_uninit(); spi_init(); @@ -302,6 +307,7 @@ bool radio_stop_transmit_si4032(radio_transmit_entry *entry, radio_module_state switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: system_enable_tick(); break; case RADIO_DATA_MODE_APRS_1200: diff --git a/src/radio_si5351.c b/src/radio_si5351.c index ebc8564..d37615b 100644 --- a/src/radio_si5351.c +++ b/src/radio_si5351.c @@ -22,6 +22,7 @@ bool radio_start_transmit_si5351(radio_transmit_entry *entry, radio_module_state switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: data_timer_init(entry->symbol_rate * CW_SYMBOL_RATE_MULTIPLIER); set_frequency_early = false; break; @@ -50,6 +51,7 @@ bool radio_start_transmit_si5351(radio_transmit_entry *entry, radio_module_state switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: system_disable_tick(); shared_state->radio_interrupt_transmit_active = true; // Setting the frequency turns on the output @@ -70,6 +72,7 @@ bool radio_transmit_symbol_si5351(radio_transmit_entry *entry, radio_module_stat { switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: return false; case RADIO_DATA_MODE_HORUS_V1: return false; @@ -115,7 +118,8 @@ inline void radio_handle_data_timer_si5351() // TODO: handle Si5351 errors switch (radio_current_transmit_entry->data_mode) { - case RADIO_DATA_MODE_CW: { + case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: { cw_symbol_rate_multiplier--; if (cw_symbol_rate_multiplier > 0) { break; @@ -179,6 +183,7 @@ bool radio_stop_transmit_si5351(radio_transmit_entry *entry, radio_module_state { switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: break; case RADIO_DATA_MODE_HORUS_V1: // use_fast_si5351 = true; @@ -195,6 +200,7 @@ bool radio_stop_transmit_si5351(radio_transmit_entry *entry, radio_module_state switch (entry->data_mode) { case RADIO_DATA_MODE_CW: + case RADIO_DATA_MODE_PIP: data_timer_uninit(); system_enable_tick(); break;