kopia lustrzana https://github.com/mikaelnousiainen/RS41ng
371 wiersze
11 KiB
C
371 wiersze
11 KiB
C
#include "config.h"
|
|
|
|
#ifdef DFM17
|
|
#include "hal/system.h"
|
|
#include "hal/spi.h"
|
|
#include "hal/pwm.h"
|
|
#include "hal/delay.h"
|
|
#include "hal/datatimer.h"
|
|
#include "drivers/si4063/si4063.h"
|
|
#include "log.h"
|
|
|
|
#include "radio_si4063.h"
|
|
#include "codecs/mfsk/mfsk.h"
|
|
|
|
#define SI4063_DEVIATION_HZ_RTTY 200.0
|
|
#define SI4063_DEVIATION_HZ_APRS 2600.0
|
|
#define SI4063_DEVIATION_HZ_CATS 4800.0
|
|
|
|
#define CW_SYMBOL_RATE_MULTIPLIER 4
|
|
|
|
// TODO: Add support for multiple APRS baud rates
|
|
// This delay is for DFM-17 radiosondes
|
|
#define symbol_delay_bell_202_1200bps_us 821
|
|
|
|
static volatile bool radio_si4063_state_change = false;
|
|
static volatile uint32_t radio_si4063_freq = 0;
|
|
|
|
bool radio_start_transmit_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
|
{
|
|
uint16_t frequency_offset;
|
|
uint32_t frequency_deviation = 0;
|
|
uint32_t data_rate = 0;
|
|
si4063_modulation_type modulation_type;
|
|
bool use_direct_mode;
|
|
bool use_fifo_mode = false;
|
|
|
|
switch (entry->data_mode) {
|
|
case RADIO_DATA_MODE_CW:
|
|
case RADIO_DATA_MODE_PIP:
|
|
frequency_offset = 1;
|
|
modulation_type = SI4063_MODULATION_TYPE_OOK;
|
|
use_direct_mode = false;
|
|
|
|
data_timer_init(entry->symbol_rate * CW_SYMBOL_RATE_MULTIPLIER);
|
|
break;
|
|
case RADIO_DATA_MODE_RTTY:
|
|
frequency_offset = 0;
|
|
frequency_deviation = SI4063_DEVIATION_HZ_RTTY;
|
|
modulation_type = SI4063_MODULATION_TYPE_CW;
|
|
use_direct_mode = false;
|
|
break;
|
|
case RADIO_DATA_MODE_APRS_1200:
|
|
frequency_offset = 0;
|
|
frequency_deviation = SI4063_DEVIATION_HZ_APRS;
|
|
modulation_type = SI4063_MODULATION_TYPE_FSK;
|
|
use_direct_mode = true;
|
|
break;
|
|
case RADIO_DATA_MODE_HORUS_V1:
|
|
case RADIO_DATA_MODE_HORUS_V2: {
|
|
fsk_tone *idle_tone = mfsk_get_idle_tone(&entry->fsk_encoder);
|
|
frequency_offset = (uint16_t) idle_tone->index + HORUS_FREQUENCY_OFFSET_SI4063;
|
|
modulation_type = SI4063_MODULATION_TYPE_CW;
|
|
use_direct_mode = false;
|
|
|
|
data_timer_init(entry->fsk_encoder_api->get_symbol_rate(&entry->fsk_encoder));
|
|
break;
|
|
}
|
|
case RADIO_DATA_MODE_CATS:
|
|
frequency_offset = 0;
|
|
frequency_deviation = SI4063_DEVIATION_HZ_CATS;
|
|
modulation_type = SI4063_MODULATION_TYPE_FIFO_FSK;
|
|
use_direct_mode = false;
|
|
use_fifo_mode = true;
|
|
data_rate = 9600;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
si4063_set_tx_frequency(entry->frequency);
|
|
si4063_set_tx_power(entry->tx_power);
|
|
si4063_set_frequency_offset(frequency_offset);
|
|
si4063_set_modulation_type(modulation_type);
|
|
si4063_set_frequency_deviation(frequency_deviation);
|
|
|
|
if (use_fifo_mode) {
|
|
si4063_set_data_rate(data_rate);
|
|
}
|
|
else {
|
|
si4063_enable_tx();
|
|
}
|
|
|
|
if (use_direct_mode) {
|
|
spi_uninit();
|
|
pwm_timer_init(100 * 100); // TODO: Idle tone
|
|
pwm_timer_use(true);
|
|
pwm_timer_pwm_enable(true);
|
|
}
|
|
|
|
switch (entry->data_mode) {
|
|
case RADIO_DATA_MODE_CW:
|
|
case RADIO_DATA_MODE_PIP:
|
|
spi_uninit();
|
|
system_disable_tick();
|
|
shared_state->radio_interrupt_transmit_active = true;
|
|
break;
|
|
case RADIO_DATA_MODE_APRS_1200:
|
|
shared_state->radio_manual_transmit_active = true;
|
|
break;
|
|
case RADIO_DATA_MODE_HORUS_V1:
|
|
case RADIO_DATA_MODE_HORUS_V2:
|
|
system_disable_tick();
|
|
shared_state->radio_interrupt_transmit_active = true;
|
|
break;
|
|
case RADIO_DATA_MODE_CATS:
|
|
shared_state->radio_fifo_transmit_active = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static uint32_t radio_next_symbol_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
|
{
|
|
switch (entry->data_mode) {
|
|
case RADIO_DATA_MODE_CW:
|
|
case RADIO_DATA_MODE_PIP:
|
|
return 0;
|
|
case RADIO_DATA_MODE_RTTY:
|
|
return 0;
|
|
case RADIO_DATA_MODE_APRS_1200: {
|
|
int8_t next_tone_index = entry->fsk_encoder_api->next_tone(&entry->fsk_encoder);
|
|
if (next_tone_index < 0) {
|
|
return 0;
|
|
}
|
|
|
|
return shared_state->radio_current_fsk_tones[next_tone_index].frequency_hz_100;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool radio_transmit_symbol_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
|
{
|
|
uint32_t frequency = radio_next_symbol_si4063(entry, shared_state);
|
|
|
|
if (frequency == 0) {
|
|
return false;
|
|
}
|
|
|
|
radio_si4063_freq = frequency;
|
|
radio_si4063_state_change = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
static void radio_handle_main_loop_manual_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
|
{
|
|
fsk_encoder_api *fsk_encoder_api = entry->fsk_encoder_api;
|
|
fsk_encoder *fsk_enc = &entry->fsk_encoder;
|
|
|
|
for (uint8_t i = 0; i < shared_state->radio_current_fsk_tone_count; i++) {
|
|
precalculated_pwm_periods[i] = pwm_calculate_period(shared_state->radio_current_fsk_tones[i].frequency_hz_100);
|
|
}
|
|
|
|
system_disable_tick();
|
|
|
|
switch (entry->data_mode) {
|
|
case RADIO_DATA_MODE_APRS_1200: {
|
|
int8_t tone_index;
|
|
|
|
while ((tone_index = fsk_encoder_api->next_tone(fsk_enc)) >= 0) {
|
|
pwm_timer_set_frequency(precalculated_pwm_periods[tone_index]);
|
|
shared_state->radio_symbol_count_loop++;
|
|
delay_us(symbol_delay_bell_202_1200bps_us);
|
|
}
|
|
|
|
radio_si4063_state_change = false;
|
|
shared_state->radio_transmission_finished = true;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
system_enable_tick();
|
|
}
|
|
|
|
void radio_handle_fifo_si4063(radio_transmit_entry *entry, radio_module_state *shared_state) {
|
|
log_debug("Start FIFO TX\n");
|
|
fsk_encoder_api *fsk_encoder_api = entry->fsk_encoder_api;
|
|
fsk_encoder *fsk_enc = &entry->fsk_encoder;
|
|
|
|
uint8_t *data = fsk_encoder_api->get_data(fsk_enc);
|
|
uint16_t len = fsk_encoder_api->get_data_len(fsk_enc);
|
|
|
|
uint16_t written = si4063_start_tx(data, len);
|
|
data += written;
|
|
len -= written;
|
|
|
|
while(len > 0) {
|
|
uint16_t written = si4063_refill_buffer(data, len);
|
|
data += written;
|
|
len -= written;
|
|
|
|
if(si4063_fifo_underflow()) {
|
|
log_info("FIFO underflow - Aborting\n");
|
|
shared_state->radio_transmission_finished = true;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
int err = si4063_wait_for_tx_complete(1000);
|
|
if(err != HAL_OK) {
|
|
log_info("Error waiting for tx complete: %d\n", err);
|
|
}
|
|
|
|
log_debug("Finished FIFO TX\n");
|
|
|
|
shared_state->radio_transmission_finished = true;
|
|
}
|
|
|
|
void radio_handle_main_loop_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
|
{
|
|
if (entry->radio_type != RADIO_TYPE_SI4063 || shared_state->radio_interrupt_transmit_active) {
|
|
return;
|
|
}
|
|
|
|
if (shared_state->radio_manual_transmit_active) {
|
|
radio_handle_main_loop_manual_si4063(entry, shared_state);
|
|
return;
|
|
}
|
|
|
|
if (shared_state->radio_fifo_transmit_active) {
|
|
radio_handle_fifo_si4063(entry, shared_state);
|
|
return;
|
|
}
|
|
|
|
if (radio_si4063_state_change) {
|
|
radio_si4063_state_change = false;
|
|
pwm_timer_set_frequency(radio_si4063_freq);
|
|
shared_state->radio_symbol_count_loop++;
|
|
}
|
|
}
|
|
|
|
inline void radio_handle_data_timer_si4063()
|
|
{
|
|
static int cw_symbol_rate_multiplier = CW_SYMBOL_RATE_MULTIPLIER;
|
|
|
|
if (radio_current_transmit_entry->radio_type != RADIO_TYPE_SI4063 || !radio_shared_state.radio_interrupt_transmit_active) {
|
|
return;
|
|
}
|
|
|
|
switch (radio_current_transmit_entry->data_mode) {
|
|
case RADIO_DATA_MODE_CW:
|
|
case RADIO_DATA_MODE_PIP: {
|
|
cw_symbol_rate_multiplier--;
|
|
if (cw_symbol_rate_multiplier > 0) {
|
|
break;
|
|
}
|
|
|
|
cw_symbol_rate_multiplier = CW_SYMBOL_RATE_MULTIPLIER;
|
|
|
|
fsk_encoder_api *fsk_encoder_api = radio_current_transmit_entry->fsk_encoder_api;
|
|
fsk_encoder *fsk_enc = &radio_current_transmit_entry->fsk_encoder;
|
|
int8_t tone_index;
|
|
|
|
tone_index = fsk_encoder_api->next_tone(fsk_enc);
|
|
if (tone_index < 0) {
|
|
si4063_set_direct_mode_pin(false);
|
|
log_info("CW TX finished\n");
|
|
radio_shared_state.radio_interrupt_transmit_active = false;
|
|
radio_shared_state.radio_transmission_finished = true;
|
|
system_enable_tick();
|
|
break;
|
|
}
|
|
|
|
si4063_set_direct_mode_pin(tone_index == 0 ? false : true);
|
|
|
|
radio_shared_state.radio_symbol_count_interrupt++;
|
|
break;
|
|
}
|
|
case RADIO_DATA_MODE_HORUS_V1:
|
|
case RADIO_DATA_MODE_HORUS_V2: {
|
|
fsk_encoder_api *fsk_encoder_api = radio_current_transmit_entry->fsk_encoder_api;
|
|
fsk_encoder *fsk_enc = &radio_current_transmit_entry->fsk_encoder;
|
|
int8_t tone_index;
|
|
|
|
tone_index = fsk_encoder_api->next_tone(fsk_enc);
|
|
if (tone_index < 0) {
|
|
log_info("Horus TX finished\n");
|
|
radio_shared_state.radio_interrupt_transmit_active = false;
|
|
radio_shared_state.radio_transmission_finished = true;
|
|
system_enable_tick();
|
|
break;
|
|
}
|
|
|
|
// NOTE: The factor of 23 will produce a tone spacing of about 270 Hz, which is the standard spacing for Horus 4FSK
|
|
si4063_set_frequency_offset(tone_index * 23 + HORUS_FREQUENCY_OFFSET_SI4063);
|
|
|
|
radio_shared_state.radio_symbol_count_interrupt++;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool radio_stop_transmit_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
|
{
|
|
bool use_direct_mode = false;
|
|
|
|
switch (entry->data_mode) {
|
|
case RADIO_DATA_MODE_CW:
|
|
case RADIO_DATA_MODE_PIP:
|
|
data_timer_uninit();
|
|
spi_init();
|
|
break;
|
|
case RADIO_DATA_MODE_RTTY:
|
|
case RADIO_DATA_MODE_HORUS_V1:
|
|
case RADIO_DATA_MODE_HORUS_V2:
|
|
data_timer_uninit();
|
|
break;
|
|
case RADIO_DATA_MODE_CATS:
|
|
break;
|
|
case RADIO_DATA_MODE_APRS_1200:
|
|
use_direct_mode = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (use_direct_mode) {
|
|
pwm_timer_pwm_enable(false);
|
|
pwm_timer_use(false);
|
|
pwm_timer_uninit();
|
|
spi_init();
|
|
}
|
|
|
|
si4063_inhibit_tx();
|
|
|
|
switch (entry->data_mode) {
|
|
case RADIO_DATA_MODE_CW:
|
|
case RADIO_DATA_MODE_PIP:
|
|
system_enable_tick();
|
|
break;
|
|
case RADIO_DATA_MODE_APRS_1200:
|
|
break;
|
|
case RADIO_DATA_MODE_HORUS_V1:
|
|
case RADIO_DATA_MODE_HORUS_V2:
|
|
system_enable_tick();
|
|
break;
|
|
case RADIO_DATA_MODE_CATS:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void radio_init_si4063()
|
|
{
|
|
}
|
|
#endif
|