Compare commits

...

3 Commits

  1. 1
      .gitignore
  2. 264
      wwvb/wwvb.ino

1
.gitignore vendored

@ -0,0 +1 @@
.DS_Store

@ -12,11 +12,10 @@ LiquidCrystal_I2C lcd(0x27, 16, 2);
#define DEBUG false #define DEBUG false
// we sample once per ms:
#define NUM_SAMPLES_PER_FRAME 700
#define CLOCKS_PER_MS 10 #define CLOCKS_PER_MS 10
#define PPS_PULSEWIDTH_MS 100
char statusString[25] = "LOS"; char statusString[25] = "LOS";
volatile unsigned int lowLatencyInState; volatile unsigned int lowLatencyInState;
@ -31,37 +30,29 @@ volatile unsigned int secondCounter = 0;
volatile unsigned int milliCounter = 0; volatile unsigned int milliCounter = 0;
volatile unsigned int clockCounter = 0; volatile unsigned int clockCounter = 0;
volatile unsigned int highFor = 0;
volatile unsigned int lowFor = 0;
volatile unsigned int lastBitHighMS = 0;
volatile unsigned int timeToTick = 0; volatile unsigned int timeToTick = 0;
volatile unsigned int oldLastLowMillis = 0;
volatile unsigned int lastLowMillis = 0;
volatile unsigned int oldLastHighMillis = 0;
volatile unsigned int lastHighMillis = 0;
volatile unsigned int frameReadyToStart = 0;
volatile unsigned int beginFrameSearch = 0;
volatile unsigned int frameSamples = 0; volatile unsigned int frameSamples = 0;
volatile unsigned int lossOfSignal = 1; volatile unsigned int lossOfSignal = 1;
volatile unsigned int displayUpdateRequired = 1; volatile unsigned int displayUpdateRequired = 1;
volatile unsigned int frameSearch = 0; volatile unsigned int waitingForSecond = 0;
volatile unsigned int frameStart = 0; volatile unsigned int frameStart = 0;
volatile unsigned int frameStartTime = 0; volatile unsigned int frameStartTime = 0;
volatile unsigned int frameHigh = 0;
volatile unsigned int frameHighReadOut = 0;
volatile unsigned int frameLow = 0;
volatile unsigned int frameLowReadOut = 0;
volatile unsigned int frameCounter = 0; volatile unsigned int frameCounter = 0;
volatile unsigned int frameReadyForRead = 0; volatile unsigned int bitReadyForRead = 0;
volatile unsigned int lastBitReceived = 0; volatile unsigned int lastBitReceived = 0;
volatile unsigned int millisSinceBoot = 0; volatile unsigned int millisSinceBoot = 0;
volatile unsigned int ppsActivationTime; volatile unsigned int ppsActivationTime = 0;
volatile unsigned int millisSinceSignalStateChange = 0; volatile unsigned int millisSinceSignalStateChange = 0;
volatile unsigned int minuteSync = 0; volatile unsigned int minuteSync = 0;
void ICACHE_RAM_ATTR WWVFallingEdge(); void ICACHE_RAM_ATTR TimerHandler();
void ICACHE_RAM_ATTR OSCEdge();
void ICACHE_RAM_ATTR MilliEdge(); void ICACHE_RAM_ATTR MilliEdge();
void ICACHE_RAM_ATTR SecondEdge(); void ICACHE_RAM_ATTR SecondEdge();
#include "ESP8266TimerInterrupt.h" #include "ESP8266TimerInterrupt.h"
ESP8266Timer ITimer; ESP8266Timer ITimer;
@ -74,10 +65,12 @@ void setup() {
Serial.println("************************************************"); Serial.println("************************************************");
Serial.println("*** ESP8266 Ready."); Serial.println("*** ESP8266 Ready.");
Serial.println("************************************************"); Serial.println("************************************************");
Serial.print(F("\nStarting WWVB on ")); Serial.println("************************************************");
Serial.print("\n\n\n");
Serial.print(F("*** Starting WWVB on "));
Serial.println(ARDUINO_BOARD); Serial.println(ARDUINO_BOARD);
Serial.println(ESP8266_TIMER_INTERRUPT_VERSION); Serial.println(ESP8266_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F("*** CPU Frequency = "));
Serial.print(F_CPU / 1000000); Serial.print(F_CPU / 1000000);
Serial.println(F(" MHz")); Serial.println(F(" MHz"));
@ -88,43 +81,36 @@ void setup() {
// 100us timer: // 100us timer:
if (ITimer.attachInterruptInterval(100, TimerHandler)) { if (ITimer.attachInterruptInterval(100, TimerHandler)) {
Serial.print(F("Starting ITimer OK, millis() = ")); Serial.println(millis()); Serial.print(F("Starting ITimer OK, millis() = "));
Serial.println(millis());
} else { } else {
Serial.println(F("Can't set ITimer. Select another freq. or timer")); Serial.println(
F("Can't set ITimer. Select another freq. or timer")
);
} }
//attachInterrupt(digitalPinToInterrupt(LOSC_INPUT_PIN), OSCEdge, RISING);
lcd.init(); lcd.init();
lcd.backlight(); lcd.backlight();
lcd.setCursor(0, 0); lcd.setCursor(0, 0);
lcd.print("booting"); lcd.print("booting");
ppsActivationTime = millis();
} }
void TimerHandler() { void TimerHandler() {
//Serial.print(F("in timer OK, millis() = ")); Serial.println(millis());
clockCounter++; clockCounter++;
// *****************************************************************
// *****************************************************************
// LOW LATENCY HACK to respond in 100us to a falling start-of-second
// edge respond really fast to a falling edge if in the waitingForSecond
// state
//lowLatencyInState = digitalRead(WWV_SIGNAL_PIN);
wwvbInState = digitalRead(WWV_SIGNAL_PIN);
// *****************************************************************
// *****************************************************************
if(clockCounter > CLOCKS_PER_MS) { if(clockCounter > CLOCKS_PER_MS) {
clockCounter -= CLOCKS_PER_MS; clockCounter -= CLOCKS_PER_MS;
// *****************************************************************************
// LOW LATENCY HACK to respond in 100us to a falling
// start-of-second edge
// respond really fast to a falling edge if in the frameReadyToStart
// state
lowLatencyInState = digitalRead(WWV_SIGNAL_PIN);
if(!lowLatencyInState && frameReadyToStart && !lossOfSignal && !frameStart) {
// TICK!
// falling edge, beginning of a new frame and second
digitalWrite(PPS_OUTPUT_PIN, 1);
timeToTick = 1;
frameStart = 1;
frameStartTime = millisSinceBoot;
frameReadyToStart = 0;
frameSearch = 0;
}
// *****************************************************************************
MilliEdge(); MilliEdge();
} }
} }
@ -135,96 +121,75 @@ void SecondEdge() {
} }
void MilliEdge() { void MilliEdge() {
digitalWrite(DEBUG1_OUTPUT_PIN, 1);
wwvbInState = digitalRead(WWV_SIGNAL_PIN);
milliCounter++; milliCounter++;
millisSinceBoot++; millisSinceBoot++;
wwvbInState = digitalRead(WWV_SIGNAL_PIN);
if(waitingForSecond && !wwvbInState) {
// TICK! falling edge, beginning of a new frame and second
// FIXME reenable pps
//digitalWrite(PPS_OUTPUT_PIN, 1);
waitingForSecond = 0;
timeToTick = 1;
lastBitHighMS = highFor;
bitReadyForRead = 1;
return;
}
if(milliCounter > 1000) { if(milliCounter > 1000) {
milliCounter -= 1000; milliCounter -= 1000;
SecondEdge(); SecondEdge();
} }
if(wwvbInState != lastWWVBInState) {
// any edge indicates we have some signal
lossOfSignal = 0;
}
if(wwvbInState && (wwvbInState != lastWWVBInState)) { if(wwvbInState && (wwvbInState != lastWWVBInState)) {
// we are on the rising edge, last low was 1ms ago // we are on the rising edge, last low was 1ms ago
oldLastLowMillis = lastLowMillis; highFor = 0;
lastLowMillis = millisSinceBoot - 1;
} }
if(!wwvbInState && (wwvbInState != lastWWVBInState)) { if(!wwvbInState && (wwvbInState != lastWWVBInState)) {
// we are on the falling edge, last high was 1ms ago // we are on the falling edge, last high was 1ms ago
oldLastHighMillis = lastHighMillis; lowFor = 0;
lastHighMillis = millisSinceBoot - 1;
} }
if(wwvbInState == lastWWVBInState) {
if(wwvbInState != lastWWVBInState) { if(wwvbInState) {
// we are on an edge highFor++;
stateStableMillis = 0; } else {
} else { lowFor++;
// nothing happening }
stateStableMillis++;
} }
if(wwvbInState && (stateStableMillis > 180) && (stateStableMillis < 2000)) { if(wwvbInState && (highFor > 80) && !lossOfSignal) {
// if we are high but for less than 2s // if we are high for at least 80ms but no LOS
// main screen turn on // main screen turn on
lossOfSignal = 0; // this enables the falling edge low latency detector
frameSearch = 1; // that happens on a tick
waitingForSecond = 1;
} }
lastWWVBInState = wwvbInState; // copy/save for next loop if(wwvbInState && (highFor > 2000) && !lossOfSignal) {
if((stateStableMillis > 2000) && !lossOfSignal) {
// we have received nothing for 2 seconds, loss of signal: // we have received nothing for 2 seconds, loss of signal:
lossOfSignal = 1; lossOfSignal = 1;
frameStart = 0; waitingForSecond = 1;
frameCounter = 0; frameCounter = 0;
minuteSync = 0; minuteSync = 0;
digitalWrite(DEBUG1_OUTPUT_PIN, 0);
return;
} }
if(!frameStart && frameSearch && wwvbInState) { lastWWVBInState = wwvbInState; // copy/save for next loop
// if we have been high for 180ms (frameSearch) we are ready to start a new frame on the mark
frameHigh = 0;
frameLow = 0;
frameReadyToStart = 1;
digitalWrite(DEBUG1_OUTPUT_PIN, 0);
return;
}
// frameReadyToStart -> frameStart (and PPS) happens in a 100us
// ISR above.
if (frameStart && (frameSamples < NUM_SAMPLES_PER_FRAME)) {
frameSearch = 0;
//begin sampling
if (wwvbInState) {
frameHigh++;
} else {
frameLow++;
}
frameSamples++;
digitalWrite(DEBUG1_OUTPUT_PIN, 0);
return;
}
if(frameStart && (frameSamples >= NUM_SAMPLES_PER_FRAME)) {
frameReadyForRead = 1;
frameHighReadOut = frameHigh;
frameLowReadOut = frameLow;
frameStart = 0;
frameHigh = 0;
frameLow = 0;
frameSamples = 0;
}
digitalWrite(DEBUG1_OUTPUT_PIN, 0);
} }
char pb[255]; char pb[255];
void loop() { void loop() {
digitalWrite(LED_BUILTIN, !wwvbInState); digitalWrite(LED_BUILTIN, !wwvbInState);
if(timeToTick) { if(timeToTick) {
@ -232,19 +197,13 @@ void loop() {
TickSecond(); TickSecond();
} }
yield(); if(bitReadyForRead) {
bitReadyForRead = 0;
if(frameReadyForRead) { readBit();
frameReadyForRead = 0;
processFrame();
} }
yield();
PPSLowIfRequired(); PPSLowIfRequired();
yield();
if (displayUpdateRequired) { if (displayUpdateRequired) {
updateDisplay(); updateDisplay();
displayUpdateRequired = 0; displayUpdateRequired = 0;
@ -260,71 +219,53 @@ void SetPPSLow() {
} }
void SendPPS() { void SendPPS() {
unsigned int tickInterval = millisSinceBoot - ppsActivationTime;
ppsActivationTime = millisSinceBoot; ppsActivationTime = millisSinceBoot;
SetPPSHigh(); SetPPSHigh();
} }
void PPSLowIfRequired() { void PPSLowIfRequired() {
if ((millisSinceBoot - ppsActivationTime) > 500) { if ((millisSinceBoot - ppsActivationTime) > PPS_PULSEWIDTH_MS) {
SetPPSLow(); SetPPSLow();
} }
} }
void TickSecond() { void TickSecond() {
char buf[255]; char buf[255];
sprintf(buf, "*** TICK(%d): WWVB going low after %d ms high (EDGE)\n", frameCounter, millisSinceBoot - lastLowMillis); sprintf(buf, "*** TICK(%d): WWVB going low after %d ms high (EDGE)\n",
SendPPS(); frameCounter, lastBitHighMS);
Serial.print(buf); Serial.print(buf);
SendPPS();
} }
void processFrame() { void readBit() {
char buf[255]; //char buf[255];
sprintf(buf, "end of frame summary: frameHigh: %d, frameLow: %d\n", frameHighReadOut, frameLowReadOut); //sprintf(buf, "*** carrier was high for %sms befor \n", lastBitHighMS);
Serial.print(buf); //Serial.print(buf);
float rawVal =
(float)frameHighReadOut
/
( (float)frameHighReadOut + (float)frameLowReadOut );
rawVal *= 1000;
unsigned int intRawVal = (int)rawVal;
if (intRawVal > 100000) {
intRawVal = 100000;
}
displayUpdateRequired++; displayUpdateRequired++;
registerBit(convertDutyCycleToBit(intRawVal)); registerBit(convertBit(lastBitHighMS));
} }
int convertDutyCycleToBit(unsigned int rawVal) { int convertBit(unsigned int ms) {
char buf[255]; char buf[255];
/*
20% - marker
50% - one bit
80% - zero bit
our cutoff points will be 50% and 80%
*/
char bitbuf[20]; char bitbuf[20];
int output = 0; int output = 0;
output = ZEROBIT; output = ZEROBIT;
sprintf(bitbuf, "ZERO"); sprintf(bitbuf, "ZERO");
if (rawVal < 800) { if (ms < 800) {
output = ONEBIT; output = ONEBIT;
sprintf(bitbuf, "ONE"); sprintf(bitbuf, "ONE");
} }
if (rawVal < 680) { if (ms < 400) {
output = MARKBIT; output = MARKBIT;
sprintf(bitbuf, "MARK"); sprintf(bitbuf, "MARK");
} }
sprintf(buf, "frame rawVal=%d, bit=%s\n", rawVal, bitbuf); sprintf(buf, "frame prevHighMs=%s, bit=%s\n", ms, bitbuf);
Serial.print(buf); Serial.print(buf);
return output; return output;
} }
void registerBit(int doot) { void registerBit(int doot) {
@ -332,6 +273,7 @@ void registerBit(int doot) {
frameCounter++; frameCounter++;
} }
if (doot == MARKBIT) { if (doot == MARKBIT) {
if (lastBitReceived == MARKBIT) { if (lastBitReceived == MARKBIT) {
// two mark bits in a row means we are in the first second of the minute // two mark bits in a row means we are in the first second of the minute
@ -361,7 +303,6 @@ void lossOfSync(int errorFrame) {
displayUpdateRequired++; displayUpdateRequired++;
} }
void sanityCheckFrame(int doot) { void sanityCheckFrame(int doot) {
if ( if (
( (
@ -405,11 +346,10 @@ void updateDisplay() {
if (lossOfSignal) { if (lossOfSignal) {
sprintf(statusString, "LOS"); sprintf(statusString, "LOS");
} } else {
if (millisSinceBoot - frameStartTime < 10000) {
sprintf(statusString, "RX(syncing)"); sprintf(statusString, "RX(syncing)");
} }
if (minuteSync) { if (minuteSync) {
sprintf(statusString, "RX(bit %d)", frameCounter); sprintf(statusString, "RX(bit %d)", frameCounter);
} }
@ -457,15 +397,7 @@ void serialDebug() {
char buf[255]; char buf[255];
sprintf(buf,"lossOfSignal=%d\n",lossOfSignal); sprintf(buf,"lossOfSignal=%d\n",lossOfSignal);
Serial.print(buf); Serial.print(buf);
sprintf(buf,"frameReadyToStart=%d\n",frameReadyToStart); sprintf(buf,"waitingForSecond=%d\n",waitingForSecond);
Serial.print(buf);
sprintf(buf,"beginFrameSearch=%d\n",beginFrameSearch);
Serial.print(buf);
sprintf(buf,"frameSearch=%d\n",frameSearch);
Serial.print(buf);
sprintf(buf,"frameStart=%d\n",frameStart);
Serial.print(buf);
sprintf(buf,"frameStartTime=%d\n",frameStartTime);
Serial.print(buf); Serial.print(buf);
sprintf(buf,"millisSinceBoot=%d\n",millisSinceBoot); sprintf(buf,"millisSinceBoot=%d\n",millisSinceBoot);
Serial.print(buf); Serial.print(buf);
@ -475,8 +407,8 @@ void serialDebug() {
Serial.print(buf); Serial.print(buf);
sprintf(buf,"timeToTick=%d\n",timeToTick); sprintf(buf,"timeToTick=%d\n",timeToTick);
Serial.print(buf); Serial.print(buf);
sprintf(buf,"frameHigh=%d\n",frameHigh); sprintf(buf,"highFor=%d\n",highFor);
Serial.print(buf); Serial.print(buf);
sprintf(buf,"frameLow=%d\n",frameLow); sprintf(buf,"lowFor=%d\n",lowFor);
Serial.print(buf); Serial.print(buf);
} }

Loading…
Cancel
Save