cros_ec_python.commands.framework_laptop

Framework Laptop specific commands.

  1"""
  2Framework Laptop specific commands.
  3"""
  4
  5from typing import Final, Literal
  6from enum import Enum
  7import struct
  8from datetime import timedelta
  9from ..baseclass import CrosEcClass
 10from ..constants.COMMON import *
 11
 12
 13EC_CMD_FLASH_NOTIFIED: Final = 0x3E01
 14
 15EC_CMD_FACTORY_MODE: Final = 0x3E02
 16
 17EC_CMD_CHARGE_LIMIT_CONTROL: Final = 0x3E03
 18
 19
 20class ChargeLimitControlModes(Enum):
 21    CHG_LIMIT_DISABLE = BIT(0)
 22    CHG_LIMIT_SET_LIMIT = BIT(1)
 23    CHG_LIMIT_GET_LIMIT = BIT(3)
 24    CHG_LIMIT_OVERRIDE = BIT(7)
 25
 26
 27def disable_charge_limit(ec: CrosEcClass) -> None:
 28    """
 29    Disables the charge limit.
 30    :param ec: The CrOS_EC object.
 31    """
 32    data = struct.pack("<Bxx", ChargeLimitControlModes.CHG_LIMIT_DISABLE.value)
 33    ec.command(0, EC_CMD_CHARGE_LIMIT_CONTROL, 3, 0, data)
 34
 35
 36def get_charge_limit(ec: CrosEcClass) -> tuple[UInt8, UInt8]:
 37    """
 38    Gets the charge limit.
 39    :param ec: The CrOS_EC object.
 40    :return: The charge limit as a tuple (max, min).
 41    """
 42    data = struct.pack("<Bxx", ChargeLimitControlModes.CHG_LIMIT_GET_LIMIT.value)
 43    resp = ec.command(0, EC_CMD_CHARGE_LIMIT_CONTROL, 3, 2, data)
 44    return struct.unpack("<BB", resp)
 45
 46
 47def set_charge_limit(ec: CrosEcClass, max: UInt8, min: UInt8) -> None:
 48    """
 49    Sets the charge limit.
 50    :param ec: The CrOS_EC object.
 51    :param limit: The charge limit.
 52    """
 53    data = struct.pack(
 54        "<BBB", ChargeLimitControlModes.CHG_LIMIT_SET_LIMIT.value, max, min
 55    )
 56    ec.command(0, EC_CMD_CHARGE_LIMIT_CONTROL, 3, 0, data)
 57
 58
 59def override_charge_limit(ec: CrosEcClass) -> None:
 60    """
 61    Overrides the charge limit to full for a single charge cycle.
 62    :param ec: The CrOS_EC object.
 63    :param limit: The charge limit.
 64    """
 65    data = struct.pack("<Bxx", ChargeLimitControlModes.CHG_LIMIT_OVERRIDE.value)
 66    ec.command(0, EC_CMD_CHARGE_LIMIT_CONTROL, 3, 0, data)
 67
 68
 69EC_CMD_PWM_GET_FAN_ACTUAL_RPM: Final = 0x3E04
 70
 71
 72def pwm_get_fan_rpm(ec: CrosEcClass, index: UInt8 = 0) -> UInt16:
 73    """
 74    Get fan RPM (Same value as `cros_ec_python.commands.memmap.get_fans`)
 75    :param ec: The CrOS_EC object.
 76    :param index: The fan index to get the RPM for.
 77    :return: The current fan RPM.
 78    """
 79    data = struct.pack("<B", index)
 80    resp = ec.command(0, EC_CMD_PWM_GET_FAN_ACTUAL_RPM, 1, 2, data)
 81    return struct.unpack("<H", resp)[0]
 82
 83
 84EC_CMD_SET_AP_REBOOT_DELAY: Final = 0x3E05
 85
 86EC_CMD_ME_CONTROL: Final = 0x3E06
 87
 88EC_CMD_NON_ACPI_NOTIFY: Final = 0x3E07
 89
 90EC_CMD_DISABLE_PS2_EMULATION: Final = 0x3E08
 91
 92EC_CMD_CHASSIS_INTRUSION: Final = 0x3E09
 93
 94
 95def get_chassis_intrusion(
 96    ec: CrosEcClass, clear_magic: UInt8 = 0, clear_chassis_status: UInt8 = 0
 97) -> dict[bool | UInt8]:
 98    """
 99    Get chassis intrusion status. It is recommended to leave the other parameters empty.
100    :param ec: The CrOS_EC object.
101    :param clear_magic: If `0xCE` then all chassis data is cleared.
102    :param clear_chassis_status: If not `0`, then `chassis_ever_opened` is cleared.
103    :return: The chassis intrusion status. `chassis_ever_opened` is True if the chassis has ever been opened, `coin_batt_ever_remove` is True if the coin battery has ever been removed, `total_open_count` is the total number of times the chassis has been opened, and `vtr_open_count` is the number of times the chassis has been opened with only RTC power.
104    """
105    data = struct.pack("<BB", clear_magic, clear_chassis_status)
106    resp = ec.command(0, EC_CMD_CHASSIS_INTRUSION, 2, 4, data)
107    unpacked = struct.unpack("<?BBB", resp)
108    return {
109        "chassis_ever_opened": unpacked[0],
110        "coin_batt_ever_remove": unpacked[1],
111        "total_open_count": unpacked[2],
112        "vtr_open_count": unpacked[3],
113    }
114
115
116EC_CMD_BB_RETIMER_CONTROL: Final = 0x3E0A
117
118EC_CMD_DIAGNOSIS: Final = 0x3E0B
119
120EC_CMD_UPDATE_KEYBOARD_MATRIX: Final = 0x3E0C
121
122EC_CMD_VPRO_CONTROL: Final = 0x3E0D
123
124EC_CMD_FP_LED_LEVEL_CONTROL: Final = 0x3E0E
125
126
127class FpLedBrightnessLevel(Enum):
128    FP_LED_BRIGHTNESS_LEVEL_HIGH = 0
129    FP_LED_BRIGHTNESS_LEVEL_MEDIUM = 1
130    FP_LED_BRIGHTNESS_LEVEL_LOW = 2
131
132
133def set_fp_led_level(ec: CrosEcClass, level: FpLedBrightnessLevel | int) -> None:
134    """
135    Set the fingerprint LED level.
136    :param ec: The CrOS_EC object.
137    :param level: The level to set the fingerprint LED to.
138    """
139    if isinstance(level, FpLedBrightnessLevel):
140        level = level.value
141    data = struct.pack("<Bx", level)
142    ec.command(0, EC_CMD_FP_LED_LEVEL_CONTROL, 2, 0, data)
143
144
145def get_fp_led_level_int(ec: CrosEcClass) -> UInt8:
146    """
147    Get the raw fingerprint LED level.
148    :param ec: The CrOS_EC object.
149    :return: The current fingerprint LED level.
150    """
151    data = struct.pack("<xB", 1)
152    resp = ec.command(0, EC_CMD_FP_LED_LEVEL_CONTROL, 2, 1, data)
153    return struct.unpack("<B", resp)[0]
154
155
156def get_fp_led_level(ec: CrosEcClass) -> FpLedBrightnessLevel:
157    """
158    Get the fingerprint LED level.
159    :param ec: The CrOS_EC object.
160    :return: The current fingerprint LED level.
161    """
162    match level := get_fp_led_level_int(ec):
163        case 55:
164            return FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_HIGH
165        case 40:
166            return FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_MEDIUM
167        case 15:
168            return FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_LOW
169        case _:
170            raise ValueError(f"Invalid fingerprint LED level ({level})")
171
172
173EC_CMD_CHASSIS_OPEN_CHECK: Final = 0x3E0F
174
175
176def get_chassis_open_check(ec: CrosEcClass) -> bool:
177    """
178    Check if the chassis is currently open.
179    :param ec: The CrOS_EC object.
180    :return: True if the chassis is open, False if it is closed.
181    """
182    resp = ec.command(0, EC_CMD_CHASSIS_OPEN_CHECK, 0, 1)
183    return struct.unpack("<?", resp)[0]
184
185
186EC_CMD_ACPI_NOTIFY: Final = 0x3E10
187
188EC_CMD_READ_PD_VERSION: Final = 0x3E11
189
190EC_CMD_THERMAL_QEVENT: Final = 0x3E12
191
192EC_CMD_STANDALONE_MODE: Final = 0x3E13
193
194EC_CMD_PRIVACY_SWITCHES_CHECK_MODE: Final = 0x3E14
195
196
197def get_privacy_switches(ec: CrosEcClass) -> dict[bool]:
198    """
199    Get the privacy switches status.
200    :param ec: The CrOS_EC object.
201    :return: The device status. True if enabled, False if disabled.
202    """
203    resp = ec.command(0, EC_CMD_PRIVACY_SWITCHES_CHECK_MODE, 0, 2)
204    unpacked = struct.unpack("<??", resp)
205    return {
206        "microphone": unpacked[0],
207        "camera": unpacked[1],
208    }
209
210
211EC_CMD_CHASSIS_COUNTER: Final = 0x3E15
212
213
214def get_chassis_counter(ec: CrosEcClass) -> UInt8:
215    """
216    Get the amount of times the chassis has been opened while the EC has power.
217    Clears on reboot and on read, use `get_chassis_intrusion` for persistent data.
218    :param ec: The CrOS_EC object.
219    :return: The chassis counter.
220    """
221    resp = ec.command(0, EC_CMD_CHASSIS_COUNTER, 0, 1)
222    return struct.unpack("<B", resp)[0]
223
224
225EC_CMD_CHECK_DECK_STATE: Final = 0x3E16
226
227EC_CMD_GET_SIMPLE_VERSION: Final = 0x3E17
228
229
230def get_simple_version(ec: CrosEcClass) -> str:
231    """
232    Get the simple ec version.
233    :param ec: The CrOS_EC object.
234    :return: The simple version as a string.
235    """
236    resp = ec.command(0, EC_CMD_GET_SIMPLE_VERSION, 0, 9)
237    return resp.decode("utf-8").rstrip("\x00")
238
239
240EC_CMD_GET_ACTIVE_CHARGE_PD_CHIP: Final = 0x3E18
241
242
243def get_active_charge_pd_chip(ec: CrosEcClass) -> UInt8:
244    """
245    Get the active charge PD chip.
246    :param ec: The CrOS_EC object.
247    :return: The active charge PD chip.
248    """
249    resp = ec.command(0, EC_CMD_GET_ACTIVE_CHARGE_PD_CHIP, 0, 1)
250    return struct.unpack("<B", resp)[0]
251
252
253EC_CMD_UEFI_APP_MODE: Final = 0x3E19
254
255EC_CMD_UEFI_APP_BTN_STATUS: Final = 0x3E1A
256
257EC_CMD_EXPANSION_BAY_STATUS: Final = 0x3E1B
258
259EC_CMD_GET_HW_DIAG: Final = 0x3E1C
260
261EC_CMD_GET_GPU_SERIAL: Final = 0x3E1D
262
263
264def get_gpu_serial(ec: CrosEcClass, idx: UInt8 = 0) -> dict[UInt8 | bool | str]:
265    """
266    Get the GPU serial. [Untested]
267    :param ec: The CrOS_EC object.
268    :return: The GPU serial as a string.
269    """
270    data = struct.pack("<B", idx)
271    resp = ec.command(0, EC_CMD_GET_GPU_SERIAL, 1, 22, data)
272    unpacked = struct.unpack("<B?20s", resp)
273    return {
274        "idx": unpacked[0],
275        "valid": unpacked[1],
276        "serial": unpacked[2].decode("utf-8").rstrip("\x00"),
277    }
278
279
280EC_CMD_GET_GPU_PCIE: Final = 0x3E1E
281
282
283class GpuPcieConfig(Enum):
284    PCIE_8X1 = 0
285    PCIE_4X1 = 1
286    PCIE_4X2 = 2
287
288
289class GpuPcieVendor(Enum):
290    GPU_AMD_R23 = 0
291    GPU_PCIE_ACCESSORY = 0xFF
292
293
294def get_gpu_pcie(ec: CrosEcClass) -> dict[GpuPcieConfig | GpuPcieVendor | UInt8]:
295    """
296    Get the PCIe configuration of the GPU module. [Untested]
297    :param ec: The CrOS_EC object.
298    :return: The GPU PCIe configuration and vendor.
299    """
300    resp = ec.command(0, EC_CMD_GET_GPU_PCIE, 0, 2)
301    gpu_pcie_config = GpuPcieConfig(resp[0])
302    gpu_vendor = (
303        GpuPcieVendor(resp[1]) if resp[1] in GpuPcieVendor._value2member_map_ else None
304    )
305
306    return {"gpu_pcie_config": gpu_pcie_config, "gpu_vendor": gpu_vendor}
307
308
309EC_CMD_PROGRAM_GPU_EEPROM: Final = 0x3E1F
310
311EC_CMD_FP_CONTROL: Final = 0x3E20
312
313
314def fp_control(ec: CrosEcClass, enable: bool) -> None:
315    """
316    Enable or disable the fingerprint sensor. [Untested]
317    :param ec: The CrOS_EC object.
318    :param enable: True to enable the fingerprint sensor, False to disable it.
319    """
320    data = struct.pack("<?", enable)
321    ec.command(0, EC_CMD_FP_CONTROL, 1, 0, data)
322
323
324# This doesn't seem to be implemented
325EC_CMD_GET_CUTOFF_STATUS: Final = 0x3E21
326
327EC_CMD_BATTERY_EXTENDER: Final = 0x3E24
328
329
330def get_battery_extender(ec: CrosEcClass) -> dict[UInt8 | UInt16 | bool | timedelta]:
331    """
332    Get the battery extender status.
333    :param ec: The CrOS_EC object.
334    :return: The battery extender status. `current_stage` is the current stage of the battery extender (0-2), `trigger_days` is the number of days on charge before reducing the charge limit, `reset_minutes` is the number of minutes off charge before resetting the charge limit, `disable` is True if the battery extender is disabled, `trigger_timedelta` is the timedelta before reducing the charge limit, and `reset_timedelta` is the timedelta before resetting the charge limit.
335    """
336    # 1 for read
337    data = struct.pack("<xxxxBx", 1)
338    resp = ec.command(0, EC_CMD_BATTERY_EXTENDER, 6, 22, data)
339    unpacked = struct.unpack("<BHH?QQ", resp)
340    return {
341        "current_stage": unpacked[0],
342        "trigger_days": unpacked[1],
343        "reset_minutes": unpacked[2],
344        "disable": unpacked[3],
345        "trigger_timedelta": timedelta(microseconds=unpacked[4]),
346        "reset_timedelta": timedelta(microseconds=unpacked[5]),
347    }
348
349
350def set_battery_extender(
351    ec: CrosEcClass, disable: bool, trigger_days: UInt8 = 0, reset_minutes: UInt16 = 0
352) -> None:
353    """
354    Set the battery extender status.
355    :param ec: The CrOS_EC object.
356    :param disable: True to disable the battery extender, False to enable it.
357    :param trigger_days: The number of days on charge before reducing the charge limit. Values less than 1 or greater than 99 will be ignored.
358    :param reset_minutes: The number of minutes off charge before resetting the charge limit. Values less than 1 or greater than 9999 will be ignored.
359    """
360    # 0 for write
361    data = struct.pack("<?BHBx", disable, trigger_days, reset_minutes, 0)
362    ec.command(0, EC_CMD_BATTERY_EXTENDER, 6, 0, data)
EC_CMD_FLASH_NOTIFIED: Final = 15873
EC_CMD_FACTORY_MODE: Final = 15874
EC_CMD_CHARGE_LIMIT_CONTROL: Final = 15875
class ChargeLimitControlModes(enum.Enum):
21class ChargeLimitControlModes(Enum):
22    CHG_LIMIT_DISABLE = BIT(0)
23    CHG_LIMIT_SET_LIMIT = BIT(1)
24    CHG_LIMIT_GET_LIMIT = BIT(3)
25    CHG_LIMIT_OVERRIDE = BIT(7)
CHG_LIMIT_SET_LIMIT = <ChargeLimitControlModes.CHG_LIMIT_SET_LIMIT: 2>
CHG_LIMIT_GET_LIMIT = <ChargeLimitControlModes.CHG_LIMIT_GET_LIMIT: 8>
CHG_LIMIT_OVERRIDE = <ChargeLimitControlModes.CHG_LIMIT_OVERRIDE: 128>
def disable_charge_limit(ec: cros_ec_python.baseclass.CrosEcClass) -> None:
28def disable_charge_limit(ec: CrosEcClass) -> None:
29    """
30    Disables the charge limit.
31    :param ec: The CrOS_EC object.
32    """
33    data = struct.pack("<Bxx", ChargeLimitControlModes.CHG_LIMIT_DISABLE.value)
34    ec.command(0, EC_CMD_CHARGE_LIMIT_CONTROL, 3, 0, data)

Disables the charge limit.

Parameters
  • ec: The CrOS_EC object.
def get_charge_limit(ec: cros_ec_python.baseclass.CrosEcClass) -> tuple[int, int]:
37def get_charge_limit(ec: CrosEcClass) -> tuple[UInt8, UInt8]:
38    """
39    Gets the charge limit.
40    :param ec: The CrOS_EC object.
41    :return: The charge limit as a tuple (max, min).
42    """
43    data = struct.pack("<Bxx", ChargeLimitControlModes.CHG_LIMIT_GET_LIMIT.value)
44    resp = ec.command(0, EC_CMD_CHARGE_LIMIT_CONTROL, 3, 2, data)
45    return struct.unpack("<BB", resp)

Gets the charge limit.

Parameters
  • ec: The CrOS_EC object.
Returns

The charge limit as a tuple (max, min).

def set_charge_limit(ec: cros_ec_python.baseclass.CrosEcClass, max: int, min: int) -> None:
48def set_charge_limit(ec: CrosEcClass, max: UInt8, min: UInt8) -> None:
49    """
50    Sets the charge limit.
51    :param ec: The CrOS_EC object.
52    :param limit: The charge limit.
53    """
54    data = struct.pack(
55        "<BBB", ChargeLimitControlModes.CHG_LIMIT_SET_LIMIT.value, max, min
56    )
57    ec.command(0, EC_CMD_CHARGE_LIMIT_CONTROL, 3, 0, data)

Sets the charge limit.

Parameters
  • ec: The CrOS_EC object.
  • limit: The charge limit.
def override_charge_limit(ec: cros_ec_python.baseclass.CrosEcClass) -> None:
60def override_charge_limit(ec: CrosEcClass) -> None:
61    """
62    Overrides the charge limit to full for a single charge cycle.
63    :param ec: The CrOS_EC object.
64    :param limit: The charge limit.
65    """
66    data = struct.pack("<Bxx", ChargeLimitControlModes.CHG_LIMIT_OVERRIDE.value)
67    ec.command(0, EC_CMD_CHARGE_LIMIT_CONTROL, 3, 0, data)

Overrides the charge limit to full for a single charge cycle.

Parameters
  • ec: The CrOS_EC object.
  • limit: The charge limit.
EC_CMD_PWM_GET_FAN_ACTUAL_RPM: Final = 15876
def pwm_get_fan_rpm(ec: cros_ec_python.baseclass.CrosEcClass, index: int = 0) -> int:
73def pwm_get_fan_rpm(ec: CrosEcClass, index: UInt8 = 0) -> UInt16:
74    """
75    Get fan RPM (Same value as `cros_ec_python.commands.memmap.get_fans`)
76    :param ec: The CrOS_EC object.
77    :param index: The fan index to get the RPM for.
78    :return: The current fan RPM.
79    """
80    data = struct.pack("<B", index)
81    resp = ec.command(0, EC_CMD_PWM_GET_FAN_ACTUAL_RPM, 1, 2, data)
82    return struct.unpack("<H", resp)[0]

Get fan RPM (Same value as cros_ec_python.commands.memmap.get_fans)

Parameters
  • ec: The CrOS_EC object.
  • index: The fan index to get the RPM for.
Returns

The current fan RPM.

EC_CMD_SET_AP_REBOOT_DELAY: Final = 15877
EC_CMD_ME_CONTROL: Final = 15878
EC_CMD_NON_ACPI_NOTIFY: Final = 15879
EC_CMD_DISABLE_PS2_EMULATION: Final = 15880
EC_CMD_CHASSIS_INTRUSION: Final = 15881
def get_chassis_intrusion( ec: cros_ec_python.baseclass.CrosEcClass, clear_magic: int = 0, clear_chassis_status: int = 0) -> dict[bool | int]:
 96def get_chassis_intrusion(
 97    ec: CrosEcClass, clear_magic: UInt8 = 0, clear_chassis_status: UInt8 = 0
 98) -> dict[bool | UInt8]:
 99    """
100    Get chassis intrusion status. It is recommended to leave the other parameters empty.
101    :param ec: The CrOS_EC object.
102    :param clear_magic: If `0xCE` then all chassis data is cleared.
103    :param clear_chassis_status: If not `0`, then `chassis_ever_opened` is cleared.
104    :return: The chassis intrusion status. `chassis_ever_opened` is True if the chassis has ever been opened, `coin_batt_ever_remove` is True if the coin battery has ever been removed, `total_open_count` is the total number of times the chassis has been opened, and `vtr_open_count` is the number of times the chassis has been opened with only RTC power.
105    """
106    data = struct.pack("<BB", clear_magic, clear_chassis_status)
107    resp = ec.command(0, EC_CMD_CHASSIS_INTRUSION, 2, 4, data)
108    unpacked = struct.unpack("<?BBB", resp)
109    return {
110        "chassis_ever_opened": unpacked[0],
111        "coin_batt_ever_remove": unpacked[1],
112        "total_open_count": unpacked[2],
113        "vtr_open_count": unpacked[3],
114    }

Get chassis intrusion status. It is recommended to leave the other parameters empty.

Parameters
  • ec: The CrOS_EC object.
  • clear_magic: If 0xCE then all chassis data is cleared.
  • clear_chassis_status: If not 0, then chassis_ever_opened is cleared.
Returns

The chassis intrusion status. chassis_ever_opened is True if the chassis has ever been opened, coin_batt_ever_remove is True if the coin battery has ever been removed, total_open_count is the total number of times the chassis has been opened, and vtr_open_count is the number of times the chassis has been opened with only RTC power.

EC_CMD_BB_RETIMER_CONTROL: Final = 15882
EC_CMD_DIAGNOSIS: Final = 15883
EC_CMD_UPDATE_KEYBOARD_MATRIX: Final = 15884
EC_CMD_VPRO_CONTROL: Final = 15885
EC_CMD_FP_LED_LEVEL_CONTROL: Final = 15886
class FpLedBrightnessLevel(enum.Enum):
128class FpLedBrightnessLevel(Enum):
129    FP_LED_BRIGHTNESS_LEVEL_HIGH = 0
130    FP_LED_BRIGHTNESS_LEVEL_MEDIUM = 1
131    FP_LED_BRIGHTNESS_LEVEL_LOW = 2
FP_LED_BRIGHTNESS_LEVEL_HIGH = <FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_HIGH: 0>
FP_LED_BRIGHTNESS_LEVEL_MEDIUM = <FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_MEDIUM: 1>
FP_LED_BRIGHTNESS_LEVEL_LOW = <FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_LOW: 2>
def set_fp_led_level( ec: cros_ec_python.baseclass.CrosEcClass, level: FpLedBrightnessLevel | int) -> None:
134def set_fp_led_level(ec: CrosEcClass, level: FpLedBrightnessLevel | int) -> None:
135    """
136    Set the fingerprint LED level.
137    :param ec: The CrOS_EC object.
138    :param level: The level to set the fingerprint LED to.
139    """
140    if isinstance(level, FpLedBrightnessLevel):
141        level = level.value
142    data = struct.pack("<Bx", level)
143    ec.command(0, EC_CMD_FP_LED_LEVEL_CONTROL, 2, 0, data)

Set the fingerprint LED level.

Parameters
  • ec: The CrOS_EC object.
  • level: The level to set the fingerprint LED to.
def get_fp_led_level_int(ec: cros_ec_python.baseclass.CrosEcClass) -> int:
146def get_fp_led_level_int(ec: CrosEcClass) -> UInt8:
147    """
148    Get the raw fingerprint LED level.
149    :param ec: The CrOS_EC object.
150    :return: The current fingerprint LED level.
151    """
152    data = struct.pack("<xB", 1)
153    resp = ec.command(0, EC_CMD_FP_LED_LEVEL_CONTROL, 2, 1, data)
154    return struct.unpack("<B", resp)[0]

Get the raw fingerprint LED level.

Parameters
  • ec: The CrOS_EC object.
Returns

The current fingerprint LED level.

def get_fp_led_level( ec: cros_ec_python.baseclass.CrosEcClass) -> FpLedBrightnessLevel:
157def get_fp_led_level(ec: CrosEcClass) -> FpLedBrightnessLevel:
158    """
159    Get the fingerprint LED level.
160    :param ec: The CrOS_EC object.
161    :return: The current fingerprint LED level.
162    """
163    match level := get_fp_led_level_int(ec):
164        case 55:
165            return FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_HIGH
166        case 40:
167            return FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_MEDIUM
168        case 15:
169            return FpLedBrightnessLevel.FP_LED_BRIGHTNESS_LEVEL_LOW
170        case _:
171            raise ValueError(f"Invalid fingerprint LED level ({level})")

Get the fingerprint LED level.

Parameters
  • ec: The CrOS_EC object.
Returns

The current fingerprint LED level.

EC_CMD_CHASSIS_OPEN_CHECK: Final = 15887
def get_chassis_open_check(ec: cros_ec_python.baseclass.CrosEcClass) -> bool:
177def get_chassis_open_check(ec: CrosEcClass) -> bool:
178    """
179    Check if the chassis is currently open.
180    :param ec: The CrOS_EC object.
181    :return: True if the chassis is open, False if it is closed.
182    """
183    resp = ec.command(0, EC_CMD_CHASSIS_OPEN_CHECK, 0, 1)
184    return struct.unpack("<?", resp)[0]

Check if the chassis is currently open.

Parameters
  • ec: The CrOS_EC object.
Returns

True if the chassis is open, False if it is closed.

EC_CMD_ACPI_NOTIFY: Final = 15888
EC_CMD_READ_PD_VERSION: Final = 15889
EC_CMD_THERMAL_QEVENT: Final = 15890
EC_CMD_STANDALONE_MODE: Final = 15891
EC_CMD_PRIVACY_SWITCHES_CHECK_MODE: Final = 15892
def get_privacy_switches(ec: cros_ec_python.baseclass.CrosEcClass) -> dict[bool]:
198def get_privacy_switches(ec: CrosEcClass) -> dict[bool]:
199    """
200    Get the privacy switches status.
201    :param ec: The CrOS_EC object.
202    :return: The device status. True if enabled, False if disabled.
203    """
204    resp = ec.command(0, EC_CMD_PRIVACY_SWITCHES_CHECK_MODE, 0, 2)
205    unpacked = struct.unpack("<??", resp)
206    return {
207        "microphone": unpacked[0],
208        "camera": unpacked[1],
209    }

Get the privacy switches status.

Parameters
  • ec: The CrOS_EC object.
Returns

The device status. True if enabled, False if disabled.

EC_CMD_CHASSIS_COUNTER: Final = 15893
def get_chassis_counter(ec: cros_ec_python.baseclass.CrosEcClass) -> int:
215def get_chassis_counter(ec: CrosEcClass) -> UInt8:
216    """
217    Get the amount of times the chassis has been opened while the EC has power.
218    Clears on reboot and on read, use `get_chassis_intrusion` for persistent data.
219    :param ec: The CrOS_EC object.
220    :return: The chassis counter.
221    """
222    resp = ec.command(0, EC_CMD_CHASSIS_COUNTER, 0, 1)
223    return struct.unpack("<B", resp)[0]

Get the amount of times the chassis has been opened while the EC has power. Clears on reboot and on read, use get_chassis_intrusion for persistent data.

Parameters
  • ec: The CrOS_EC object.
Returns

The chassis counter.

EC_CMD_CHECK_DECK_STATE: Final = 15894
EC_CMD_GET_SIMPLE_VERSION: Final = 15895
def get_simple_version(ec: cros_ec_python.baseclass.CrosEcClass) -> str:
231def get_simple_version(ec: CrosEcClass) -> str:
232    """
233    Get the simple ec version.
234    :param ec: The CrOS_EC object.
235    :return: The simple version as a string.
236    """
237    resp = ec.command(0, EC_CMD_GET_SIMPLE_VERSION, 0, 9)
238    return resp.decode("utf-8").rstrip("\x00")

Get the simple ec version.

Parameters
  • ec: The CrOS_EC object.
Returns

The simple version as a string.

EC_CMD_GET_ACTIVE_CHARGE_PD_CHIP: Final = 15896
def get_active_charge_pd_chip(ec: cros_ec_python.baseclass.CrosEcClass) -> int:
244def get_active_charge_pd_chip(ec: CrosEcClass) -> UInt8:
245    """
246    Get the active charge PD chip.
247    :param ec: The CrOS_EC object.
248    :return: The active charge PD chip.
249    """
250    resp = ec.command(0, EC_CMD_GET_ACTIVE_CHARGE_PD_CHIP, 0, 1)
251    return struct.unpack("<B", resp)[0]

Get the active charge PD chip.

Parameters
  • ec: The CrOS_EC object.
Returns

The active charge PD chip.

EC_CMD_UEFI_APP_MODE: Final = 15897
EC_CMD_UEFI_APP_BTN_STATUS: Final = 15898
EC_CMD_EXPANSION_BAY_STATUS: Final = 15899
EC_CMD_GET_HW_DIAG: Final = 15900
EC_CMD_GET_GPU_SERIAL: Final = 15901
def get_gpu_serial( ec: cros_ec_python.baseclass.CrosEcClass, idx: int = 0) -> dict[int | bool | str]:
265def get_gpu_serial(ec: CrosEcClass, idx: UInt8 = 0) -> dict[UInt8 | bool | str]:
266    """
267    Get the GPU serial. [Untested]
268    :param ec: The CrOS_EC object.
269    :return: The GPU serial as a string.
270    """
271    data = struct.pack("<B", idx)
272    resp = ec.command(0, EC_CMD_GET_GPU_SERIAL, 1, 22, data)
273    unpacked = struct.unpack("<B?20s", resp)
274    return {
275        "idx": unpacked[0],
276        "valid": unpacked[1],
277        "serial": unpacked[2].decode("utf-8").rstrip("\x00"),
278    }

Get the GPU serial. [Untested]

Parameters
  • ec: The CrOS_EC object.
Returns

The GPU serial as a string.

EC_CMD_GET_GPU_PCIE: Final = 15902
class GpuPcieConfig(enum.Enum):
284class GpuPcieConfig(Enum):
285    PCIE_8X1 = 0
286    PCIE_4X1 = 1
287    PCIE_4X2 = 2
PCIE_8X1 = <GpuPcieConfig.PCIE_8X1: 0>
PCIE_4X1 = <GpuPcieConfig.PCIE_4X1: 1>
PCIE_4X2 = <GpuPcieConfig.PCIE_4X2: 2>
class GpuPcieVendor(enum.Enum):
290class GpuPcieVendor(Enum):
291    GPU_AMD_R23 = 0
292    GPU_PCIE_ACCESSORY = 0xFF
GPU_AMD_R23 = <GpuPcieVendor.GPU_AMD_R23: 0>
GPU_PCIE_ACCESSORY = <GpuPcieVendor.GPU_PCIE_ACCESSORY: 255>
def get_gpu_pcie( ec: cros_ec_python.baseclass.CrosEcClass) -> dict[GpuPcieConfig | GpuPcieVendor | int]:
295def get_gpu_pcie(ec: CrosEcClass) -> dict[GpuPcieConfig | GpuPcieVendor | UInt8]:
296    """
297    Get the PCIe configuration of the GPU module. [Untested]
298    :param ec: The CrOS_EC object.
299    :return: The GPU PCIe configuration and vendor.
300    """
301    resp = ec.command(0, EC_CMD_GET_GPU_PCIE, 0, 2)
302    gpu_pcie_config = GpuPcieConfig(resp[0])
303    gpu_vendor = (
304        GpuPcieVendor(resp[1]) if resp[1] in GpuPcieVendor._value2member_map_ else None
305    )
306
307    return {"gpu_pcie_config": gpu_pcie_config, "gpu_vendor": gpu_vendor}

Get the PCIe configuration of the GPU module. [Untested]

Parameters
  • ec: The CrOS_EC object.
Returns

The GPU PCIe configuration and vendor.

EC_CMD_PROGRAM_GPU_EEPROM: Final = 15903
EC_CMD_FP_CONTROL: Final = 15904
def fp_control(ec: cros_ec_python.baseclass.CrosEcClass, enable: bool) -> None:
315def fp_control(ec: CrosEcClass, enable: bool) -> None:
316    """
317    Enable or disable the fingerprint sensor. [Untested]
318    :param ec: The CrOS_EC object.
319    :param enable: True to enable the fingerprint sensor, False to disable it.
320    """
321    data = struct.pack("<?", enable)
322    ec.command(0, EC_CMD_FP_CONTROL, 1, 0, data)

Enable or disable the fingerprint sensor. [Untested]

Parameters
  • ec: The CrOS_EC object.
  • enable: True to enable the fingerprint sensor, False to disable it.
EC_CMD_GET_CUTOFF_STATUS: Final = 15905
EC_CMD_BATTERY_EXTENDER: Final = 15908
def get_battery_extender( ec: cros_ec_python.baseclass.CrosEcClass) -> dict[int | bool | datetime.timedelta]:
331def get_battery_extender(ec: CrosEcClass) -> dict[UInt8 | UInt16 | bool | timedelta]:
332    """
333    Get the battery extender status.
334    :param ec: The CrOS_EC object.
335    :return: The battery extender status. `current_stage` is the current stage of the battery extender (0-2), `trigger_days` is the number of days on charge before reducing the charge limit, `reset_minutes` is the number of minutes off charge before resetting the charge limit, `disable` is True if the battery extender is disabled, `trigger_timedelta` is the timedelta before reducing the charge limit, and `reset_timedelta` is the timedelta before resetting the charge limit.
336    """
337    # 1 for read
338    data = struct.pack("<xxxxBx", 1)
339    resp = ec.command(0, EC_CMD_BATTERY_EXTENDER, 6, 22, data)
340    unpacked = struct.unpack("<BHH?QQ", resp)
341    return {
342        "current_stage": unpacked[0],
343        "trigger_days": unpacked[1],
344        "reset_minutes": unpacked[2],
345        "disable": unpacked[3],
346        "trigger_timedelta": timedelta(microseconds=unpacked[4]),
347        "reset_timedelta": timedelta(microseconds=unpacked[5]),
348    }

Get the battery extender status.

Parameters
  • ec: The CrOS_EC object.
Returns

The battery extender status. current_stage is the current stage of the battery extender (0-2), trigger_days is the number of days on charge before reducing the charge limit, reset_minutes is the number of minutes off charge before resetting the charge limit, disable is True if the battery extender is disabled, trigger_timedelta is the timedelta before reducing the charge limit, and reset_timedelta is the timedelta before resetting the charge limit.

def set_battery_extender( ec: cros_ec_python.baseclass.CrosEcClass, disable: bool, trigger_days: int = 0, reset_minutes: int = 0) -> None:
351def set_battery_extender(
352    ec: CrosEcClass, disable: bool, trigger_days: UInt8 = 0, reset_minutes: UInt16 = 0
353) -> None:
354    """
355    Set the battery extender status.
356    :param ec: The CrOS_EC object.
357    :param disable: True to disable the battery extender, False to enable it.
358    :param trigger_days: The number of days on charge before reducing the charge limit. Values less than 1 or greater than 99 will be ignored.
359    :param reset_minutes: The number of minutes off charge before resetting the charge limit. Values less than 1 or greater than 9999 will be ignored.
360    """
361    # 0 for write
362    data = struct.pack("<?BHBx", disable, trigger_days, reset_minutes, 0)
363    ec.command(0, EC_CMD_BATTERY_EXTENDER, 6, 0, data)

Set the battery extender status.

Parameters
  • ec: The CrOS_EC object.
  • disable: True to disable the battery extender, False to enable it.
  • trigger_days: The number of days on charge before reducing the charge limit. Values less than 1 or greater than 99 will be ignored.
  • reset_minutes: The number of minutes off charge before resetting the charge limit. Values less than 1 or greater than 9999 will be ignored.