Compare commits
4 commits
7a66438ec9
...
af7007f77f
| Author | SHA1 | Date | |
|---|---|---|---|
| af7007f77f | |||
| ac8b14f7f2 | |||
| 9f26e319da | |||
| 54d0b4f0f2 |
3 changed files with 36 additions and 11 deletions
4
Makefile
4
Makefile
|
|
@ -36,6 +36,10 @@ coverage:
|
|||
$(Q)$(PYTHON) -mcoverage xml $(COVERAGE_INCLUDE)
|
||||
$(Q)$(PYTHON) -mcoverage report --fail-under=100 $(COVERAGE_INCLUDE)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(Q)env PYTHONPATH=src $(PYTHON) -munittest discover -s test
|
||||
|
||||
.PHONY: test_venv
|
||||
test_venv:
|
||||
$(Q)$(PYTHON) -mvenv --clear _env
|
||||
|
|
|
|||
28
src/uwwvb.py
28
src/uwwvb.py
|
|
@ -19,7 +19,6 @@ ZERO, ONE, MARK = range(3)
|
|||
|
||||
always_mark = set((0, 9, 19, 29, 39, 49, 59))
|
||||
always_zero = set((4, 10, 11, 14, 20, 21, 34, 35, 44, 54))
|
||||
bcd_weights = (1, 2, 4, 8, 10, 20, 40, 80, 100, 200, 400, 800)
|
||||
|
||||
WWVBMinute = namedtuple("WWVBMinute", ["year", "days", "hour", "minute", "dst", "ut1", "ls", "ly"])
|
||||
|
||||
|
|
@ -76,16 +75,16 @@ class WWVBDecoder:
|
|||
|
||||
def get_am_bcd(seq: list[int], *poslist: int) -> int | None:
|
||||
"""Convert the bits seq[positions[0]], ... seq[positions[len(positions-1)]] [in MSB order] from BCD to decimal"""
|
||||
pos = list(poslist)[::-1]
|
||||
val = [int(seq[p]) for p in pos]
|
||||
while len(val) % 4 != 0:
|
||||
val.append(0)
|
||||
k = len(poslist)
|
||||
result = 0
|
||||
base = 1
|
||||
for i in range(0, len(val), 4):
|
||||
while k >= 0:
|
||||
digit = 0
|
||||
for j in range(4):
|
||||
digit += 1 << j if val[i + j] else 0
|
||||
k -= 1
|
||||
if k < 0:
|
||||
break
|
||||
digit += 1 << j if seq[poslist[k]] else 0
|
||||
if digit > 9:
|
||||
return None
|
||||
result += digit * base
|
||||
|
|
@ -99,10 +98,17 @@ def decode_wwvb(
|
|||
"""Convert a received minute of wwvb symbols to a WWVBMinute. Returns None if any error is detected."""
|
||||
if not t:
|
||||
return None
|
||||
if not all(t[i] == MARK for i in always_mark):
|
||||
return None
|
||||
if not all(t[i] == ZERO for i in always_zero):
|
||||
return None
|
||||
for i in range(len(t)):
|
||||
is_mark: bool = t[i] == MARK
|
||||
is_zero: bool = t[i] == ZERO
|
||||
expect_mark = i in always_mark or i == 60
|
||||
expect_zero = i in always_zero
|
||||
|
||||
if expect_mark != is_mark:
|
||||
return None
|
||||
if expect_zero and not is_zero:
|
||||
return None
|
||||
|
||||
# Checking redundant DUT1 sign bits
|
||||
if t[36] == t[37]:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -197,6 +197,21 @@ class WWVBRoundtrip(unittest.TestCase):
|
|||
decoded = uwwvb.decode_wwvb(test_input)
|
||||
self.assertIsNone(decoded)
|
||||
|
||||
def test_noise4(self) -> None:
|
||||
"""Test of the full minute decoder with marks at every never-mark position"""
|
||||
minute = wwvb.WWVBMinuteIERS.from_datetime(
|
||||
datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
|
||||
)
|
||||
timecode = minute.as_timecode()
|
||||
for position in range(60):
|
||||
if position in uwwvb.always_mark:
|
||||
continue
|
||||
with self.subTest(test=position):
|
||||
test_input = [int(i) for i in timecode.am]
|
||||
test_input[position] = uwwvb.MARK
|
||||
decoded = uwwvb.decode_wwvb(test_input)
|
||||
self.assertIsNone(decoded)
|
||||
|
||||
def test_str(self) -> None:
|
||||
"""Test the str() of a WWVBDecoder"""
|
||||
self.assertEqual(str(uwwvb.WWVBDecoder()), "<WWVBDecoder 1 []>")
|
||||
|
|
|
|||
Loading…
Reference in a new issue