add tests, refine arduino program

This commit is contained in:
Jeff Epler 2021-11-05 08:41:08 -05:00
parent d947fcbced
commit a4e875b7e3
6 changed files with 190 additions and 24 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@
*.o
decoder
firmware
tests

View file

@ -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, $^)

View file

@ -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.SUBSEC>(dec.sos, dec.SUBSEC - 5);
auto subsec = mod_diff<dec.SUBSEC>(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.SUBSEC>(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);

View file

@ -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);

View file

@ -72,7 +72,7 @@ template <int N, int M> 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<SUBSEC; i++) {
printf("%c", signal.at(OFFSET + i) ? '_' : '#');
}
#endif
int count_a = count(OFFSET + p0, OFFSET + p1);
int count_b = count(OFFSET + p1, OFFSET + p2);
int count_c = count(OFFSET + p2, OFFSET + p3);
@ -246,16 +250,23 @@ struct WWVBDecoder {
int result = 0;
if (count_c > 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<SYMBOLS; i++) {
printf("%d", symbols.at(i));
}
printf("\n", result);
#endif
}
mutable bool bcderr;

124
tests.cpp Normal file
View file

@ -0,0 +1,124 @@
// SPDX-FileCopyrightText: 2021 Jeff Epler
//
// SPDX-License-Identifier: GPL-3.0-only
#ifndef ARDUINO
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>
#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