cros_ec_python.commands.general

General / test commands

  1"""
  2General / test commands
  3"""
  4
  5from typing import Final, Literal
  6import struct
  7from ..baseclass import CrosEcClass
  8from ..constants.COMMON import *
  9from ..exceptions import ECError
 10
 11EC_CMD_PROTO_VERSION: Final = 0x0000
 12
 13
 14def proto_version(ec: CrosEcClass) -> UInt32:
 15    """
 16    Get protocol version, used to deal with non-backward compatible protocol changes.
 17    :param ec: The CrOS_EC object.
 18    :return: The protocol version as a uint32.
 19    """
 20    resp = ec.command(0, EC_CMD_PROTO_VERSION, 0, 4)
 21    return struct.unpack("<I", resp)[0]
 22
 23
 24EC_CMD_HELLO: Final = 0x0001
 25
 26
 27def hello(ec: CrosEcClass, in_data: UInt32) -> UInt32:
 28    """
 29    Hello.  This is a simple command to test the EC is responsive to commands.
 30    :param ec: The CrOS_EC object.
 31    :param in_data: Pass anything here. Max value is 0xFFFFFFFF (uint32).
 32    :return: Output will be in_data + 0x01020304.
 33    """
 34    data = struct.pack("<I", in_data)
 35    resp = ec.command(0, EC_CMD_HELLO, len(data), 4, data)
 36    return struct.unpack("<I", resp)[0]
 37
 38
 39EC_CMD_GET_VERSION: Final = 0x0002
 40
 41
 42def get_version(ec: CrosEcClass, version: Literal[0, 1] = 0) -> dict[str, str | int]:
 43    """
 44    Get version number
 45    :param ec: The CrOS_EC object.
 46    :param version: The command version to use. Default is 0.
 47    :return: The EC version as strings, and the RW status.
 48    """
 49    match version:
 50        case 0:
 51            resp = ec.command(version, EC_CMD_GET_VERSION, 0, 32 + 32 + 32 + 4)
 52            unpacked = struct.unpack("<32s32s32sI", resp)
 53            return {
 54                "version_string_ro": unpacked[0].decode("utf-8").rstrip("\x00"),
 55                "version_string_rw": unpacked[1].decode("utf-8").rstrip("\x00"),
 56                "reserved": unpacked[2].decode("utf-8").rstrip("\x00"),
 57                "current_image": unpacked[3]
 58            }
 59        case 1:
 60            resp = ec.command(version, EC_CMD_GET_VERSION, 0, 32 + 32 + 32 + 4 + 32)
 61            unpacked = struct.unpack("<32s32s32sI32s", resp)
 62            return {
 63                "version_string_ro": unpacked[0].decode("utf-8").rstrip("\x00"),
 64                "version_string_rw": unpacked[1].decode("utf-8").rstrip("\x00"),
 65                "cros_fwid_ro": unpacked[2].decode("utf-8").rstrip("\x00"),
 66                "current_image": unpacked[3],
 67                "crod_fwid_rw": unpacked[4].decode("utf-8").rstrip("\x00")
 68            }
 69        case _:
 70            raise NotImplementedError
 71
 72
 73# Read test - OBSOLETE
 74EC_CMD_READ_TEST: Final = 0x0003
 75
 76EC_CMD_GET_BUILD_INFO: Final = 0x0004
 77
 78
 79def get_build_info(ec: CrosEcClass) -> str:
 80    """
 81    Get build information
 82    :param ec: The CrOS_EC object.
 83    :return: The build info as a string.
 84    """
 85    # 0xEC is the max command size on some platforms
 86    resp = ec.command(0, EC_CMD_GET_BUILD_INFO, 0, 0xEC, warn=False)
 87    return resp.decode("utf-8").rstrip("\x00")
 88
 89
 90EC_CMD_GET_CHIP_INFO: Final = 0x0005
 91
 92
 93def get_chip_info(ec: CrosEcClass) -> dict[str, str]:
 94    """
 95    Get chip info
 96    :param ec: The CrOS_EC object.
 97    :return: The chip vendor, name, and revision as strings.
 98    """
 99    resp = ec.command(0, EC_CMD_GET_CHIP_INFO, 0, 32 + 32 + 32)
100    unpacked = struct.unpack("<32s32s32s", resp)
101    return {
102        "vendor": unpacked[0].decode("utf-8").rstrip("\x00"),
103        "name": unpacked[1].decode("utf-8").rstrip("\x00"),
104        "revision": unpacked[2].decode("utf-8").rstrip("\x00")
105    }
106
107
108EC_CMD_GET_BOARD_VERSION: Final = 0x0006
109
110
111def get_board_version(ec: CrosEcClass) -> UInt16:
112    """
113    Get board HW version
114    :param ec: The CrOS_EC object.
115    :return: The board version as a uint16.
116    """
117    resp = ec.command(0, EC_CMD_GET_BOARD_VERSION, 0, 2)
118    return struct.unpack("<H", resp)[0]
119
120
121# use the CrOS_EC.memmap method instead
122EC_CMD_READ_MEMMAP: Final = 0x0007
123
124EC_CMD_GET_CMD_VERSIONS: Final = 0x0008
125
126
127def get_cmd_versions(ec: CrosEcClass, cmd: UInt8 | UInt16, version: Literal[0, 1] | None = None) -> UInt32 | None:
128    """
129    Read versions supported for a command.
130    :param ec: The CrOS_EC object.
131    :param cmd: The command to get the supported versions of.
132    :param version: The command version to use. Default is guess. 0 supports 8 bit commands, 1 supports 16 bit commands.
133    :return: The supported versions as a bitmask. Bit 0 is version 0, bit 1 is version 1, etc. None if the command is not supported.
134    """
135    if version is None:
136        version = int(cmd > 0xFF)
137    try:
138        match version:
139            case 0:
140                resp = ec.command(version, EC_CMD_GET_CMD_VERSIONS, 1, 4, struct.pack("<B", cmd))
141                return struct.unpack("<I", resp)[0]
142            case 1:
143                resp = ec.command(version, EC_CMD_GET_CMD_VERSIONS, 2, 4, struct.pack("<H", cmd))
144                return struct.unpack("<I", resp)[0]
145            case _:
146                raise NotImplementedError
147    except ECError as e:
148        # EC_CMD_GET_CMD_VERSIONS throws EC_RES_INVALID_PARAM if the command is not supported
149        # Catch this and return None
150        if e.status == EcStatus.EC_RES_INVALID_PARAM.value:
151            return None
152        # Otherwise, raise the exception
153        raise e
154
155def check_cmd_version(ec: CrosEcClass, cmd: UInt8 | UInt16, version: int) -> bool:
156    """
157    Check if a command supports a specific version.
158    :param ec: The CrOS_EC object.
159    :param cmd: The command to check.
160    :param version: The version to check for.
161    :return: True if the command supports the version, False otherwise.
162    """
163    supported_versions = get_cmd_versions(ec, cmd)
164    if supported_versions is None:
165        return False
166    return (supported_versions & (1 << version)) != 0
167
168EC_CMD_GET_COMMS_STATUS: Final = 0x0009
169
170EC_CMD_TEST_PROTOCOL: Final = 0x000A
171
172
173def test_protocol(ec: CrosEcClass, result: UInt32, ret_len: UInt32, buf: bytes, in_size: Int32 | None = None) -> bytes:
174    """
175    Fake a variety of responses, purely for testing purposes.
176    :param ec: The CrOS_EC object.
177    :param result: Result for the EC to return.
178    :param ret_len: Length of return data.
179    :param buf: Data to return. Max length is 32 bytes.
180    :param in_size: Max number of bytes to accept from the EC. None to use ret_len.
181    :return: The data returned.
182    """
183    data = struct.pack("<II", result, ret_len) + buf
184    resp = ec.command(0, EC_CMD_TEST_PROTOCOL, len(data), in_size or ret_len, data)
185    return resp
186
187
188EC_CMD_GET_PROTOCOL_INFO: Final = 0x000B
189
190
191def get_protocol_info(ec: CrosEcClass) -> dict[str, int]:
192    """
193    Get protocol info
194    :param ec: The CrOS_EC object.
195    :return: The protocol info as a dictionary.
196    """
197    resp = ec.command(0, EC_CMD_GET_PROTOCOL_INFO, 0, 12)
198    unpacked = struct.unpack("<IHHI", resp)
199    return {
200        "protocol_versions": unpacked[0],
201        "max_request_packet_size": unpacked[1],
202        "max_response_packet_size": unpacked[2],
203        "flags": unpacked[3]
204    }
EC_CMD_PROTO_VERSION: Final = 0
def proto_version(ec: cros_ec_python.baseclass.CrosEcClass) -> int:
15def proto_version(ec: CrosEcClass) -> UInt32:
16    """
17    Get protocol version, used to deal with non-backward compatible protocol changes.
18    :param ec: The CrOS_EC object.
19    :return: The protocol version as a uint32.
20    """
21    resp = ec.command(0, EC_CMD_PROTO_VERSION, 0, 4)
22    return struct.unpack("<I", resp)[0]

Get protocol version, used to deal with non-backward compatible protocol changes.

Parameters
  • ec: The CrOS_EC object.
Returns

The protocol version as a uint32.

EC_CMD_HELLO: Final = 1
def hello(ec: cros_ec_python.baseclass.CrosEcClass, in_data: int) -> int:
28def hello(ec: CrosEcClass, in_data: UInt32) -> UInt32:
29    """
30    Hello.  This is a simple command to test the EC is responsive to commands.
31    :param ec: The CrOS_EC object.
32    :param in_data: Pass anything here. Max value is 0xFFFFFFFF (uint32).
33    :return: Output will be in_data + 0x01020304.
34    """
35    data = struct.pack("<I", in_data)
36    resp = ec.command(0, EC_CMD_HELLO, len(data), 4, data)
37    return struct.unpack("<I", resp)[0]

Hello. This is a simple command to test the EC is responsive to commands.

Parameters
  • ec: The CrOS_EC object.
  • in_data: Pass anything here. Max value is 0xFFFFFFFF (uint32).
Returns

Output will be in_data + 0x01020304.

EC_CMD_GET_VERSION: Final = 2
def get_version( ec: cros_ec_python.baseclass.CrosEcClass, version: Literal[0, 1] = 0) -> dict[str, str | int]:
43def get_version(ec: CrosEcClass, version: Literal[0, 1] = 0) -> dict[str, str | int]:
44    """
45    Get version number
46    :param ec: The CrOS_EC object.
47    :param version: The command version to use. Default is 0.
48    :return: The EC version as strings, and the RW status.
49    """
50    match version:
51        case 0:
52            resp = ec.command(version, EC_CMD_GET_VERSION, 0, 32 + 32 + 32 + 4)
53            unpacked = struct.unpack("<32s32s32sI", resp)
54            return {
55                "version_string_ro": unpacked[0].decode("utf-8").rstrip("\x00"),
56                "version_string_rw": unpacked[1].decode("utf-8").rstrip("\x00"),
57                "reserved": unpacked[2].decode("utf-8").rstrip("\x00"),
58                "current_image": unpacked[3]
59            }
60        case 1:
61            resp = ec.command(version, EC_CMD_GET_VERSION, 0, 32 + 32 + 32 + 4 + 32)
62            unpacked = struct.unpack("<32s32s32sI32s", resp)
63            return {
64                "version_string_ro": unpacked[0].decode("utf-8").rstrip("\x00"),
65                "version_string_rw": unpacked[1].decode("utf-8").rstrip("\x00"),
66                "cros_fwid_ro": unpacked[2].decode("utf-8").rstrip("\x00"),
67                "current_image": unpacked[3],
68                "crod_fwid_rw": unpacked[4].decode("utf-8").rstrip("\x00")
69            }
70        case _:
71            raise NotImplementedError

Get version number

Parameters
  • ec: The CrOS_EC object.
  • version: The command version to use. Default is 0.
Returns

The EC version as strings, and the RW status.

EC_CMD_READ_TEST: Final = 3
EC_CMD_GET_BUILD_INFO: Final = 4
def get_build_info(ec: cros_ec_python.baseclass.CrosEcClass) -> str:
80def get_build_info(ec: CrosEcClass) -> str:
81    """
82    Get build information
83    :param ec: The CrOS_EC object.
84    :return: The build info as a string.
85    """
86    # 0xEC is the max command size on some platforms
87    resp = ec.command(0, EC_CMD_GET_BUILD_INFO, 0, 0xEC, warn=False)
88    return resp.decode("utf-8").rstrip("\x00")

Get build information

Parameters
  • ec: The CrOS_EC object.
Returns

The build info as a string.

EC_CMD_GET_CHIP_INFO: Final = 5
def get_chip_info(ec: cros_ec_python.baseclass.CrosEcClass) -> dict[str, str]:
 94def get_chip_info(ec: CrosEcClass) -> dict[str, str]:
 95    """
 96    Get chip info
 97    :param ec: The CrOS_EC object.
 98    :return: The chip vendor, name, and revision as strings.
 99    """
100    resp = ec.command(0, EC_CMD_GET_CHIP_INFO, 0, 32 + 32 + 32)
101    unpacked = struct.unpack("<32s32s32s", resp)
102    return {
103        "vendor": unpacked[0].decode("utf-8").rstrip("\x00"),
104        "name": unpacked[1].decode("utf-8").rstrip("\x00"),
105        "revision": unpacked[2].decode("utf-8").rstrip("\x00")
106    }

Get chip info

Parameters
  • ec: The CrOS_EC object.
Returns

The chip vendor, name, and revision as strings.

EC_CMD_GET_BOARD_VERSION: Final = 6
def get_board_version(ec: cros_ec_python.baseclass.CrosEcClass) -> int:
112def get_board_version(ec: CrosEcClass) -> UInt16:
113    """
114    Get board HW version
115    :param ec: The CrOS_EC object.
116    :return: The board version as a uint16.
117    """
118    resp = ec.command(0, EC_CMD_GET_BOARD_VERSION, 0, 2)
119    return struct.unpack("<H", resp)[0]

Get board HW version

Parameters
  • ec: The CrOS_EC object.
Returns

The board version as a uint16.

EC_CMD_READ_MEMMAP: Final = 7
EC_CMD_GET_CMD_VERSIONS: Final = 8
def get_cmd_versions( ec: cros_ec_python.baseclass.CrosEcClass, cmd: int, version: Optional[Literal[0, 1]] = None) -> int | None:
128def get_cmd_versions(ec: CrosEcClass, cmd: UInt8 | UInt16, version: Literal[0, 1] | None = None) -> UInt32 | None:
129    """
130    Read versions supported for a command.
131    :param ec: The CrOS_EC object.
132    :param cmd: The command to get the supported versions of.
133    :param version: The command version to use. Default is guess. 0 supports 8 bit commands, 1 supports 16 bit commands.
134    :return: The supported versions as a bitmask. Bit 0 is version 0, bit 1 is version 1, etc. None if the command is not supported.
135    """
136    if version is None:
137        version = int(cmd > 0xFF)
138    try:
139        match version:
140            case 0:
141                resp = ec.command(version, EC_CMD_GET_CMD_VERSIONS, 1, 4, struct.pack("<B", cmd))
142                return struct.unpack("<I", resp)[0]
143            case 1:
144                resp = ec.command(version, EC_CMD_GET_CMD_VERSIONS, 2, 4, struct.pack("<H", cmd))
145                return struct.unpack("<I", resp)[0]
146            case _:
147                raise NotImplementedError
148    except ECError as e:
149        # EC_CMD_GET_CMD_VERSIONS throws EC_RES_INVALID_PARAM if the command is not supported
150        # Catch this and return None
151        if e.status == EcStatus.EC_RES_INVALID_PARAM.value:
152            return None
153        # Otherwise, raise the exception
154        raise e

Read versions supported for a command.

Parameters
  • ec: The CrOS_EC object.
  • cmd: The command to get the supported versions of.
  • version: The command version to use. Default is guess. 0 supports 8 bit commands, 1 supports 16 bit commands.
Returns

The supported versions as a bitmask. Bit 0 is version 0, bit 1 is version 1, etc. None if the command is not supported.

def check_cmd_version(ec: cros_ec_python.baseclass.CrosEcClass, cmd: int, version: int) -> bool:
156def check_cmd_version(ec: CrosEcClass, cmd: UInt8 | UInt16, version: int) -> bool:
157    """
158    Check if a command supports a specific version.
159    :param ec: The CrOS_EC object.
160    :param cmd: The command to check.
161    :param version: The version to check for.
162    :return: True if the command supports the version, False otherwise.
163    """
164    supported_versions = get_cmd_versions(ec, cmd)
165    if supported_versions is None:
166        return False
167    return (supported_versions & (1 << version)) != 0

Check if a command supports a specific version.

Parameters
  • ec: The CrOS_EC object.
  • cmd: The command to check.
  • version: The version to check for.
Returns

True if the command supports the version, False otherwise.

EC_CMD_GET_COMMS_STATUS: Final = 9
EC_CMD_TEST_PROTOCOL: Final = 10
def test_protocol( ec: cros_ec_python.baseclass.CrosEcClass, result: int, ret_len: int, buf: bytes, in_size: int | None = None) -> bytes:
174def test_protocol(ec: CrosEcClass, result: UInt32, ret_len: UInt32, buf: bytes, in_size: Int32 | None = None) -> bytes:
175    """
176    Fake a variety of responses, purely for testing purposes.
177    :param ec: The CrOS_EC object.
178    :param result: Result for the EC to return.
179    :param ret_len: Length of return data.
180    :param buf: Data to return. Max length is 32 bytes.
181    :param in_size: Max number of bytes to accept from the EC. None to use ret_len.
182    :return: The data returned.
183    """
184    data = struct.pack("<II", result, ret_len) + buf
185    resp = ec.command(0, EC_CMD_TEST_PROTOCOL, len(data), in_size or ret_len, data)
186    return resp

Fake a variety of responses, purely for testing purposes.

Parameters
  • ec: The CrOS_EC object.
  • result: Result for the EC to return.
  • ret_len: Length of return data.
  • buf: Data to return. Max length is 32 bytes.
  • in_size: Max number of bytes to accept from the EC. None to use ret_len.
Returns

The data returned.

EC_CMD_GET_PROTOCOL_INFO: Final = 11
def get_protocol_info(ec: cros_ec_python.baseclass.CrosEcClass) -> dict[str, int]:
192def get_protocol_info(ec: CrosEcClass) -> dict[str, int]:
193    """
194    Get protocol info
195    :param ec: The CrOS_EC object.
196    :return: The protocol info as a dictionary.
197    """
198    resp = ec.command(0, EC_CMD_GET_PROTOCOL_INFO, 0, 12)
199    unpacked = struct.unpack("<IHHI", resp)
200    return {
201        "protocol_versions": unpacked[0],
202        "max_request_packet_size": unpacked[1],
203        "max_response_packet_size": unpacked[2],
204        "flags": unpacked[3]
205    }

Get protocol info

Parameters
  • ec: The CrOS_EC object.
Returns

The protocol info as a dictionary.