diff --git a/i2c_raw.py b/i2c_raw.py deleted file mode 100644 index 4389f90..0000000 --- a/i2c_raw.py +++ /dev/null @@ -1,29 +0,0 @@ -import io -import fcntl -import struct - -I2C_SLAVE = 0x0703 - - -class I2CRaw: - def __init__(self, address, bus): - self.fr = io.open(f"/dev/i2c-{bus}", "rb", buffering=0) - self.fw = io.open(f"/dev/i2c-{bus}", "wb", buffering=0) - fcntl.ioctl(self.fr, I2C_SLAVE, address) - fcntl.ioctl(self.fw, I2C_SLAVE, address) - - def write_i2c_block_data(self, data): - if type(data) is not list: - return -1 - data = bytearray(data) - self.fw.write(data) - return 0 - - def read_i2c_block_data(self, n_bytes): - data_raw = self.fr.read(n_bytes) - unpack_format = 'B'*n_bytes - return list(struct.unpack(unpack_format, data_raw)) - - def close(self): - self.fr.close() - self.fw.close() diff --git a/itho-wpu.py b/itho-wpu.py index 7b1e510..eb6eef0 100755 --- a/itho-wpu.py +++ b/itho-wpu.py @@ -1,9 +1,7 @@ #!/usr/bin/env python3 import argparse -import i2c_raw import logging -import pigpio import queue import sys import time @@ -12,6 +10,7 @@ import datetime import json import db from collections import namedtuple +from itho_i2c import I2CMaster, I2CSlave logger = logging.getLogger('stdout') logger.setLevel(logging.INFO) @@ -73,99 +72,6 @@ def parse_args(): return args -class I2CSlave(): - def __init__(self, address, queue): - self.address = address - self.queue = queue - self.pi = pigpio.pi() - if not self.pi.connected: - logger.error("not pi.connected") - return - - def set_callback(self): - logger.debug("set_callback()") - self.event_callback = self.pi.event_callback(pigpio.EVENT_BSC, self.callback) - self.pi.bsc_i2c(self.address) - - def callback(self, id, tick): - logger.debug(f"callback({id}, {tick})") - s, b, d = self.pi.bsc_i2c(self.address) - result = None - if b: - logger.debug(f"Received {b} bytes! Status {s}") - result = [hex(c) for c in d] - logger.debug(f"Callback Response: {result}") - if self.is_checksum_valid(result) and self.is_length_valid(result): - self.queue.put(result) - else: - logger.debug(f"Received number of bytes was {b}") - - def is_checksum_valid(self, b): - s = 0x80 - for i in b[:-1]: - s += int(i, 0) - checksum = 256 - (s % 256) - if checksum == 256: - checksum = 0 - if checksum != int(b[-1], 0): - logger.debug(f"Checksum invalid (0x{checksum:02x} != {b[-1]})") - return False - return True - - def is_length_valid(self, b): - length_in_msg = int(b[4], 0) - actual_length = len(b) - 6 - if length_in_msg != actual_length: - logger.debug(f"Length invalid ({length_in_msg} != {actual_length})") - return False - return True - - def close(self): - self.event_callback.cancel() - self.pi.bsc_i2c(0) - self.pi.stop() - - -class I2CMaster: - def __init__(self, address, bus, queue): - self.i = i2c_raw.I2CRaw(address=address, bus=bus) - self.queue = queue - - def compose_request(self, action): - # 0x80 = source, 0x04 = msg_type, 0x00 = length - request = [0x80] + actions[action] + [0x04, 0x00] - request.append(self.calculate_checksum(request)) - return request - - def calculate_checksum(self, request): - s = 0x82 - for i in request: - s += i - checksum = 256 - (s % 256) - if checksum == 256: - checksum = 0 - return checksum - - def execute_action(self, action): - request = self.compose_request(action) - result = None - for i in range(0, 20): - logger.debug(f"Executing action: {action}") - self.i.write_i2c_block_data(request) - time.sleep(0.21) - logger.debug("Queue size: {}".format(self.queue.qsize())) - if self.queue.qsize() > 0: - result = self.queue.get() - break - - if result is None: - logger.error(f"No valid result in 20 requests") - return result - - def close(self): - self.i.close() - - class IthoWPU(): def __init__(self, master_only, slave_only, slave_timeout, no_cache): self.master_only = master_only diff --git a/itho_i2c.py b/itho_i2c.py new file mode 100644 index 0000000..97773ce --- /dev/null +++ b/itho_i2c.py @@ -0,0 +1,133 @@ +import fcntl +import io +import logging +import pigpio +import struct +import time + +logger = logging.getLogger(__name__) + +actions = { + "getnodeid": [0x90, 0xE0], + "getserial": [0x90, 0xE1], + "getdatatype": [0xA4, 0x00], + "getdatalog": [0xA4, 0x01], +} + + +class I2CRaw: + def __init__(self, address, bus): + I2C_SLAVE = 0x0703 + self.fr = io.open(f"/dev/i2c-{bus}", "rb", buffering=0) + self.fw = io.open(f"/dev/i2c-{bus}", "wb", buffering=0) + fcntl.ioctl(self.fr, I2C_SLAVE, address) + fcntl.ioctl(self.fw, I2C_SLAVE, address) + + def write_i2c_block_data(self, data): + if type(data) is not list: + return -1 + data = bytearray(data) + self.fw.write(data) + return 0 + + def read_i2c_block_data(self, n_bytes): + data_raw = self.fr.read(n_bytes) + unpack_format = 'B'*n_bytes + return list(struct.unpack(unpack_format, data_raw)) + + def close(self): + self.fr.close() + self.fw.close() + + +class I2CMaster: + def __init__(self, address, bus, queue): + self.i = I2CRaw(address=address, bus=bus) + self.queue = queue + + def compose_request(self, action): + # 0x80 = source, 0x04 = msg_type, 0x00 = length + request = [0x80] + actions[action] + [0x04, 0x00] + request.append(self.calculate_checksum(request)) + return request + + def calculate_checksum(self, request): + s = 0x82 + for i in request: + s += i + checksum = 256 - (s % 256) + if checksum == 256: + checksum = 0 + return checksum + + def execute_action(self, action): + request = self.compose_request(action) + result = None + for i in range(0, 20): + logger.debug(f"Executing action: {action}") + self.i.write_i2c_block_data(request) + time.sleep(0.21) + logger.debug("Queue size: {}".format(self.queue.qsize())) + if self.queue.qsize() > 0: + result = self.queue.get() + break + + if result is None: + logger.error("No valid result in 20 requests") + return result + + def close(self): + self.i.close() + + +class I2CSlave(): + def __init__(self, address, queue): + self.address = address + self.queue = queue + self.pi = pigpio.pi() + if not self.pi.connected: + logger.error("not pi.connected") + return + + def set_callback(self): + logger.debug("set_callback()") + self.event_callback = self.pi.event_callback(pigpio.EVENT_BSC, self.callback) + self.pi.bsc_i2c(self.address) + + def callback(self, id, tick): + logger.debug(f"callback({id}, {tick})") + s, b, d = self.pi.bsc_i2c(self.address) + result = None + if b: + logger.debug(f"Received {b} bytes! Status {s}") + result = [hex(c) for c in d] + logger.debug(f"Callback Response: {result}") + if self.is_checksum_valid(result) and self.is_length_valid(result): + self.queue.put(result) + else: + logger.debug(f"Received number of bytes was {b}") + + def is_checksum_valid(self, b): + s = 0x80 + for i in b[:-1]: + s += int(i, 0) + checksum = 256 - (s % 256) + if checksum == 256: + checksum = 0 + if checksum != int(b[-1], 0): + logger.debug(f"Checksum invalid (0x{checksum:02x} != {b[-1]})") + return False + return True + + def is_length_valid(self, b): + length_in_msg = int(b[4], 0) + actual_length = len(b) - 6 + if length_in_msg != actual_length: + logger.debug(f"Length invalid ({length_in_msg} != {actual_length})") + return False + return True + + def close(self): + self.event_callback.cancel() + self.pi.bsc_i2c(0) + self.pi.stop()