class LED_Flashable(): def __init__(self, loop, led_no): self.led = pyb.LED(led_no) self.event = Event() loop.create_task(self.flash_task()) def flash(self, period_ms): if self.event.is_set(): return self.event.set(period_ms) async def flash_task(self): while True: await self.event period_ms = self.event.value() self.event.clear() self.led.on() await asyncio.sleep_ms(period_ms) self.led.off()
class NEC_IR(): def __init__(self, pin, callback, extended, *args): # Optional args for callback self._ev_start = Event() self._callback = callback self._extended = extended self._addr = 0 self.block_time = 80 if extended else 73 # Allow for some tx tolerance (?) self._args = args self._times = array('i', (0 for _ in range(_EDGECOUNT + 1))) # +1 for overrun if platform == 'pyboard': ExtInt(pin, ExtInt.IRQ_RISING_FALLING, Pin.PULL_NONE, self._cb_pin) else: # PR5962 ESP8266 hard IRQ's not supported pin.irq(handler=self._cb_pin, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING)) #elif ESP32: #pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING)) #else: #pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING), hard = True) self._edge = 0 self._ev_start.clear() loop = asyncio.get_event_loop() loop.create_task(self._run()) async def _run(self): loop = asyncio.get_event_loop() while True: await self._ev_start # Wait until data collection has started # Compensate for asyncio latency latency = ticks_diff(loop.time(), self._ev_start.value()) await asyncio.sleep_ms(self.block_time - latency ) # Data block should have ended self._decode() # decode, clear event, prepare for new rx, call cb # Pin interrupt. Save time of each edge for later decode. def _cb_pin(self, line): t = ticks_us() # On overrun ignore pulses until software timer times out if self._edge <= _EDGECOUNT: # Allow 1 extra pulse to record overrun if not self._ev_start.is_set(): # First edge received loop = asyncio.get_event_loop() self._ev_start.set(loop.time()) # asyncio latency compensation self._times[self._edge] = t self._edge += 1 def _decode(self): overrun = self._edge > _EDGECOUNT val = OVERRUN if overrun else BADSTART if not overrun: width = ticks_diff(self._times[1], self._times[0]) if width > 4000: # 9ms leading mark for all valid data width = ticks_diff(self._times[2], self._times[1]) if width > 3000: # 4.5ms space for normal data if self._edge < _EDGECOUNT: # Haven't received the correct number of edges val = BADBLOCK else: # Time spaces only (marks are always 562.5µs) # Space is 1.6875ms (1) or 562.5µs (0) # Skip last bit which is always 1 val = 0 for edge in range(3, _EDGECOUNT - 2, 2): val >>= 1 if ticks_diff(self._times[edge + 1], self._times[edge]) > 1120: val |= 0x80000000 elif width > 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges. val = REPEAT if self._edge == 4 else BADREP addr = 0 if val >= 0: # validate. Byte layout of val ~cmd cmd ~addr addr addr = val & 0xff cmd = (val >> 16) & 0xff if addr == ((val >> 8) ^ 0xff) & 0xff: # 8 bit address OK val = cmd if cmd == (val >> 24) ^ 0xff else BADDATA self._addr = addr else: addr |= val & 0xff00 # pass assumed 16 bit address to callback if self._extended: val = cmd if cmd == (val >> 24) ^ 0xff else BADDATA self._addr = addr else: val = BADADDR if val == REPEAT: addr = self._addr # Last valid addresss self._edge = 0 # Set up for new data burst and run user callback self._ev_start.clear() self._callback(val, addr, *self._args)
class NEC_IR(): edgecount = 68 block_time = 73 # 68.1ms nominal. Allow for some tx tolerance (?) def __init__(self, pin, callback): self._ev_start = Event() self._callback = callback self._times = array('i', (0 for _ in range(self.edgecount + 1))) # 1 for overrun ExtInt(pin, ExtInt.IRQ_RISING_FALLING, Pin.PULL_NONE, self._cb_pin) self._reset() loop = asyncio.get_event_loop() loop.create_task(self._run()) def _reset(self): self._edge = 0 self._in_block = False self._overrun = False self._ev_start.clear() async def _run(self): loop = asyncio.get_event_loop() block_time = self.block_time while True: await self._ev_start # Wait unitl data collection has started delta = block_time - ticks_diff(loop.time(), self._ev_start.value()) await asyncio.sleep_ms(delta) # Data block should have ended self._decode() # decode, clear event, prepare for new rx, call cb # Pin interrupt. Save time of each edge for later decode. def _cb_pin(self, line): if self._overrun: # Ignore pulses until software timer times out return if not self._in_block: # First edge received loop = asyncio.get_event_loop() self._ev_start.set(loop.time()) # time for latency compensation self._in_block = True self._times[self._edge] = ticks_us() if self._edge < self.edgecount: self._edge += 1 else: self._overrun = True # Overrun. decode() will test and reset def _decode(self): val = -3 if self._overrun else 0 if not self._overrun: width = ticks_diff(self._times[1], self._times[0]) if width > 4000: # 9ms leading mark for all valid data width = ticks_diff(self._times[2], self._times[1]) if width > 3000: # 4.5ms space for normal data if self._edge < self.edgecount: val = -1 # Haven't received the correct number of edges else: # Time spaces only (marks are identical) for edge_no in range(3, self.edgecount, 2): val &= 0x1fffffff # Constrain to 32 bit integer (b30 == b31) val <<= 1 # nos. will still be unique because of logical inverse address width = ticks_diff(self._times[edge_no + 1], self._times[edge_no]) if width > 1120: val += 1 elif width > 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges. val = 1 if self._edge == 4 else -2 self._reset() self._callback(val)