diff --git a/Firmware/radio/at.c b/Firmware/radio/at.c index e1610889..a5070061 100644 --- a/Firmware/radio/at.c +++ b/Firmware/radio/at.c @@ -37,6 +37,7 @@ #include "flash_layout.h" #include "at.h" #include "board.h" +#include "ham.h" #ifdef INCLUDE_AES #include "AES/aes.h" @@ -70,6 +71,7 @@ static void at_m(void); #pragma save #pragma nooverlay + void at_input(register uint8_t c) { @@ -458,7 +460,58 @@ at_ampersand(void) break; } #endif // INCLUDE_AES - default: + case 'C': + switch (at_cmd[4]) { + case 'E': + // enables transmission of callsign (default every 10 minutes) + enable_callsign = true; + printf("Transmission of callsign enabled: %s\n",callsign); + break; + case 'D': + // disables transmission of callsign + enable_callsign = false; + printf("Transmission of callsign disabled: %s\n",callsign); + break; + case 'S': + // user is entering their callsign + // interval (in seconds) between transmission of callsign + // get the register number first + if(at_cmd[5] == '=') + { + register uint8_t c; + idx = 6; + uint8_t cs_idx = 0; + for (;;) { + c = at_cmd[idx]; + // if (!isalnum(c)) + if (!(isalpha(c) || isdigit(c))) + break; + callsign[cs_idx++] = c; + idx++; + } + printf("Callsign set to %s\n",callsign); + } + else + at_error(); + break; + case 'I': + // interval (in seconds) between transmission of callsign + // get the register number first + if(at_cmd[5] == '=') + { + idx = 6; + at_parse_number(); + // Max allowed interval is 10 minutes + callsign_tx_interval_secs = at_num < MAX_CALLSIGN_INTERVAL_SEC ? at_num : MAX_CALLSIGN_INTERVAL_SEC; + printf("Callsign transmission interval %d s\n",callsign_tx_interval_secs); + } + else + at_error(); + break; + } + break; + + default: at_error(); break; } diff --git a/Firmware/radio/ham.c b/Firmware/radio/ham.c new file mode 100644 index 00000000..47214676 --- /dev/null +++ b/Firmware/radio/ham.c @@ -0,0 +1,51 @@ +// -*- Mode: C; c-basic-offset: 8; -*- +// +// Copyright (c) 2025 Alexis Nicole Benini, Ph.D. +// www.alexisbenini.com +// All Rights Reserved +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// o Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// o Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +// + +/// +/// @file ham.c +/// +/// Functions for transmission of HAM radio callsign +/// + +#include "ham.h" +#include + +__xdata char callsign[CALLSIGN_MAX_LENGTH]; +__pdata uint16_t callsign_tx_interval_secs; +__pdata bool enable_callsign; + +#pragma nooverlay + +void initialize_ham_callsign_tx_params() +{ + enable_callsign = false; + memcpy(callsign,"NOSIGN",7); + callsign_tx_interval_secs = 2; // 600; +} diff --git a/Firmware/radio/ham.h b/Firmware/radio/ham.h new file mode 100644 index 00000000..f83a46ca --- /dev/null +++ b/Firmware/radio/ham.h @@ -0,0 +1,53 @@ +// -*- Mode: C; c-basic-offset: 8; -*- +// +// Copyright (c) 2025 Alexis Nicole Benini, Ph.D. +// www.alexisbenini.com +// All Rights Reserved +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// o Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// o Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +// + +/// +/// @file ham.h +/// +/// Function and parameters for transmission of HAM radio callsign +/// + +#ifndef _HAM_H_ +#define _HAM_H_ + +#include +#include +#include "cdt.h" + +#define MAX_CALLSIGN_INTERVAL_SEC 10*60 // According to FCC rules, the call sign must be transmitted at least every 10 minutes. +#define CALLSIGN_MAX_LENGTH 8 // This includes the initial "DE" sequence +extern __xdata char callsign[CALLSIGN_MAX_LENGTH]; // This assumes that the operator is using a standard callsign length (6). + // However, some regions might use 7 characters. The length of this array includes also the \0 at the end +extern __pdata uint16_t callsign_tx_interval_secs; // This is set to 600 seconds (10 minutes) by default +extern __pdata bool enable_callsign; // Set to false by default (no callsign transmission) + +void initialize_ham_callsign_tx_params(); + +#endif // _HAM_H_ diff --git a/Firmware/radio/main.c b/Firmware/radio/main.c index c6ff302c..356b39e0 100644 --- a/Firmware/radio/main.c +++ b/Firmware/radio/main.c @@ -41,6 +41,7 @@ #include "tdm.h" #include "timer.h" #include "freq_hopping.h" +#include "ham.h" #ifdef INCLUDE_AES #include "AES/aes.h" @@ -129,6 +130,9 @@ main(void) // do radio initialisation radio_init(); + // ham radio callsign initialization + initialize_ham_callsign_tx_params(); + // turn on the receiver if (!radio_receiver_on()) { panic("failed to enable receiver"); diff --git a/Firmware/radio/tdm.c b/Firmware/radio/tdm.c index 39eb45c5..6470b929 100644 --- a/Firmware/radio/tdm.c +++ b/Firmware/radio/tdm.c @@ -42,6 +42,7 @@ #include "freq_hopping.h" #include "crc.h" #include "serial.h" +#include "ham.h" #ifdef INCLUDE_AES #include "AES/aes.h" @@ -139,6 +140,7 @@ static __bit send_statistics; /// set when we should send a MAVLink report pkt extern uint8_t seen_mavlink; + struct tdm_trailer { uint16_t window:13; uint16_t command:1; @@ -156,6 +158,7 @@ static __pdata char remote_at_cmd[AT_CMD_MAXLEN + 1]; #define PACKET_OVERHEAD (sizeof(trailer)+16) + /// display RSSI output /// void @@ -495,6 +498,7 @@ handle_at_command(__pdata uint8_t len) // a stack carary to detect a stack overflow __at(0xFF) uint8_t __idata _canary; + /// main loop for time division multiplexing transparent serial /// void @@ -516,9 +520,13 @@ tdm_serial_loop(void) __pdata uint16_t last_t = timer2_tick(); __pdata uint16_t last_link_update = last_t; + __pdata uint16_t half_seconds = 0; + __pdata bool tx_callsign = false; _canary = 42; + uint8_t counter = 0; + for (;;) { if (_canary != 42) { panic("stack blown\n"); @@ -627,7 +635,7 @@ tdm_serial_loop(void) } continue; } - + // see how many 16usec ticks have passed and update // the tdm state machine. We re-fetch tnow as a bad // packet could have cost us a lot of time. @@ -640,8 +648,15 @@ tdm_serial_loop(void) if (tnow - last_link_update > 32768) { link_update(); last_link_update = tnow; + half_seconds++; } + // enable transmission of callsign + if(enable_callsign && half_seconds/2 > callsign_tx_interval_secs) + { + tx_callsign = true; + half_seconds = 0; + } if (lbt_rssi != 0) { // implement listen before talk @@ -738,26 +753,37 @@ tdm_serial_loop(void) pins_user_check(); #endif - // ask the packet system for the next packet to send - if (send_at_command && - max_xmit >= strlen(remote_at_cmd)) { - // send a remote AT command - len = strlen(remote_at_cmd); - memcpy(pbuf, remote_at_cmd, len); - trailer.command = 1; - send_at_command = false; - } else { - // get a packet from the serial port - len = packet_get_next(max_xmit, pbuf); - - if (len > 0) { - trailer.command = packet_is_injected(); - } else { - trailer.command = 0; - } + if(tx_callsign) + { + len = 7; + // printf("time to send: %s\n",callsign); + memcpy(pbuf,callsign, 7); + trailer.command = 1; + tx_callsign = false; + } + else + { + // ask the packet system for the next packet to send + if (send_at_command && + max_xmit >= strlen(remote_at_cmd)) { + // send a remote AT command + len = strlen(remote_at_cmd); + memcpy(pbuf, remote_at_cmd, len); + trailer.command = 1; + send_at_command = false; + } else { + // get a packet from the serial port + len = packet_get_next(max_xmit, pbuf); + + if (len > 0) { + trailer.command = packet_is_injected(); + } else { + trailer.command = 0; + } #ifdef INCLUDE_AES - trailer.crc = crc16(len, pbuf); + trailer.crc = crc16(len, pbuf); #endif + } } if (len > max_data_packet_length) {