async def read_cmd(iface: io.HID) -> Cmd: desc_init = frame_init() desc_cont = frame_cont() buf, = await loop.select(iface.iface_num()) # log.debug(__name__, 'read init %s', buf) ifrm = overlay_struct(buf, desc_init) bcnt = ifrm.bcnt data = ifrm.data datalen = len(data) seq = 0 if ifrm.cmd & _TYPE_MASK == _TYPE_CONT: # unexpected cont packet, abort current msg log.warning(__name__, '_TYPE_CONT') return None if datalen < bcnt: databuf = bytearray(bcnt) utils.memcpy(databuf, 0, data, 0, bcnt) data = databuf else: data = data[:bcnt] while datalen < bcnt: buf, = await loop.select(iface.iface_num()) # log.debug(__name__, 'read cont %s', buf) cfrm = overlay_struct(buf, desc_cont) if cfrm.seq == _CMD_INIT: # _CMD_INIT frame, cancels current channel ifrm = overlay_struct(buf, desc_init) data = ifrm.data[:ifrm.bcnt] break if cfrm.cid != ifrm.cid: # cont frame for a different channel, reply with BUSY and skip log.warning(__name__, '_ERR_CHANNEL_BUSY') send_cmd(cmd_error(cfrm.cid, _ERR_CHANNEL_BUSY), iface) continue if cfrm.seq != seq: # cont frame for this channel, but incorrect seq number, abort # current msg log.warning(__name__, '_ERR_INVALID_SEQ') send_cmd(cmd_error(cfrm.cid, _ERR_INVALID_SEQ), iface) return None datalen += utils.memcpy(data, datalen, cfrm.data, 0, bcnt - datalen) seq += 1 return Cmd(ifrm.cid, ifrm.cmd, data)
async def send_cmd(cmd: Cmd, iface: io.HID) -> None: init_desc = frame_init() cont_desc = frame_cont() offset = 0 seq = 0 datalen = len(cmd.data) buf, frm = make_struct(init_desc) frm.cid = cmd.cid frm.cmd = cmd.cmd frm.bcnt = datalen offset += utils.memcpy(frm.data, 0, cmd.data, offset, datalen) iface.write(buf) if offset < datalen: frm = overlay_struct(buf, cont_desc) write = loop.wait(iface.iface_num() | io.POLL_WRITE) while offset < datalen: frm.seq = seq offset += utils.memcpy(frm.data, 0, cmd.data, offset, datalen) while True: await write if iface.write(buf) > 0: break seq += 1