WIP
This commit is contained in:
parent
ac421b605c
commit
c9911474c1
1 changed files with 145 additions and 45 deletions
190
cwwvb.ino
190
cwwvb.ino
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue