Remote Procedure Call (RPC)¶
Introduction¶
The Remote Procedure Call (RPC) component enables communication between distributed components in an embedded system or between a device and a host. It abstracts the underlying transport layer (UART, SPI, USB, etc.) and provides a request-response mechanism for executing functions remotely.
Key features include: - Asynchronous communication via non-blocking queues. - Serialization and deserialization (Marshaling/Unmarshaling) of messages. - Error detection via CRC (Cyclic Redundancy Check). - Support for encryption flags (logic to be implemented by user). - Flexible command dispatching via a service table.
Component Structure¶
The RPC component follows a modular design centered around the ezRpc instance structure. It interacts with the following sub-components:
Communication Interface: Defines the
ezRpcCommInterfacestruct withtransmitandreceivefunction pointers. This adapter pattern allows the RPC component to run on any stream-oriented physical interface.message Queues: Uses
ezQueueinstances for buffering: -tx_msg_queue: valid RPC messages ready to be sent to the physical link. -rx_msg_queue: valid RPC messages received from the link, waiting to be processed by simple handlers.Marshaler (Serializer): Constructs the RPC frame (Header + Payload + CRC) from parameters and pushes it to the transmit queue.
Unmarshaler (Deserializer): A state machine that processes the incoming byte stream from the receive interface, validates the framing, and reconstructs the message.
Dispatcher: Locates the appropriate callback function from the
ezRpcCommandEntrytable based on the Command ID and executes it.
Component Behavior¶
The component operates in a polling mode or event-driven mode usually triggered via the ezRPC_Run function.
Initialization¶
The user must initialize the instance with memory for queues and a command table mapping IDs to handler functions. The communication interface (transmit/receive functions) and CRC handler must be registered before starting.
Runtime Loop (ezRPC_Run)¶
This function creates the heartbeat of the component:
1. Receive Phase: Reads bytes from the receive interface and feeds them into the Unmarshaler state machine.
2. Process Phase: Checks the rx_msg_queue. If a message is complete and valid, it looks up the command ID and triggers the registered callback.
3. Transmit Phase: Checks the tx_msg_queue. If data is pending, it calls the transmit interface to send data to the hardware.
4. Timeout Check: Monitors pending requests for timeouts (if the record tracking is active).
Unmarshaling State Machine¶
The deserializer parses the incoming stream through the following states:
STATE_SYNC: Waiting for the synchronization bytes (0xCAFE).STATE_UUID: Reading the 2-byte unique message ID.Header Parsing: -
STATE_MSG_TYPE: Request, Response, or Event. -STATE_ENCRYPT_FLAG: Encryption status. -STATE_CMD_ID: The command identifier. -STATE_PAYLOAD_SIZE: The length of the data payload.STATE_PAYLOAD: Reading the payload data byte-by-byte.STATE_CRC: verifying the checksum (if enabled).
Data Flow¶
Receive Path¶
flowchart TD
A[Physical Link] --> B[ezRpcCommInterface.receive]
B --> C[Unmarshaler State Machine]
C --> D[Valid Check<br/>CRC/Header]
D --> E[rx_msg_queue]
E --> F[Dispatcher]
F --> G[Command Handler]
Transmit Path¶
flowchart TD
A[User App] --> B[ezRPC_CreateRpcRequest/Response]
B --> C[Marshaler]
C --> D[tx_msg_queue]
D --> E[ezRpcCommInterface.transmit]
E --> F[Physical Link]
Component Data Types¶
RPC Message Header Layout¶
Every message starts with a fixed-size header followed by the payload.
Field |
Size |
Description |
|---|---|---|
Sync Bytes |
2 Bytes |
Fixed value |
UUID |
2 Bytes |
Unique ID to match requests with responses. |
Type |
1 Byte |
|
Encrypt |
1 Byte |
Flag indicating payload encryption. |
Cmd ID |
2 Bytes |
Identifier matching the function to execute. |
Payload Size |
4 Bytes |
Size of the data following the header. |
Total Header Size: 12 Bytes.
CRC and Payload¶
If CRC is enabled, a CRC checksum (size defined by handler, typically 2 or 4 bytes) is appended immediately after the payload.