Example #1
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
Example #2
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.wait(self.iface.iface_num() | io.POLL_READ)
     write = loop.wait(self.iface.iface_num() | io.POLL_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)
Example #3
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.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
Example #4
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.wait(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
Example #5
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.wait(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
                while True:
                    await write
                    n = self.iface.write(self.data)
                    if n == len(self.data):
                        break
                self.ofs = _REP_CONT_DATA

        return nwritten
Example #6
0
 def wait(self, *tasks):
     '''
     Wait until one of the passed tasks finishes, and return the result,
     while servicing the wire context.  If a message comes until one of the
     tasks ends, `UnexpectedMessageError` is raised.
     '''
     return loop.wait(self.read(()), *tasks)
Example #7
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.wait(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, and prepare header
                await write
                self.iface.write(self.data)
                ustruct.pack_into(_REP_CONT, self.data, 0, _REP_MARKER_CONT,
                                  self.sid, self.seq)
                self.ofs = _REP_CONT_DATA
                self.seq += 1

        return nwritten
Example #8
0
async def write_message(iface: WireInterface, mtype: int,
                        mdata: bytes) -> None:
    write = loop.wait(iface.iface_num() | io.POLL_WRITE)

    # gather data from msg
    msize = len(mdata)

    # prepare the report buffer with header data
    report = bytearray(_REP_LEN)
    repofs = _REP_INIT_DATA
    ustruct.pack_into(_REP_INIT, report, 0, _REP_MARKER, _REP_MAGIC,
                      _REP_MAGIC, mtype, msize)

    nwritten = 0
    while True:
        # copy as much as possible to the report buffer
        nwritten += utils.memcpy(report, repofs, mdata, nwritten)

        # write the report
        while True:
            await write
            n = iface.write(report)
            if n == len(report):
                break

        # if we have more data to write, use continuation reports for it
        if nwritten < msize:
            repofs = _REP_CONT_DATA
        else:
            break
Example #9
0
 def __iter__(self):
     touch = loop.wait(io.TOUCH)
     result = None
     while result is None:
         self.render()
         event, *pos = yield touch
         result = self.touch(event, pos)
     return result
Example #10
0
 def __iter__(self):
     try:
         touch = loop.wait(io.TOUCH)
         while True:
             event, x, y = yield touch
             self.dispatch(event, x, y)
     except ui.Result as result:
         return result.value
Example #11
0
 def __iter__(self) -> loop.Task:  # type: ignore [awaitable-is-generator]
     try:
         touch = loop.wait(io.TOUCH)
         while True:
             event, x, y = yield touch
             self.dispatch(event, x, y)
     except ui.Result as result:
         return result.value
Example #12
0
 def handle_input(self) -> Generator:
     """Task that is waiting for the user input."""
     button = loop.wait(io.BUTTON)
     while True:
         event, button_num = yield button
         workflow.idle_timer.touch()
         self.dispatch(event, button_num, 0)
         self.dispatch(RENDER, 0, 0)
Example #13
0
 def handle_input(self) -> loop.Task:  # type: ignore
     """Task that is waiting for the user input."""
     touch = loop.wait(io.TOUCH)
     while True:
         event, x, y = yield touch
         self.dispatch(event, x, y)
         # We dispatch a render event right after the touch.  Quick and dirty
         # way to get the lowest input-to-render latency.
         self.dispatch(RENDER, 0, 0)
Example #14
0
 async def __iter__(self):
     self.edit(self.input.content)  # init button state
     while True:
         change = self.change_page()
         enter = self.enter_text()
         wait = loop.wait(change, enter)
         result = await wait
         if enter in wait.finished:
             return result
Example #15
0
async def read_cmd(iface: io.HID) -> Cmd:
    desc_init = frame_init()
    desc_cont = frame_cont()
    read = loop.wait(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)
Example #16
0
async def homescreen() -> None:
    # render homescreen in dimmed mode and fade back in
    ui.backlight_fade(ui.BACKLIGHT_DIM)
    display_homescreen()
    ui.backlight_fade(ui.BACKLIGHT_NORMAL)

    # loop forever, never return
    touch = loop.wait(io.TOUCH)
    while True:
        await touch
Example #17
0
async def paginate(render_page, page_count, page=0, *args):
    while True:
        changer = change_page(page, page_count)
        renderer = render_page(page, page_count, *args)
        waiter = loop.wait(changer, renderer)
        result = await waiter
        if changer in waiter.finished:
            page = result
        else:
            return result
Example #18
0
 def handle_input(self) -> loop.Task:  # type: ignore
     """Task that is waiting for the user input."""
     touch = loop.wait(io.TOUCH)
     while True:
         # Using `yield` instead of `await` to avoid allocations.
         event, x, y = yield touch
         workflow.idle_timer.touch()
         self.dispatch(event, x, y)
         # We dispatch a render event right after the touch.  Quick and dirty
         # way to get the lowest input-to-render latency.
         self.dispatch(RENDER, 0, 0)
Example #19
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
Example #20
0
async def click() -> Pos:
    touch = loop.wait(io.TOUCH)
    while True:
        ev, *pos = await touch
        if ev == io.TOUCH_START:
            break
    while True:
        ev, *pos = await touch
        if ev == io.TOUCH_END:
            break
    return pos  # type: ignore [Expression of type "list[Unknown]" cannot be assigned to return type "Pos"]
Example #21
0
async def click() -> tuple:
    touch = loop.wait(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
Example #22
0
async def click() -> Pos:
    touch = loop.wait(io.TOUCH)
    while True:
        ev, *pos = await touch
        if ev == io.TOUCH_START:
            break
    while True:
        ev, *pos = await touch
        if ev == io.TOUCH_END:
            break
    return pos  # type: ignore
Example #23
0
async def hold_to_confirm(ctx, content, code=None, *args, **kwargs):
    if code is None:
        code = ButtonRequestType.Other
    await ctx.call(ButtonRequest(code=code), wire_types.ButtonAck)

    dialog = HoldToConfirmDialog(content, 'Hold to confirm', *args, **kwargs)

    if __debug__:
        waiter = loop.wait(signal, dialog)
    else:
        waiter = dialog
    return await waiter == CONFIRMED
Example #24
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()
Example #25
0
 def handle_input_and_rendering(
         self) -> loop.Task:  # type: ignore [awaitable-is-generator]
     button = loop.wait(io.BUTTON)
     ui.display.clear()
     self.layout.paint()
     while True:
         # Using `yield` instead of `await` to avoid allocations.
         event, button_num = yield button
         workflow.idle_timer.touch()
         msg = None
         if event in (io.BUTTON_PRESSED, io.BUTTON_RELEASED):
             msg = self.layout.button_event(event, button_num)
         self.layout.paint()
         if msg is not None:
             raise ui.Result(msg)
Example #26
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()
Example #27
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.wait(self.iface.iface_num() | io.POLL_WRITE)
            while True:
                await write
                n = self.iface.write(self.data)
                if n == len(self.data):
                    break
Example #28
0
 def handle_input_and_rendering(
         self) -> loop.Task:  # type: ignore [awaitable-is-generator]
     touch = loop.wait(io.TOUCH)
     ui.display.clear()
     self.layout.paint()
     # self.layout.bounds()
     while True:
         # Using `yield` instead of `await` to avoid allocations.
         event, x, y = yield touch
         workflow.idle_timer.touch()
         msg = None
         if event in (io.TOUCH_START, io.TOUCH_MOVE, io.TOUCH_END):
             msg = self.layout.touch_event(event, x, y)
         self.layout.paint()
         # self.layout.bounds()
         if msg is not None:
             raise ui.Result(msg)
Example #29
0
async def read_message(iface: WireInterface,
                       buffer: utils.BufferType) -> Message:
    read = loop.wait(iface.iface_num() | io.POLL_READ)

    # wait for initial report
    report = await read
    if report[0] != _REP_MARKER:
        raise CodecError("Invalid magic")
    _, magic1, magic2, mtype, msize = ustruct.unpack(_REP_INIT, report)
    if magic1 != _REP_MAGIC or magic2 != _REP_MAGIC:
        raise CodecError("Invalid magic")

    read_and_throw_away = False

    with buffer_lock:
        if msize > len(buffer):
            # allocate a new buffer to fit the message
            try:
                mdata: utils.BufferType = bytearray(msize)
            except MemoryError:
                mdata = bytearray(_REP_LEN)
                read_and_throw_away = True
        else:
            # reuse a part of the supplied buffer
            mdata = memoryview(buffer)[:msize]

        # buffer the initial data
        nread = utils.memcpy(mdata, 0, report, _REP_INIT_DATA)

        while nread < msize:
            # wait for continuation report
            report = await read
            if report[0] != _REP_MARKER:
                raise CodecError("Invalid magic")

            # buffer the continuation data
            if read_and_throw_away:
                nread += len(report) - 1
            else:
                nread += utils.memcpy(mdata, nread, report, _REP_CONT_DATA)

    if read_and_throw_away:
        raise CodecError("Message too large")

    return Message(mtype, mdata)
    async def handle_input(self) -> None:
        touch = loop.wait(io.TOUCH)
        timeout = loop.sleep(1000)
        race_touch = loop.race(touch)
        race_timeout = loop.race(touch, timeout)

        while True:
            if self.pending_button is not None:
                race = race_timeout
            else:
                race = race_touch
            result = await race

            if touch in race.finished:
                event, x, y = result
                self.dispatch(event, x, y)
            else:
                self.on_timeout()