Skip to content

Commit

Permalink
more
Browse files Browse the repository at this point in the history
  • Loading branch information
via committed Aug 24, 2024
1 parent 612594e commit 9ce1cec
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 9 deletions.
28 changes: 22 additions & 6 deletions integration/decoder-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import sys
import cbor

from validation import validate_outputs

class ToothEvent:
def __init__(self, time, delay, trigger, angle=None, rpm=None, cycle=None):
self.time = time
Expand Down Expand Up @@ -255,16 +257,30 @@ def test_start_stop_start(self):
first_output = next(results.filter_between(t1, t2).filter_outputs())
self.assertEqual(first_output.cycle, 1)


# t1-t5:
# t2-t4:
# - should have sync
# - ignition: dwell and advance match
# - fuel: pw matches
for f in results.filter_between(t2, t4).filter_feeds():
self.assertEqual(f.values['sync'], 1)

#
# t5:
# - we lose sync within X ms
#
validate_outputs(results.filter_between(t2, t4))

# t4-t5:
# - we lose sync within X ms, and it stays lost
# - last output within Y ms
last_sync = next(filter(lambda i: i.values['sync'] == 0,
results.filter_between(t4, t5).filter_feeds()))

self.assertWithin(last_sync.time - t4, ms_ticks(1), ms_ticks(100))
remaining_syncs = filter(lambda i: i.values['sync'] == 1,
results.filter_between(last_sync.time, t5).filter_feeds())
self.assertEqual(len(list(remaining_syncs)), 0)

outputs = list(results.filter_between(t4, t5).filter_outputs())
if len(outputs) > 0:
self.assertWithin(outputs[-1].time, ms_ticks(1), ms_ticks(100))


if __name__ == "__main__":
Expand Down
110 changes: 107 additions & 3 deletions integration/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def filter_between(self, start, end):
filter(lambda i: i.time >= start and i.time <= end, self.log)
)


def __next__(self):
return next(self.log)

Expand All @@ -33,6 +34,8 @@ def __iter__(self):





def degrees_for_tick_rpm(ticks, rpm):
ticks_per_degree = (4000000 / 6.0) / rpm
return ticks / ticks_per_degree
Expand All @@ -44,6 +47,67 @@ def clamp_angle(angle):
angle += 720
return angle

class OutputConfig:
FUEL = 1
IGN = 2

def __init__(self, pin, typ, angle):
self.pin = pin
self.typ = typ
self.angle = angle

def _offset(self, angle):
adv = angle - self.angle

# normalize to (-360, 360) for easy comparison with bounds
if adv >= 360:
adv -= 720
if adv <= -360:
adv += 720
return adv

class Config:
def __init__(self):
self.outputs = [
OutputConfig(pin=0, typ=OutputConfig.IGN, angle=0),
OutputConfig(pin=1, typ=OutputConfig.IGN, angle=120),
OutputConfig(pin=2, typ=OutputConfig.IGN, angle=240),
OutputConfig(pin=0, typ=OutputConfig.IGN, angle=360),
OutputConfig(pin=1, typ=OutputConfig.IGN, angle=480),
OutputConfig(pin=2, typ=OutputConfig.IGN, angle=600),

OutputConfig(pin=8, typ=OutputConfig.FUEL, angle=700),
OutputConfig(pin=9, typ=OutputConfig.FUEL, angle=460),
OutputConfig(pin=10, typ=OutputConfig.FUEL, angle=220),
]


def _offset_within(self, oc, angle, lower, upper):
"""Validate that the advance is within bounds. lower and upper must
both be within (-360, 360)."""

adv = oc._offset(angle)
if adv >= lower and adv <= upper:
return True
return False

def lookup(self, pin, end_angle):
# TODO maybe don't hardcode this, but until then:
# - assume fuel is +/- 10 degrees
# - assume ignition is -50 to +10 degrees
for oc in self.outputs:
if pin != oc.pin:
continue

if oc.typ == OutputConfig.IGN:
if self._offset_within(oc, end_angle, -50, 10):
return oc

if oc.typ == OutputConfig.FUEL:
if self._offset_within(oc, end_angle, -10, 10):
return oc

config = Config()

class OutputEvent:
def __init__(self, time, pin, duration_us, end_angle, cycle):
Expand All @@ -52,9 +116,9 @@ def __init__(self, time, pin, duration_us, end_angle, cycle):
self.duration_us = duration_us
self.end_angle = end_angle
self.cycle = cycle

# self.relative_angle
# self.type =
self.oc = config.lookup(pin, end_angle)
if self.oc:
self.advance = -self.oc._offset(end_angle)

class FeedEvent:

Expand Down Expand Up @@ -122,3 +186,43 @@ def enrich_log(inputs, log) -> EnrichedLog:
entry["values"]))

return EnrichedLog(result)

def validate_outputs(log):
"""Validate that all outputs are associated with a configured output,
and that there are no gaps or missing outputs. Each cycle should have
the full count of configured outputs, except for the first and last.
If feed values containing advance and durations (dwell, pw) are present,
also evaluate that those values are reasonably close."""

is_first_cycle = True
current_cycle = None
current_cycle_outputs = 0
cycles = []
for o in log.filter_outputs():
if o.oc is None:
return False

if is_first_cycle:
is_first_cycle = False
current_cycle = o.cycle
if o.cycle != current_cycle:
if o.cycle > current_cycle + 1:
# We skipped a cycle
return False
cycles.append(current_cycle_outputs)
current_cycle_outputs = 0
current_cycle = o.cycle

current_cycle_outputs += 1

expected_count = len(config.outputs)

if cycles[0] <= expected_count and \
cycles[-1] <= expected_count and ( \
len(cycles) < 3 or \
all(map(lambda c: c == expected_count, cycles[1:-2]))):
return True

return False

0 comments on commit 9ce1cec

Please sign in to comment.