This commit is contained in:
2022-01-11 02:08:04 -08:00
commit 2d9aa994a8
7 changed files with 2878 additions and 0 deletions

175
wwvb/floats.csv Normal file
View File

@@ -0,0 +1,175 @@
94.34
39.62
67.36
48.64
71.57
78.93
86.80
37.59
41.87
76.45
65.54
70.19
77.87
73.15
70.13
33.27
27.52
87.68
74.66
49.75
74.90
68.83
69.74
58.10
49.23
61.75
94.63
85.94
46.70
68.18
48.62
75.80
50.17
52.28
66.22
68.36
70.89
46.68
71.96
90.99
74.44
97.34
22.63
25.14
54.39
47.70
80.27
75.28
73.23
63.09
71.75
73.39
29.64
60.99
78.13
73.29
52.33
68.42
71.71
60.31
54.13
76.60
58.99
75.99
85.64
74.30
77.69
79.76
79.61
60.93
54.99
45.50
81.65
74.05
67.01
85.79
83.92
76.03
72.04
32.79
33.62
67.26
71.17
78.02
63.84
67.86
58.04
71.88
72.92
72.11
68.45
68.71
93.77
65.92
78.33
63.78
58.41
48.74
71.87
53.10
80.33
58.18
72.19
79.94
85.44
78.55
82.78
71.12
63.79
62.94
63.66
58.44
50.59
91.02
89.28
68.35
86.34
31.90
69.33
65.45
76.41
83.79
73.95
73.08
60.52
51.60
59.42
82.91
82.62
64.72
69.13
67.46
71.94
78.55
73.33
70.58
80.87
77.23
75.79
87.83
88.32
79.55
60.92
71.68
69.79
83.03
89.25
76.60
55.45
67.67
82.52
77.72
65.99
60.15
73.46
68.14
61.96
85.54
64.17
83.86
61.66
79.66
64.02
45.70
76.10
63.10
64.77
94.71
76.37
75.78
76.00
35.66
65.96
68.23
91.41
1 94.34
2 39.62
3 67.36
4 48.64
5 71.57
6 78.93
7 86.80
8 37.59
9 41.87
10 76.45
11 65.54
12 70.19
13 77.87
14 73.15
15 70.13
16 33.27
17 27.52
18 87.68
19 74.66
20 49.75
21 74.90
22 68.83
23 69.74
24 58.10
25 49.23
26 61.75
27 94.63
28 85.94
29 46.70
30 68.18
31 48.62
32 75.80
33 50.17
34 52.28
35 66.22
36 68.36
37 70.89
38 46.68
39 71.96
40 90.99
41 74.44
42 97.34
43 22.63
44 25.14
45 54.39
46 47.70
47 80.27
48 75.28
49 73.23
50 63.09
51 71.75
52 73.39
53 29.64
54 60.99
55 78.13
56 73.29
57 52.33
58 68.42
59 71.71
60 60.31
61 54.13
62 76.60
63 58.99
64 75.99
65 85.64
66 74.30
67 77.69
68 79.76
69 79.61
70 60.93
71 54.99
72 45.50
73 81.65
74 74.05
75 67.01
76 85.79
77 83.92
78 76.03
79 72.04
80 32.79
81 33.62
82 67.26
83 71.17
84 78.02
85 63.84
86 67.86
87 58.04
88 71.88
89 72.92
90 72.11
91 68.45
92 68.71
93 93.77
94 65.92
95 78.33
96 63.78
97 58.41
98 48.74
99 71.87
100 53.10
101 80.33
102 58.18
103 72.19
104 79.94
105 85.44
106 78.55
107 82.78
108 71.12
109 63.79
110 62.94
111 63.66
112 58.44
113 50.59
114 91.02
115 89.28
116 68.35
117 86.34
118 31.90
119 69.33
120 65.45
121 76.41
122 83.79
123 73.95
124 73.08
125 60.52
126 51.60
127 59.42
128 82.91
129 82.62
130 64.72
131 69.13
132 67.46
133 71.94
134 78.55
135 73.33
136 70.58
137 80.87
138 77.23
139 75.79
140 87.83
141 88.32
142 79.55
143 60.92
144 71.68
145 69.79
146 83.03
147 89.25
148 76.60
149 55.45
150 67.67
151 82.52
152 77.72
153 65.99
154 60.15
155 73.46
156 68.14
157 61.96
158 85.54
159 64.17
160 83.86
161 61.66
162 79.66
163 64.02
164 45.70
165 76.10
166 63.10
167 64.77
168 94.71
169 76.37
170 75.78
171 76.00
172 35.66
173 65.96
174 68.23
175 91.41

1086
wwvb/output.txt Normal file

File diff suppressed because it is too large Load Diff

482
wwvb/wwvb.ino Normal file
View File

@@ -0,0 +1,482 @@
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define SERIAL_RATE 115200
#define WWV_SIGNAL_PIN 14
#define PPS_OUTPUT_PIN 16
#define DEBUG1_OUTPUT_PIN 15
#define ONEBIT 1
#define ZEROBIT 2
#define MARKBIT 3
#define DEBUG false
// we sample once per ms:
#define NUM_SAMPLES_PER_FRAME 700
#define CLOCKS_PER_MS 10
char statusString[25] = "LOS";
volatile unsigned int lowLatencyInState;
volatile unsigned int wwvbInState;
volatile unsigned int lastWWVBInState;
volatile unsigned int stateStableCounter = 0;
volatile unsigned int stateStableMillis = 0;
volatile unsigned int lastStateStableMillis = 0;
volatile unsigned int secondCounter = 0;
volatile unsigned int milliCounter = 0;
volatile unsigned int clockCounter = 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 lossOfSignal = 1;
volatile unsigned int displayUpdateRequired = 1;
volatile unsigned int frameSearch = 0;
volatile unsigned int frameStart = 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 frameReadyForRead = 0;
volatile unsigned int lastBitReceived = 0;
volatile unsigned int millisSinceBoot = 0;
volatile unsigned int ppsActivationTime;
volatile unsigned int millisSinceSignalStateChange = 0;
volatile unsigned int minuteSync = 0;
void ICACHE_RAM_ATTR WWVFallingEdge();
void ICACHE_RAM_ATTR OSCEdge();
void ICACHE_RAM_ATTR MilliEdge();
void ICACHE_RAM_ATTR SecondEdge();
#include "ESP8266TimerInterrupt.h"
ESP8266Timer ITimer;
void setup() {
Serial.begin(SERIAL_RATE);
while (!Serial);
delay(200);
Serial.print("\n\n\n");
Serial.println("************************************************");
Serial.println("************************************************");
Serial.println("*** ESP8266 Ready.");
Serial.println("************************************************");
Serial.print(F("\nStarting WWVB on "));
Serial.println(ARDUINO_BOARD);
Serial.println(ESP8266_TIMER_INTERRUPT_VERSION);
Serial.print(F("CPU Frequency = "));
Serial.print(F_CPU / 1000000);
Serial.println(F(" MHz"));
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PPS_OUTPUT_PIN, OUTPUT);
pinMode(DEBUG1_OUTPUT_PIN, OUTPUT);
pinMode(WWV_SIGNAL_PIN, INPUT);
// 100us timer:
if (ITimer.attachInterruptInterval(100, TimerHandler)) {
Serial.print(F("Starting ITimer OK, millis() = ")); Serial.println(millis());
} else {
Serial.println(F("Can't set ITimer. Select another freq. or timer"));
}
//attachInterrupt(digitalPinToInterrupt(LOSC_INPUT_PIN), OSCEdge, RISING);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("booting");
ppsActivationTime = millis();
}
void TimerHandler() {
//Serial.print(F("in timer OK, millis() = ")); Serial.println(millis());
clockCounter++;
if(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();
}
}
void SecondEdge() {
secondCounter++;
displayUpdateRequired = 1;
}
void MilliEdge() {
digitalWrite(DEBUG1_OUTPUT_PIN, 1);
wwvbInState = digitalRead(WWV_SIGNAL_PIN);
milliCounter++;
millisSinceBoot++;
if(milliCounter > 1000) {
milliCounter -= 1000;
SecondEdge();
}
if(wwvbInState && (wwvbInState != lastWWVBInState)) {
// we are on the rising edge, last low was 1ms ago
oldLastLowMillis = lastLowMillis;
lastLowMillis = millisSinceBoot - 1;
}
if(!wwvbInState && (wwvbInState != lastWWVBInState)) {
// we are on the falling edge, last high was 1ms ago
oldLastHighMillis = lastHighMillis;
lastHighMillis = millisSinceBoot - 1;
}
if(wwvbInState != lastWWVBInState) {
// we are on an edge
stateStableMillis = 0;
} else {
// nothing happening
stateStableMillis++;
}
if(wwvbInState && (stateStableMillis > 180) && (stateStableMillis < 2000)) {
// if we are high but for less than 2s
// main screen turn on
lossOfSignal = 0;
frameSearch = 1;
}
lastWWVBInState = wwvbInState; // copy/save for next loop
if((stateStableMillis > 2000) && !lossOfSignal) {
// we have received nothing for 2 seconds, loss of signal:
lossOfSignal = 1;
frameStart = 0;
frameCounter = 0;
minuteSync = 0;
digitalWrite(DEBUG1_OUTPUT_PIN, 0);
return;
}
if(!frameStart && frameSearch && wwvbInState) {
// 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];
void loop() {
digitalWrite(LED_BUILTIN, !wwvbInState);
if(timeToTick) {
timeToTick = 0;
TickSecond();
}
yield();
if(frameReadyForRead) {
frameReadyForRead = 0;
processFrame();
}
yield();
PPSLowIfRequired();
yield();
if (displayUpdateRequired) {
updateDisplay();
displayUpdateRequired = 0;
}
}
void SetPPSHigh() {
digitalWrite(PPS_OUTPUT_PIN, 1);
}
void SetPPSLow() {
digitalWrite(PPS_OUTPUT_PIN, 0);
}
void SendPPS() {
unsigned int tickInterval = millisSinceBoot - ppsActivationTime;
ppsActivationTime = millisSinceBoot;
SetPPSHigh();
}
void PPSLowIfRequired() {
if ((millisSinceBoot - ppsActivationTime) > 500) {
SetPPSLow();
}
}
void TickSecond() {
char buf[255];
sprintf(buf, "*** TICK(%d): WWVB going low after %d ms high (EDGE)\n", frameCounter, millisSinceBoot - lastLowMillis);
SendPPS();
Serial.print(buf);
}
void processFrame() {
char buf[255];
sprintf(buf, "end of frame summary: frameHigh: %d, frameLow: %d\n", frameHighReadOut, frameLowReadOut);
Serial.print(buf);
float rawVal =
(float)frameHighReadOut
/
( (float)frameHighReadOut + (float)frameLowReadOut );
rawVal *= 1000;
unsigned int intRawVal = (int)rawVal;
if (intRawVal > 100000) {
intRawVal = 100000;
}
displayUpdateRequired++;
registerBit(convertDutyCycleToBit(intRawVal));
}
int convertDutyCycleToBit(unsigned int rawVal) {
char buf[255];
/*
20% - marker
50% - one bit
80% - zero bit
our cutoff points will be 50% and 80%
*/
char bitbuf[20];
int output = 0;
output = ZEROBIT;
sprintf(bitbuf, "ZERO");
if (rawVal < 800) {
output = ONEBIT;
sprintf(bitbuf, "ONE");
}
if (rawVal < 680) {
output = MARKBIT;
sprintf(bitbuf, "MARK");
}
sprintf(buf, "frame rawVal=%d, bit=%s\n", rawVal, bitbuf);
Serial.print(buf);
return output;
}
void registerBit(int doot) {
if (minuteSync) {
frameCounter++;
}
if (doot == MARKBIT) {
if (lastBitReceived == MARKBIT) {
// two mark bits in a row means we are in the first second of the minute
frameCounter = 0;
minuteSync = 1;
}
}
if (!minuteSync) {
frameCounter = 0;
}
sanityCheckFrame(doot);
lastBitReceived = doot;
logBit(doot);
}
void logBit(int doot) {
}
void lossOfSync(int errorFrame) {
char buf[255];
sprintf(buf, "ERROR: %d bit incorrect for framing, loss of sync!\n", errorFrame);
Serial.print(buf);
minuteSync = 0;
displayUpdateRequired++;
}
void sanityCheckFrame(int doot) {
if (
(
(frameCounter == 9)
||
(frameCounter == 19)
||
(frameCounter == 29)
||
(frameCounter == 39)
||
(frameCounter == 49)
)
&& doot != MARKBIT) {
lossOfSync(frameCounter);
}
if (
(doot == MARKBIT)
&&
(
(frameCounter != 0)
&&
(frameCounter != 9)
&&
(frameCounter != 19)
&&
(frameCounter != 29)
&&
(frameCounter != 39)
&&
(frameCounter != 49)
)
) {
lossOfSync(frameCounter);
}
}
void updateDisplay() {
//Serial.print("updateDisplay()\n");
if (lossOfSignal) {
sprintf(statusString, "LOS");
}
if (millisSinceBoot - frameStartTime < 10000) {
sprintf(statusString, "RX(syncing)");
}
if (minuteSync) {
sprintf(statusString, "RX(bit %d)", frameCounter);
}
char d[20];
if (lastBitReceived == MARKBIT) {
sprintf(d, "%d=MARK", frameCounter);
}
if (lastBitReceived == ONEBIT) {
sprintf(d, "%d=ONE ", frameCounter);
}
if (lastBitReceived == ZEROBIT) {
sprintf(d, "%d=ZERO", frameCounter);
}
lcd.clear();
lcd.setCursor(0, 0);
char msg[20];
sprintf(msg, "up:%03d", secondCounter);
lcd.print(msg);
lcd.setCursor(0, 1);
sprintf(msg, "s:%s", statusString);
lcd.print(msg);
if (minuteSync) {
lcd.setCursor(10, 0);
lcd.print(d);
}
if(DEBUG) {
if(secondCounter % 10 == 0) {
serialDebug();
}
}
}
void fastSerialDebug() {
char buf[255];
sprintf(buf,"stateStableMillis=%d\n",stateStableMillis);
Serial.print(buf);
}
void serialDebug() {
char buf[255];
sprintf(buf,"lossOfSignal=%d\n",lossOfSignal);
Serial.print(buf);
sprintf(buf,"frameReadyToStart=%d\n",frameReadyToStart);
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);
sprintf(buf,"millisSinceBoot=%d\n",millisSinceBoot);
Serial.print(buf);
sprintf(buf,"frameStartAge=%d\n",millisSinceBoot-frameStartTime);
Serial.print(buf);
sprintf(buf,"secondCounter=%d\n",secondCounter);
Serial.print(buf);
sprintf(buf,"timeToTick=%d\n",timeToTick);
Serial.print(buf);
sprintf(buf,"frameHigh=%d\n",frameHigh);
Serial.print(buf);
sprintf(buf,"frameLow=%d\n",frameLow);
Serial.print(buf);
}