Addition of FSQ

pull/5/head
Jason Milldrum 2016-07-05 14:11:00 -07:00
rodzic 89fdbea1cb
commit 7b06dd1890
3 zmienionych plików z 363 dodań i 2 usunięć

Wyświetl plik

@ -47,16 +47,19 @@
#define JT65_TONE_SPACING 269 // ~2.69 Hz
#define JT4_TONE_SPACING 437 // ~4.37 Hz
#define WSPR_TONE_SPACING 146 // ~1.46 Hz
#define FSQ_TONE_SPACING 174 // ~1.74 Hz
#define JT9_CTC 9000 // CTC value for JT9-1
#define JT65_CTC 5812 // CTC value for JT65A
#define JT4_CTC 3578 // CTC value for JT4
#define WSPR_CTC 10672 // CTC value for WSPR
#define FSQ_2_CTC 7812 // CTC value for 2 baud FSQ
#define JT9_DEFAULT_FREQ 14078600UL
#define JT65_DEFAULT_FREQ 14077500UL
#define JT4_DEFAULT_FREQ 14077500UL
#define WSPR_DEFAULT_FREQ 14097100UL
#define FSQ_DEFAULT_FREQ 7105350UL; // Base freq is 1350 Hz higher than dial freq in USB
#define DEFAULT_MODE MODE_JT4
@ -65,7 +68,8 @@
#define LED_PIN 13
// Enumerations
enum mode {MODE_JT9, MODE_JT65, MODE_JT4, MODE_WSPR};
enum mode {MODE_JT9, MODE_JT65, MODE_JT4, MODE_WSPR, MODE_FSQ_2, MODE_FSQ_3,
MODE_FSQ_4_5, MODE_FSQ_6};
// Class instantiation
Si5351 si5351;
@ -116,6 +120,12 @@ void encode()
case MODE_WSPR:
jtencode.wspr_encode(call, loc, dbm, tx_buffer);
break;
case MODE_FSQ_2:
case MODE_FSQ_3:
case MODE_FSQ_4_5:
case MODE_FSQ_6:
jtencode.fsq_encode(call, message, tx_buffer);
break;
}
// Reset the tone to the base frequency and turn on the output
@ -145,6 +155,9 @@ void setup()
// Use a button connected to pin 12 as a transmit trigger
pinMode(BUTTON, INPUT_PULLUP);
// Set the mode to use
cur_mode = MODE_FSQ_2;
//Serial.begin(57600);
// Set the proper frequency, tone spacing, symbol count, and
@ -175,6 +188,11 @@ void setup()
symbol_count = WSPR_SYMBOL_COUNT; // From the library defines
tone_spacing = WSPR_TONE_SPACING;
break;
case MODE_FSQ_2:
freq = FSQ_DEFAULT_FREQ;
ctc = FSQ_2_CTC;
tone_spacing = FSQ_TONE_SPACING;
break;
}
// Initialize the Si5351

Wyświetl plik

@ -27,6 +27,14 @@
#include <ctype.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
// Define an upper bound on the number of glyphs. Defining it this
// way allows adding characters without having to update a hard-coded
// upper bound.
#define NGLYPHS (sizeof(fsq_code_table)/sizeof(fsq_code_table[0]))
uint8_t JTEncode::crc8_table[256];
/* Public Class Members */
@ -34,6 +42,9 @@ JTEncode::JTEncode(void)
{
// Initialize the Reed-Solomon encoder
rs_inst = (struct rs *)(intptr_t)init_rs_int(6, 0x43, 3, 1, 51, 0);
// Initialize the CRC8 table
init_crc8();
}
/*
@ -173,7 +184,7 @@ void JTEncode::jt4_encode(char * message, uint8_t * symbols)
*/
void JTEncode::wspr_encode(char * call, char * loc, uint8_t dbm, uint8_t * symbols)
{
// Ensure that the message text conforms to standards
// Ensure that the message text conforms to standards
// --------------------------------------------------
wspr_message_prep(call, loc, dbm);
@ -196,6 +207,181 @@ void JTEncode::wspr_encode(char * call, char * loc, uint8_t dbm, uint8_t * symbo
wspr_merge_sync_vector(s, symbols);
}
/*
* fsq_dir_encode(char * from_call, char * from_call, char * message, uint8_t * symbols)
*
* Takes an arbitrary message and returns a FSQ channel symbol table.
*
* from_call - Callsign of issuing station
* message - Null-terminated message string, no greater than 200 chars in length
* symbols - Array of channel symbols to transmit retunred by the method.
* Ensure that you pass a uint8_t array of at least the size of the message
* plus 5 characters to the method. Terminated in 0xFF.
*
*/
void JTEncode::fsq_encode(char * from_call, char * message, uint8_t * symbols)
{
uint16_t symbol_pos = 0;
uint8_t i, fch, vcode1, vcode2, tone;
uint8_t cur_tone = 0;
char tx_buffer[255];
char * tx_message;
// Clearn the transmit message buffer
memset(tx_buffer, 0, 255);
// Create the message to be transmitted
sprintf(tx_buffer, " \n%s: %s", from_call, message);
tx_message = tx_buffer;
// Iterate through the message and encode
// --------------------------------------
while(*tx_message != '\0')
{
for(i = 0; i < NGLYPHS; i++)
{
uint8_t ch = (uint8_t)*tx_message;
// Check each element of the varicode table to see if we've found the
// character we're trying to send.
fch = pgm_read_byte(&fsq_code_table[i].ch);
if(fch == ch)
{
// Found the character, now fetch the varicode chars
vcode1 = pgm_read_byte(&(fsq_code_table[i].var[0]));
vcode2 = pgm_read_byte(&(fsq_code_table[i].var[1]));
// Transmit the appropriate tone per a varicode char
if(vcode2 == 0)
{
// If the 2nd varicode char is a 0 in the table,
// we are transmitting a lowercase character, and thus
// only transmit one tone for this character.
// Generate tone
cur_tone = ((cur_tone + vcode1 + 1) % 33);
symbols[symbol_pos++] = cur_tone;
}
else
{
// If the 2nd varicode char is anything other than 0 in
// the table, then we need to transmit both
// Generate 1st tone
cur_tone = ((cur_tone + vcode1 + 1) % 33);
symbols[symbol_pos++] = cur_tone;
// Generate 2nd tone
cur_tone = ((cur_tone + vcode2 + 1) % 33);
symbols[symbol_pos++] = cur_tone;
}
break; // We've found and transmitted the char,
// so exit the for loop
}
}
tx_message++;
}
// Message termination
// ----------------
symbols[symbol_pos] = 0xff;
}
/*
* fsq_dir_encode(char * from_call, char * to_call, char * cmd, char * message, uint8_t * symbols)
*
* Takes an arbitrary message and returns a FSQ channel symbol table.
*
* from_call - Callsign from which message is directed
* to_call - Callsign to which message is directed
* cmd - Directed command
* message - Null-terminated message string, no greater than 200 chars in length
* symbols - Array of channel symbols to transmit retunred by the method.
* Ensure that you pass a uint8_t array of at least the size of the message
* plus 5 characters to the method. Terminated in 0xFF.
*
*/
void JTEncode::fsq_dir_encode(char * from_call, char * to_call, char * cmd, char * message, uint8_t * symbols)
{
uint16_t symbol_pos = 0;
uint8_t i, fch, vcode1, vcode2, tone, from_call_crc;
uint8_t cur_tone = 0;
char tx_buffer[255];
char * tx_message;
// Generate a CRC on from_call
// ---------------------------
from_call_crc = crc8(from_call);
// Clearn the transmit message buffer
memset(tx_buffer, 0, 255);
// Create the message to be transmitted
// We are building a directed message here.
// FSQ very specifically needs " \b " in
// directed mode to indicate EOT. A single backspace won't do it.
sprintf(tx_buffer, " \n%s:%02x%s%s%s%s", from_call, from_call_crc, to_call, cmd, message, " \b ");
tx_message = tx_buffer;
// Iterate through the message and encode
// --------------------------------------
while(*tx_message != '\0')
{
for(i = 0; i < NGLYPHS; i++)
{
uint8_t ch = (uint8_t)*tx_message;
// Check each element of the varicode table to see if we've found the
// character we're trying to send.
fch = pgm_read_byte(&fsq_code_table[i].ch);
if(fch == ch)
{
// Found the character, now fetch the varicode chars
vcode1 = pgm_read_byte(&(fsq_code_table[i].var[0]));
vcode2 = pgm_read_byte(&(fsq_code_table[i].var[1]));
// Transmit the appropriate tone per a varicode char
if(vcode2 == 0)
{
// If the 2nd varicode char is a 0 in the table,
// we are transmitting a lowercase character, and thus
// only transmit one tone for this character.
// Generate tone
cur_tone = ((cur_tone + vcode1 + 1) % 33);
symbols[symbol_pos++] = cur_tone;
}
else
{
// If the 2nd varicode char is anything other than 0 in
// the table, then we need to transmit both
// Generate 1st tone
cur_tone = ((cur_tone + vcode1 + 1) % 33);
symbols[symbol_pos++] = cur_tone;
// Generate 2nd tone
cur_tone = ((cur_tone + vcode2 + 1) % 33);
symbols[symbol_pos++] = cur_tone;
}
break; // We've found and transmitted the char,
// so exit the for loop
}
}
tx_message++;
}
// Message termination
// ----------------
symbols[symbol_pos] = 0xff;
}
/* Private Class Members */
uint8_t JTEncode::jt_code(char c)
@ -798,3 +984,35 @@ void JTEncode::rs_encode(uint8_t * data, uint8_t * symbols)
symbols[i + 51] = dat1[11 - i];
}
}
void JTEncode::init_crc8(void)
{
int i,j;
uint8_t crc;
for(i = 0; i < 256; i++)
{
crc = i;
for(j = 0; j < 8; j++)
{
crc = (crc << 1) ^ ((crc & 0x80) ? 0x07 : 0);
}
crc8_table[i] = crc & 0xFF;
}
}
uint8_t JTEncode::crc8(char * text)
{
uint8_t crc = '\0';
uint8_t ch;
int i;
for(i = 0; i < strlen(text); i++)
{
ch = text[i];
crc = crc8_table[(crc) ^ ch];
crc &= 0xFF;
}
return crc;
}

Wyświetl plik

@ -25,6 +25,7 @@
#include "rs_common.h"
#include <stdint.h>
#include <avr/pgmspace.h>
#define JT65_SYMBOL_COUNT 126
#define JT9_SYMBOL_COUNT 85
@ -38,6 +39,125 @@
#define JT4_BIT_COUNT 206
#define WSPR_BIT_COUNT 162
// Define the structure of a varicode table
typedef struct fsq_varicode
{
uint8_t ch;
uint8_t var[2];
} Varicode;
// The FSQ varicode table, based on the FSQ Varicode V3.0
// document provided by Murray Greenman, ZL1BPU
const Varicode fsq_code_table[] PROGMEM =
{
{' ', {00, 00}}, // space
{'!', {11, 30}},
{'"', {12, 30}},
{'#', {13, 30}},
{'$', {14, 30}},
{'%', {15, 30}},
{'&', {16, 30}},
{'\'', {17, 30}},
{'(', {18, 30}},
{')', {19, 30}},
{'*', {20, 30}},
{'+', {21, 30}},
{',', {27, 29}},
{'-', {22, 30}},
{'.', {27, 00}},
{'/', {23, 30}},
{'0', {10, 30}},
{'1', {01, 30}},
{'2', {02, 30}},
{'3', {03, 30}},
{'4', {04, 30}},
{'5', {05, 30}},
{'6', {06, 30}},
{'7', {07, 30}},
{'8', {8, 30}},
{'9', {9, 30}},
{':', {24, 30}},
{';', {25, 30}},
{'<', {26, 30}},
{'=', {00, 31}},
{'>', {27, 30}},
{'?', {28, 29}},
{'@', {00, 29}},
{'A', {01, 29}},
{'B', {02, 29}},
{'C', {03, 29}},
{'D', {04, 29}},
{'E', {05, 29}},
{'F', {06, 29}},
{'G', {07, 29}},
{'H', {8, 29}},
{'I', {9, 29}},
{'J', {10, 29}},
{'K', {11, 29}},
{'L', {12, 29}},
{'M', {13, 29}},
{'N', {14, 29}},
{'O', {15, 29}},
{'P', {16, 29}},
{'Q', {17, 29}},
{'R', {18, 29}},
{'S', {19, 29}},
{'T', {20, 29}},
{'U', {21, 29}},
{'V', {22, 29}},
{'W', {23, 29}},
{'X', {24, 29}},
{'Y', {25, 29}},
{'Z', {26, 29}},
{'[', {01, 31}},
{'\\', {02, 31}},
{']', {03, 31}},
{'^', {04, 31}},
{'_', {05, 31}},
{'`', {9, 31}},
{'a', {01, 00}},
{'b', {02, 00}},
{'c', {03, 00}},
{'d', {04, 00}},
{'e', {05, 00}},
{'f', {06, 00}},
{'g', {07, 00}},
{'h', {8, 00}},
{'i', {9, 00}},
{'j', {10, 00}},
{'k', {11, 00}},
{'l', {12, 00}},
{'m', {13, 00}},
{'n', {14, 00}},
{'o', {15, 00}},
{'p', {16, 00}},
{'q', {17, 00}},
{'r', {18, 00}},
{'s', {19, 00}},
{'t', {20, 00}},
{'u', {21, 00}},
{'v', {22, 00}},
{'w', {23, 00}},
{'x', {24, 00}},
{'y', {25, 00}},
{'z', {26, 00}},
{'{', {06, 31}},
{'|', {07, 31}},
{'}', {8, 31}},
{'~', {00, 30}},
{127, {28, 31}}, // DEL
{13, {28, 00}}, // CR
{10, {28, 00}}, // LF
{0, {28, 30}}, // IDLE
{241, {10, 31}}, // plus/minus
{246, {11, 31}}, // division sign
{248, {12, 31}}, // degrees sign
{158, {13, 31}}, // multiply sign
{156, {14, 31}}, // pound sterling sign
{8, {27, 31}} // BS
};
class JTEncode
{
public:
@ -46,6 +166,8 @@ public:
void jt9_encode(char *, uint8_t *);
void jt4_encode(char *, uint8_t *);
void wspr_encode(char *, char *, uint8_t, uint8_t *);
void fsq_encode(char *, char *, uint8_t *);
void fsq_dir_encode(char *, char *, char *, char *, uint8_t *);
private:
uint8_t jt_code(char);
uint8_t wspr_code(char);
@ -69,8 +191,11 @@ private:
void encode_rs_int(void *,data_t *, data_t *);
void free_rs_int(void *);
void * init_rs_int(int, int, int, int, int, int);
void init_crc8(void);
uint8_t crc8(char *);
void * rs_inst;
char callsign[7];
char locator[5];
uint8_t power;
static uint8_t crc8_table[256];
};