- Half-Duplex
- Memory-Based Master-Slave Communication Protocol for Microcontrollers
The GenericMaster class provides a hardware-agnostic implementation of the master-side logic for the EmbeddedComm protocol. It handles packet construction, checksum calculation, and protocol flow control, while leaving the actual byte transmission to derived classes.
template <typename slaveInfo>
class GenericMasterslaveInfo: A user-defined type containing information required to identify and connect to a specific slave (e.g., I2C address, CS pin number, SPI handle). This type is passed by reference to all methods.
Constructs a new GenericMaster object.
Writes bytes to the slave's memory starting at a specific address.
StatusValue write(
slaveInfo &sinfo,
uint32_t memoryAddress,
uint8_t *data,
uint32_t writeSize
);Parameters:
sinfo: Reference to the slave configuration object.memoryAddress: The 32-bit start address in the slave's memory map to write to.data: Pointer to the buffer containing the data to send.writeSize: Number of bytes to write.
Returns:
StatusValue: The status byte returned by the slave (e.g.,Ok,ErrDataCorrupted,ErrMemoryOutOfRange). Returns0if the low-level transport write/read failed.
Constructs a protocol packet containing the data length, target address, payload, and checksum. It transmits this packet using writeBytes() and immediately reads back the status byte from the slave to confirm success.
Reads bytes from the slave's memory starting at a specific address.
StatusValue read(
slaveInfo &sinfo,
uint32_t memoryAddress,
uint8_t *buffer,
uint32_t readSize
);Parameters:
sinfo: Reference to the slave configuration object.memoryAddress: The 32-bit start address in the slave's memory to read from.buffer: Pointer to the destination buffer where received data will be stored. Must be at leastreadSizebytes large.readSize: Number of bytes to read.
Returns:
StatusValue: status received from slave if the read was successful and checksums matched. ReturnsErrDataCorruptedif the checksum validation failed on the master side. Returns0if low-level transport failed.
Description: Sends a read request header (length + address) to the slave. It then reads the requested data bytes, followed by a checksum byte and a status byte. The master validates the integrity of the received data by recalculating the checksum.
Reads the current status of the slave without performing a significant data transfer.
inline StatusValue readStatus(slaveInfo &sinfo);Parameters:
sinfo: Reference to the slave configuration object.
Returns:
StatusValue: The current status code of the slave.
These pure virtual methods must be implemented by any child class to define the specific hardware transport layer (e.g., I2C, SPI, UART).
Transmits raw bytes to the physical medium.
virtual int writeBytes(
slaveInfo &sinfo,
uint8_t *bytes,
uint32_t numberOfBytes
) = 0;Returns:
- Should return
0(or positive) on success, and a negative value on failure.
Receives raw bytes from the physical medium.
virtual int readBytes(
slaveInfo &sinfo,
uint8_t *bytes,
uint32_t numberOfBytes
) = 0;Returns:
- Should return
0(or positive) on success, and a negative value on failure.
The GenericSlave class implements the slave-side logic for the EmbeddedComm protocol. It is hardware-agnostic and designed to operate within interrupt service routines (ISRs) for byte-by-byte processing, while offloading heavier tasks (like callbacks and memory restoration) to the main loop.
class GenericSlaveConstructs a new GenericSlave object.
Assigns the memory buffer that acts as the slave's register map or storage.
void initialize(
uint8_t *memory,
uint32_t memorySize
);Parameters:
memory: Pointer to the byte array that will serve as the device's accessible memory.memorySize: The size of the memory buffer in bytes.
Description: Configures the main storage area. The master will read from and write directly to this buffer based on the protocol commands.
Enables the transactional backup feature to prevent data corruption during failed writes.
void enableMemBackups(
uint8_t *backupBuffer,
uint32_t backupBufferSize
);Parameters:
backupBuffer: Pointer to a separate buffer used to temporarily store data before a write is finalized.backupBufferSize: The size of the backup buffer in bytes.
Description:
When enabled, the slave saves the current state of memory to backupBuffer before applying new writes from the master. If the transaction fails (checksum mismatch), the original data is automatically restored during the process() call. This limits the maximum writable data length per transaction to backupBufferSize.
Processes a single byte received from the master.
void writeHandler(uint8_t receivedByte);Parameters:
receivedByte: The byte received from the hardware interface (e.g., I2C RX register).
Description: This function drives the internal state machine. It handles the protocol phases: receiving data length, memory address, payload, and checksum verification. It is typically called inside a hardware Receive Interrupt.
Retrieves the next byte to send to the master.
uint8_t readHandler();Returns:
uint8_t: The byte to be transmitted to the hardware interface (e.g., I2C TX register).
Description: Calculates the response byte based on the current protocol state. This may be requested data from memory, the calculated checksum, or the status byte. It is typically called inside a hardware Transmit Request Interrupt.
Registers a callback function to be executed when a specific memory address is modified by the master.
bool addMemoryChangeCallback(
uint32_t memoryAddress,
CallbackFunction callback
);Parameters:
memoryAddress: The index in the memory buffer to monitor.callback: Function pointer (void(*)()) to execute when the value atmemoryAddresschanges.
Returns:
trueif the callback was successfully registered.falseif the maximum number of callbacks (defined byMAX_MEMORY_CHANGE_CALLBACKS, default 10) has been reached.
Performs non-time-critical maintenance tasks.
void process();Description: This method must be called frequently from the main application loop. It handles tasks that are too slow for an interrupt context, such as:
- Restoring memory from the backup buffer if a transaction was corrupted.
- Executing registered callbacks if memory values were changed by the master.
- Clearing the
Busystatus flag once these tasks are complete.
The EmbeddedComm protocol is a binary, master-slave communication standard designed for reliable memory access over byte-oriented streams (I2C, SPI, UART). It supports data integrity checks via checksums and transactional atomic operations using status flags.
Byte Order: Little Endian (LSB first)
| Type | Size | Description |
|---|---|---|
| Address | 4 Bytes | 32-bit Memory Address. |
| Length | 4 Bytes | 32-bit Data Length. Bit 31 (MSB): Read Flag (1 = Read, 0 = Write). |
| Checksum | 1 Byte | 8-bit Checksum (Algorithm defined by implementation). |
| Status | 1 Byte | 8-bit Status Register (Bitmap). |
Length field visualization:
31 0
+---+---------------------------------------------------------+
| R | Data Length |
+---+---------------------------------------------------------+
^ ^
| |
+-- Read Flag +-- Actual Length
1: Master Read
0: Master Write
Used to write
Sequence:
-
Master sends Header:
-
Data Length. Bit 31 is 0 (ReadFlag)(4 Bytes) -
Memory Address(4 Bytes)
-
-
Master sends Payload:
-
Data($N$ Bytes)
-
-
Master sends Checksum:
-
Checksum(1 Byte) - Calculated over [Length + Address + Data].
-
-
Slave responds:
-
Status(1 Byte) - ReturnsOk(0x80) or Error Flags.
-
Master >>> [Length. Bit 31 is 0. (4B)] [Address (4B)] [Data (N Bytes)] [Checksum (1B)] >>> Slave
Master <<< [Status (1B)] <<< Slave
Used to read
Sequence:
-
Master sends Header:
-
Read Size. Bit 31 is 1 (ReadFlag)(4 Bytes) -
Memory Address(4 Bytes)
-
-
Slave sends Payload:
-
Data($N$ Bytes)
-
-
Slave sends Checksum:
-
Checksum(1 Byte) - Calculated over [Header + Data].
-
-
Slave sends Status:
-
Status(1 Byte) - ReturnsOk(0x80) or Error Flags.
-
Master >>> [Length. Bit 31 is 1. (4B)] [Address (4B)] >>> Slave
Master <<< [Data (N Bytes)] [Checksum (1B)] [Status (1B)] <<< Slave
The Status Byte indicates the result of the last operation. It is a bitmask where 0x80 represents Success, and lower bits represent specific errors.
Status Code Definitions:
| Name | Value (Hex) | Value (Dec) | Description |
|---|---|---|---|
| NotUsed | 0x00 |
0 | Default value, indicates initialization or failed low-level read. |
| ErrMemoryOutOfRange | 0x01 |
1 | Address falls outside valid memory range. |
| ErrBackupBufferOverflow | 0x02 |
2 | Write size exceeds the enabled backup buffer capacity. |
| ErrInvalidRead | 0x04 |
4 | Protocol violation: Read requested without valid header. |
| ErrInvalidWrite | 0x08 |
8 | Protocol violation: Write attempted during read phase. |
| ErrDataCorrupted | 0x10 |
16 | Checksum mismatch. |
| Busy | 0x20 |
32 | Slave is processing previous request or callback. |
| Ok | 0x80 |
128 | Success. Operation completed without errors. |