mirror of
https://github.com/pommi/python-itho-wpu.git
synced 2024-11-22 14:02:15 +01:00
refactor: put all i2c related stuff in itho_i2c.py
This commit is contained in:
parent
cb3cde86be
commit
7f4cdc8682
29
i2c_raw.py
29
i2c_raw.py
@ -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()
|
|
96
itho-wpu.py
96
itho-wpu.py
@ -1,9 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import i2c_raw
|
|
||||||
import logging
|
import logging
|
||||||
import pigpio
|
|
||||||
import queue
|
import queue
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
@ -12,6 +10,7 @@ import datetime
|
|||||||
import json
|
import json
|
||||||
import db
|
import db
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from itho_i2c import I2CMaster, I2CSlave
|
||||||
|
|
||||||
logger = logging.getLogger('stdout')
|
logger = logging.getLogger('stdout')
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
@ -73,99 +72,6 @@ def parse_args():
|
|||||||
return 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():
|
class IthoWPU():
|
||||||
def __init__(self, master_only, slave_only, slave_timeout, no_cache):
|
def __init__(self, master_only, slave_only, slave_timeout, no_cache):
|
||||||
self.master_only = master_only
|
self.master_only = master_only
|
||||||
|
133
itho_i2c.py
Normal file
133
itho_i2c.py
Normal file
@ -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()
|
Loading…
Reference in New Issue
Block a user