如何在Python中事先读取I2C消息的长度和头部
我有一个工具,用来与我用Python实现的I2C从设备进行交互。这个从设备不是一台PC,而是一个自定义设备(不过我无法获得编辑该设备的软件的权限)。目前,我被迫在每条I2C消息中读取任意数量的字节。我需要能够最多读取4000字节,因此如果对所有消息都设为4000,就会造成过大的延迟。
我需要能够在读取完整消息之前读取I2C头中的长度字节,以便确定要读取多少字节。问题在于,一旦读取,I2C邮箱就会被清空,因此我不能简单地把读取代码写成两段——一次用于头部,一次用于完整的消息及其载荷。
下面是我的I2C读取函数,在需要时会被调用:
def I2cRead(addr, ReadLength,split=0):
MsgSplit = int(split)
readLength = int(ReadLength)
readSplit = []
if split == 0:
## only need 1 block
readSplit.append(readLength)
else:
## number of blocks
blocks = math.floor(readLength / MsgSplit)
readSplit += [MsgSplit] * blocks
## Add remainder if not zero
if (readLength % MsgSplit) != 0:
readSplit.append(readLength % MsgSplit)
#print(readSplit)
i2c_msgs = []
msg_buffers = []
# Create I2C message
data = [0x01]
msg = i2c_msg()
msg.addr = addr
msg.flags = I2C_M_WR
msg.len = 1
data_bytes = (ctypes.c_ubyte * 1)(*data)
msg.buf = ctypes.cast(data_bytes, ctypes.c_void_p)
i2c_msgs.append(msg)
## Print out length of msgs
for i,element in enumerate(readSplit):
# Create I2C message
msg = i2c_msg()
msg.addr = addr
msg.flags = I2C_M_RD
msg.len = element ## length of read msg
## Create buffer in memory
data_bytes = (ctypes.c_ubyte * element)()
msg_buffers.append(data_bytes)
## point to buffer
msg.buf = ctypes.cast(data_bytes, ctypes.c_void_p)
## append to i2c msg
i2c_msgs.append(msg)
MsgArrayType = i2c_msg * len(i2c_msgs)
msgs_array = MsgArrayType(*i2c_msgs)
# Wrap in ioctl_data
ioctl_data = i2c_rdwr_ioctl_data()
ioctl_data.msgs = ctypes.cast(msgs_array,ctypes.POINTER(i2c_msg))
ioctl_data.nmsgs = len(i2c_msgs)
# Open I2C device and send
with open("/dev/i2c-1", "rb+", buffering=0) as f:
fcntl.ioctl(f, I2C_RDWR, ioctl_data)
CollectedBuffer = []
for i,element in enumerate(msg_buffers):
## loop through msgs
buffer = []
for i in range(len(element)):
buffer.append(element[i])
#print(buffer)
CollectedBuffer.append(buffer)
return CollectedBuffer[0]
解决方案
要点是:使用现有的Python I2C库,例如 smbus2,并查阅设备的文档,了解在单次I2C读取操作允许的32字节之外,如何精确地读取一段数据。
问题在于,一旦I2C邮箱被读取就会被清空,因此我不能简单地把我的读取代码写成两段——一次用于头部,一次用于完整的消息和载荷。
这听起来有点蹊跷。如果你是这么描述,设备要么在读取之前就删除了数据——这显然不是情况——要么它有某种方式来判断你已经处理了哪些数据、哪些没处理——这也是不可能的,因为它所做的只是把数据发送到线上,并没有办法知道接下来会发生什么。
根据 smbus2.SMBus.read_block_data 文档,I2C协议一次读取一个设备寄存器最多只能达到32字节。因此,设备中必然存在某种机制,允许你在不丢弃你将要读取的数据的情况下读取更多字节。
我的猜测是,你可能先读取前面的(最多)32字节,提取长度字段,然后你就知道还需要执行多少次读取。也许你还需要在设备中设置某个其他的“锁定”标志,以表示你正在读取多块数据的过程。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。