kopia lustrzana https://github.com/mikaelnousiainen/RS41ng
Add support for morse code (CW)
rodzic
6d2416d307
commit
7af1ada130
|
@ -1,151 +0,0 @@
|
|||
// Morse Code Playback Functions
|
||||
// Mark Jessop 2018-04
|
||||
// OK1TE 2018-11
|
||||
//
|
||||
// Based on code from https://github.com/Paradoxis/Arduino-morse-code-translator/blob/master/main.ino
|
||||
//
|
||||
#include "morse.h"
|
||||
#include "config.h"
|
||||
|
||||
// All morse delays
|
||||
#define MORSE_DELAY (1200 / MORSE_WPM)
|
||||
#define MORSE_DELAY_DOT (MORSE_DELAY * 1)
|
||||
#define MORSE_DELAY_DASH (MORSE_DELAY * 3)
|
||||
#define MORSE_DELAY_SPACE (MORSE_DELAY * 7)
|
||||
|
||||
// All morse characters
|
||||
const char MORSE_DOT = '.';
|
||||
const char MORSE_DASH = '-';
|
||||
|
||||
// Letters
|
||||
const char* const MORSE_LETTERS[] = {
|
||||
".-", // A
|
||||
"-...", // B
|
||||
"-.-.", // C
|
||||
"-..", // D
|
||||
".", // E
|
||||
"..-.", // F
|
||||
"--.", // G
|
||||
"....", // H
|
||||
"..", // I
|
||||
".---", // J
|
||||
"-.-", // K
|
||||
".-..", // L
|
||||
"--", // M
|
||||
"-.", // N
|
||||
"---", // O
|
||||
".--.", // P
|
||||
"--.-", // Q
|
||||
".-.", // R
|
||||
"...", // S
|
||||
"-", // T
|
||||
"..-", // U
|
||||
"...-", // V
|
||||
".--", // W
|
||||
"-..-", // X
|
||||
"-.--", // Y
|
||||
"--.." // Z
|
||||
};
|
||||
|
||||
// Numerals.
|
||||
const char* const MORSE_NUMBERS[] = {
|
||||
"-----", // 0
|
||||
".----", // 1
|
||||
"..---", // 2
|
||||
"...--", // 3
|
||||
"....-", // 4
|
||||
".....", // 5
|
||||
"-....", // 6
|
||||
"--...", // 7
|
||||
"---..", // 8
|
||||
"----." // 9
|
||||
};
|
||||
|
||||
// Symbols
|
||||
const char Morse_Slash[] = "-..-.";
|
||||
const char Morse_Equal[] = "-...-";
|
||||
const char Morse_FullStop[] = ".-.-.-";
|
||||
const char Morse_Comma[] = "--..--";
|
||||
const char Morse_QuestionMark[] = "..--..";
|
||||
const char Morse_Plus[] = ".-.-.";
|
||||
const char Morse_AtSign[] = ".--.-.";
|
||||
|
||||
// Send a single character
|
||||
void sendDotOrDash (char unit) {
|
||||
//radio_enable_tx();
|
||||
|
||||
// Unit is a dot (500 ms)
|
||||
if (unit == MORSE_DOT) {
|
||||
//_delay_ms(MORSE_DELAY_DOT);
|
||||
}
|
||||
|
||||
// Unit is a dash (1500 ms)
|
||||
else if (unit == MORSE_DASH) {
|
||||
//_delay_ms(MORSE_DELAY_DASH);
|
||||
}
|
||||
|
||||
// Inter-element gap
|
||||
//radio_inhibit_tx();
|
||||
//_delay_ms(MORSE_DELAY);
|
||||
}
|
||||
|
||||
void sendMorseSequence (const char* sequence) {
|
||||
// Counter
|
||||
int i = 0;
|
||||
|
||||
// Loop through every character until an 'end-of-line' (null) character is found
|
||||
while (sequence[i] != 0) {
|
||||
sendDotOrDash(sequence[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Delay between every letter
|
||||
//_delay_ms(MORSE_DELAY * 3);
|
||||
}
|
||||
|
||||
void sendMorse(const char* message){
|
||||
int i = 0;
|
||||
while (message[i] != 0){
|
||||
const char current = message[i];
|
||||
|
||||
// Lower case letters
|
||||
if (current >= 'a' && current <= 'z') {
|
||||
sendMorseSequence(MORSE_LETTERS[current - 'a']);
|
||||
}
|
||||
|
||||
// Capital case letters
|
||||
else if (current >= 'A' && current <= 'Z') {
|
||||
sendMorseSequence(MORSE_LETTERS[current - 'A']);
|
||||
}
|
||||
|
||||
// Numbers
|
||||
else if (current >= '0' && current <= '9') {
|
||||
sendMorseSequence(MORSE_NUMBERS[current - '0']);
|
||||
}
|
||||
|
||||
else switch (current) {
|
||||
case '/': sendMorseSequence(Morse_Slash);
|
||||
break;
|
||||
case '=': sendMorseSequence(Morse_Equal);
|
||||
break;
|
||||
case '.': sendMorseSequence(Morse_FullStop);
|
||||
break;
|
||||
case ',': sendMorseSequence(Morse_Comma);
|
||||
break;
|
||||
case '?': sendMorseSequence(Morse_QuestionMark);
|
||||
break;
|
||||
case '+': sendMorseSequence(Morse_Plus);
|
||||
break;
|
||||
case '@': sendMorseSequence(Morse_AtSign);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
// Treat all other characters as a space.
|
||||
//_delay_ms(MORSE_DELAY_SPACE);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
//radio_disable_tx();
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
//
|
||||
// Morse Code Playback Functions
|
||||
// Mark Jessop 2018-04
|
||||
// OK1TE 2018-10
|
||||
//
|
||||
#ifndef __MORSE_H
|
||||
#define __MORSE_H
|
||||
|
||||
void sendDotOrDash (char unit);
|
||||
void sendMorseSequence (const char* sequence);
|
||||
void sendMorse(const char* message);
|
||||
|
||||
#endif //__MORSE_H
|
|
@ -0,0 +1,265 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "morse.h"
|
||||
|
||||
// Morse code definitions adapted from code by Mark Jessop VK5QI and OK1TE, also based on
|
||||
// https://github.com/Paradoxis/Arduino-morse-code-translator/blob/master/main.ino
|
||||
|
||||
#define MORSE_UNITS_DOT 1
|
||||
#define MORSE_UNITS_DASH 3
|
||||
#define MORSE_UNITS_GAP 3
|
||||
#define MORSE_UNITS_SPACE 7
|
||||
|
||||
const char MORSE_DOT = '.';
|
||||
const char MORSE_DASH = '-';
|
||||
const char MORSE_SPACE = ' ';
|
||||
|
||||
const char *const morse_letters[] = {
|
||||
".-", // A
|
||||
"-...", // B
|
||||
"-.-.", // C
|
||||
"-..", // D
|
||||
".", // E
|
||||
"..-.", // F
|
||||
"--.", // G
|
||||
"....", // H
|
||||
"..", // I
|
||||
".---", // J
|
||||
"-.-", // K
|
||||
".-..", // L
|
||||
"--", // M
|
||||
"-.", // N
|
||||
"---", // O
|
||||
".--.", // P
|
||||
"--.-", // Q
|
||||
".-.", // R
|
||||
"...", // S
|
||||
"-", // T
|
||||
"..-", // U
|
||||
"...-", // V
|
||||
".--", // W
|
||||
"-..-", // X
|
||||
"-.--", // Y
|
||||
"--.." // Z
|
||||
};
|
||||
|
||||
const char *const morse_numbers[] = {
|
||||
"-----", // 0
|
||||
".----", // 1
|
||||
"..---", // 2
|
||||
"...--", // 3
|
||||
"....-", // 4
|
||||
".....", // 5
|
||||
"-....", // 6
|
||||
"--...", // 7
|
||||
"---..", // 8
|
||||
"----." // 9
|
||||
};
|
||||
|
||||
const char morse_stroke[] = "-..-.";
|
||||
const char morse_equal[] = "-...-";
|
||||
const char morse_full_stop[] = ".-.-.-";
|
||||
const char morse_comma[] = "--..--";
|
||||
const char morse_question_mark[] = "..--..";
|
||||
const char morse_plus[] = ".-.-.";
|
||||
const char morse_at_sign[] = ".--.-.";
|
||||
const char morse_space[] = " ";
|
||||
|
||||
static const char *morse_get_sequence(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z') { // Uppercase letters
|
||||
return morse_letters[c - 'A'];
|
||||
} else if (c >= 'a' && c <= 'z') { // Lowercase letters
|
||||
return morse_letters[c - 'a'];
|
||||
} else if (c >= '0' && c <= '9') { // Numbers
|
||||
return morse_numbers[c - '0'];
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '/':
|
||||
return morse_stroke;
|
||||
case '=':
|
||||
return morse_equal;
|
||||
case '.':
|
||||
return morse_full_stop;
|
||||
case ',':
|
||||
return morse_comma;
|
||||
case '?':
|
||||
return morse_question_mark;
|
||||
case '+':
|
||||
return morse_plus;
|
||||
case '@':
|
||||
return morse_at_sign;
|
||||
default:
|
||||
// Treat all other characters as a space
|
||||
return morse_space;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _morse_encoder {
|
||||
uint32_t symbol_rate;
|
||||
|
||||
uint16_t data_length;
|
||||
uint8_t *data;
|
||||
|
||||
uint16_t current_byte_index;
|
||||
|
||||
const char *current_sequence;
|
||||
uint8_t current_sequence_index;
|
||||
|
||||
bool tone_active;
|
||||
uint8_t units_left;
|
||||
|
||||
bool start;
|
||||
|
||||
fsk_tone tones[2];
|
||||
} morse_encoder;
|
||||
|
||||
void morse_encoder_new(fsk_encoder *encoder, uint32_t symbol_rate)
|
||||
{
|
||||
encoder->priv = malloc(sizeof(morse_encoder));
|
||||
memset(encoder->priv, 0, sizeof(morse_encoder));
|
||||
|
||||
morse_encoder *morse = (morse_encoder *) encoder->priv;
|
||||
morse->symbol_rate = symbol_rate;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
morse->tones[i].index = (int8_t) i;
|
||||
morse->tones[i].frequency_hz_100 = i;
|
||||
}
|
||||
}
|
||||
|
||||
void morse_encoder_destroy(fsk_encoder *encoder)
|
||||
{
|
||||
if (encoder->priv != NULL) {
|
||||
free(encoder->priv);
|
||||
encoder->priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void morse_encoder_set_data(fsk_encoder *encoder, uint16_t data_length, uint8_t *data)
|
||||
{
|
||||
morse_encoder *morse = (morse_encoder *) encoder->priv;
|
||||
|
||||
morse->data = data;
|
||||
morse->data_length = data_length;
|
||||
|
||||
morse->current_byte_index = 0;
|
||||
morse->current_sequence = morse_get_sequence((char) data[0]);
|
||||
morse->current_sequence_index = 0;
|
||||
morse->tone_active = false;
|
||||
morse->units_left = 0;
|
||||
morse->start = true;
|
||||
}
|
||||
|
||||
void morse_encoder_get_tones(fsk_encoder *encoder, int8_t *tone_count, fsk_tone **tones)
|
||||
{
|
||||
morse_encoder *morse = (morse_encoder *) encoder->priv;
|
||||
|
||||
*tone_count = 2;
|
||||
*tones = morse->tones;
|
||||
}
|
||||
|
||||
uint32_t morse_encoder_get_tone_spacing(fsk_encoder *encoder)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t morse_encoder_get_symbol_rate(fsk_encoder *encoder)
|
||||
{
|
||||
morse_encoder *morse = (morse_encoder *) encoder->priv;
|
||||
return morse->symbol_rate;
|
||||
}
|
||||
|
||||
uint32_t morse_encoder_get_symbol_delay(fsk_encoder *encoder)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t morse_encoder_next_tone(fsk_encoder *encoder)
|
||||
{
|
||||
morse_encoder *morse = (morse_encoder *) encoder->priv;
|
||||
|
||||
if (morse->current_byte_index >= morse->data_length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!morse->start && morse->units_left == 0) {
|
||||
char next_element = morse->current_sequence[morse->current_sequence_index + 1];
|
||||
if (morse->tone_active) {
|
||||
if (next_element == 0) {
|
||||
bool char_gap = true;
|
||||
|
||||
if (morse->current_byte_index + 1 < morse->data_length) {
|
||||
const char *next_byte_sequence = morse_get_sequence((char) morse->data[morse->current_byte_index + 1]);
|
||||
if (next_byte_sequence[0] == MORSE_SPACE) {
|
||||
char_gap = false;
|
||||
}
|
||||
} else {
|
||||
char_gap = false;
|
||||
}
|
||||
|
||||
if (char_gap) {
|
||||
// Char gap
|
||||
morse->tone_active = false;
|
||||
morse->units_left = MORSE_UNITS_GAP - 1;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Unit gap
|
||||
morse->tone_active = false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
morse->current_sequence_index++;
|
||||
|
||||
if (next_element == 0) {
|
||||
morse->current_byte_index++;
|
||||
|
||||
if (morse->current_byte_index >= morse->data_length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
morse->current_sequence = morse_get_sequence((char) morse->data[morse->current_byte_index]);
|
||||
morse->current_sequence_index = 0;
|
||||
|
||||
morse->tone_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
morse->start = false;
|
||||
|
||||
char element = morse->current_sequence[morse->current_sequence_index];
|
||||
|
||||
if (morse->units_left > 0) {
|
||||
morse->units_left--;
|
||||
return morse->tone_active ? 1 : 0;
|
||||
}
|
||||
|
||||
if (element == MORSE_DOT) {
|
||||
morse->units_left = MORSE_UNITS_DOT;
|
||||
morse->tone_active = true;
|
||||
} else if (element == MORSE_DASH) {
|
||||
morse->units_left = MORSE_UNITS_DASH;
|
||||
morse->tone_active = true;
|
||||
} else {
|
||||
morse->units_left = MORSE_UNITS_SPACE;
|
||||
morse->tone_active = false;
|
||||
}
|
||||
|
||||
morse->units_left--;
|
||||
|
||||
return morse->tone_active ? 1 : 0;
|
||||
}
|
||||
|
||||
fsk_encoder_api morse_fsk_encoder_api = {
|
||||
.get_tones = morse_encoder_get_tones,
|
||||
.get_tone_spacing = morse_encoder_get_tone_spacing,
|
||||
.get_symbol_rate = morse_encoder_get_symbol_rate,
|
||||
.get_symbol_delay = morse_encoder_get_symbol_delay,
|
||||
.set_data = morse_encoder_set_data,
|
||||
.next_tone = morse_encoder_next_tone,
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef __MORSE_H
|
||||
#define __MORSE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "codecs/fsk/fsk.h"
|
||||
|
||||
void morse_encoder_new(fsk_encoder *encoder, uint32_t symbol_rate);
|
||||
void morse_encoder_destroy(fsk_encoder *encoder);
|
||||
void morse_encoder_set_data(fsk_encoder *encoder, uint16_t data_length, uint8_t *data);
|
||||
void morse_encoder_get_tones(fsk_encoder *encoder, int8_t *tone_count, fsk_tone **tones);
|
||||
uint32_t morse_encoder_get_symbol_rate(fsk_encoder *encoder);
|
||||
uint32_t morse_encoder_get_symbol_delay(fsk_encoder *encoder);
|
||||
int8_t morse_encoder_next_tone(fsk_encoder *encoder);
|
||||
|
||||
extern fsk_encoder_api morse_fsk_encoder_api;
|
||||
|
||||
#endif
|
24
src/config.c
24
src/config.c
|
@ -46,6 +46,16 @@ bool si5351_enabled = RADIO_SI5351_ENABLE;
|
|||
|
||||
volatile bool system_initialized = false;
|
||||
|
||||
/**
|
||||
* CW mode messages.
|
||||
* Maximum length: 64 characters.
|
||||
*/
|
||||
char *cw_message_templates[] = {
|
||||
"$cs",
|
||||
"$loc6",
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* APRS mode comment messages.
|
||||
* Maximum length: depends on the packet contents, but keeping this under 100 characters is usually safe.
|
||||
|
@ -64,8 +74,8 @@ char *aprs_comment_templates[] = {
|
|||
* Maximum length: 130 characters.
|
||||
*/
|
||||
char *fsq_comment_templates[] = {
|
||||
" $lat $lon, $alt m, $cl m/s, $gs km/h, $he deg - " FSQ_COMMENT,
|
||||
" $loc12, $teC $hu% $prmb $hh:$mm:$ss @ $tow ms - " FSQ_COMMENT,
|
||||
// " $lat $lon, $alt m, $cl m/s, $gs km/h, $he deg - " FSQ_COMMENT,
|
||||
// " $loc12, $teC $hu% $prmb $hh:$mm:$ss @ $tow ms - " FSQ_COMMENT,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -74,10 +84,10 @@ char *fsq_comment_templates[] = {
|
|||
* Maximum length: 13 characters allowed by the protocols.
|
||||
*/
|
||||
char *ftjt_message_templates[] = {
|
||||
"$cs $loc4",
|
||||
"$loc12",
|
||||
"$altm $cl",
|
||||
"$bvmV $tiC",
|
||||
"$hu% $prmb",
|
||||
// "$cs $loc4",
|
||||
// "$loc12",
|
||||
// "$altm $cl",
|
||||
// "$bvmV $tiC",
|
||||
// "$hu% $prmb",
|
||||
NULL
|
||||
};
|
||||
|
|
16
src/config.h
16
src/config.h
|
@ -42,14 +42,12 @@
|
|||
#define RADIO_SI4032_TX_POWER 7
|
||||
|
||||
// Which modes to transmit using the built-in Si4032 transmitter chip
|
||||
#define RADIO_SI4032_TX_CW false
|
||||
#define RADIO_SI4032_TX_RTTY false
|
||||
#define RADIO_SI4032_TX_CW true
|
||||
#define RADIO_SI4032_TX_APRS true
|
||||
#define RADIO_SI4032_TX_HORUS_V1 true
|
||||
|
||||
// Transmit frequencies for the Si4032 transmitter modes
|
||||
#define RADIO_SI4032_TX_FREQUENCY_CW 432060000
|
||||
#define RADIO_SI4032_TX_FREQUENCY_RTTY 432060000
|
||||
#define RADIO_SI4032_TX_FREQUENCY_CW 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
|
||||
|
@ -132,10 +130,16 @@
|
|||
#define HORUS_V1_TIME_SYNC_OFFSET_SECONDS 0
|
||||
|
||||
/**
|
||||
* TODO: CW settings (once implemented)
|
||||
* CW settings
|
||||
*/
|
||||
|
||||
#define CW_LOCATOR_PAIR_COUNT 4 // max. 6 (12 characters WWL)
|
||||
// CW speed in WPM, range 5 - 40
|
||||
#define CW_SPEED_WPM 20
|
||||
|
||||
// Schedule transmission every N seconds, counting from beginning of an hour (based on GPS time). Set to zero to disable time sync.
|
||||
#define CW_TIME_SYNC_SECONDS 1
|
||||
// Delay transmission for an N second offset after the scheduled time.
|
||||
#define CW_TIME_SYNC_OFFSET_SECONDS 0
|
||||
|
||||
/**
|
||||
* WSPR settings
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#define RADIO_SYMBOL_DATA_MAX_LENGTH 512
|
||||
#define RADIO_PAYLOAD_MESSAGE_MAX_LENGTH 128
|
||||
|
||||
// PARIS: 50 dot durations, 20 WPM -> 60ms per unit
|
||||
#define MORSE_WPM_TO_SYMBOL_RATE(wpm) (1000 / (60 * 20 / wpm))
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern bool leds_enabled;
|
||||
|
@ -13,6 +16,7 @@ extern bool si5351_enabled;
|
|||
|
||||
extern volatile bool system_initialized;
|
||||
|
||||
extern char *cw_message_templates[];
|
||||
extern char *aprs_comment_templates[];
|
||||
extern char *fsq_comment_templates[];
|
||||
extern char *ftjt_message_templates[];
|
||||
|
|
|
@ -7,22 +7,20 @@
|
|||
|
||||
#define SI4032_CLOCK 26.0f
|
||||
|
||||
#define GPIO_SI_4032_CS GPIOC
|
||||
#define GPIO_PIN_SI4032_CS GPIO_Pin_13
|
||||
#define GPIO_SI4032_NSEL GPIOC
|
||||
#define GPIO_PIN_SI4032_NSEL GPIO_Pin_13
|
||||
|
||||
// TODO: For CW support:
|
||||
// TODO: static const uint16_t radioSDIpin = GPIO_Pin_15; // @ GPIOB!
|
||||
// TODO: Add methods to init SDI pin GPIO and to set SDI pin state -> Verify it can be used for OOK (CW), NSEL (CS) must be high
|
||||
// TODO: Call uninitialization of PWM timer after use so that SDI pin is free to use
|
||||
#define GPIO_SI4032_SDI GPIOB
|
||||
#define GPIO_PIN_SI4032_SDI GPIO_Pin_15
|
||||
|
||||
static inline uint8_t si4032_write(uint8_t reg, uint8_t value)
|
||||
{
|
||||
return spi_send_and_receive(GPIO_SI_4032_CS, GPIO_PIN_SI4032_CS, ((reg | SPI_WRITE_FLAG) << 8U) | value);
|
||||
return spi_send_and_receive(GPIO_SI4032_NSEL, GPIO_PIN_SI4032_NSEL, ((reg | SPI_WRITE_FLAG) << 8U) | value);
|
||||
}
|
||||
|
||||
static inline uint8_t si4032_read(uint8_t reg)
|
||||
{
|
||||
return spi_send_and_receive(GPIO_SI_4032_CS, GPIO_PIN_SI4032_CS, (reg << 8U) | 0xFFU);
|
||||
return spi_send_and_receive(GPIO_SI4032_NSEL, GPIO_PIN_SI4032_NSEL, (reg << 8U) | 0xFFU);
|
||||
}
|
||||
|
||||
void si4032_soft_reset()
|
||||
|
@ -50,9 +48,9 @@ void si4032_disable_tx()
|
|||
void si4032_use_direct_mode(bool use)
|
||||
{
|
||||
if (use) {
|
||||
GPIO_SetBits(GPIO_SI_4032_CS, GPIO_PIN_SI4032_CS);
|
||||
GPIO_SetBits(GPIO_SI4032_NSEL, GPIO_PIN_SI4032_NSEL);
|
||||
} else {
|
||||
GPIO_ResetBits(GPIO_SI_4032_CS, GPIO_PIN_SI4032_CS);
|
||||
GPIO_ResetBits(GPIO_SI4032_NSEL, GPIO_PIN_SI4032_NSEL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,15 +136,49 @@ int32_t si4032_read_temperature_celsius_100()
|
|||
return temperature;
|
||||
}
|
||||
|
||||
static void si4032_set_nsel_pin(bool high)
|
||||
{
|
||||
if (high) {
|
||||
GPIO_SetBits(GPIO_SI4032_NSEL, GPIO_PIN_SI4032_NSEL);
|
||||
} else {
|
||||
GPIO_ResetBits(GPIO_SI4032_NSEL, GPIO_PIN_SI4032_NSEL);
|
||||
}
|
||||
}
|
||||
|
||||
void si4032_set_sdi_pin(bool high)
|
||||
{
|
||||
if (high) {
|
||||
GPIO_SetBits(GPIO_SI4032_SDI, GPIO_PIN_SI4032_SDI);
|
||||
} else {
|
||||
GPIO_ResetBits(GPIO_SI4032_SDI, GPIO_PIN_SI4032_SDI);
|
||||
}
|
||||
}
|
||||
|
||||
void si4032_use_sdi_pin(bool use)
|
||||
{
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
si4032_set_nsel_pin(true);
|
||||
|
||||
gpio_init.GPIO_Pin = GPIO_PIN_SI4032_SDI;
|
||||
gpio_init.GPIO_Mode = use ? GPIO_Mode_Out_PP : GPIO_Mode_AF_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIO_SI4032_SDI, &gpio_init);
|
||||
|
||||
si4032_set_sdi_pin(false);
|
||||
}
|
||||
|
||||
void si4032_init()
|
||||
{
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
// Si4032 chip select pin
|
||||
gpio_init.GPIO_Pin = GPIO_PIN_SI4032_CS;
|
||||
gpio_init.GPIO_Pin = GPIO_PIN_SI4032_NSEL;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIO_SI_4032_CS, &gpio_init);
|
||||
GPIO_Init(GPIO_SI4032_NSEL, &gpio_init);
|
||||
|
||||
si4032_set_nsel_pin(true);
|
||||
|
||||
si4032_soft_reset();
|
||||
si4032_set_tx_power(0);
|
||||
|
|
|
@ -22,6 +22,8 @@ void si4032_set_frequency_offset_small(uint8_t offset);
|
|||
void si4032_set_frequency_deviation(uint8_t deviation);
|
||||
void si4032_set_modulation_type(si4032_modulation_type type);
|
||||
int32_t si4032_read_temperature_celsius_100();
|
||||
void si4032_set_sdi_pin(bool high);
|
||||
void si4032_use_sdi_pin(bool use);
|
||||
void si4032_init();
|
||||
|
||||
#endif
|
||||
|
|
23
src/radio.c
23
src/radio.c
|
@ -6,6 +6,7 @@
|
|||
#include "hal/system.h"
|
||||
#include "hal/delay.h"
|
||||
#include "hal/usart_gps.h"
|
||||
#include "codecs/morse/morse.h"
|
||||
#include "codecs/bell/bell.h"
|
||||
#include "codecs/mfsk/mfsk.h"
|
||||
#include "codecs/jtencode/jtencode.h"
|
||||
|
@ -13,6 +14,7 @@
|
|||
#include "radio_internal.h"
|
||||
#include "radio_si4032.h"
|
||||
#include "radio_si5351.h"
|
||||
#include "radio_payload_cw.h"
|
||||
#include "radio_payload_aprs.h"
|
||||
#include "radio_payload_horus_v1.h"
|
||||
#include "radio_payload_wspr.h"
|
||||
|
@ -20,6 +22,18 @@
|
|||
#include "radio_payload_fsq.h"
|
||||
|
||||
radio_transmit_entry radio_transmit_schedule[] = {
|
||||
{
|
||||
.enabled = RADIO_SI4032_TX_CW,
|
||||
.radio_type = RADIO_TYPE_SI4032,
|
||||
.data_mode = RADIO_DATA_MODE_CW,
|
||||
.time_sync_seconds = CW_TIME_SYNC_SECONDS,
|
||||
.time_sync_seconds_offset = CW_TIME_SYNC_OFFSET_SECONDS,
|
||||
.frequency = RADIO_SI4032_TX_FREQUENCY_CW,
|
||||
.tx_power = RADIO_SI4032_TX_POWER,
|
||||
.symbol_rate = MORSE_WPM_TO_SYMBOL_RATE(CW_SPEED_WPM),
|
||||
.payload_encoder = &radio_cw_payload_encoder,
|
||||
.fsk_encoder_api = &morse_fsk_encoder_api,
|
||||
},
|
||||
{
|
||||
.enabled = RADIO_SI4032_TX_APRS,
|
||||
.radio_type = RADIO_TYPE_SI4032,
|
||||
|
@ -233,6 +247,11 @@ static bool radio_start_transmit(radio_transmit_entry *entry)
|
|||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
morse_encoder_new(&entry->fsk_encoder, entry->symbol_rate);
|
||||
radio_shared_state.radio_current_symbol_rate = entry->fsk_encoder_api->get_symbol_rate(&entry->fsk_encoder);
|
||||
entry->fsk_encoder_api->get_tones(&entry->fsk_encoder, &radio_shared_state.radio_current_fsk_tone_count,
|
||||
&radio_shared_state.radio_current_fsk_tones);
|
||||
entry->fsk_encoder_api->set_data(&entry->fsk_encoder, radio_current_payload_length, radio_current_payload);
|
||||
break;
|
||||
case RADIO_DATA_MODE_RTTY:
|
||||
break;
|
||||
|
@ -354,6 +373,7 @@ static bool radio_stop_transmit(radio_transmit_entry *entry)
|
|||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
morse_encoder_destroy(&entry->fsk_encoder);
|
||||
break;
|
||||
case RADIO_DATA_MODE_RTTY:
|
||||
break;
|
||||
|
@ -616,6 +636,9 @@ void radio_init()
|
|||
for (uint8_t i = 0; i < radio_transmit_entry_count; i++) {
|
||||
radio_transmit_entry *entry = &radio_transmit_schedule[i];
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
entry->messages = cw_message_templates;
|
||||
break;
|
||||
case RADIO_DATA_MODE_APRS_1200:
|
||||
entry->messages = aprs_comment_templates;
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "radio_payload_cw.h"
|
||||
|
||||
uint16_t radio_cw_encode(uint8_t *payload, uint16_t length, telemetry_data *telemetry_data, char *message)
|
||||
{
|
||||
return snprintf((char *) payload, length, "%s", message);
|
||||
}
|
||||
|
||||
payload_encoder radio_cw_payload_encoder = {
|
||||
.encode = radio_cw_encode,
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __RADIO_PAYLOAD_CW_H
|
||||
#define __RADIO_PAYLOAD_CW_H
|
||||
|
||||
#include "payload.h"
|
||||
|
||||
extern payload_encoder radio_cw_payload_encoder;
|
||||
|
||||
#endif
|
|
@ -12,6 +12,8 @@
|
|||
#include "radio_si4032.h"
|
||||
#include "codecs/mfsk/mfsk.h"
|
||||
|
||||
#define CW_SYMBOL_RATE_MULTIPLIER 4
|
||||
|
||||
/**
|
||||
* I have attempted to implement Bell 202 frequency generation using hardware DMA and PWM, but have failed to generate
|
||||
* correct symbol rate that other APRS equipment are able to decode. I have tried to decode the DMA-based modulation with
|
||||
|
@ -46,6 +48,8 @@ bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state
|
|||
frequency_offset = 1;
|
||||
modulation_type = SI4032_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;
|
||||
|
@ -83,12 +87,19 @@ bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state
|
|||
|
||||
if (use_direct_mode) {
|
||||
spi_uninit();
|
||||
pwm_timer_init(100 * 100); // TODO: Idle tone
|
||||
pwm_timer_use(true);
|
||||
pwm_timer_pwm_enable(true);
|
||||
si4032_use_direct_mode(true);
|
||||
}
|
||||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
spi_uninit();
|
||||
system_disable_tick();
|
||||
si4032_use_sdi_pin(true);
|
||||
shared_state->radio_interrupt_transmit_active = true;
|
||||
break;
|
||||
case RADIO_DATA_MODE_APRS_1200:
|
||||
if (si4032_use_dma) {
|
||||
shared_state->radio_dma_transfer_active = true;
|
||||
|
@ -196,11 +207,40 @@ void radio_handle_main_loop_si4032(radio_transmit_entry *entry, radio_module_sta
|
|||
|
||||
inline void radio_handle_data_timer_si4032()
|
||||
{
|
||||
static int cw_symbol_rate_multiplier = CW_SYMBOL_RATE_MULTIPLIER;
|
||||
|
||||
if (radio_current_transmit_entry->radio_type != RADIO_TYPE_SI4032 || !radio_shared_state.radio_interrupt_transmit_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (radio_current_transmit_entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW: {
|
||||
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) {
|
||||
si4032_set_sdi_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;
|
||||
}
|
||||
|
||||
si4032_set_sdi_pin(tone_index == 0 ? false : true);
|
||||
|
||||
radio_shared_state.radio_symbol_count_interrupt++;
|
||||
break;
|
||||
}
|
||||
case RADIO_DATA_MODE_HORUS_V1: {
|
||||
fsk_encoder_api *fsk_encoder_api = radio_current_transmit_entry->fsk_encoder_api;
|
||||
fsk_encoder *fsk_enc = &radio_current_transmit_entry->fsk_encoder;
|
||||
|
@ -216,6 +256,7 @@ inline void radio_handle_data_timer_si4032()
|
|||
}
|
||||
|
||||
si4032_set_frequency_offset_small(tone_index + HORUS_V1_FREQUENCY_OFFSET);
|
||||
|
||||
radio_shared_state.radio_symbol_count_interrupt++;
|
||||
break;
|
||||
}
|
||||
|
@ -230,9 +271,13 @@ bool radio_stop_transmit_si4032(radio_transmit_entry *entry, radio_module_state
|
|||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
si4032_use_sdi_pin(false);
|
||||
data_timer_uninit();
|
||||
spi_init();
|
||||
break;
|
||||
case RADIO_DATA_MODE_RTTY:
|
||||
case RADIO_DATA_MODE_HORUS_V1:
|
||||
use_direct_mode = false;
|
||||
data_timer_uninit();
|
||||
break;
|
||||
case RADIO_DATA_MODE_APRS_1200:
|
||||
use_direct_mode = true;
|
||||
|
@ -245,12 +290,16 @@ bool radio_stop_transmit_si4032(radio_transmit_entry *entry, radio_module_state
|
|||
si4032_use_direct_mode(false);
|
||||
pwm_timer_pwm_enable(false);
|
||||
pwm_timer_use(false);
|
||||
pwm_timer_uninit();
|
||||
spi_init();
|
||||
}
|
||||
|
||||
si4032_inhibit_tx();
|
||||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
system_enable_tick();
|
||||
break;
|
||||
case RADIO_DATA_MODE_APRS_1200:
|
||||
if (si4032_use_dma) {
|
||||
pwm_data_timer_uninit();
|
||||
|
@ -258,7 +307,6 @@ bool radio_stop_transmit_si4032(radio_transmit_entry *entry, radio_module_state
|
|||
}
|
||||
break;
|
||||
case RADIO_DATA_MODE_HORUS_V1:
|
||||
data_timer_uninit();
|
||||
system_enable_tick();
|
||||
break;
|
||||
default:
|
||||
|
@ -338,8 +386,6 @@ void radio_init_si4032()
|
|||
pwm_handle_dma_transfer_half = radio_si4032_handle_pwm_transfer_half;
|
||||
pwm_handle_dma_transfer_full = radio_si4032_handle_pwm_transfer_full;
|
||||
|
||||
pwm_timer_init(100 * 100);
|
||||
|
||||
if (si4032_use_dma) {
|
||||
pwm_data_timer_init();
|
||||
pwm_dma_init();
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "codecs/morse/morse.h"
|
||||
#include "config.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
fsk_encoder morse;
|
||||
|
||||
printf("%d\n", MORSE_WPM_TO_SYMBOL_RATE(20));
|
||||
printf("%d\n", MORSE_WPM_TO_SYMBOL_RATE(15));
|
||||
printf("%d\n", MORSE_WPM_TO_SYMBOL_RATE(10));
|
||||
|
||||
char *input = "TEST T";
|
||||
|
||||
morse_encoder_new(&morse, 25);
|
||||
|
||||
morse_encoder_set_data(&morse, strlen(input), (uint8_t *) input);
|
||||
|
||||
int8_t tone_index;
|
||||
|
||||
while ((tone_index = morse_encoder_next_tone(&morse)) >= 0) {
|
||||
printf("CW: %d\n", tone_index);
|
||||
}
|
||||
|
||||
morse_encoder_destroy(&morse);
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
#include <bsd/string.h>
|
||||
#include "template.h"
|
||||
|
||||
int main(void)
|
||||
int main3(void)
|
||||
{
|
||||
char *source = "DE $cs: $bv $loc6, $hh:$mm:$ss, $tow, Ti$ti Te$te $hu $pr";
|
||||
char dest[512];
|
||||
|
|
Ładowanie…
Reference in New Issue