2017-05-30 22:58:20 +00:00
|
|
|
#include "ch.h"
|
|
|
|
#include "hal.h"
|
2017-09-07 19:56:00 +00:00
|
|
|
|
|
|
|
#include "tracking.h"
|
2017-05-30 22:58:20 +00:00
|
|
|
#include "debug.h"
|
|
|
|
#include "radio.h"
|
|
|
|
#include "si4464.h"
|
|
|
|
#include "geofence.h"
|
|
|
|
#include "pi2c.h"
|
|
|
|
#include "padc.h"
|
|
|
|
#include <string.h>
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
// APRS related
|
2017-08-30 03:29:59 +00:00
|
|
|
#define PLAYBACK_RATE ((STM32_PCLK1) / 500) /* Samples per second (48Mhz / 250 = 192kHz) */
|
2017-05-30 22:58:20 +00:00
|
|
|
#define BAUD_RATE 1200 /* APRS AFSK baudrate */
|
2017-06-15 06:08:48 +00:00
|
|
|
#define SAMPLES_PER_BAUD (PLAYBACK_RATE / BAUD_RATE) /* Samples per baud (192kHz / 1200baud = 160samp/baud) */
|
2017-05-30 22:58:20 +00:00
|
|
|
#define PHASE_DELTA_1200 (((2 * 1200) << 16) / PLAYBACK_RATE) /* Delta-phase per sample for 1200Hz tone */
|
|
|
|
#define PHASE_DELTA_2200 (((2 * 2200) << 16) / PLAYBACK_RATE) /* Delta-phase per sample for 2200Hz tone */
|
|
|
|
|
2017-06-15 06:08:48 +00:00
|
|
|
static uint32_t phase_delta; // 1200/2200 for standard AX.25
|
|
|
|
static uint32_t phase; // Fixed point 9.7 (2PI = TABLE_SIZE)
|
|
|
|
static uint32_t packet_pos; // Next bit to be sent out
|
|
|
|
static uint32_t current_sample_in_baud; // 1 bit = SAMPLES_PER_BAUD samples
|
|
|
|
static uint8_t current_byte;
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
// 2FSK related
|
2017-06-15 06:08:48 +00:00
|
|
|
static uint8_t txs; // Serial maschine state
|
|
|
|
static uint8_t txc; // Current byte
|
|
|
|
static uint32_t txi; // Bitcounter of current byte
|
|
|
|
static uint32_t txj; // Bytecounter
|
2017-06-12 14:46:03 +00:00
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
// Radio related
|
|
|
|
static mutex_t radio_mtx; // Radio mutex
|
|
|
|
bool radio_mtx_init = false;
|
|
|
|
static mod_t active_mod = MOD_NOT_SET;
|
|
|
|
static radioMSG_t radio_msg;
|
|
|
|
static uint8_t radio_buffer[8192];
|
|
|
|
static uint32_t radio_freq;
|
|
|
|
|
2017-06-12 14:46:03 +00:00
|
|
|
static const char *getModulation(uint8_t key) {
|
2017-06-15 06:08:48 +00:00
|
|
|
const char *val[] = {"unknown", "OOK", "2FSK", "2GFSK", "AFSK"};
|
2017-06-12 14:46:03 +00:00
|
|
|
return val[key];
|
|
|
|
};
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
static void initAFSK(void) {
|
2017-09-05 06:35:23 +00:00
|
|
|
// Initialize radio
|
2017-06-15 06:08:48 +00:00
|
|
|
Si4464_Init();
|
|
|
|
setModemAFSK();
|
2017-09-05 06:35:23 +00:00
|
|
|
active_mod = MOD_AFSK;
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
static void sendAFSK(void) {
|
2017-06-15 06:08:48 +00:00
|
|
|
// Initialize variables for timer
|
2017-05-30 22:58:20 +00:00
|
|
|
phase_delta = PHASE_DELTA_1200;
|
|
|
|
phase = 0;
|
|
|
|
packet_pos = 0;
|
|
|
|
current_sample_in_baud = 0;
|
|
|
|
current_byte = 0;
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
// Tune
|
2017-10-02 19:16:02 +00:00
|
|
|
radioTune(radio_freq, 0, radio_msg.power, 0);
|
2017-09-05 06:35:23 +00:00
|
|
|
|
2017-06-15 06:08:48 +00:00
|
|
|
// Initialize timer
|
2017-05-30 22:58:20 +00:00
|
|
|
RCC->APB1ENR |= RCC_APB1ENR_TIM7EN;
|
2017-06-15 06:08:48 +00:00
|
|
|
nvicEnableVector(TIM7_IRQn, 1);
|
2017-09-05 06:35:23 +00:00
|
|
|
TIM7->ARR = 500;
|
2017-06-15 06:08:48 +00:00
|
|
|
TIM7->CR1 &= ~STM32_TIM_CR1_ARPE;
|
|
|
|
TIM7->DIER |= STM32_TIM_DIER_UIE;
|
|
|
|
|
|
|
|
// Start timer
|
|
|
|
TIM7->CR1 |= STM32_TIM_CR1_CEN;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// Block execution while timer is running
|
|
|
|
while(TIM7->CR1 & STM32_TIM_CR1_CEN)
|
|
|
|
chThdSleepMilliseconds(10);
|
2017-09-05 06:35:23 +00:00
|
|
|
|
|
|
|
shutdownRadio();
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
static void init2GFSK(void) {
|
2017-09-02 03:43:13 +00:00
|
|
|
// Initialize radio
|
2017-06-15 06:08:48 +00:00
|
|
|
Si4464_Init();
|
2017-10-02 19:16:02 +00:00
|
|
|
setModem2GFSK(radio_msg.gfsk_conf);
|
2017-09-05 06:35:23 +00:00
|
|
|
active_mod = MOD_2GFSK;
|
2017-06-15 06:08:48 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
static thread_t *feeder_thd = NULL;
|
2017-09-06 22:46:59 +00:00
|
|
|
static THD_WORKING_AREA(si_fifo_feeder_wa, 1024);
|
2017-09-05 06:35:23 +00:00
|
|
|
THD_FUNCTION(si_fifo_feeder_thd, arg)
|
|
|
|
{
|
|
|
|
(void)arg;
|
|
|
|
|
2017-09-02 03:43:13 +00:00
|
|
|
uint16_t c = 64;
|
2017-10-02 19:16:02 +00:00
|
|
|
uint16_t all = (radio_msg.bin_len+7)/8;
|
2017-06-15 06:08:48 +00:00
|
|
|
|
2017-09-05 11:56:20 +00:00
|
|
|
chRegSetThreadName("radio_tx_feeder");
|
2017-09-02 03:43:13 +00:00
|
|
|
// Initial FIFO fill
|
2017-10-02 19:16:02 +00:00
|
|
|
Si4464_writeFIFO(radio_msg.buffer, c);
|
2017-09-05 06:35:23 +00:00
|
|
|
|
2017-09-06 20:03:56 +00:00
|
|
|
// Start transmission
|
2017-10-02 19:16:02 +00:00
|
|
|
radioTune(radio_freq, 0, radio_msg.power, all);
|
2017-06-15 06:08:48 +00:00
|
|
|
|
2017-09-02 03:43:13 +00:00
|
|
|
while(c < all) { // Do while bytes not written into FIFO completely
|
|
|
|
// Determine free memory in Si4464-FIFO
|
2017-09-05 11:56:20 +00:00
|
|
|
uint8_t more = Si4464_freeFIFO();
|
|
|
|
if(more > all-c) {
|
|
|
|
if((more = all-c) == 0) // Calculate remainder to send
|
|
|
|
break; // End if nothing left
|
|
|
|
}
|
2017-10-02 19:16:02 +00:00
|
|
|
Si4464_writeFIFO(&radio_msg.buffer[c], more); // Write into FIFO
|
2017-09-02 03:43:13 +00:00
|
|
|
c += more;
|
2017-09-08 22:00:55 +00:00
|
|
|
chThdSleepMilliseconds(15); // That value is ok up to 38k4
|
2017-09-02 03:43:13 +00:00
|
|
|
}
|
2017-09-05 06:35:23 +00:00
|
|
|
|
2017-09-06 20:03:56 +00:00
|
|
|
// Shutdown radio (and wait for Si4464 to finish transmission)
|
2017-09-05 06:35:23 +00:00
|
|
|
shutdownRadio();
|
2017-09-06 20:03:56 +00:00
|
|
|
|
2017-09-05 11:56:20 +00:00
|
|
|
chThdExit(MSG_OK);
|
2017-09-05 06:35:23 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
static void send2GFSK(void) {
|
2017-09-05 11:56:20 +00:00
|
|
|
// Start/re-start FIFO feeder
|
|
|
|
feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_thd, NULL);
|
2017-09-05 06:35:23 +00:00
|
|
|
|
|
|
|
// Wait for the transmitter to start (because it is used as mutex)
|
|
|
|
while(Si4464_getState() != SI4464_STATE_TX)
|
|
|
|
chThdSleepMilliseconds(1);
|
2017-06-15 06:08:48 +00:00
|
|
|
}
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
/**
|
2017-09-05 06:35:23 +00:00
|
|
|
* Fast interrupt handler for AFSK modulation. It has has the highest priority
|
|
|
|
* in order to provide an accurate low jitter modulation.
|
2017-05-30 22:58:20 +00:00
|
|
|
*/
|
|
|
|
CH_FAST_IRQ_HANDLER(STM32_TIM7_HANDLER)
|
|
|
|
{
|
2017-09-05 06:35:23 +00:00
|
|
|
if(active_mod == MOD_AFSK) // AFSK
|
|
|
|
{
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
if(packet_pos == radio_msg.bin_len) { // Packet transmission finished
|
2017-05-30 22:58:20 +00:00
|
|
|
TIM7->CR1 &= ~STM32_TIM_CR1_CEN; // Disable timer
|
|
|
|
TIM7->SR &= ~STM32_TIM_SR_UIF; // Reset interrupt flag
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(current_sample_in_baud == 0) {
|
|
|
|
if((packet_pos & 7) == 0) { // Load up next byte
|
2017-10-02 19:16:02 +00:00
|
|
|
current_byte = radio_msg.buffer[packet_pos >> 3];
|
2017-05-30 22:58:20 +00:00
|
|
|
} else { // Load up next bit
|
|
|
|
current_byte = current_byte / 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Toggle tone (1200 <> 2200)
|
|
|
|
phase_delta = (current_byte & 1) ? PHASE_DELTA_1200 : PHASE_DELTA_2200;
|
|
|
|
|
2017-06-15 06:08:48 +00:00
|
|
|
phase += phase_delta; // Add delta-phase (delta-phase tone dependent)
|
2017-09-05 06:35:23 +00:00
|
|
|
RADIO_WRITE_GPIO((phase >> 16) & 1); // Set modulaton pin (connected to Si4464)
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
current_sample_in_baud++;
|
|
|
|
|
|
|
|
if(current_sample_in_baud == SAMPLES_PER_BAUD) { // Old bit consumed, load next bit
|
|
|
|
current_sample_in_baud = 0;
|
|
|
|
packet_pos++;
|
|
|
|
}
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
} else { // 2FSK
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
switch(txs)
|
|
|
|
{
|
|
|
|
case 6: // TX-delay
|
|
|
|
txj++;
|
2017-10-02 19:16:02 +00:00
|
|
|
if(txj > (uint32_t)(radio_msg.fsk_conf->predelay * radio_msg.fsk_conf->baud / 1000)) {
|
2017-09-05 06:35:23 +00:00
|
|
|
txj = 0;
|
|
|
|
txs = 7;
|
|
|
|
}
|
|
|
|
break;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
case 7: // Transmit a single char
|
2017-10-02 19:16:02 +00:00
|
|
|
if(txj < radio_msg.bin_len/8) {
|
|
|
|
txc = radio_msg.buffer[txj]; // Select char
|
2017-09-05 06:35:23 +00:00
|
|
|
txj++;
|
|
|
|
RADIO_WRITE_GPIO(LOW); // Start Bit (Synchronizing)
|
|
|
|
txi = 0;
|
|
|
|
txs = 8;
|
|
|
|
} else { // Finished to transmit string
|
|
|
|
RADIO_WRITE_GPIO(HIGH);
|
|
|
|
TIM7->CR1 &= ~STM32_TIM_CR1_CEN; // Disable timer
|
|
|
|
TIM7->SR &= ~STM32_TIM_SR_UIF; // Reset interrupt flag
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
case 8:
|
2017-10-02 19:16:02 +00:00
|
|
|
if(txi < radio_msg.fsk_conf->bits) {
|
2017-09-05 06:35:23 +00:00
|
|
|
txi++;
|
|
|
|
RADIO_WRITE_GPIO(txc & 1);
|
|
|
|
txc = txc >> 1;
|
|
|
|
} else {
|
|
|
|
RADIO_WRITE_GPIO(HIGH); // Stop Bit
|
|
|
|
txi = 0;
|
|
|
|
txs = 9;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 9:
|
2017-10-02 19:16:02 +00:00
|
|
|
if(radio_msg.fsk_conf->stopbits == 2)
|
2017-09-05 06:35:23 +00:00
|
|
|
RADIO_WRITE_GPIO(HIGH); // Stop Bit
|
|
|
|
txs = 7;
|
|
|
|
}
|
2017-07-24 22:46:23 +00:00
|
|
|
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
palToggleLine(LINE_IO_LED1);
|
|
|
|
|
2017-06-15 06:08:48 +00:00
|
|
|
TIM7->SR &= ~STM32_TIM_SR_UIF; // Reset interrupt flag
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
static void initOOK(void) {
|
2017-09-05 06:35:23 +00:00
|
|
|
// Initialize radio
|
2017-06-15 06:08:48 +00:00
|
|
|
Si4464_Init();
|
|
|
|
setModemOOK();
|
2017-09-05 06:35:23 +00:00
|
|
|
active_mod = MOD_OOK;
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Transmits binary OOK message. One bit = 20ms (1: TONE, 0: NO TONE)
|
|
|
|
*/
|
2017-10-02 19:16:02 +00:00
|
|
|
static void sendOOK(void) {
|
2017-09-05 06:35:23 +00:00
|
|
|
// Tune
|
2017-10-02 19:16:02 +00:00
|
|
|
radioTune(radio_freq, 0, radio_msg.power, 0);
|
2017-09-05 06:35:23 +00:00
|
|
|
|
2017-05-30 22:58:20 +00:00
|
|
|
// Transmit data
|
|
|
|
uint32_t bit = 0;
|
|
|
|
systime_t time = chVTGetSystemTimeX();
|
2017-10-02 19:16:02 +00:00
|
|
|
while(bit < radio_msg.bin_len) {
|
|
|
|
RADIO_WRITE_GPIO((radio_msg.buffer[bit/8] >> (bit%8)) & 0x1);
|
2017-05-30 22:58:20 +00:00
|
|
|
bit++;
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
time = chThdSleepUntilWindowed(time, time + MS2ST(1200 / radio_msg.ook_conf->speed));
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
2017-09-05 06:35:23 +00:00
|
|
|
shutdownRadio();
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
static void init2FSK(void) {
|
2017-05-30 22:58:20 +00:00
|
|
|
// Initialize radio and tune
|
2017-06-15 06:08:48 +00:00
|
|
|
Si4464_Init();
|
|
|
|
setModem2FSK();
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
static void send2FSK(void) {
|
2017-05-30 22:58:20 +00:00
|
|
|
txs = 6;
|
|
|
|
txc = 0;
|
|
|
|
txi = 0;
|
|
|
|
txj = 0;
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
// Tune
|
2017-10-02 19:16:02 +00:00
|
|
|
radioTune(radio_freq, radio_msg.fsk_conf->shift, radio_msg.power, 0);
|
2017-09-05 06:35:23 +00:00
|
|
|
|
|
|
|
// Initialize timer
|
|
|
|
RCC->APB1ENR |= RCC_APB1ENR_TIM7EN;
|
|
|
|
nvicEnableVector(TIM7_IRQn, 1);
|
2017-10-02 19:16:02 +00:00
|
|
|
TIM7->ARR = STM32_PCLK1 / 16 / radio_msg.fsk_conf->baud;
|
2017-09-05 06:35:23 +00:00
|
|
|
TIM7->PSC = 15;
|
|
|
|
TIM7->CR1 &= ~STM32_TIM_CR1_ARPE;
|
|
|
|
TIM7->DIER |= STM32_TIM_DIER_UIE;
|
|
|
|
|
|
|
|
// Start timer
|
|
|
|
TIM7->CR1 |= STM32_TIM_CR1_CEN;
|
|
|
|
|
|
|
|
// Block execution while timer is running
|
|
|
|
while(TIM7->CR1 & STM32_TIM_CR1_CEN)
|
|
|
|
chThdSleepMilliseconds(10);
|
|
|
|
|
|
|
|
shutdownRadio();
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
2017-08-27 19:14:30 +00:00
|
|
|
void shutdownRadio(void)
|
|
|
|
{
|
2017-09-02 03:43:13 +00:00
|
|
|
// Wait for PH to finish transmission for 2GFSK
|
|
|
|
while(active_mod == MOD_2GFSK && Si4464_getState() == SI4464_STATE_TX)
|
2017-09-08 22:00:55 +00:00
|
|
|
chThdSleepMilliseconds(10);
|
2017-09-02 03:43:13 +00:00
|
|
|
|
2017-08-27 19:14:30 +00:00
|
|
|
Si4464_shutdown();
|
|
|
|
active_mod = MOD_NOT_SET;
|
|
|
|
}
|
|
|
|
|
2017-05-30 22:58:20 +00:00
|
|
|
/**
|
|
|
|
* Returns APRS region specific frequency determined by GPS location. It will
|
|
|
|
* use the APRS default frequency set in the config file if no GPS fix has
|
|
|
|
* been received.
|
|
|
|
*/
|
2017-06-15 06:08:48 +00:00
|
|
|
uint32_t getAPRSRegionFrequency(void) {
|
2017-05-30 22:58:20 +00:00
|
|
|
trackPoint_t *point = getLastTrackPoint();
|
|
|
|
|
2017-09-11 04:45:19 +00:00
|
|
|
// Position unknown
|
|
|
|
if(point == NULL || (point->gps_lat == 0 && point->gps_lon == 0))
|
|
|
|
return 0;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// America 144.390 MHz
|
|
|
|
if(isPointInAmerica(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_AMERICA;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// China 144.640 MHz
|
|
|
|
if(isPointInChina(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_CHINA;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// Japan 144.660 MHz
|
|
|
|
if(isPointInJapan(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_JAPAN;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// Southkorea 144.620 MHz
|
|
|
|
if(isPointInSouthkorea(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_SOUTHKOREA;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// Southkorea 144.620 MHz
|
|
|
|
if(isPointInSoutheastAsia(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_SOUTHEASTASIA;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// Australia 145.175 MHz
|
|
|
|
if(isPointInAustralia(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_AUSTRALIA;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// Australia 144.575 MHz
|
|
|
|
if(isPointInNewZealand(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_NEWZEALAND;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// Argentina/Paraguay/Uruguay 144.930 MHz
|
|
|
|
if(isPointInArgentina(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_ARGENTINA;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
// Brazil 145.575 MHz
|
|
|
|
if(isPointInBrazil(point->gps_lat, point->gps_lon))
|
2017-09-11 04:45:19 +00:00
|
|
|
return APRS_FREQ_BRAZIL;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-09-11 04:45:19 +00:00
|
|
|
// For the rest of the world 144.800 MHz
|
|
|
|
return 144800000;
|
2017-05-30 22:58:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends radio message into message box. This method will return false if message box is full.
|
|
|
|
*/
|
2017-09-05 06:35:23 +00:00
|
|
|
bool transmitOnRadio(radioMSG_t *msg, bool shutdown)
|
|
|
|
{
|
2017-09-06 20:03:56 +00:00
|
|
|
(void)shutdown;
|
2017-10-02 19:16:02 +00:00
|
|
|
uint32_t freq = getFrequency(msg->freq); // Get transmission frequency
|
|
|
|
if(inRadioBand(freq)) // Frequency in radio radio band
|
2017-09-05 06:35:23 +00:00
|
|
|
{
|
2017-10-02 19:16:02 +00:00
|
|
|
if(msg->bin_len > 0) // Message length is not zero
|
2017-09-05 06:35:23 +00:00
|
|
|
{
|
|
|
|
lockRadio(); // Lock radio
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-10-02 19:16:02 +00:00
|
|
|
// Copy data
|
|
|
|
memcpy(&radio_msg, msg, sizeof(radioMSG_t));
|
2017-10-07 04:55:11 +00:00
|
|
|
memcpy(&radio_buffer, msg->buffer, sizeof(radio_buffer));
|
2017-10-02 19:16:02 +00:00
|
|
|
radio_msg.buffer = radio_buffer;
|
|
|
|
radio_freq = freq;
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
TRACE_INFO( "RAD > Transmit %d.%03d MHz, Pwr %d, %s, %d bits",
|
2017-10-02 19:16:02 +00:00
|
|
|
freq/1000000, (freq%1000000)/1000, msg->power,
|
2017-09-05 06:35:23 +00:00
|
|
|
getModulation(msg->mod), msg->bin_len
|
|
|
|
);
|
|
|
|
|
|
|
|
switch(msg->mod)
|
|
|
|
{
|
|
|
|
case MOD_2FSK:
|
|
|
|
if(active_mod != msg->mod)
|
2017-10-02 19:16:02 +00:00
|
|
|
init2FSK();
|
|
|
|
send2FSK();
|
2017-09-05 06:35:23 +00:00
|
|
|
break;
|
|
|
|
case MOD_2GFSK:
|
|
|
|
if(active_mod != msg->mod)
|
2017-10-02 19:16:02 +00:00
|
|
|
init2GFSK();
|
|
|
|
send2GFSK();
|
2017-09-05 06:35:23 +00:00
|
|
|
break;
|
|
|
|
case MOD_AFSK:
|
|
|
|
if(active_mod != msg->mod)
|
2017-10-02 19:16:02 +00:00
|
|
|
initAFSK();
|
|
|
|
sendAFSK();
|
2017-09-05 06:35:23 +00:00
|
|
|
break;
|
|
|
|
case MOD_OOK:
|
|
|
|
if(active_mod != msg->mod)
|
2017-10-02 19:16:02 +00:00
|
|
|
initOOK();
|
|
|
|
sendOOK();
|
2017-09-05 06:35:23 +00:00
|
|
|
break;
|
|
|
|
case MOD_NOT_SET:
|
|
|
|
TRACE_ERROR("RAD > Modulation not set");
|
|
|
|
break;
|
|
|
|
}
|
2017-10-02 19:16:02 +00:00
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
unlockRadio(); // Unlock radio
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
} else {
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
TRACE_ERROR("RAD > It is nonsense to transmit 0 bits, %d.%03d MHz, Pwr dBm, %s, %d bits",
|
2017-10-02 19:16:02 +00:00
|
|
|
freq/1000000, (freq%1000000)/1000, msg->power, getModulation(msg->mod), msg->bin_len
|
2017-09-05 06:35:23 +00:00
|
|
|
);
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
}
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-06-20 13:24:22 +00:00
|
|
|
} else { // Frequency out of radio band
|
2017-05-30 22:58:20 +00:00
|
|
|
|
2017-06-20 13:24:22 +00:00
|
|
|
TRACE_ERROR("RAD > Radio cant transmit on this frequency, %d.%03d MHz, Pwr dBm, %s, %d bits",
|
2017-10-02 19:16:02 +00:00
|
|
|
freq/1000000, (freq%1000000)/1000, msg->power, getModulation(msg->mod), msg->bin_len
|
2017-05-30 22:58:20 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-15 06:08:48 +00:00
|
|
|
uint32_t getFrequency(freq_conf_t *config)
|
2017-05-30 22:58:20 +00:00
|
|
|
{
|
|
|
|
switch(config->type) {
|
2017-06-15 06:08:48 +00:00
|
|
|
case FREQ_APRS_REGION:; // Dynamic frequency (determined by GPS position)
|
|
|
|
uint32_t freq = getAPRSRegionFrequency();
|
2017-09-11 04:45:19 +00:00
|
|
|
if(!freq) // Use default frequency (if freq is 0 = position unknown)
|
2017-05-30 22:58:20 +00:00
|
|
|
return config->hz;
|
2017-06-15 06:08:48 +00:00
|
|
|
return freq;
|
2017-05-30 22:58:20 +00:00
|
|
|
|
|
|
|
case FREQ_STATIC: // Static frequency
|
|
|
|
return config->hz;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
void lockRadio(void)
|
|
|
|
{
|
2017-09-08 22:00:55 +00:00
|
|
|
// Initialize mutex
|
|
|
|
if(!radio_mtx_init)
|
|
|
|
chMtxObjectInit(&radio_mtx);
|
|
|
|
radio_mtx_init = true;
|
|
|
|
|
2017-09-05 06:35:23 +00:00
|
|
|
chMtxLock(&radio_mtx);
|
|
|
|
|
2017-09-06 20:03:56 +00:00
|
|
|
// Wait for old feeder thread to terminate
|
|
|
|
if(feeder_thd != NULL) // No waiting on first use
|
|
|
|
chThdWait(feeder_thd);
|
2017-09-05 06:35:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void unlockRadio(void)
|
|
|
|
{
|
|
|
|
chMtxUnlock(&radio_mtx);
|
|
|
|
}
|
|
|
|
|