- Yes we are using spidev directly, this is how we use the Infrared. Might as well share the whole file:
The run method in a different file calls get_ir_signal() in a loop and returns something if the code matches.
self._spi = SpiDev(1, 0)
from spidev import SpiDev
from configparser import ConfigParser
import time
SEND_IR = 1
READ_IR = 2
CONF_IR_TIMER = 10
class Infrared:
"""
Class for sending receiving infrared signals
"""
def __init__(self):
"""
Imports IR codes from config file and initiates SPI bus for IR interface
"""
self.parser = ConfigParser()
self.parser.read("config.ini")
self._spi = SpiDev(1, 0)
self._spi.mode = 0b01
self._read_toggle = "0"
self._write_toggle = "0"
self._last_code = ""
def _read_write(self, code=None):
"""
Read write function. SPI interface reads everytime it writes. If code is none means we want to read.
For reading a zero message is generated and sent just to read from the bus.
For sending signal a message is extracted from hex code provided and sent over SPI bus. System will read
incoming signals even when sending.
:param code: IR code as hex string
:return: data read from SPI bus
"""
speed = 40000
if code is None:
message = self._get_zero_message()
else:
message = self._hex_to_spi_output(code)
data = self._spi.xfer2(message, speed)
return data
# TODO: lägg in något stopp för längd på meddelande
def _get_raw_ir_data(self):
"""
Reads and decodes raw IR data from SPI bus. A buffer from SPI bus is read and recoded. If no data is reveived
all data in buffer will be 255 and ignored. If there are zeros in buffer it will be decoded.
Values < 125 = 0, values >= 125 = 1.
The infrared signal will look like 0000111100001111 with 4 ones/zeros representing low/high. This is the way
infrared protocols work. One bit in the RC5 protocol is represented by two bits, a one is 01 and a zero is 10
For more info read up on Infrared RTC5 protocol.
The filtering will read 3 ro more ones/zeros in a row as one bit. 00001111000111 = 0101
Six or more ones/zeros in a row will be read as two bits. 00011100000001111 = 01001
Data will be read until length of message is greater than 28 bits.
If there are more than 9 ones in a row the message is incomplete and None is returned.
:return: list of 28 integers representing the RC5 14 bit signal. None if incomplete.
"""
start_bit_read = False
zeros_added = ones_added = 0
zeros = ones = 0
bits = "1"
data = self._read_write()
read = data.count(0) > 0
while read:
for d in data:
if d < 125:
start_bit_read = True
zeros += 1
if zeros_added == 0 or (zeros > 5 and zeros_added < 2):
bits += '0'
zeros_added += 1
ones = 0
ones_added = 0
else:
if start_bit_read:
ones += 1
if ones_added == 0 or (ones > 5 and ones_added < 2):
bits += '1'
ones_added += 1
zeros = 0
zeros_added = 0
if ones > 9:
if len(bits) > 28:
bits = bits[0:28]
print(bits)
return bits
else:
return None
data = self._read_write()
return None
def _filter_raw_ir_signal(self, raw):
"""
Filers 28 integer list to RC5 14 integers signal.
Converts 01 -> 1 and 10 -> 0.
:param raw: unfiltered data
:return: RC5 code, toggle status of message
"""
toggle_bit = ""
rc5_code = None
if raw is not None and len(raw) >= 28:
signal = ""
for i in range(0, 28, 2):
signal += raw[i + 1]
if len(signal) != 14:
print("wrong signal", signal, len(signal))
print("raw", raw)
return None, ""
data = signal[len(signal) - 11:len(signal)]
# data = signal[3:14]
toggle_bit = signal[2]
rc5_code = hex(int(data, 2))
return rc5_code, toggle_bit
def _hex_to_spi_output(self, hex_string):
"""
Converts RC5 hex code to SPI data to be sent
0 -> [255, 255, 255, 255, 0, 0, 0, 0]
1 -> [0, 0, 0, 0, 255, 255, 255, 255]
:param hex_string: RC5 code
:return: Buffer for SPI bus
"""
scale = 16
num_of_bits = 11
self._write_toggle = str(int(not int(self._write_toggle)))
bit_string = "00" + self._write_toggle
bit_string += bin(int(hex_string, scale))[2:].zfill(num_of_bits)
spi_output = []
for bit in bit_string:
if bit == "0":
spi_output += [255, 255, 255, 255, 0, 0, 0, 0]
else:
spi_output += [0, 0, 0, 0, 255, 255, 255, 255]
return spi_output
def _get_zero_message(self):
"""
Return zero buffer to be sent on SPI bus
:return: SPI buffer full of zeros
"""
message = []
for i in range(32):
message += [0, 0, 0, 0]
return message
def get_ir_signal(self):
"""
Decode RC5 code and find which key the code represents
:return: key representation, RC5 code
"""
key_pressed = None
raw = self._get_raw_ir_data()
rc5_code, toggle_bit = self._filter_raw_ir_signal(raw)
if rc5_code is not None and (rc5_code != self._last_code or self._read_toggle != toggle_bit):
for key, value in self.parser.items("rc5_read"):
if value == rc5_code:
key_pressed = key
self._read_toggle = toggle_bit
self._last_code = rc5_code
self._read_write()
print("key_pressed ", key_pressed, "rc_5 ", rc5_code)
return key_pressed, rc5_code
def send_ir_signal(self, key, group):
"""
Send IR signal for key pressed
:param key: Key pressed
"""
parser_key = f"rc5_send_{group}"
value = self.parser[parser_key][str(key)]
print("send key group", key, group, value)
self._read_write(value)
time.sleep(0.5)
Here is the community thread we found it in:
But yeah I guess you are right since the workaround didn’t really help. We have also tried filling the SPI buffer with a lot of bytes to reduce the amount of time delays but that did not work either, also it comes with another set of problems.