162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci.. |u8| replace:: :c:type:`u8 <u8>`
462306a36Sopenharmony_ci.. |u16| replace:: :c:type:`u16 <u16>`
562306a36Sopenharmony_ci.. |TYPE| replace:: ``TYPE``
662306a36Sopenharmony_ci.. |LEN| replace:: ``LEN``
762306a36Sopenharmony_ci.. |SEQ| replace:: ``SEQ``
862306a36Sopenharmony_ci.. |SYN| replace:: ``SYN``
962306a36Sopenharmony_ci.. |NAK| replace:: ``NAK``
1062306a36Sopenharmony_ci.. |ACK| replace:: ``ACK``
1162306a36Sopenharmony_ci.. |DATA| replace:: ``DATA``
1262306a36Sopenharmony_ci.. |DATA_SEQ| replace:: ``DATA_SEQ``
1362306a36Sopenharmony_ci.. |DATA_NSQ| replace:: ``DATA_NSQ``
1462306a36Sopenharmony_ci.. |TC| replace:: ``TC``
1562306a36Sopenharmony_ci.. |TID| replace:: ``TID``
1662306a36Sopenharmony_ci.. |SID| replace:: ``SID``
1762306a36Sopenharmony_ci.. |IID| replace:: ``IID``
1862306a36Sopenharmony_ci.. |RQID| replace:: ``RQID``
1962306a36Sopenharmony_ci.. |CID| replace:: ``CID``
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci===========================
2262306a36Sopenharmony_ciSurface Serial Hub Protocol
2362306a36Sopenharmony_ci===========================
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciThe Surface Serial Hub (SSH) is the central communication interface for the
2662306a36Sopenharmony_ciembedded Surface Aggregator Module controller (SAM or EC), found on newer
2762306a36Sopenharmony_ciSurface generations. We will refer to this protocol and interface as
2862306a36Sopenharmony_ciSAM-over-SSH, as opposed to SAM-over-HID for the older generations.
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciOn Surface devices with SAM-over-SSH, SAM is connected to the host via UART
3162306a36Sopenharmony_ciand defined in ACPI as device with ID ``MSHW0084``. On these devices,
3262306a36Sopenharmony_cisignificant functionality is provided via SAM, including access to battery
3362306a36Sopenharmony_ciand power information and events, thermal read-outs and events, and many
3462306a36Sopenharmony_cimore. For Surface Laptops, keyboard input is handled via HID directed
3562306a36Sopenharmony_cithrough SAM, on the Surface Laptop 3 and Surface Book 3 this also includes
3662306a36Sopenharmony_citouchpad input.
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ciNote that the standard disclaimer for this subsystem also applies to this
3962306a36Sopenharmony_cidocument: All of this has been reverse-engineered and may thus be erroneous
4062306a36Sopenharmony_ciand/or incomplete.
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciAll CRCs used in the following are two-byte ``crc_ccitt_false(0xffff, ...)``.
4362306a36Sopenharmony_ciAll multi-byte values are little-endian, there is no implicit padding between
4462306a36Sopenharmony_civalues.
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ciSSH Packet Protocol: Definitions
4862306a36Sopenharmony_ci================================
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ciThe fundamental communication unit of the SSH protocol is a frame
5162306a36Sopenharmony_ci(:c:type:`struct ssh_frame <ssh_frame>`). A frame consists of the following
5262306a36Sopenharmony_cifields, packed together and in order:
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci.. flat-table:: SSH Frame
5562306a36Sopenharmony_ci   :widths: 1 1 4
5662306a36Sopenharmony_ci   :header-rows: 1
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci   * - Field
5962306a36Sopenharmony_ci     - Type
6062306a36Sopenharmony_ci     - Description
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci   * - |TYPE|
6362306a36Sopenharmony_ci     - |u8|
6462306a36Sopenharmony_ci     - Type identifier of the frame.
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci   * - |LEN|
6762306a36Sopenharmony_ci     - |u16|
6862306a36Sopenharmony_ci     - Length of the payload associated with the frame.
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci   * - |SEQ|
7162306a36Sopenharmony_ci     - |u8|
7262306a36Sopenharmony_ci     - Sequence ID (see explanation below).
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciEach frame structure is followed by a CRC over this structure. The CRC over
7562306a36Sopenharmony_cithe frame structure (|TYPE|, |LEN|, and |SEQ| fields) is placed directly
7662306a36Sopenharmony_ciafter the frame structure and before the payload. The payload is followed by
7762306a36Sopenharmony_ciits own CRC (over all payload bytes). If the payload is not present (i.e.
7862306a36Sopenharmony_cithe frame has ``LEN=0``), the CRC of the payload is still present and will
7962306a36Sopenharmony_cievaluate to ``0xffff``. The |LEN| field does not include any of the CRCs, it
8062306a36Sopenharmony_ciequals the number of bytes between the CRC of the frame and the CRC of the
8162306a36Sopenharmony_cipayload.
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciAdditionally, the following fixed two-byte sequences are used:
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci.. flat-table:: SSH Byte Sequences
8662306a36Sopenharmony_ci   :widths: 1 1 4
8762306a36Sopenharmony_ci   :header-rows: 1
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci   * - Name
9062306a36Sopenharmony_ci     - Value
9162306a36Sopenharmony_ci     - Description
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci   * - |SYN|
9462306a36Sopenharmony_ci     - ``[0xAA, 0x55]``
9562306a36Sopenharmony_ci     - Synchronization bytes.
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciA message consists of |SYN|, followed by the frame (|TYPE|, |LEN|, |SEQ| and
9862306a36Sopenharmony_ciCRC) and, if specified in the frame (i.e. ``LEN > 0``), payload bytes,
9962306a36Sopenharmony_cifollowed finally, regardless if the payload is present, the payload CRC. The
10062306a36Sopenharmony_cimessages corresponding to an exchange are, in part, identified by having the
10162306a36Sopenharmony_cisame sequence ID (|SEQ|), stored inside the frame (more on this in the next
10262306a36Sopenharmony_cisection). The sequence ID is a wrapping counter.
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciA frame can have the following types
10562306a36Sopenharmony_ci(:c:type:`enum ssh_frame_type <ssh_frame_type>`):
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci.. flat-table:: SSH Frame Types
10862306a36Sopenharmony_ci   :widths: 1 1 4
10962306a36Sopenharmony_ci   :header-rows: 1
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci   * - Name
11262306a36Sopenharmony_ci     - Value
11362306a36Sopenharmony_ci     - Short Description
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci   * - |NAK|
11662306a36Sopenharmony_ci     - ``0x04``
11762306a36Sopenharmony_ci     - Sent on error in previously received message.
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci   * - |ACK|
12062306a36Sopenharmony_ci     - ``0x40``
12162306a36Sopenharmony_ci     - Sent to acknowledge receival of |DATA| frame.
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci   * - |DATA_SEQ|
12462306a36Sopenharmony_ci     - ``0x80``
12562306a36Sopenharmony_ci     - Sent to transfer data. Sequenced.
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci   * - |DATA_NSQ|
12862306a36Sopenharmony_ci     - ``0x00``
12962306a36Sopenharmony_ci     - Same as |DATA_SEQ|, but does not need to be ACKed.
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciBoth |NAK|- and |ACK|-type frames are used to control flow of messages and
13262306a36Sopenharmony_cithus do not carry a payload. |DATA_SEQ|- and |DATA_NSQ|-type frames on the
13362306a36Sopenharmony_ciother hand must carry a payload. The flow sequence and interaction of
13462306a36Sopenharmony_cidifferent frame types will be described in more depth in the next section.
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ciSSH Packet Protocol: Flow Sequence
13862306a36Sopenharmony_ci==================================
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciEach exchange begins with |SYN|, followed by a |DATA_SEQ|- or
14162306a36Sopenharmony_ci|DATA_NSQ|-type frame, followed by its CRC, payload, and payload CRC. In
14262306a36Sopenharmony_cicase of a |DATA_NSQ|-type frame, the exchange is then finished. In case of a
14362306a36Sopenharmony_ci|DATA_SEQ|-type frame, the receiving party has to acknowledge receival of
14462306a36Sopenharmony_cithe frame by responding with a message containing an |ACK|-type frame with
14562306a36Sopenharmony_cithe same sequence ID of the |DATA| frame. In other words, the sequence ID of
14662306a36Sopenharmony_cithe |ACK| frame specifies the |DATA| frame to be acknowledged. In case of an
14762306a36Sopenharmony_cierror, e.g. an invalid CRC, the receiving party responds with a message
14862306a36Sopenharmony_cicontaining an |NAK|-type frame. As the sequence ID of the previous data
14962306a36Sopenharmony_ciframe, for which an error is indicated via the |NAK| frame, cannot be relied
15062306a36Sopenharmony_ciupon, the sequence ID of the |NAK| frame should not be used and is set to
15162306a36Sopenharmony_cizero. After receival of an |NAK| frame, the sending party should re-send all
15262306a36Sopenharmony_cioutstanding (non-ACKed) messages.
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciSequence IDs are not synchronized between the two parties, meaning that they
15562306a36Sopenharmony_ciare managed independently for each party. Identifying the messages
15662306a36Sopenharmony_cicorresponding to a single exchange thus relies on the sequence ID as well as
15762306a36Sopenharmony_cithe type of the message, and the context. Specifically, the sequence ID is
15862306a36Sopenharmony_ciused to associate an ``ACK`` with its ``DATA_SEQ``-type frame, but not
15962306a36Sopenharmony_ci``DATA_SEQ``- or ``DATA_NSQ``-type frames with other ``DATA``- type frames.
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ciAn example exchange might look like this:
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci::
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci    tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) -----------------------------
16662306a36Sopenharmony_ci    rx: ------------------------------------- SYN FRAME(A) CRC(F) CRC(P) --
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ciwhere both frames have the same sequence ID (``SEQ``). Here, ``FRAME(D)``
16962306a36Sopenharmony_ciindicates a |DATA_SEQ|-type frame, ``FRAME(A)`` an ``ACK``-type frame,
17062306a36Sopenharmony_ci``CRC(F)`` the CRC over the previous frame, ``CRC(P)`` the CRC over the
17162306a36Sopenharmony_ciprevious payload. In case of an error, the exchange would look like this:
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci::
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci    tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) -----------------------------
17662306a36Sopenharmony_ci    rx: ------------------------------------- SYN FRAME(N) CRC(F) CRC(P) --
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ciupon which the sender should re-send the message. ``FRAME(N)`` indicates an
17962306a36Sopenharmony_ci|NAK|-type frame. Note that the sequence ID of the |NAK|-type frame is fixed
18062306a36Sopenharmony_cito zero. For |DATA_NSQ|-type frames, both exchanges are the same:
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci::
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci    tx: -- SYN FRAME(DATA_NSQ) CRC(F) PAYLOAD CRC(P) ----------------------
18562306a36Sopenharmony_ci    rx: -------------------------------------------------------------------
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciHere, an error can be detected, but not corrected or indicated to the
18862306a36Sopenharmony_cisending party. These exchanges are symmetric, i.e. switching ``rx`` and
18962306a36Sopenharmony_ci``tx`` results again in a valid exchange. Currently, no longer exchanges are
19062306a36Sopenharmony_ciknown.
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ciCommands: Requests, Responses, and Events
19462306a36Sopenharmony_ci=========================================
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ciCommands are sent as payload inside a data frame. Currently, this is the
19762306a36Sopenharmony_cionly known payload type of |DATA| frames, with a payload-type value of
19862306a36Sopenharmony_ci``0x80`` (:c:type:`SSH_PLD_TYPE_CMD <ssh_payload_type>`).
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ciThe command-type payload (:c:type:`struct ssh_command <ssh_command>`)
20162306a36Sopenharmony_ciconsists of an eight-byte command structure, followed by optional and
20262306a36Sopenharmony_civariable length command data. The length of this optional data is derived
20362306a36Sopenharmony_cifrom the frame payload length given in the corresponding frame, i.e. it is
20462306a36Sopenharmony_ci``frame.len - sizeof(struct ssh_command)``. The command struct contains the
20562306a36Sopenharmony_cifollowing fields, packed together and in order:
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci.. flat-table:: SSH Command
20862306a36Sopenharmony_ci   :widths: 1 1 4
20962306a36Sopenharmony_ci   :header-rows: 1
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci   * - Field
21262306a36Sopenharmony_ci     - Type
21362306a36Sopenharmony_ci     - Description
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci   * - |TYPE|
21662306a36Sopenharmony_ci     - |u8|
21762306a36Sopenharmony_ci     - Type of the payload. For commands always ``0x80``.
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci   * - |TC|
22062306a36Sopenharmony_ci     - |u8|
22162306a36Sopenharmony_ci     - Target category.
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci   * - |TID|
22462306a36Sopenharmony_ci     - |u8|
22562306a36Sopenharmony_ci     - Target ID for commands/messages.
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci   * - |SID|
22862306a36Sopenharmony_ci     - |u8|
22962306a36Sopenharmony_ci     - Source ID for commands/messages.
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci   * - |IID|
23262306a36Sopenharmony_ci     - |u8|
23362306a36Sopenharmony_ci     - Instance ID.
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci   * - |RQID|
23662306a36Sopenharmony_ci     - |u16|
23762306a36Sopenharmony_ci     - Request ID.
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci   * - |CID|
24062306a36Sopenharmony_ci     - |u8|
24162306a36Sopenharmony_ci     - Command ID.
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ciThe command struct and data, in general, does not contain any failure
24462306a36Sopenharmony_cidetection mechanism (e.g. CRCs), this is solely done on the frame level.
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ciCommand-type payloads are used by the host to send commands and requests to
24762306a36Sopenharmony_cithe EC as well as by the EC to send responses and events back to the host.
24862306a36Sopenharmony_ciWe differentiate between requests (sent by the host), responses (sent by the
24962306a36Sopenharmony_ciEC in response to a request), and events (sent by the EC without a preceding
25062306a36Sopenharmony_cirequest).
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ciCommands and events are uniquely identified by their target category
25362306a36Sopenharmony_ci(``TC``) and command ID (``CID``). The target category specifies a general
25462306a36Sopenharmony_cicategory for the command (e.g. system in general, vs. battery and AC, vs.
25562306a36Sopenharmony_citemperature, and so on), while the command ID specifies the command inside
25662306a36Sopenharmony_cithat category. Only the combination of |TC| + |CID| is unique. Additionally,
25762306a36Sopenharmony_cicommands have an instance ID (``IID``), which is used to differentiate
25862306a36Sopenharmony_cibetween different sub-devices. For example ``TC=3`` ``CID=1`` is a
25962306a36Sopenharmony_cirequest to get the temperature on a thermal sensor, where |IID| specifies
26062306a36Sopenharmony_cithe respective sensor. If the instance ID is not used, it should be set to
26162306a36Sopenharmony_cizero. If instance IDs are used, they, in general, start with a value of one,
26262306a36Sopenharmony_ciwhereas zero may be used for instance independent queries, if applicable. A
26362306a36Sopenharmony_ciresponse to a request should have the same target category, command ID, and
26462306a36Sopenharmony_ciinstance ID as the corresponding request.
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ciResponses are matched to their corresponding request via the request ID
26762306a36Sopenharmony_ci(``RQID``) field. This is a 16 bit wrapping counter similar to the sequence
26862306a36Sopenharmony_ciID on the frames. Note that the sequence ID of the frames for a
26962306a36Sopenharmony_cirequest-response pair does not match. Only the request ID has to match.
27062306a36Sopenharmony_ciFrame-protocol wise these are two separate exchanges, and may even be
27162306a36Sopenharmony_ciseparated, e.g. by an event being sent after the request but before the
27262306a36Sopenharmony_ciresponse. Not all commands produce a response, and this is not detectable by
27362306a36Sopenharmony_ci|TC| + |CID|. It is the responsibility of the issuing party to wait for a
27462306a36Sopenharmony_ciresponse (or signal this to the communication framework, as is done in
27562306a36Sopenharmony_ciSAN/ACPI via the ``SNC`` flag).
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ciEvents are identified by unique and reserved request IDs. These IDs should
27862306a36Sopenharmony_cinot be used by the host when sending a new request. They are used on the
27962306a36Sopenharmony_cihost to, first, detect events and, second, match them with a registered
28062306a36Sopenharmony_cievent handler. Request IDs for events are chosen by the host and directed to
28162306a36Sopenharmony_cithe EC when setting up and enabling an event source (via the
28262306a36Sopenharmony_cienable-event-source request). The EC then uses the specified request ID for
28362306a36Sopenharmony_cievents sent from the respective source. Note that an event should still be
28462306a36Sopenharmony_ciidentified by its target category, command ID, and, if applicable, instance
28562306a36Sopenharmony_ciID, as a single event source can send multiple different event types. In
28662306a36Sopenharmony_cigeneral, however, a single target category should map to a single reserved
28762306a36Sopenharmony_cievent request ID.
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ciFurthermore, requests, responses, and events have an associated target ID
29062306a36Sopenharmony_ci(``TID``) and source ID (``SID``). These two fields indicate where a message
29162306a36Sopenharmony_cioriginates from (``SID``) and what the intended target of the message is
29262306a36Sopenharmony_ci(``TID``). Note that a response to a specific request therefore has the source
29362306a36Sopenharmony_ciand target IDs swapped when compared to the original request (i.e. the request
29462306a36Sopenharmony_citarget is the response source and the request source is the response target).
29562306a36Sopenharmony_ciSee (:c:type:`enum ssh_request_id <ssh_request_id>`) for possible values of
29662306a36Sopenharmony_ciboth.
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ciNote that, even though requests and events should be uniquely identifiable by
29962306a36Sopenharmony_citarget category and command ID alone, the EC may require specific target ID and
30062306a36Sopenharmony_ciinstance ID values to accept a command. A command that is accepted for
30162306a36Sopenharmony_ci``TID=1``, for example, may not be accepted for ``TID=2`` and vice versa. While
30262306a36Sopenharmony_cithis may not always hold in reality, you can think of different target/source
30362306a36Sopenharmony_ciIDs indicating different physical ECs with potentially different feature sets.
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ciLimitations and Observations
30762306a36Sopenharmony_ci============================
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciThe protocol can, in theory, handle up to ``U8_MAX`` frames in parallel,
31062306a36Sopenharmony_ciwith up to ``U16_MAX`` pending requests (neglecting request IDs reserved for
31162306a36Sopenharmony_cievents). In practice, however, this is more limited. From our testing
31262306a36Sopenharmony_ci(although via a python and thus a user-space program), it seems that the EC
31362306a36Sopenharmony_cican handle up to four requests (mostly) reliably in parallel at a certain
31462306a36Sopenharmony_citime. With five or more requests in parallel, consistent discarding of
31562306a36Sopenharmony_cicommands (ACKed frame but no command response) has been observed. For five
31662306a36Sopenharmony_cisimultaneous commands, this reproducibly resulted in one command being
31762306a36Sopenharmony_cidropped and four commands being handled.
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ciHowever, it has also been noted that, even with three requests in parallel,
32062306a36Sopenharmony_cioccasional frame drops happen. Apart from this, with a limit of three
32162306a36Sopenharmony_cipending requests, no dropped commands (i.e. command being dropped but frame
32262306a36Sopenharmony_cicarrying command being ACKed) have been observed. In any case, frames (and
32362306a36Sopenharmony_cipossibly also commands) should be re-sent by the host if a certain timeout
32462306a36Sopenharmony_ciis exceeded. This is done by the EC for frames with a timeout of one second,
32562306a36Sopenharmony_ciup to two re-tries (i.e. three transmissions in total). The limit of
32662306a36Sopenharmony_cire-tries also applies to received NAKs, and, in a worst case scenario, can
32762306a36Sopenharmony_cilead to entire messages being dropped.
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ciWhile this also seems to work fine for pending data frames as long as no
33062306a36Sopenharmony_citransmission failures occur, implementation and handling of these seems to
33162306a36Sopenharmony_cidepend on the assumption that there is only one non-acknowledged data frame.
33262306a36Sopenharmony_ciIn particular, the detection of repeated frames relies on the last sequence
33362306a36Sopenharmony_cinumber. This means that, if a frame that has been successfully received by
33462306a36Sopenharmony_cithe EC is sent again, e.g. due to the host not receiving an |ACK|, the EC
33562306a36Sopenharmony_ciwill only detect this if it has the sequence ID of the last frame received
33662306a36Sopenharmony_ciby the EC. As an example: Sending two frames with ``SEQ=0`` and ``SEQ=1``
33762306a36Sopenharmony_cifollowed by a repetition of ``SEQ=0`` will not detect the second ``SEQ=0``
33862306a36Sopenharmony_ciframe as such, and thus execute the command in this frame each time it has
33962306a36Sopenharmony_cibeen received, i.e. twice in this example. Sending ``SEQ=0``, ``SEQ=1`` and
34062306a36Sopenharmony_cithen repeating ``SEQ=1`` will detect the second ``SEQ=1`` as repetition of
34162306a36Sopenharmony_cithe first one and ignore it, thus executing the contained command only once.
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ciIn conclusion, this suggests a limit of at most one pending un-ACKed frame
34462306a36Sopenharmony_ci(per party, effectively leading to synchronous communication regarding
34562306a36Sopenharmony_ciframes) and at most three pending commands. The limit to synchronous frame
34662306a36Sopenharmony_citransfers seems to be consistent with behavior observed on Windows.
347