EC service is where the business logic glues the HAL + common EC functional traits + EC peripheral driver together.
Hardware specific HAL leveraging Rust Async framework
- Must implement embedded-hal traits to allow a generic hardware agnostic interface
- Desire is for HALs to be open-sourced and upstreamed to Embassy main repo
- Plan to partner with MCU vendor to support more MCU in the future
For example, embassy-imxrt
classDiagram
class embassy-imxrt["embassy-imxrt I2C master HAL"]
class embedded-hal["embedded-hal I2C master traits"]
<<interface>> embedded-hal
embedded-hal <|-- embassy-imxrt
embedded-hal: +read()
embedded-hal: +write()
embassy-imxrt: +read()
embassy-imxrt: +write()
There are sets of generic Rust traits the define an EC functional subsystem like thermal, USB PD, fan, battery. This abstraction serves to abstract the underlying HW design away from the business logic.
For example, embedded-sensor
classDiagram
embedded-sensor: +temperature()
<<interface>> embedded-sensor
There are MCU platform agnostic Rust drivers for specific HW parts connected to the EC like TMP108 temp sensor.
- Depending on embedded-hal interface so it is talking to a generic HW interface, not tying to any specific MCU platform
- Implements a EC function platform abstraction traits like
embedded-sensor
,embedded-battery
,embedded-fan
- Plan to partner with vendor to open-source these drivers
For example, tmp108
classDiagram
embedded-sensor <|-- TMP108
embedded-sensor: +temperature()
<<interface>> embedded-sensor
TMP108 --> embedded-hal
TMP108: +temperature()
class embassy-imxrt["embassy-imxrt I2C master HAL"]
class embedded-hal["embedded-hal I2C master traits"]
<<interface>> embedded-hal
embedded-hal <|-- embassy-imxrt
embedded-hal: +read()
embedded-hal: +write()
embassy-imxrt: +read()
embassy-imxrt: +write()
EC service houses the business logic that glues the EC peripheral Rust driver + EC subsystem platform abstraction + MC platform HAL together/.
- embedded-services repo
- embedded-services library crate
- service traits
- intrusive-list
- transport/router
- embedded-services library crate
- power-button-service
- library crate
- hid-service
- library crate
- cfu-service
- library crate
- host traits
- client traits
- library crate
This houses common EC service utilities to build a service. It includes:
- instrusive-list that allows dynamic number of subscribers and publishers for a service
- transport (IPC) logic that allows EC services to talk to each other
Protocol agnostric transport allowing dynamic number of endpoints to send and receive message. It makes use of the instrusive list to allow dynamic number of endpoints corresponding to each endpoint ID.
erDiagram
service_a ||..|| endpoint_a :contains
endpoint_a ||..|| transport : send_message
transport ||--|| endpoint_b : route
service_b ||..|| endpoint_b :contains
transport {
list endpoint_a
list endpoint_b
list endpoint_c
}
Message are opaque pointer to a Rust object, so it literally can be anything.
Services will be separate crates in this repo. Each service crate will be implementation of the interfaces for a functional area.
The service itself should be hardware/platform agnostic and contains the application logic for EC functionality.
For example, temperature_service
classDiagram
temperature-service --> embedded-hal
temperature-service --> embedded-sensor
embedded-sensor <|-- TMP108
embedded-sensor: +temperature()
<<interface>> embedded-sensor
TMP108 --> embedded-hal
TMP108: +temperature()
class embassy-imxrt["embassy-imxrt I2C master HAL"]
class embedded-hal["embedded-hal I2C master traits"]
<<interface>> embedded-hal
embedded-hal <|-- embassy-imxrt
embedded-hal: +read()
embedded-hal: +write()
embassy-imxrt: +read()
embassy-imxrt: +write()
HID over I2c transport
classDiagram
keyboard-service --> embedded-keyboard-rs
keyboard-service --> embedded-hid
touchpad-service --> passthrough-service
passthrough-service --> embedded-hid
passthrough-service --> i2c-host-service
passthrough-service --> i2c-device-service
-
keyboard-service
- embedded-keyboard-rs
- embedded-hid
-
touchpad-service
- passthrough-service
- embedded-hid
- i2c-host-service
- i2c-device-service
- passthrough-service
Service to manage a power button
Provide eSPI transport, similar to traditional x86 EC, a memory map table of information will be maintained.
erDiagram
p[MemoryTable] {
u32 battery_status
u32 battery_charge_threshold
u32 field
}
sequenceDiagram
battery_service->>espi_service: Update battery status
host-->>espi_service: Get battery status
espi_service-->>host: Provide cached battery status
battery_service->>espi_service: Update battery status
- service register with the espi service for an entry in the table
- service periodically update their table entries by sending a message throught transport to espi_service
- host eSPI peripheral channel read always gets the cached value
sequenceDiagram
host-->>espi_service: Set battery charge threshold
espi_service->>battery_service: Set battery charge threshold
battery_service-->>charger: Set battery charge threshold
battery_service->>espi_service: Done setting battery charge threshold
espi_service-->>host: Battery charge threshold updated
- service register with the espi service for an entry in the table
- host eSPI peripherla channel write opertions triggers espi_service to send message to battery_service to update the charge threshold
- battery service performs the bus operation to update the charge threshold on the charge
- after bus operation is done, battery service notifies espi_service
- espi_service updates the memory table and optionally can notify the host
classDiagram
nvm-service --> embedded-storage
embedded-storage <|-- FlexSPI
embedded-storage <|-- SPI
<<interface>> embedded-storage
class FlexSPI["embassy-imxrt FlexSPI HAL"]
class SPI["embassy-imxrt SPI HAL"]
- nvm-service
- embedded-nvm (generic, would prefer to have filesystem features like error checking and file structures)
- embedded-storage
- FlexSPI
- SPI
- embedded-storage
- embedded-nvm (generic, would prefer to have filesystem features like error checking and file structures)
classDiagram
rtc-service --> embedded-rtc
embedded-rtc <|-- RTC
<<interface>> embedded-rtc
class RTC["embassy-imxrt RTC HAL"]
- rtc-service
- embedded-rtc
- embassy-imxrt RTC HAL
- embedded-rtc
classDiagram
thermal-service --> embedded-fan
thermal-service --> embedded-sensor
embedded-sensor <|-- sensor-driver
embedded-fan <|-- fan-driver
<<interface>> embedded-fan
<<interface>> embedded-sensor
sensor-driver --> embedded-hal
fan-driver --> embedded-timer
<<interface>> embedded-hal
<<interface>> embedded-timer
- thermal-service
- embedded-sensor
- product specific sensor driver
- embedded-fan
- product specific fan driver
- embedded-sensor
classDiagram
cfu-service --> embedded-cfu
cfu-service --> embedded-hal
cfu-service --> embedded-storage
- cfu-service
- embedded-cfu
- embedded-hal
- embedded-storage
classDiagram
battery-service --> embedded-battery
battery-service --> embedded-charger
- battery-service
- embedded-battery
- embedded-charger
classDiagram
usb-c-service --> embedded-usb-pd
- usb-c-service
- embedded-usb-pd
At the top-level, a EC is an aggregate of service.
Sets of services can be grouped into subsystem. For instance, thermal subsystem will consist of temperature-service + fan-service + battery-service + debug-service + host-comm-service. The service talks to each other through the transport (IPC) layer. An EC service can also be shared between different subsystems. For instance, debug-service will subcribe to debug messages from other services.
async fn (spawner: Spawner) {
//initialize HW peripheral and system level managemetn
spawn(services(periphal, configuration))
...
}