kopia lustrzana https://github.com/etherkit/JTEncode
Addition of FSQ
rodzic
89fdbea1cb
commit
7b06dd1890
|
@ -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
|
||||
|
|
220
src/JTEncode.cpp
220
src/JTEncode.cpp
|
@ -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;
|
||||
}
|
||||
|
|
125
src/JTEncode.h
125
src/JTEncode.h
|
@ -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];
|
||||
};
|
||||
|
|
Ładowanie…
Reference in New Issue