Create a gist now

Instantly share code, notes, and snippets.

/* -KS-24361 REF-0 standalone operation
-Tested on an Arduino Uno
-Other models will work with modifications
-Pinout:
D3: PPS input
D11: Serial out to REF-0
D13: Output to LED on the Arduino, PPS indicator
-Written by Dan Watson 8/9/2015 */
#include <SoftwareSerial.h> // Used to communicate with the REF-0
#define PPSINTERRUPT 1 // Interrupt 1 for PPS - This is actually D3 on the Uno
#define LEDPIN 13 // Output IO pin for indicating the PPS
#define RXPIN 10 // D10 for software serial RX (unused)
#define TXPIN 11 // D11 for software serial TX (to REF-0)
SoftwareSerial mySerial(RXPIN, TXPIN); // D10 RX is unused, D11 TX goes to REF-0
//SoftwareSerial mySerial(RXPIN, TXPIN, true); // Or try this, which does software inversion
// and eliminates the need for an inverter
/* Motorola Oncore messages that will be sent to the REF-0
These take up a LOT of RAM. If you run out, store them in PROGMEM instead
I chose to put @@Ea and @@En in the same array, since they get sent together */
uint8_t EaEn[145] = {
0x40, 0x40, 0x45, 0x61, 0x01, 0x01, 0x07, 0xCE, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08,
0x02, 0x08, 0xFF, 0x82, 0x04, 0x08, 0xFF, 0x82, 0x06, 0x08,
0xFF, 0x82, 0x08, 0x08, 0xFF, 0x82, 0x0A, 0x08, 0xFF, 0x82,
0x0C, 0x08, 0xFF, 0x82, 0x0E, 0x08, 0xFF, 0x82, 0x10, 0x08,
0xFF, 0x82, 0x20, 0xDF, 0x0D, 0x0A, 0x40, 0x40, 0x45, 0x6E,
0x01, 0x01, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x00, 0xFA, 0x0D, 0x0A };
uint8_t Bb[92] = {
0x40, 0x40, 0x42, 0x62, 0x0A, 0x02, 0x00, 0x00, 0x5A, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x5A,
0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
0x5A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x5A, 0x00, 0x00,
0x00, 0x12, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C,
0x0D, 0x0A };
uint8_t Ap[25] = {
0x40, 0x40, 0x41, 0x70, 0x32, 0x61, 0x52, 0x99, 0x00, 0x81,
0x01, 0x2A, 0x0F, 0x54, 0xEB, 0x8B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x0D, 0x0A };
uint8_t Aw[8] = {
0x40, 0x40, 0x41, 0x77, 0x00, 0x36, 0x0D, 0x0A };
uint8_t Bj[8] = {
0x40, 0x40, 0x42, 0x6A, 0x00, 0x28, 0x0D, 0x0A };
uint8_t Az[11] = {
0x40, 0x40, 0x41, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x0D,
0x0A };
uint8_t At[8] = {
0x40, 0x40, 0x41, 0x74, 0x01, 0x34, 0x0D, 0x0A };
uint8_t Bo[8] = {
0x40, 0x40, 0x42, 0x6F, 0x00, 0x2D, 0x0D, 0x0A };
uint8_t Ag[8] = {
0x40, 0x40, 0x41, 0x67, 0x0A, 0x2C, 0x0D, 0x0A };
// Variables for handling the PPS and message rotation
int messageRotation = 0;
boolean gotPPS = false;
void setup()
{
mySerial.begin(9600); // Start SoftwareSerial
pinMode(LEDPIN, OUTPUT); // We will blink the D13 LED on the board each PPS
attachInterrupt(PPSINTERRUPT, intPPS, RISING); // Use an interrupt to act on the PPS
}
/* This main loop does nothing but act on the PPS flag.
If you add more code here later, make sure it doesn't take too long to execute.
You don't want to start missing seconds or delaying your transmissions to the REF-0 */
void loop()
{
if (gotPPS)
{
digitalWrite(LEDPIN, HIGH); // Turn on D13 LED
delay(75); // Wait the necessary 75ms before starting to send messages
EaEn[73] = EaEn[73] ^ EaEn[10]; // XOR the seconds out of the check character
EaEn[10]++; // Increment seconds
if (EaEn[10] == 60) // If we reached 59 seconds, XOR the minute out
{ // of the check character and increment
EaEn[10] = 0;
EaEn[73] = EaEn[73] ^ EaEn[9];
EaEn[9]++;
if (EaEn[9] == 60) // If we reached 59 minutes, XOR the hour out
{ // of the check character and increment
EaEn[9] = 0;
EaEn[73] = EaEn[73] ^ EaEn[8];
EaEn[8]++;
if (EaEn[8] == 24) // If it's midnight, set hours to zero
{
EaEn[8] = 0;
}
EaEn[73] = EaEn[73] ^ EaEn[8]; // XOR the new hours back in to the check character
}
EaEn[73] = EaEn[73] ^ EaEn[9]; // XOR the new minutes back into the check character
}
EaEn[73] = EaEn[73] ^ EaEn[10]; // XOR the new seconds back into the check character
for (int i = 0; i < 145; i++) // Send @@Ea with incremented time, and @@En
{
mySerial.write(EaEn[i]);
}
messageRotation++; // Cycle message rotation
if (messageRotation >= 30) messageRotation = 0;
if (messageRotation % 2 == 0) // Send @@Bb every two seconds
{
for (int i = 0; i < 92; i++)
{
mySerial.write(Bb[i]);
}
}
if (messageRotation % 5 == 0) // Send @@Ap every five seconds
{
for (int i = 0; i < 25; i++)
{
mySerial.write(Ap[i]);
}
}
if (messageRotation % 20 == 0) // Send @@Aw every 20 seconds
{
for (int i = 0; i < 8; i++)
{
mySerial.write(Aw[i]);
}
}
switch(messageRotation) { // Distribute the other messages throughout
case 8: // the 30 second period of rotation
for (int i = 0; i < 8; i++) // I chose seconds arbitrarily...
{
mySerial.write(Bj[i]);
}
break;
case 13:
for (int i = 0; i < 11; i++)
{
mySerial.write(Az[i]);
}
break;
case 17:
for (int i = 0; i < 8; i++)
{
mySerial.write(At[i]);
}
break;
case 23:
for (int i = 0; i < 8; i++)
{
mySerial.write(Bo[i]);
}
break;
case 27:
for (int i = 0; i < 8; i++)
{
mySerial.write(Ag[i]);
}
break;
}
digitalWrite(LEDPIN, LOW); // Turn off the D13 LED. This will cause a blink every PPS
gotPPS = false; // Clear PPS flag
}
}
/* When the PPS happens, this interrupt routine will set the
got PPS flag. Everything else is handled by the main loop */
void intPPS()
{
gotPPS = true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment