LightAPRS-W-1.0/libraries/LightAPRS_JTEncode/examples/Si5351JTDemo/Si5351JTDemo.ino

252 wiersze
7.6 KiB
C++
Executable File

//
// Simple JT65/JT9/JT4/FT8/WSPR/FSQ beacon for Arduino, with the Etherkit
// Si5351A Breakout Board, by Jason Milldrum NT7S.
//
// Transmit an abritrary message of up to 13 valid characters
// (a Type 6 message) in JT65, JT9, JT4, a type 0.0 or type 0.5 FT8 message,
// a FSQ message, or a standard Type 1 message in WSPR.
//
// Connect a momentary push button to pin 12 to use as the
// transmit trigger. Get fancy by adding your own code to trigger
// off of the time from a GPS or your PC via virtual serial.
//
// Original code based on Feld Hell beacon for Arduino by Mark
// Vandewettering K6HX, adapted for the Si5351A by Robert
// Liesenfeld AK6L <ak6l@ak6l.org>.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#include <si5351.h>
#include <JTEncode.h>
#include <rs_common.h>
#include <int.h>
#include <string.h>
#include "Wire.h"
// Mode defines
#define JT9_TONE_SPACING 174 // ~1.74 Hz
#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 879 // ~8.79 Hz
#define FT8_TONE_SPACING 625 // ~6.25 Hz
#define JT9_DELAY 576 // Delay value for JT9-1
#define JT65_DELAY 371 // Delay in ms for JT65A
#define JT4_DELAY 229 // Delay value for JT4A
#define WSPR_DELAY 683 // Delay value for WSPR
#define FSQ_2_DELAY 500 // Delay value for 2 baud FSQ
#define FSQ_3_DELAY 333 // Delay value for 3 baud FSQ
#define FSQ_4_5_DELAY 222 // Delay value for 4.5 baud FSQ
#define FSQ_6_DELAY 167 // Delay value for 6 baud FSQ
#define FT8_DELAY 159 // Delay value for FT8
#define JT9_DEFAULT_FREQ 14078700UL
#define JT65_DEFAULT_FREQ 14078300UL
#define JT4_DEFAULT_FREQ 14078500UL
#define WSPR_DEFAULT_FREQ 14097200UL
#define FSQ_DEFAULT_FREQ 7105350UL // Base freq is 1350 Hz higher than dial freq in USB
#define FT8_DEFAULT_FREQ 14075000UL
#define DEFAULT_MODE MODE_JT65
// Hardware defines
#define BUTTON 12
#define LED_PIN 13
// Enumerations
enum mode {MODE_JT9, MODE_JT65, MODE_JT4, MODE_WSPR, MODE_FSQ_2, MODE_FSQ_3,
MODE_FSQ_4_5, MODE_FSQ_6, MODE_FT8};
// Class instantiation
Si5351 si5351;
JTEncode jtencode;
// Global variables
unsigned long freq;
char message[] = "N0CALL AA00";
char call[] = "N0CALL";
char loc[] = "AA00";
uint8_t dbm = 27;
uint8_t tx_buffer[255];
enum mode cur_mode = DEFAULT_MODE;
uint8_t symbol_count;
uint16_t tone_delay, tone_spacing;
// Loop through the string, transmitting one character at a time.
void encode()
{
uint8_t i;
// Reset the tone to the base frequency and turn on the output
si5351.output_enable(SI5351_CLK0, 1);
digitalWrite(LED_PIN, HIGH);
// Now transmit the channel symbols
if(cur_mode == MODE_FSQ_2 || cur_mode == MODE_FSQ_3 || cur_mode == MODE_FSQ_4_5 || cur_mode == MODE_FSQ_6)
{
uint8_t j = 0;
while(tx_buffer[j++] != 0xff);
symbol_count = j - 1;
}
for(i = 0; i < symbol_count; i++)
{
si5351.set_freq((freq * 100) + (tx_buffer[i] * tone_spacing), SI5351_CLK0);
delay(tone_delay);
}
// Turn off the output
si5351.output_enable(SI5351_CLK0, 0);
digitalWrite(LED_PIN, LOW);
}
void set_tx_buffer()
{
// Clear out the transmit buffer
memset(tx_buffer, 0, 255);
// Set the proper frequency and timer CTC depending on mode
switch(cur_mode)
{
case MODE_JT9:
jtencode.jt9_encode(message, tx_buffer);
break;
case MODE_JT65:
jtencode.jt65_encode(message, tx_buffer);
break;
case MODE_JT4:
jtencode.jt4_encode(message, tx_buffer);
break;
case MODE_WSPR:
jtencode.wspr_encode(call, loc, dbm, tx_buffer);
break;
case MODE_FT8:
jtencode.ft8_encode(message, tx_buffer);
break;
case MODE_FSQ_2:
case MODE_FSQ_3:
case MODE_FSQ_4_5:
case MODE_FSQ_6:
jtencode.fsq_dir_encode(call, "n0call", ' ', "hello world", tx_buffer);
break;
}
}
void setup()
{
// Initialize the Si5351
// Change the 2nd parameter in init if using a ref osc other
// than 25 MHz
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
// Use the Arduino's on-board LED as a keying indicator.
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Use a button connected to pin 12 as a transmit trigger
pinMode(BUTTON, INPUT_PULLUP);
// Set the mode to use
cur_mode = MODE_JT65;
// Set the proper frequency, tone spacing, symbol count, and
// tone delay depending on mode
switch(cur_mode)
{
case MODE_JT9:
freq = JT9_DEFAULT_FREQ;
symbol_count = JT9_SYMBOL_COUNT; // From the library defines
tone_spacing = JT9_TONE_SPACING;
tone_delay = JT9_DELAY;
break;
case MODE_JT65:
freq = JT65_DEFAULT_FREQ;
symbol_count = JT65_SYMBOL_COUNT; // From the library defines
tone_spacing = JT65_TONE_SPACING;
tone_delay = JT65_DELAY;
break;
case MODE_JT4:
freq = JT4_DEFAULT_FREQ;
symbol_count = JT4_SYMBOL_COUNT; // From the library defines
tone_spacing = JT4_TONE_SPACING;
tone_delay = JT4_DELAY;
break;
case MODE_WSPR:
freq = WSPR_DEFAULT_FREQ;
symbol_count = WSPR_SYMBOL_COUNT; // From the library defines
tone_spacing = WSPR_TONE_SPACING;
tone_delay = WSPR_DELAY;
break;
case MODE_FT8:
freq = FT8_DEFAULT_FREQ;
symbol_count = FT8_SYMBOL_COUNT; // From the library defines
tone_spacing = FT8_TONE_SPACING;
tone_delay = FT8_DELAY;
break;
case MODE_FSQ_2:
freq = FSQ_DEFAULT_FREQ;
tone_spacing = FSQ_TONE_SPACING;
tone_delay = FSQ_2_DELAY;
break;
case MODE_FSQ_3:
freq = FSQ_DEFAULT_FREQ;
tone_spacing = FSQ_TONE_SPACING;
tone_delay = FSQ_3_DELAY;
break;
case MODE_FSQ_4_5:
freq = FSQ_DEFAULT_FREQ;
tone_spacing = FSQ_TONE_SPACING;
tone_delay = FSQ_4_5_DELAY;
break;
case MODE_FSQ_6:
freq = FSQ_DEFAULT_FREQ;
tone_spacing = FSQ_TONE_SPACING;
tone_delay = FSQ_6_DELAY;
break;
}
// Set CLK0 output
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); // Set for max power if desired
si5351.output_enable(SI5351_CLK0, 0); // Disable the clock initially
// Encode the message in the transmit buffer
// This is RAM intensive and should be done separately from other subroutines
set_tx_buffer();
}
void loop()
{
// Debounce the button and trigger TX on push
if(digitalRead(BUTTON) == LOW)
{
delay(50); // delay to debounce
if (digitalRead(BUTTON) == LOW)
{
encode();
delay(50); //delay to avoid extra triggers
}
}
}