Пример #1
0
 async def listen(self):
     '''
     Listen for open/close requests on configured interface.  After open
     request, session is started and a new task is scheduled to handle it.
     After close request, the handling task is closed and session terminated.
     Both requests receive responses confirming the operation.
     '''
     read = loop.select(self.iface.iface_num() | loop.READ)
     write = loop.select(self.iface.iface_num() | loop.WRITE)
     while True:
         report = await read
         repmarker, repsid = ustruct.unpack(_REP, report)
         # because tasks paused on I/O have a priority over time-scheduled
         # tasks, we need to `yield` explicitly before sending a response to
         # open/close request.  Otherwise the handler would have no chance to
         # run and schedule communication.
         if repmarker == _REP_MARKER_OPEN:
             newsid = self.newsid()
             self.open(newsid)
             yield
             await write
             self.writeopen(newsid)
         elif repmarker == _REP_MARKER_CLOSE:
             self.close(repsid)
             yield
             await write
             self.writeclose(repsid)
Пример #2
0
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.select(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
Пример #3
0
    async def areadinto(self, buf):
        '''
        Read exactly `len(buf)` bytes into `buf`, waiting for additional
        reports, if needed.  Raises `EOFError` if end-of-message is encountered
        before the full read can be completed.
        '''
        if self.size < len(buf):
            raise EOFError

        read = loop.select(self.iface.iface_num() | io.POLL_READ)
        nread = 0
        while nread < len(buf):
            if self.ofs == len(self.data):
                # we are at the end of received data
                # wait for continuation report
                while True:
                    report = await read
                    marker = report[0]
                    if marker == _REP_MARKER:
                        break
                self.data = report[_REP_CONT_DATA:_REP_CONT_DATA + self.size]
                self.ofs = 0

            # copy as much as possible to target buffer
            nbytes = utils.memcpy(buf, nread, self.data, self.ofs, len(buf))
            nread += nbytes
            self.ofs += nbytes
            self.size -= nbytes

        return nread
Пример #4
0
    async def awrite(self, buf):
        '''
        Encode and write every byte from `buf`.  Does not need to be called in
        case message has zero length.  Raises `EOFError` if the length of `buf`
        exceeds the remaining message length.
        '''
        if self.size < len(buf):
            raise EOFError

        write = loop.select(self.iface.iface_num() | io.POLL_WRITE)
        nwritten = 0
        while nwritten < len(buf):
            # copy as much as possible to report buffer
            nbytes = utils.memcpy(self.data, self.ofs, buf, nwritten, len(buf))
            nwritten += nbytes
            self.ofs += nbytes
            self.size -= nbytes

            if self.ofs == _REP_LEN:
                # we are at the end of the report, flush it
                await write
                self.iface.write(self.data)
                self.ofs = _REP_CONT_DATA

        return nwritten
Пример #5
0
    async def __iter__(self):
        timeout = loop.sleep(1000 * 1000 * 1)
        touch = loop.select(io.TOUCH)
        wait_timeout = loop.wait(touch, timeout)
        wait_touch = loop.wait(touch)
        content = None

        self.back.taint()
        self.input.taint()

        while content is None:
            self.render()
            if self.pbutton is not None:
                wait = wait_timeout
            else:
                wait = wait_touch
            result = await wait
            if touch in wait.finished:
                event, *pos = result
                content = self.touch(event, pos)
            else:
                if self.input.word:
                    # just reset the pending state
                    self.edit(self.input.content)
                else:
                    # invalid character, backspace it
                    self.edit(self.input.content[:-1])
        return content
Пример #6
0
 def __iter__(self):
     touch = loop.select(io.TOUCH)
     result = None
     while result is None:
         self.render()
         event, *pos = yield touch
         result = self.touch(event, pos)
     return result
Пример #7
0
def _dispatch_reports():
    read = loop.select(_interface)
    while True:
        report = yield read
        # if __debug__:
        #     log.debug(__name__, 'read report %s', ubinascii.hexlify(report))
        sessions.dispatch(memoryview(report), _session_open, _session_close,
                          _session_unknown)
Пример #8
0
async def read_cmd(iface: io.HID) -> Cmd:
    desc_init = frame_init()
    desc_cont = frame_cont()
    read = loop.select(iface.iface_num() | io.POLL_READ)

    buf = await read

    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
        if __debug__:
            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 read

        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
            if __debug__:
                log.warning(__name__, '_ERR_CHANNEL_BUSY')
            await 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
            if __debug__:
                log.warning(__name__, '_ERR_INVALID_SEQ')
            await 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)
Пример #9
0
async def click() -> tuple:
    touch = loop.select(io.TOUCH)
    while True:
        ev, *pos = yield touch
        if ev == io.TOUCH_START:
            break
    while True:
        ev, *pos = yield touch
        if ev == io.TOUCH_END:
            break
    return pos
Пример #10
0
 def __iter__(self):
     timeout = loop.sleep(1000 * 1000 * 1)
     touch = loop.select(io.TOUCH)
     wait = loop.wait(touch, timeout)
     while True:
         self.render()
         result = yield wait
         if touch in wait.finished:
             event, *pos = result
             self.touch(event, pos)
         elif self.zoom_buttons:
             self.zoom_buttons = None
             for btn in self.key_buttons:
                 btn.taint()
Пример #11
0
    async def aclose(self):
        '''Flush and close the message transmission.'''
        if self.ofs != _REP_CONT_DATA:
            # we didn't write anything or last write() wasn't report-aligned,
            # pad the final report and flush it
            while self.ofs < _REP_LEN:
                self.data[self.ofs] = 0x00
                self.ofs += 1

            write = loop.select(self.iface.iface_num() | io.POLL_WRITE)
            while True:
                await write
                n = self.iface.write(self.data)
                if n == len(self.data):
                    break
Пример #12
0
 def __iter__(self):
     timeout = loop.sleep(1000 * 1000 * 1)
     touch = loop.select(io.TOUCH)
     wait = loop.wait(touch, timeout)
     while True:
         self.render()
         result = yield wait
         if touch in wait.finished:
             event, *pos = result
             self.touch(event, pos)
         else:
             self.pending_button = None
             self.pending_index = 0
             self._update_suggestion()
             self._update_buttons()
Пример #13
0
    async def aopen(self):
        '''
        Begin the message transmission by waiting for initial V2 message report
        on this session. `self.type` and `self.size` are initialized and
        available after `aopen()` returns.
        '''
        read = loop.select(self.iface.iface_num() | loop.READ)
        while True:
            # wait for initial report
            report = await read
            marker, sid, mtype, msize = ustruct.unpack(_REP_INIT, report)
            if sid == self.sid and marker == _REP_MARKER_INIT:
                break

        # load received message header
        self.type = mtype
        self.size = msize
        self.data = report[_REP_INIT_DATA:_REP_INIT_DATA + msize]
        self.ofs = 0
        self.seq = 0
Пример #14
0
 async def enter_text(self):
     timeout = loop.sleep(1000 * 1000 * 1)
     touch = loop.select(io.TOUCH)
     wait_timeout = loop.wait(touch, timeout)
     wait_touch = loop.wait(touch)
     content = None
     while content is None:
         self.render()
         if self.pbutton is not None:
             wait = wait_timeout
         else:
             wait = wait_touch
         result = await wait
         if touch in wait.finished:
             event, *pos = result
             content = self.touch(event, pos)
         else:
             # disable the pending buttons
             self.edit(self.input.content)
     return content
Пример #15
0
    async def aopen(self):
        '''
        Begin the message transmission by waiting for initial V2 message report
        on this session.  `self.type` and `self.size` are initialized and
        available after `aopen()` returns.
        '''
        read = loop.select(self.iface.iface_num() | io.POLL_READ)
        while True:
            # wait for initial report
            report = await read
            marker = report[0]
            if marker == _REP_MARKER:
                _, m1, m2, mtype, msize = ustruct.unpack(_REP_INIT, report)
                if m1 != _REP_MAGIC or m2 != _REP_MAGIC:
                    raise ValueError
                break

        # load received message header
        self.type = mtype
        self.size = msize
        self.data = report[_REP_INIT_DATA:_REP_INIT_DATA + msize]
        self.ofs = 0
Пример #16
0
def test_reader():
    rep_len = 64
    interface_num = 0xdeadbeef
    message_type = 0x4321
    message_len = 250
    interface = MockHID(interface_num)
    reader = codec_v1.Reader(interface)

    message = bytearray(range(message_len))
    report_header = bytearray(unhexlify('3f23234321000000fa'))

    # open, expected one read
    first_report = report_header + message[:rep_len - len(report_header)]
    assert_async(reader.aopen(), [
        (None, select(io.POLL_READ | interface_num)),
        (first_report, StopIteration()),
    ])
    assert_eq(reader.type, message_type)
    assert_eq(reader.size, message_len)

    # empty read
    empty_buffer = bytearray()
    assert_async(reader.areadinto(empty_buffer), [
        (None, StopIteration()),
    ])
    assert_eq(len(empty_buffer), 0)
    assert_eq(reader.size, message_len)

    # short read, expected no read
    short_buffer = bytearray(32)
    assert_async(reader.areadinto(short_buffer), [
        (None, StopIteration()),
    ])
    assert_eq(len(short_buffer), 32)
    assert_eq(short_buffer, message[:len(short_buffer)])
    assert_eq(reader.size, message_len - len(short_buffer))

    # aligned read, expected no read
    aligned_buffer = bytearray(rep_len - len(report_header) -
                               len(short_buffer))
    assert_async(reader.areadinto(aligned_buffer), [
        (None, StopIteration()),
    ])
    assert_eq(aligned_buffer,
              message[len(short_buffer):][:len(aligned_buffer)])
    assert_eq(reader.size,
              message_len - len(short_buffer) - len(aligned_buffer))

    # one byte read, expected one read
    next_report_header = bytearray(unhexlify('3f'))
    next_report = next_report_header + message[
        rep_len - len(report_header):][:rep_len - len(next_report_header)]
    onebyte_buffer = bytearray(1)
    assert_async(reader.areadinto(onebyte_buffer), [
        (None, select(io.POLL_READ | interface_num)),
        (next_report, StopIteration()),
    ])
    assert_eq(
        onebyte_buffer, message[len(short_buffer):][len(aligned_buffer):]
        [:len(onebyte_buffer)])
    assert_eq(
        reader.size, message_len - len(short_buffer) - len(aligned_buffer) -
        len(onebyte_buffer))

    # too long read, raises eof
    assert_async(reader.areadinto(bytearray(reader.size + 1)), [
        (None, EOFError()),
    ])

    # long read, expect multiple reads
    start_size = reader.size
    long_buffer = bytearray(start_size)
    report_payload = message[rep_len - len(report_header) + rep_len -
                             len(next_report_header):]
    report_payload_head = report_payload[:rep_len - len(next_report_header) -
                                         len(onebyte_buffer)]
    report_payload_rest = report_payload[len(report_payload_head):]
    report_payload_rest = list(
        chunks(report_payload_rest, rep_len - len(next_report_header)))
    report_payloads = [report_payload_head] + report_payload_rest
    next_reports = [next_report_header + r for r in report_payloads]
    expected_syscalls = []
    for i, _ in enumerate(next_reports):
        prev_report = next_reports[i - 1] if i > 0 else None
        expected_syscalls.append(
            (prev_report, select(io.POLL_READ | interface_num)))
    expected_syscalls.append((next_reports[-1], StopIteration()))
    assert_async(reader.areadinto(long_buffer), expected_syscalls)
    assert_eq(long_buffer, message[-start_size:])
    assert_eq(reader.size, 0)

    # one byte read, raises eof
    assert_async(reader.areadinto(onebyte_buffer), [
        (None, EOFError()),
    ])
Пример #17
0
def test_writer():
    rep_len = 64
    interface_num = 0xdeadbeef
    message_type = 0x87654321
    message_len = 1024
    interface = MockHID(interface_num)
    writer = codec_v1.Writer(interface)
    writer.setheader(message_type, message_len)

    # init header corresponding to the data above
    report_header = bytearray(unhexlify('3f2323432100000400'))

    assert_eq(writer.data,
              report_header + bytearray(rep_len - len(report_header)))

    # empty write
    start_size = writer.size
    assert_async(writer.awrite(bytearray()), [
        (None, StopIteration()),
    ])
    assert_eq(writer.data,
              report_header + bytearray(rep_len - len(report_header)))
    assert_eq(writer.size, start_size)

    # short write, expected no report
    start_size = writer.size
    short_payload = bytearray(range(4))
    assert_async(writer.awrite(short_payload), [
        (None, StopIteration()),
    ])
    assert_eq(writer.size, start_size - len(short_payload))
    assert_eq(
        writer.data, report_header + short_payload +
        bytearray(rep_len - len(report_header) - len(short_payload)))

    # aligned write, expected one report
    start_size = writer.size
    aligned_payload = bytearray(
        range(rep_len - len(report_header) - len(short_payload)))
    assert_async(writer.awrite(aligned_payload), [
        (None, select(io.POLL_WRITE | interface_num)),
        (None, StopIteration()),
    ])
    assert_eq(interface.data, [
        report_header + short_payload + aligned_payload +
        bytearray(rep_len - len(report_header) - len(short_payload) -
                  len(aligned_payload)),
    ])
    assert_eq(writer.size, start_size - len(aligned_payload))
    interface.data.clear()

    # short write, expected no report, but data starts with correct seq and cont marker
    report_header = bytearray(unhexlify('3f'))
    start_size = writer.size
    assert_async(writer.awrite(short_payload), [
        (None, StopIteration()),
    ])
    assert_eq(writer.size, start_size - len(short_payload))
    assert_eq(writer.data[:len(report_header) + len(short_payload)],
              report_header + short_payload)

    # long write, expected multiple reports
    start_size = writer.size
    long_payload_head = bytearray(
        range(rep_len - len(report_header) - len(short_payload)))
    long_payload_rest = bytearray(range(start_size - len(long_payload_head)))
    long_payload = long_payload_head + long_payload_rest
    expected_payloads = [short_payload + long_payload_head] + list(
        chunks(long_payload_rest, rep_len - len(report_header)))
    expected_reports = [report_header + r for r in expected_payloads]
    expected_reports[-1] += bytearray(
        bytes(1) * (rep_len - len(expected_reports[-1])))
    # test write
    expected_write_reports = expected_reports[:-1]
    assert_async(
        writer.awrite(long_payload),
        len(expected_write_reports) *
        [(None, select(io.POLL_WRITE | interface_num))] +
        [(None, StopIteration())])
    assert_eq(interface.data, expected_write_reports)
    assert_eq(writer.size, start_size - len(long_payload))
    interface.data.clear()
    # test write raises eof
    assert_async(writer.awrite(bytearray(1)), [(None, EOFError())])
    assert_eq(interface.data, [])
    # test close
    expected_close_reports = expected_reports[-1:]
    assert_async(
        writer.aclose(),
        len(expected_close_reports) *
        [(None, select(io.POLL_WRITE | interface_num))] +
        [(None, StopIteration())])
    assert_eq(interface.data, expected_close_reports)
    assert_eq(writer.size, 0)