This commit is contained in:
Jeff Epler 2021-10-30 09:18:45 -05:00
parent ac421b605c
commit c9911474c1

190
cwwvb.ino
View file

@ -4,7 +4,8 @@
#define PIN_OUT (12)
#define PIN_PDN (10)
#define PIN_MON (5)
#include <algorithm>
#include <atomic>
#include "SAMDTimerInterrupt.h"
@ -12,32 +13,80 @@
#include "decoder.h"
#define MONITOR_LL (0)
#define MONITOR_SYM (0)
#define CENTRAL_COUNT (59963)
#define AUTO_STEERING (1)
// SAMD51 Hardware Timer only TC3
constexpr int TIMER0_INTERVAL_MS = 20;
SAMDTimer ITimer0(TIMER_TC3);
std::atomic<int> symbol_count;
int cc;
void TimerHandler0(void) {
int i = digitalRead(PIN_OUT);
digitalWrite(PIN_MON, HIGH);
digitalWrite(PIN_MON, LOW);
TC3->COUNT16.CC[0].reg = cc;
#if MONITOR_LL
Serial.write(i ? '#' : '_');
#endif
if (update(i)) {
int sym = decode_symbol();
#if MONITOR_SYM
Serial.write('\t');
Serial.write('0' + sym);
Serial.write('\n');
#endif
symbols.put(sym);
symbol_count.fetch_add(1);
}
}
void moveto(int x, int y) {
char buf[32];
snprintf(buf, sizeof(buf), "\033[%d;%dH", y, x);
Serial.write(buf);
}
int ss_I, ss_P;
void set_tc(int n) {
moveto(1, 25);
cc = CENTRAL_COUNT + n;
char buf[64];
snprintf(buf, sizeof(buf), "Steer %+4d CC = %5d I = %+5d P=%+5d ", n, cc,
ss_I, ss_P);
Serial.print(buf);
}
void steer_tc(int delta) { set_tc(cc - CENTRAL_COUNT + delta); }
int last_count = 0;
void loop() {
while (Serial.available() > 0)
Serial.read();
while (Serial.available() > 0) {
int c = Serial.read();
#if !AUTO_STEERING
if (c == '+' || c == '=') {
steer_tc(1);
}
if (c == '-') {
steer_tc(-1);
}
if (c == '0') {
set_tc(0);
}
#endif
}
int new_count = symbol_count.load();
if (new_count == last_count) {
return;
}
// unless something REALLY weird happens, delta should be 1!
int delta = new_count - last_count;
circular_symbol_array<SYMBOLS, 2> symbols_snapshot;
@ -50,30 +99,89 @@ void loop() {
sos_snapshot = sos;
interrupts();
Serial.write('\t');
for (int i = 0; i < delta; i++) {
Serial.write('0' + symbols_snapshot.at(SYMBOLS - delta + i));
}
Serial.write(" ");
Serial.print(sos_snapshot, DEC);
Serial.write("\r\n");
if (symbols_snapshot.at(SYMBOLS - 1) == 2) {
wwvb_minute w;
if (decode_minute(symbols_snapshot, w)) {
Serial.write(" ");
Serial.print(w.year + 2000, DEC);
Serial.print("-");
Serial.print(w.yday, DEC);
Serial.print("T");
Serial.print(w.hour, DEC);
Serial.print(":");
Serial.print(w.minute, DEC);
Serial.print(" ");
#if AUTO_STEERING
// Try to steer the start-of-subsec to the "0" value
// This is a simple proportional(ish) control, which should
// settle with some constant phase error. (or, more likely, oscillate
// around two nearby values)
//
// Problems:
// * during signal loss, the adjustment can be totally wrong
// * it's very coarse
// * the CENTRAL_COUNT value has to be pretty close
//
// Should add: I-term to force error to 0, hold while signal quality
// is not known, and some kind of fractional control.
ss_P = mod_diff<SUBSEC>(sos_snapshot, 0);
ss_I += ss_P;
set_tc(ss_P * 4 + ss_I / 20);
#endif
{
#define ROWS (22)
char screen[ROWS][SUBSEC];
memset(screen, ' ', sizeof(screen));
int max_counts = 0;
int max_edges = 0;
for (int i = 0; i < SUBSEC; i++) {
max_counts = std::max(max_counts, (int)counts_snapshot[i]);
max_edges = std::max(max_edges, (int)abs(edges_snapshot[i]));
}
for (int i = 0; i < ROWS; i++) {
screen[i][sos_snapshot] = '.';
}
for (int i = 0; i < SUBSEC; i++) {
int j = i;
while (j >= SUBSEC)
j -= SUBSEC;
{
int r =
ROWS / 2 - edges_snapshot[j] * (ROWS - 1) / max_edges / 2;
if (r < 0 || r >= ROWS) {
Serial.println("r out of range [edges]");
Serial.println(i);
Serial.println(j);
Serial.println(r);
continue;
}
screen[r][i] = '_';
}
{
int r = ROWS - 1 -
counts_snapshot[j] * ROWS / (1 + BUFFER / SUBSEC);
if (r < 0 || r >= ROWS) {
Serial.println("r out of range");
Serial.println(r);
} else {
screen[r][i] = '#';
}
}
}
moveto(1, 2);
for (int i = 0; i < ROWS; i++) {
Serial.write(screen[i], SUBSEC);
Serial.write("|\r\n");
}
}
{
char buf[SYMBOLS];
for (int i = 0; i < sizeof(buf); i++) {
buf[i] = '0' + symbols_snapshot.at(i);
}
Serial.write(buf, sizeof(buf));
}
if (symbols_snapshot.at(SYMBOLS - 1) == 2) {
wwvb_minute w;
moveto(1, 1);
if (decode_minute(symbols_snapshot, w)) {
time_t now = wwvb_to_utc(w);
Serial.print((unsigned)(now >> 32), HEX);
Serial.print((unsigned)(now), HEX);
Serial.print(" ");
struct tm tm;
gmtime_r(&now, &tm);
@ -88,30 +196,22 @@ void loop() {
void setup() {
pinMode(PIN_PDN, OUTPUT);
pinMode(PIN_MON, OUTPUT);
pinMode(PIN_OUT, INPUT_PULLUP);
digitalWrite(PIN_PDN, 0);
Serial.begin(115200);
while (!Serial) { /* wait for connect */
}
Serial.println("hello world");
wwvb_minute w = {};
w.year = 21;
w.yday = 301;
w.hour = 19;
w.minute = 20;
time_t now = wwvb_to_utc(w);
Serial.print((unsigned)(now >> 32), HEX);
Serial.print("|");
Serial.print((unsigned)(now), HEX);
Serial.print(" ");
struct tm tm;
gmtime_r(&now, &tm);
char buf[32];
strftime(buf, sizeof(buf), "%FT%RZ", &tm);
Serial.println(buf);
ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 1000, TimerHandler0);
// 59999 counts [the value you get with the above interval] is about
// 300ppm off on my HW.
// 300ppm _slow_ on my HW. Each adjustment step is about 16.67ppm.
// Making the number _BIGGER_ makes the `sos` value decrease over time
// (because it makes the interrupt _slower_)
// and making it _SMALLER_ makes the `sos` value incrase over time.
// (making the interrupt _faster_)
set_tc(0);
Serial.write("\033[2J");
}