Skip to content

Commit

Permalink
Reorganize for the Arduino library standard
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Milldrum committed Jan 3, 2016
1 parent 75827c9 commit e9af3f5
Show file tree
Hide file tree
Showing 13 changed files with 798 additions and 65 deletions.
621 changes: 621 additions & 0 deletions COPYING

Large diffs are not rendered by default.

46 changes: 39 additions & 7 deletions README.md
@@ -1,6 +1,6 @@
JT65/JT9/WSPR Encoder Library for Arduino
=========================================
This library very simply generates a set of channel symbols for JT65, JT9, or WSPR based on the user providing a properly formatted Type 6 message for JT65 or JT9 (which is 13 valid characters) or a callsign, Maidenhead grid locator, and power output for WSPR. When paired with a synthesizer that can output frequencies in fine, phase-continuous tuning steps (such as the Si5351), then a beacon or telemetry transmitter can be created which can change the transmitted characters as needed from the Arduino.
JT65/JT9/JT4/WSPR Encoder Library for Arduino
=============================================
This library very simply generates a set of channel symbols for JT65, JT9, JT4, or WSPR based on the user providing a properly formatted Type 6 message for JT65, JT9, or JT4 (which is 13 valid characters) or a callsign, Maidenhead grid locator, and power output for WSPR. When paired with a synthesizer that can output frequencies in fine, phase-continuous tuning steps (such as the Si5351), then a beacon or telemetry transmitter can be created which can change the transmitted characters as needed from the Arduino.

Please feel free to use the issues feature of GitHub if you run into problems or have suggestions for important features to implement.

Expand All @@ -16,11 +16,11 @@ Include the JTEncode library into your instance of the Arduino IDE. Download a Z

Example
-------
There is a simple example that is placed in your examples menu under JTEncode. Open this to see how to incorporate this library with your code. The example provided with with the library is meant to be used in conjuction with the [Etherkit Si5351A Breakout Board](https://www.etherkit.com/rf-modules/si5351a-breakout-board.html), although it could be modified to use with other synthesizers which meet the technical requirements of the JT65/JT9/WSPR modes.
There is a simple example that is placed in your examples menu under JTEncode. Open this to see how to incorporate this library with your code. The example provided with with the library is meant to be used in conjuction with the [Etherkit Si5351A Breakout Board](https://www.etherkit.com/rf-modules/si5351a-breakout-board.html), although it could be modified to use with other synthesizers which meet the technical requirements of the JT65/JT9/JT4/WSPR modes.

To run this example, be sure to download the [Si5351Arduino](https://github.com/etherkit/Si5351Arduino) library and follow the instructions there to connect the Si5351A Breakout Board to your Arduino. In order to trigger transmissions, you will also need to connect a momentary pushbutton from pin 12 of the Arduino to ground.

The example sketch itself is fairly straightforward. JT65, JT9, and WSPR modes are modulated in same way: phase-continuous multiple-frequency shift keying (MFSK). The message to be transmitted is passed to the JTEncode method corresponding to the desired mode, along with a pointer to an array which holds the returned channel symbols. When the pushbutton is pushed, the sketch then transmits each channel symbol sequentially as an offset from the base frequency given in the sketch define section.
The example sketch itself is fairly straightforward. JT65, JT9, JT4, and WSPR modes are modulated in same way: phase-continuous multiple-frequency shift keying (MFSK). The message to be transmitted is passed to the JTEncode method corresponding to the desired mode, along with a pointer to an array which holds the returned channel symbols. When the pushbutton is pushed, the sketch then transmits each channel symbol sequentially as an offset from the base frequency given in the sketch define section.

An instance of the JTEncode object is created:

Expand All @@ -44,6 +44,12 @@ On sketch startup, the mode parameters are set based on which mode is currently
symbol_count = JT65_SYMBOL_COUNT; // From the library defines
tone_spacing = JT65_TONE_SPACING;
break;
case MODE_JT4:
freq = JT4_DEFAULT_FREQ;
ctc = JT4_CTC;
symbol_count = JT4_SYMBOL_COUNT; // From the library defines
tone_spacing = JT4_TONE_SPACING;
break;
case MODE_WSPR:
freq = WSPR_DEFAULT_FREQ;
ctc = WSPR_CTC;
Expand All @@ -65,12 +71,15 @@ During transmit, the proper class method is chosen based on the desired mode, th
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;
}

Once the channel symbols have been generate, it is a simple matter of transmitting them in sequence, each of the correct amount of time:
Once the channel symbols have been generated, it is a simple matter of transmitting them in sequence, each the correct amount of time:

// Now transmit the channel symbols
for(i = 0; i < symbol_count; i++)
Expand Down Expand Up @@ -111,6 +120,21 @@ Public Methods
*/
```

###jt4_encode()
```
/*
* jt4_encode(char * message, uint8_t * symbols)
*
* Takes an arbitrary message of up to 13 allowable characters and returns
* a channel symbol table.
*
* message - Plaintext Type 6 message.
* symbols - Array of channel symbols to transmit retunred by the method.
* Ensure that you pass a uint8_t array of size JT4_SYMBOL_COUNT to the method.
*
*/
```

###wspr_encode()
```
/*
Expand All @@ -132,8 +156,16 @@ Here are the defines, structs, and enumerations you will find handy to use with

Defines:

JT65_SYMBOL_COUNT, JT9_SYMBOL_COUNT, WSPR_SYMBOL_COUNT
JT65_SYMBOL_COUNT, JT9_SYMBOL_COUNT, JT4_SYMBOL_COUNT, WSPR_SYMBOL_COUNT

Acknowledgements
----------------
Many thanks to Joe Taylor K1JT for his innovative work in amateur radio. We are lucky to have him. The algorithms in this program were derived from the source code in the [WSJT](http://sourceforge.net/projects/wsjt/) suite of applications. Also, many thanks for Andy Talbot G4JNT for [his paper](http://www.g4jnt.com/JTModesBcns.htm) on the WSPR coding protocol, which helped me to understand the WSPR encoding process, which in turn helped me to understand the related JT protocols.

License
-------
JTEncode is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

JTEncode is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with JTEncode. If not, see <http://www.gnu.org/licenses/>.
60 changes: 36 additions & 24 deletions examples/Si5351JTDemo/Si5351JTDemo.ino
Expand Up @@ -9,22 +9,22 @@
// 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
//
// 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.
Expand All @@ -45,24 +45,27 @@
// 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 JT9_CTC 9000 // CTC value for JT9-1
#define JT65_CTC 5812 // CTC value for JT65A
#define WSPR_CTC 10672 // CTC value for WSPR
#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 JT9_DEFAULT_FREQ 14078600UL
#define JT65_DEFAULT_FREQ 14077500UL
#define JT4_DEFAULT_FREQ 14077500UL
#define WSPR_DEFAULT_FREQ 14097100UL

#define DEFAULT_MODE MODE_JT65
#define DEFAULT_MODE MODE_JT4

// Hardware defines
#define BUTTON 12
#define LED_PIN 13

// Enumerations
enum mode {MODE_JT9, MODE_JT65, MODE_WSPR};
enum mode {MODE_JT9, MODE_JT65, MODE_JT4, MODE_WSPR};

// Class instantiation
Si5351 si5351;
Expand All @@ -89,15 +92,15 @@ ISR(TIMER1_COMPA_vect)
{
proceed = true;
}

// Loop through the string, transmitting one character at a time.
void encode()
{
uint8_t i;

// Clear out the old transmit buffer
memset(tx_buffer, 0, 255);

// Set the proper frequency and timer CTC depending on mode
switch(cur_mode)
{
Expand All @@ -107,29 +110,32 @@ void encode()
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;
}

// 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
for(i = 0; i < symbol_count; i++)
{
si5351.set_freq((freq * 100) + (tx_buffer[i] * tone_spacing), 0, SI5351_CLK0);
proceed = false;
while(!proceed);
}

// Turn off the output
si5351.output_enable(SI5351_CLK0, 0);
digitalWrite(LED_PIN, LOW);
}


void setup()
{
// Use the Arduino's on-board LED as a keying indicator.
Expand All @@ -138,10 +144,10 @@ void setup()

// Use a button connected to pin 12 as a transmit trigger
pinMode(BUTTON, INPUT_PULLUP);

//Serial.begin(57600);

// Set the proper frequency, tone spacing, symbol count, and
// Set the proper frequency, tone spacing, symbol count, and
// timer CTC depending on mode
switch(cur_mode)
{
Expand All @@ -157,14 +163,20 @@ void setup()
symbol_count = JT65_SYMBOL_COUNT; // From the library defines
tone_spacing = JT65_TONE_SPACING;
break;
case MODE_JT4:
freq = JT4_DEFAULT_FREQ;
ctc = JT4_CTC;
symbol_count = JT4_SYMBOL_COUNT; // From the library defines
tone_spacing = JT4_TONE_SPACING;
break;
case MODE_WSPR:
freq = WSPR_DEFAULT_FREQ;
ctc = WSPR_CTC;
symbol_count = WSPR_SYMBOL_COUNT; // From the library defines
tone_spacing = WSPR_TONE_SPACING;
break;
}

// Initialize the Si5351
// Change the 2nd parameter in init if using a ref osc other
// than 25 MHz
Expand All @@ -175,7 +187,7 @@ void setup()
si5351.set_freq(freq * 100, 0, SI5351_CLK0);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); // Set for max power if desired
si5351.output_enable(SI5351_CLK0, 0); // Disable the clock initially

// Set up Timer1 for interrupts every symbol period.
noInterrupts(); // Turn off interrupts.
TCCR1A = 0; // Set entire TCCR1A register to 0; disconnects
Expand All @@ -190,7 +202,7 @@ void setup()
OCR1A = ctc; // Set up interrupt trigger count;
interrupts(); // Re-enable interrupts.
}

void loop()
{
// Debounce the button and trigger TX on push
Expand All @@ -200,7 +212,7 @@ void loop()
if (digitalRead(BUTTON) == LOW)
{
encode();

delay(50); //delay to avoid extra triggers
}
}
Expand Down
25 changes: 0 additions & 25 deletions int.h

This file was deleted.

9 changes: 9 additions & 0 deletions library.properties
@@ -0,0 +1,9 @@
name=Etherkit JTEncode
version=1.0.0
author=Jason Milldrum <milldrum@gmail.com>
maintainer=Jason Milldrum <milldrum@gmail.com>
sentence=Generate JT65, JT9, JT4, and WSPR symbols on your Arduino.
paragraph=This library very simply generates a set of channel symbols for JT65, JT9, JT4, or WSPR based on the user providing a properly formatted Type 6 message for JT65, JT9, or JT4 (which is 13 valid characters) or a callsign, Maidenhead grid locator, and power output for WSPR. When paired with a synthesizer that can output frequencies in fine, phase-continuous tuning steps (such as the Si5351), then a beacon or telemetry transmitter can be created which can change the transmitted characters as needed from the Arduino.
category=Data Processing
url=https://github.com/etherkit/JTEncode
architectures=*

0 comments on commit e9af3f5

Please sign in to comment.