The Hexabitz communication backend is based on a custom messaging protocol, documented here. Each module port is configured in messaging mode by default. Data from all ports is continuously received in an array called Rx_Data (Rx_Data[port_index]), where port_index = port_number -1, and sent to a state machine built primarily into a UART receive callback that is responsible for sorting the received bytes from all ports into either CLI task or arrays related to BOS messaging.
We use an array called MSG_Buffer to store the BOS messages received from each port (here we should mention that each port has its own copy of MSG_Buffer array), and we use the array Process_Message_Buffer to organize a queue for processing messages received from all ports in BackEndTask().
Figure(1): State Machine
The state machine works as follows:
- Forwarding data to the CLI task:
If the port is FREE and receives the character ‘\r’ (0x0D), this port becomes a PcPort, and if another port was previously in PcPort state, its state is changed to FREE state, and the CLI session continues (or starts for the first time) with this port number as PcPort.
- Forwarding data to message buffers:
If the port is free and receives an ‘H’ character (0x48), we’re in H- STATE, and then if the port receives any character other than a ‘Z’ character (0x7A), it returns to the FREE state, otherwise we’re in Z- STATE and ready to receive the next length byte.
After receiving the length byte, the state of this port changes to MSG _STATE and remains in this state until we receive (X + 1) bytes (the message bytes + the CRC value of this message), then the state of this port returns to FREE-STATE.
The backend task (BackEndTask()) runs every RTOS cycle and checks the Process_Message_Buffer to detect if a message is ready for processing, and if there is any, the backend task calculates the CRC8 and compares it to the CRC contained in that message. If the message is valid (based on CRC8 comparision), it is forwarded to one of the module messaging tasks (PxMessagingTask()).
Each module port has its own messaging task (PxMessagingTask()), which is activated by the RTOS scheduler when a valid message is received in the backend task. The message is copied to the cMessage array for processing. Within the port messaging task, the message header is parsed, and if the message code is a BOS message, the payload is parsed and processed by the appropriate instructions, and then the task passes control to the scheduler. If the message code is a module message, it is routed to module messaging parser (Module_MessagingTask()), which executes the appropriate instructions and returns to the port messaging task to yield control to the scheduler. It should be noted that although the state machine transmits incoming messages simultaneously, the port messaging tasks can only be executed serially – one in each RTOS cycle.
Figure(2): Hexabitz Backend Messaging Receive Path
Messaging Workflow
- The source module builds a message in the form of the BOS messaging protocol.
- The source sends the message over the UART port.
- The destination receives the entire message in the state machine.
- The backend task parses the messages (if there’s any) and notifies the corresponding messaging task when a message is received correctly.
- In the messaging task (PxMessagingTask), the messages are parsed to read the source, destination, and code bytes. The length of the received message is compared with the length byte.
- If it is a transit message, it is forwarded directly. If it is a broadcast message, it is sent and then processed.
- The messages are processed according to their message codes.
- The response to the message and the TRACE flags are checked to generate the appropriate response.
- If the message is long, the longMessage flag is enabled and can be used to concatenate successive payloads before processing.