Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions m5stack/libs/driver/ir/receiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
# IR_RX abstract base class for IR receivers.

# Author: Peter Hinch
# Copyright Peter Hinch 2020-2021 Released under the MIT license
# Copyright (c) 2024 M5Stack Technology CO LTD
# Copyright Peter Hinch 2020-2024 Released under the MIT license

# Thanks are due to @Pax-IT for diagnosing a problem with ESP32C3.

from machine import Timer, Pin
from array import array
from utime import ticks_us

# Save RAM
# from micropython import alloc_emergency_exception_buf
# alloc_emergency_exception_buf(100)

Expand All @@ -21,6 +21,7 @@


class IR_RX:
Timer_id = -1 # Software timer but enable override
# Result/error codes
# Repeat button code
REPEAT = -1
Expand All @@ -44,7 +45,7 @@ def __init__(self, pin, nedges, tblock, callback, *args): # Optional args for c
self._times = array("i", (0 for _ in range(nedges + 1))) # +1 for overrun
pin.irq(handler=self._cb_pin, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING))
self.edge = 0
self.tim = Timer(-1) # Sofware timer
self.tim = Timer(self.Timer_id) # Defaul is sofware timer
self.cb = self.decode

# Pin interrupt. Save time of each edge for later decode.
Expand Down
70 changes: 70 additions & 0 deletions m5stack/libs/driver/ir/sony_rx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# sony.py Decoder for IR remote control using synchronous code
# Sony SIRC protocol.

# Author: Peter Hinch
# Copyright Peter Hinch 2020 Released under the MIT license

from utime import ticks_us, ticks_diff
from .receiver import IR_RX

class SONY_ABC(IR_RX): # Abstract base class
def __init__(self, pin, bits, callback, *args):
# 20 bit block has 42 edges and lasts <= 39ms nominal. Add 4ms to time
# for tolerances except in 20 bit case where timing is tight with a
# repeat period of 45ms.
t = int(3 + bits * 1.8) + (1 if bits == 20 else 4)
super().__init__(pin, 2 + bits * 2, t, callback, *args)
self._addr = 0
self._bits = 20

def decode(self, _):
try:
nedges = self.edge # No. of edges detected
self.verbose and print('nedges', nedges)
if nedges > 42:
raise RuntimeError(self.OVERRUN)
bits = (nedges - 2) // 2
if nedges not in (26, 32, 42) or bits > self._bits:
raise RuntimeError(self.BADBLOCK)
self.verbose and print('SIRC {}bit'.format(bits))
width = ticks_diff(self._times[1], self._times[0])
if not 1800 < width < 3000: # 2.4ms leading mark for all valid data
raise RuntimeError(self.BADSTART)
width = ticks_diff(self._times[2], self._times[1])
if not 350 < width < 1000: # 600μs space
raise RuntimeError(self.BADSTART)

val = 0 # Data received, LSB 1st
x = 2
bit = 1
while x <= nedges - 2:
if ticks_diff(self._times[x + 1], self._times[x]) > 900:
val |= bit
bit <<= 1
x += 2
cmd = val & 0x7f # 7 bit command
val >>= 7
if nedges < 42:
addr = val & 0xff # 5 or 8 bit addr
val = 0
else:
addr = val & 0x1f # 5 bit addr
val >>= 5 # 8 bit extended
except RuntimeError as e:
cmd = e.args[0]
addr = 0
val = 0
self.do_callback(cmd, addr, val)

class SONY_12(SONY_ABC):
def __init__(self, pin, callback, *args):
super().__init__(pin, 12, callback, *args)

class SONY_15(SONY_ABC):
def __init__(self, pin, callback, *args):
super().__init__(pin, 15, callback, *args)

class SONY_20(SONY_ABC):
def __init__(self, pin, callback, *args):
super().__init__(pin, 20, callback, *args)

48 changes: 48 additions & 0 deletions m5stack/libs/driver/ir/sony_tx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# sony.py Encoder for IR remote control using synchronous code
# Sony SIRC protocol.

# Author: Peter Hinch
# Copyright Peter Hinch 2020 Released under the MIT license

from micropython import const
from .transmitter import IR

class SONY_ABC(IR):

def __init__(self, pin, bits, freq, verbose):
super().__init__(pin, freq, 3 + bits * 2, 30, verbose)
if bits not in (12, 15, 20):
raise ValueError('bits must be 12, 15 or 20.')
self.bits = bits

def tx(self, addr, data, ext):
self.append(2400, 600)
bits = self.bits
v = data & 0x7f
if bits == 12:
v |= (addr & 0x1f) << 7
elif bits == 15:
v |= (addr & 0xff) << 7
else:
v |= (addr & 0x1f) << 7
v |= (ext & 0xff) << 12
for _ in range(bits):
self.append(1200 if v & 1 else 600, 600)
v >>= 1

# Sony specifies 40KHz
class SONY_12(SONY_ABC):
valid = (0x1f, 0x7f, 0) # Max addr, data, toggle
def __init__(self, pin, freq=40000, verbose=False):
super().__init__(pin, 12, freq, verbose)

class SONY_15(SONY_ABC):
valid = (0xff, 0x7f, 0) # Max addr, data, toggle
def __init__(self, pin, freq=40000, verbose=False):
super().__init__(pin, 15, freq, verbose)

class SONY_20(SONY_ABC):
valid = (0x1f, 0x7f, 0xff) # Max addr, data, toggle
def __init__(self, pin, freq=40000, verbose=False):
super().__init__(pin, 20, freq, verbose)

48 changes: 40 additions & 8 deletions m5stack/libs/unit/ir.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,49 @@
# SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
#
# SPDX-License-Identifier: MIT
from driver.ir.nec import NEC, NEC_8
from driver.ir.nec import NEC as NEC_TX, NEC_8 as NEC_8_RX, NEC_16 as NEC_16_RX, SAMSUNG as SAMSUNG_RX
from driver.ir.sony_tx import SONY_ABC as SONY_TX
from driver.ir.sony_rx import SONY_12 AS SONY_12_RX, SONY_15 as SONY_15_RX, SONY_20 as SONY_20_RX
from driver.ir.receiver import IR_RX
import machine


class IRUnit:
# def __new__(cls, port, proto):
# if proto.upper() == "NEC":
# return NEC(Pin(port[1], Pin.IN))
class NEC_8:
tx = NEC_TX
rx = NEC_8_RX


class NEC_16:
tx = NEC_TX
rx = NEC_8_TX


class SAMSUNG:
tx = NEC_TX
rx = SAMSUNG_RX


class SONY_12:
tx = SONY_TX
rx = SONY_12_RX

def __init__(self, port) -> None:

class SONY_15:
tx = SONY_TX
rx = SONY_15_RX


class SONY_20:
tx = SONY_TX
rx = SONY_20_RX


class IRUnit:
def __init__(self, port, ir_cls=NEC_8, timer=1) -> None:
(self._rx_pin, self._tx_pin) = port
self._transmitter = NEC(machine.Pin(self._tx_pin, machine.Pin.OUT, value=0))
self._ir_cls = ir_cls
self._timer = timer
self._transmitter = self._ir_cls.tx(machine.Pin(self._tx_pin, machine.Pin.OUT, value=0))
self._receiver = None

def tx(self, cmd, data):
Expand All @@ -21,4 +52,5 @@ def tx(self, cmd, data):
def rx_cb(self, cb):
if self._receiver:
self._receiver.close()
self._receiver = NEC_8(machine.Pin(self._rx_pin, machine.Pin.IN), cb)
IR_RX.Timer_id = self._timer
self._receiver = self._ir_cls_rx(machine.Pin(self._rx_pin, machine.Pin.IN), cb)