1
0
forked from sneak/hacks
This commit is contained in:
2022-01-10 04:58:59 -08:00
parent ac052d190a
commit ae9c16e405
4 changed files with 2493 additions and 84 deletions

View File

@@ -1,110 +1,405 @@
/*
ESP8266 Blink by Simon Peter
Blink the blue LED on the ESP-01 module
This example code is in the public domain
The blue LED on the ESP-01 module is connected to GPIO1
(which is also the TXD pin; so we cannot use Serial.print() at the same time)
Note that this sketch uses LED_BUILTIN to find the pin with the internal LED
*/
#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 LOSC_INPUT_PIN 0
#define DEBUG1_OUTPUT_PIN 15
void ICACHE_RAM_ATTR readLevel();
#define ONEBIT 1
#define ZEROBIT 2
#define MARKBIT 3
volatile byte wwvbInState; // store receiver signal level
#define NUM_SAMPLES_PER_FRAME 32000
#define CLOCKS_PER_MS 32
byte prevWwvbInState; // store previous signal level
unsigned int prevEdgeMillis; // store time signal was read
byte bitVal; // bit decoded 0, 1 or Mark
byte badBit; // bad bit, noise detected
byte prevMark; // store previous mark bit
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 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();
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
pinMode(WWV_SIGNAL_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(WWV_SIGNAL_PIN), readLevel, CHANGE); // fire interrupt on edge detected
Serial.begin(9600);
Serial.print("herro booted\n");
pinMode(LED_BUILTIN, OUTPUT);
pinMode(PPS_OUTPUT_PIN, OUTPUT);
pinMode(DEBUG1_OUTPUT_PIN, OUTPUT);
pinMode(WWV_SIGNAL_PIN, INPUT);
pinMode(LOSC_INPUT_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(LOSC_INPUT_PIN), OSCEdge, RISING);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("booting");
Serial.begin(SERIAL_RATE);
Serial.print("\n\n************\n\nherro booted\n");
ppsActivationTime = millis();
}
void OSCEdge() {
clockCounter++;
if(clockCounter > CLOCKS_PER_MS) {
clockCounter -= CLOCKS_PER_MS;
// *****************************************************************************
// LOW LATENCY HACK to respond in 1/32nd of a ms 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 == lastWWVBInState) {
stateStableMillis++;
if(stateStableMillis > 1000) {
stateStableMillis = 1000;
}
} else {
//edge of some sort.
lastStateStableMillis = stateStableMillis;
// if it's a falling edge
if(!wwvbInState && (stateStableMillis > 100) && (stateStableMillis < 2000)) {
// main screen turn on
lossOfSignal = 0;
frameSearch = 1;
}
stateStableMillis = 0;
}
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(frameSearch && wwvbInState) {
// if we have been high for 100ms (frameSearch) we are ready to start a new frame on the mark
frameHigh = 0;
frameLow = 0;
frameReadyToStart = 1;
digitalWrite(DEBUG1_OUTPUT_PIN, 0);
return;
}
if (frameStart && (frameSamples < NUM_SAMPLES_PER_FRAME)) {
//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];
// the loop function runs over and over again forever
void loop() {
if (wwvbInState != prevWwvbInState) {
pulseValue();
prevWwvbInState = wwvbInState;
}
yield();
}
digitalWrite(LED_BUILTIN, !wwvbInState);
void pulseValue() {
unsigned int edgeMillis = millis(); // save current time
badBit = 0; // set noise counter to zero
if (wwvbInState == 1) { // rising edge
prevEdgeMillis = edgeMillis; // set previous time to current
}
else { // falling edge
int pulseLength = edgeMillis - prevEdgeMillis; // calculate pulse length millis
if (pulseLength < 100) { // less than 100ms, noise pulses
badBit = 1;
}
else if (pulseLength < 400) { // 800ms carrier drop mark
bitVal = 2;
}
else if (pulseLength < 700) { // 500ms carrier drop one
bitVal = 1;
}
else { // 200ms carrier drop zero
bitVal = 0;
if(timeToTick) {
Serial.println("*** TICK in loop()");
timeToTick = 0;
TickSecond();
}
if (badBit == 0) {
printBitVal();
yield();
if(frameReadyForRead) {
Serial.println("*** processFrame() in loop()");
frameReadyForRead = 0;
processFrame();
}
yield();
PPSLowIfRequired();
yield();
if (displayUpdateRequired) {
Serial.println("*** updateDisplay() in loop()");
sprintf(pb,"*** secondCounter=%d\n", secondCounter);
Serial.print(pb);
updateDisplay();
displayUpdateRequired = 0;
}
}
}
void SetPPSHigh() {
digitalWrite(PPS_OUTPUT_PIN, 1);
}
void readLevel() {
wwvbInState = digitalRead(WWV_SIGNAL_PIN); // read signal level
digitalWrite(LED_BUILTIN, !wwvbInState); // flash WWVB receiver indicator pin
yield();
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\n", frameCounter, lastStateStableMillis);
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 / 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 > 20000) {
output = MARKBIT;
sprintf(bitbuf, "MARK");
}
if (rawVal > 30000) {
output = ONEBIT;
sprintf(bitbuf, "ONE");
}
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 printBitVal() {
if ((bitVal == 2) && (prevMark == 0)) {
Serial.print(" : ");
prevMark = 1;
}
else if ((bitVal == 2) && (prevMark == 1)) {
Serial.print("\nBit Value: ");
Serial.print("| ");
prevMark = 0;
}
else {
Serial.print(bitVal, DEC);
prevMark = 0;
}
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++;
}
/*****************************************************************************
* Time display functions
*****************************************************************************/
void printTime() {
Serial.print("?x00?y0?f"); // movie cursor to line 1 char 1, clear screen
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);
}
}
// LCD routines to initialize LCD and clear screen
void lcdInit() { // using P H Anderson Serial LCD driver board
Serial.print("?G216"); // configure driver for 2 x 16 LCD
delay(300);
Serial.print("?BDD"); // set backlight brightness
delay(300);
Serial.print("?f"); // clear screen
Serial.print("?c0"); // set cursor off
void updateDisplay() {
//Serial.print("updateDisplay()\n");
if (frameStart) {
// don't do anything if we are currently sampling.
return;
}
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", millisSinceBoot/1000);
lcd.print(msg);
lcd.setCursor(0, 1);
sprintf(msg, "s:%s", statusString);
lcd.print(msg);
if (minuteSync) {
lcd.setCursor(10, 0);
lcd.print(d);
}
}