From a4e875b7e31dba67d792accc86e7d8d3bfd65345 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 5 Nov 2021 08:41:08 -0500 Subject: [PATCH] add tests, refine arduino program --- .gitignore | 1 + Makefile | 13 +++++- cwwvb.ino | 21 ++++++--- decoder.cpp | 10 +++-- decoder.h | 45 +++++++++++++------ tests.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 190 insertions(+), 24 deletions(-) create mode 100644 tests.cpp diff --git a/.gitignore b/.gitignore index f166175..b9abdc6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.o decoder firmware +tests diff --git a/Makefile b/Makefile index 436ffcc..528320c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # SPDX-License-Identifier: GPL-3.0-only FIRMWARE = firmware/cwwvb.ino.elf -all: decoder $(FIRMWARE) +all: decoder $(FIRMWARE) run-tests decoder: decoder.cpp Makefile decoder.h g++ -Wall -g -Og -o $@ $< -DMAIN @@ -18,3 +18,14 @@ PORT := /dev/ttyACM0 .PHONY: flash flash: $(FIRMWARE) arduino-cli upload -b adafruit:samd:adafruit_feather_m4 -i $(FIRMWARE:.elf=.hex) -p $(PORT) + +.PHONY: clean +clean: + rm -f *.o decoder firmware + +.PHONY: run-tests +run-tests: tests + ./tests + +tests: decoder.cpp decoder.h Makefile tests.cpp + g++ -Wall -g -Og -o $@ $(filter %.cpp, $^) diff --git a/cwwvb.ino b/cwwvb.ino index 5abf9f2..4e7dd03 100644 --- a/cwwvb.ino +++ b/cwwvb.ino @@ -26,6 +26,8 @@ SAMDTimer ITimer0(TIMER_TC3); int cc; +int tick_subsec; + WWVBDecoder<> dec; constexpr int CENTRAL_COUNT = 3000000 / dec.SUBSEC; static_assert(CENTRAL_COUNT <= 65535); @@ -75,7 +77,7 @@ void TimerHandler0(void) { digitalWrite(PIN_MON, LOW); TC3->COUNT16.CC[0].reg = cc; #if MONITOR_LL - putc(i ? '#' : '_'); + putc(i ? '_' : '#', stderr); #endif if (introduced_error.load()) { introduced_error.fetch_sub(1); @@ -84,7 +86,8 @@ void TimerHandler0(void) { if (dec.update(i)) { wq.put(try_decode); } - auto subsec = mod_diff(dec.sos, dec.SUBSEC - 5); + + auto subsec = mod_diff(dec.subsec, tick_subsec); if (subsec == 0) { wq.put(tick); } @@ -102,6 +105,8 @@ void set_tc(int n, bool hold) { if (n < -(int)CENTRAL_COUNT / 100) n = -(int)CENTRAL_COUNT / 100; cc = CENTRAL_COUNT + n; + moveto(1, 24); + fflush(stdout); fprintf(stderr, "Steer %+4d CC = %5d I = %+5d P=%+5d %.4s\n", n, cc, ss_I, ss_P, hold ? "HOLD" : "INTG"); } @@ -158,6 +163,7 @@ void loop() { digitalWrite(PIN_LED, HIGH); wq.take()(); + fflush(stdout); digitalWrite(PIN_LED, LOW); } @@ -223,7 +229,8 @@ void try_decode() { { char buf[snapshot.SYMBOLS]; for (int i = 0; i < sizeof(buf); i++) { - buf[i] = '0' + snapshot.symbols.at(i); + static const char sym2char[] = "012?"; + buf[i] = sym2char[snapshot.symbols.at(i)]; } moveto(1, 25); printf("%.*s health=%3d%%", sizeof(buf), buf, @@ -232,19 +239,19 @@ void try_decode() { if (snapshot.symbols.at(snapshot.SYMBOLS - 1) == 2) { if (snapshot.decode_minute(w)) { + tick_subsec = mod_diff(snapshot.sos, 5); w.advance_minutes(); ever_set = true; + display_time(); } } - - if (ever_set) { - tick(); - } } void tick() { + // if (ever_set) { w.advance_seconds(); display_time(); + //} } extern "C" int write(int file, char *ptr, int len); diff --git a/decoder.cpp b/decoder.cpp index ab38728..19a0fe6 100644 --- a/decoder.cpp +++ b/decoder.cpp @@ -104,8 +104,12 @@ static bool last_yday(int year) { return 365 + isly(year); } // advance to exactly the top of the n'th minute from now void wwvb_time::advance_minutes(int n) { - if (seconds_in_minute() == 61) { + if (seconds_in_minute() != 60) { ls = 0; + if (dut1 < 0) + dut1 += 10; + else if (dut1 > 0) + dut1 -= 10; } second = 0; @@ -122,7 +126,7 @@ void wwvb_time::advance_minutes(int n) { yday++; if (dst == 1) dst = 0; - if (dst == 2) + else if (dst == 2) dst = 3; if (yday < last_yday(year)) return; @@ -137,7 +141,7 @@ void wwvb_time::advance_minutes(int n) { using namespace std; int main() { - WWVBDecoder<120> dec; + WWVBDecoder<> dec; static char zone[] = "TZ=UTC"; putenv(zone); diff --git a/decoder.h b/decoder.h index 016a579..03b02be 100644 --- a/decoder.h +++ b/decoder.h @@ -72,7 +72,7 @@ template struct circular_symbol_array { return result; } - bool put(int v) { + int put(int v) { int result = 0; for (int j = 0; j < M; j++) { result = (result << 1) | data.put(v & (1 << (M - 1))); @@ -89,7 +89,6 @@ struct wwvb_time { int16_t yday; int8_t year, hour, minute, second; int8_t ls, ly, dst, dut1; - int8_t month, mday; time_t to_utc() const; struct tm apply_zone_and_dst(int zone_offset, bool observe_dst) const; @@ -234,11 +233,16 @@ struct WWVBDecoder { return expect ? count : length - count; } - // We're informed that a new second _just started_, so - // signal.at(BUFFER-1) is the first sample of the new second. and - // signal.at(BUFFER-SUBSEC-1) is the first sample of the previous second + // A second just concluded, so signal.at(BUFFER-1) is the last sample of + // the second, and signal.at(BUFFER-SUBSEC) is the first sample of the + // second void decode_symbol() { - constexpr auto OFFSET = BUFFER - SUBSEC - 1; + constexpr auto OFFSET = BUFFER - SUBSEC; +#if 0 + for(size_t i=0; i lc / 2) - result = 2; - else if (count_b > lb / 2) + if (count_c > lc / 2) { + if (count_b > lb / 2) { + result = 2; + } else { + result = 3; // a nonsense symbol + } + } else if (count_b > lb / 2) { result = 1; + } int h = 0; - h += check_health(count_a, la, 1); - h += check_health(count_b, lb, result != 0); - h += check_health(count_c, lc, result == 2); - h += check_health(count_d, ld, 0); + if (result != 3) { + h += check_health(count_a, la, 1); + h += check_health(count_b, lb, result != 0); + h += check_health(count_c, lc, result == 2); + h += check_health(count_d, ld, 0); + } int sc = symbol_count++; int si = sc % SYMBOLS; @@ -264,6 +275,14 @@ struct WWVBDecoder { health += (h - oh); symbols.put(result); + +#if 0 + printf(" %d\n", result); + for(size_t i=0; i + +#include "decoder.h" + +circular_bit_array<6> cba; +circular_symbol_array<6, 4> csa; + +TEST_CASE("test bit array") { + for (int i = 0; i < 6; i++) + cba.put(0); + + // The next puts need to read out six zeros + for (int i = 0; i < 6; i++) + CHECK(cba.put(1) == 0); + + // The next puts need to read out six ones + for (int i = 0; i < 6; i++) + CHECK(cba.put(1) == 1); + + cba.put(0); + // content now 111110 + + CHECK(cba.at(0) == 1); + CHECK(cba.at(1) == 1); + CHECK(cba.at(2) == 1); + CHECK(cba.at(3) == 1); + CHECK(cba.at(4) == 1); + CHECK(cba.at(5) == 0); +} + +TEST_CASE("test symbol array") { + for (int i = 0; i < 6; i++) + csa.put(0); + + // The next puts need to read out six zeros + for (int i = 0; i < 6; i++) + CHECK(csa.put(i) == 0); + + // The next puts need to read out the values above + for (int i = 0; i < 6; i++) + CHECK(csa.put(1) == i); + + csa.put(0); + csa.put(1); + csa.put(2); + csa.put(3); + csa.put(4); + csa.put(5); + // content now 012345 + + CHECK(csa.at(0) == 0); + CHECK(csa.at(1) == 1); + CHECK(csa.at(2) == 2); + CHECK(csa.at(3) == 3); + CHECK(csa.at(4) == 4); + CHECK(csa.at(5) == 5); +} + +TEST_CASE("test leap second") { + struct wwvb_time ww = { + .yday = 366, + .year = 16, + .hour = 23, + .minute = 59, + .second = 59, + .ls = 1, + .ly = 1, + .dst = 0, + .dut1 = -4, + }; + + ww.advance_seconds(); + CHECK(ww.second == 60); + CHECK(ww.ls); + CHECK(ww.dut1 == -4); + + ww.advance_seconds(); + CHECK(ww.second == 0); + CHECK(!ww.ls); + CHECK(ww.dut1 == 6); +} + +TEST_CASE("test dst next day") { + struct wwvb_time ww = { + .yday = 73, + .year = 21, + .hour = 23, + .minute = 59, + .second = 59, + .ls = 1, + .ly = 1, + .dst = 2, + }; + + ww.advance_seconds(); + CHECK(ww.second == 0); + CHECK(ww.dst == 3); +} + +TEST_CASE("test std next day") { + struct wwvb_time ww = { + .yday = 311, + .year = 21, + .hour = 23, + .minute = 59, + .second = 59, + .ls = 1, + .ly = 1, + .dst = 1, + }; + + ww.advance_seconds(); + CHECK(ww.second == 0); + CHECK(ww.dst == 0); +} + +#endif