Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CATS on RS41ng #95

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// DFM-17 transmissions, especially APRS, may not decode correctly because of incorrect timing before the internal oscillator has been calibrated.

// Define radiosonde type. Remove the "//" comment to select either RS41 or DFM17.
//#define RS41
#define RS41
//#define DFM17

#if !defined(RS41) && !defined(DFM17)
Expand All @@ -21,8 +21,8 @@
// Enable semihosting to receive debug logs during development
// See the README for details on how to set up debugging and debug logs with GDB
// NOTE: Semihosting has to be disabled when the radiosonde is not connected to an STM32 programmer dongle, otherwise the firmware will not run.
//#define SEMIHOSTING_ENABLE
//#define LOGGING_ENABLE
#define SEMIHOSTING_ENABLE
#define LOGGING_ENABLE

/**
* Global configuration
Expand Down Expand Up @@ -147,12 +147,14 @@
#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 false
#define RADIO_SI4032_TX_APRS_COUNT 2
#define RADIO_SI4032_TX_HORUS_V1 false
#define RADIO_SI4032_TX_HORUS_V1_COUNT 1
#define RADIO_SI4032_TX_HORUS_V2 true
#define RADIO_SI4032_TX_HORUS_V2 false
#define RADIO_SI4032_TX_HORUS_V2_COUNT 6
#define RADIO_SI4032_TX_CATS true
#define RADIO_SI4032_TX_CATS_COUNT 1

// Continuous transmit mode can be enabled for *either* Horus V1 or V2, but not both. This disables all other transmission modes.
// The continuous mode transmits Horus 4FSK preamble between transmissions
Expand All @@ -167,6 +169,7 @@
// Use a frequency offset to place FSK tones slightly above the defined frequency for SSB reception
#define RADIO_SI4032_TX_FREQUENCY_HORUS_V1 432501000
#define RADIO_SI4032_TX_FREQUENCY_HORUS_V2 432501000
#define RADIO_SI4032_TX_FREQUENCY_CATS 430450000

/**
* DFM-17 only: Built-in Si4063 radio chip transmission configuration
Expand Down
117 changes: 117 additions & 0 deletions src/drivers/si4032/si4032.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#include <stm32f10x_gpio.h>

#include "hal/spi.h"
#include "hal/hal.h"
#include "hal/delay.h"
#include "si4032.h"
#include "log.h"

#define SPI_WRITE_FLAG 0x80

#define SI4032_CLOCK 26.0f
#define EXPECTED_SI4032_CLOCK 30

#define GPIO_SI4032_NSEL GPIOC
#define GPIO_PIN_SI4032_NSEL GPIO_Pin_13
Expand All @@ -15,6 +19,7 @@

static inline uint8_t si4032_write(uint8_t reg, uint8_t value)
{
// log_info("write %x %x\n", reg, value);
return spi_send_and_receive(GPIO_SI4032_NSEL, GPIO_PIN_SI4032_NSEL, ((reg | SPI_WRITE_FLAG) << 8U) | value);
}

Expand Down Expand Up @@ -45,6 +50,89 @@ void si4032_disable_tx()
si4032_write(0x07, 0x40);
}

// Returns number of bytes sent from *data
// If less than len, remaining bytes will need to be used to top up the buffer
uint16_t si4032_start_tx(uint8_t *data, int len)
{
// Clear fifo underflow interrupt, along with other interrupts
si4032_read(0x03);

// Clear fifo
si4032_write(0x08, 1);
si4032_write(0x08, 0);

// Set packet length (max 255 bytes)
si4032_write(0x3E, len);

// Fill our FIFO
int fifo_len = len;
if(fifo_len > 64) {
fifo_len = 64;
}
for(int i = 0; i < fifo_len; i++) {
si4032_write(0x7F, data[i]);
}

// disable packet handler - just transmit whatever's in the FIFO
si4032_write(0x30, 0x08);

// Start transmitting
si4032_write(0x07, 0x09);

return fifo_len;
}

// Add additional bytes to the si4032's FIFO buffer
// Needed for large packets that don't fit in its buffer.
// Keep refilling it while transmitting
// Returns number of bytes taken from *data
// If less than len, you will need to keep calling this
uint16_t si4032_refill_buffer(uint8_t *data, int len, bool *overflow)
{
uint8_t interrupts = si4032_read(0x03);
int i = 0;

// check for free buffer space
// TX FIFO almost full
while (!(interrupts & 0x40) && i < len) {
// check for FIFO underflow
if (interrupts & 0x80) {
*overflow = true;
return i;
}

si4032_write(0x7F, data[i]);

interrupts = si4032_read(0x03);
i++;
}

if (interrupts & 0x80) {
*overflow = true;
}

return i;
}

int si4032_wait_for_tx_complete(int timeout_ms)
{
for(int i = 0; i < timeout_ms; i++) {
uint8_t status = si4032_read(0x03);

// ipksent is set
if (status & 0x04) {
return HAL_OK;
}

delay_ms(1);
}

// clear txon manually
si4032_write(0x07, 0x40);

return HAL_ERROR_TIMEOUT;
}

void si4032_use_direct_mode(bool use)
{
if (use) {
Expand All @@ -67,6 +155,15 @@ void si4032_set_tx_frequency(const float frequency_mhz)
si4032_write(0x77, (uint8_t) ((uint16_t) fc & 0xff));
}

void si4032_set_data_rate(const uint32_t rate_bps)
{
uint32_t rate = (uint64_t) rate_bps * (1 << 21) * EXPECTED_SI4032_CLOCK / 1000000 / ((uint64_t) SI4032_CLOCK);

si4032_write(0x6E, rate >> 8);
si4032_write(0x6F, rate & 0xFF);
si4032_write(0x70, 0b00100000);
}

void si4032_set_tx_power(uint8_t power)
{
si4032_write(0x6D, power & 0x7U);
Expand Down Expand Up @@ -110,6 +207,10 @@ void si4032_set_modulation_type(si4032_modulation_type type)
// Direct Async Mode with FSK modulation
value = 0b00010010;
break;
case SI4032_MODULATION_TYPE_FIFO_FSK:
// FIFO with FSK modulation
value = 0b00100010;
break;
default:
return;
}
Expand Down Expand Up @@ -194,5 +295,21 @@ void si4032_init()
si4032_set_frequency_offset(0);
si4032_set_frequency_deviation(5); // Was: 5 for APRS in RS41HUP?

// No TX header
// Fixed packet length (don't transmit length)
// Synchronization word of 1 byte (not possible to select 0 bytes)
si4032_write(0x33, 0b00001000);
// 1 preamble byte (the minimum allowed)
// Setting this to 0 is equivalent to setting it to 1 TODO FIXME
si4032_write(0x34, 1);
// Set our sync word to 0x55, so it looks like a preamble
si4032_write(0x36, 0x55);

// set almost full threshold to 63 (max allowed; buffer size - 1)
si4032_write(0x7C, 63);

// enable interrupts
si4032_write(0x05, 0b11100100);

si4032_set_modulation_type(SI4032_MODULATION_TYPE_NONE);
}
5 changes: 5 additions & 0 deletions src/drivers/si4032/si4032.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@ typedef enum _si4032_modulation_type {
SI4032_MODULATION_TYPE_NONE = 0,
SI4032_MODULATION_TYPE_OOK,
SI4032_MODULATION_TYPE_FSK,
SI4032_MODULATION_TYPE_FIFO_FSK,
} si4032_modulation_type;

void si4032_soft_reset();
void si4032_enable_tx();
void si4032_inhibit_tx();
void si4032_disable_tx();
uint16_t si4032_start_tx(uint8_t *data, int len);
uint16_t si4032_refill_buffer(uint8_t *data, int len, bool *overflow);
int si4032_wait_for_tx_complete(int timeout_ms);
void si4032_use_direct_mode(bool use);
void si4032_set_tx_frequency(float frequency_mhz);
void si4032_set_data_rate(const uint32_t rate_bps);
void si4032_set_tx_power(uint8_t power);
void si4032_set_frequency_offset(uint16_t offset);
void si4032_set_frequency_offset_small(uint8_t offset);
Expand Down
14 changes: 14 additions & 0 deletions src/radio.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,20 @@ radio_transmit_entry radio_transmit_schedule[] = {
.fsk_encoder_api = &mfsk_fsk_encoder_api,
},
#endif
#if RADIO_SI4032_TX_CATS
{
.enabled = RADIO_SI4032_TX_CATS,
.radio_type = RADIO_TYPE_SI4032,
.data_mode = RADIO_DATA_MODE_CATS,
.transmit_count = RADIO_SI4032_TX_CATS_COUNT,
.time_sync_seconds = CATS_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = CATS_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4032_TX_FREQUENCY_CATS,
.tx_power = RADIO_SI4032_TX_POWER,
.payload_encoder = &radio_cats_payload_encoder,
.fsk_encoder_api = &raw_fsk_encoder_api,
},
#endif
#endif
#endif

Expand Down
67 changes: 66 additions & 1 deletion src/radio_si4032.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ static bool si4032_use_dma = false;
// TODO: Add support for multiple APRS baud rates
// This delay is for RS41 radiosondes
#define symbol_delay_bell_202_1200bps_us 823
#define SI4032_DEVIATION_HZ_625_CATS 8 // 4800 / 625

static volatile bool radio_si4032_state_change = false;
static volatile uint32_t radio_si4032_freq = 0;
Expand All @@ -41,8 +42,11 @@ uint16_t radio_si4032_fill_pwm_buffer(uint16_t offset, uint16_t length, uint16_t
bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state *shared_state)
{
uint16_t frequency_offset;
uint32_t frequency_deviation = 5;
uint32_t data_rate = 0;
si4032_modulation_type modulation_type;
bool use_direct_mode;
bool use_fifo_mode = false;

switch (entry->data_mode) {
case RADIO_DATA_MODE_CW:
Expand Down Expand Up @@ -80,6 +84,14 @@ bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state
data_timer_init(entry->fsk_encoder_api->get_symbol_rate(&entry->fsk_encoder));
break;
}
case RADIO_DATA_MODE_CATS:
frequency_offset = 0;
frequency_deviation = SI4032_DEVIATION_HZ_625_CATS;
modulation_type = SI4032_MODULATION_TYPE_FIFO_FSK;
use_direct_mode = false;
use_fifo_mode = true;
data_rate = 9600 * 8; // TODO why a factor of 5 here?
break;
default:
return false;
}
Expand All @@ -88,8 +100,14 @@ bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state
si4032_set_tx_power(entry->tx_power);
si4032_set_frequency_offset(frequency_offset);
si4032_set_modulation_type(modulation_type);
si4032_set_frequency_deviation(frequency_deviation);

si4032_enable_tx();
if(use_fifo_mode) {
si4032_set_data_rate(data_rate);
}
else {
si4032_enable_tx();
}

if (use_direct_mode) {
spi_uninit();
Expand Down Expand Up @@ -122,6 +140,9 @@ bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state
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;
}
Expand Down Expand Up @@ -196,6 +217,45 @@ static void radio_handle_main_loop_manual_si4032(radio_transmit_entry *entry, ra
system_enable_tick();
}

void radio_handle_fifo_si4032(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 = si4032_start_tx(data, len);
data += written;
len -= written;

bool overflow = false;

while(len > 0) {
uint16_t written = si4032_refill_buffer(data, len, &overflow);
data += written;
len -= written;

// log_info("FIFO wrote %d bytes\n", written);

/*if(overflow) {
log_info("FIFO underflow - Aborting\n");
shared_state->radio_transmission_finished = true;

return;
}*/
}

int err = si4032_wait_for_tx_complete(10000); // TODO FIXME
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_si4032(radio_transmit_entry *entry, radio_module_state *shared_state)
{
if (entry->radio_type != RADIO_TYPE_SI4032 || shared_state->radio_interrupt_transmit_active) {
Expand All @@ -207,6 +267,11 @@ void radio_handle_main_loop_si4032(radio_transmit_entry *entry, radio_module_sta
return;
}

if (shared_state->radio_fifo_transmit_active) {
radio_handle_fifo_si4032(entry, shared_state);
return;
}

if (radio_si4032_state_change) {
radio_si4032_state_change = false;
pwm_timer_set_frequency(radio_si4032_freq);
Expand Down