FSCI: Framework Serial Communication Interface
Overview
The Framework Serial Communication Interface (FSCI) is both a software module and a protocol that allows monitoring and extensive testing of the protocol layers. It also allows separation of the protocol stack between two protocol layers in a two processing entities setup, the host processor (typically running the upper layers of a protocol stack) and the Black Box application (typically containing the lower layers of the stack, serving as a modem). The Test Tool software is an example of a host processor, which can interact with FSCI Black Boxes at various layers. In this setup, the user can run numerous commands to test the Black Box application services and interfaces.
The FSCI enables common service features for each device enables monitoring of specific interfaces and API calls. Additionally, the FSCI injects or calls specific events and commands into the interfaces between layers.
An entity which needs to be interfaced to the FSCI module can use the API to register opcodes to specific interfaces. After doing so, any packet coming from that interface with the same opcode triggers a callback execution. Two or more entities cannot register the same opcode on the same interface, but they can do so on different interfaces. For example, two MAC instances can register the same opcodes, one over UARTA, and the other over UARTB. This way, Test Tool can communicate with each MAC layer over two UART interfaces.
The FSCI module executes either in the context of the Serial Manager task or owns its dedicated task if the compilation Macro gFsciUseDedicatedTask_c is set to 1.
FSCI packet structure
The FSCI module sends and receives messages as shown in the figure below. This structure is not specific to a serial interface and is designed to offer the best communication reliability. The Black Box device expects messages in little-endian format. It also responds with messages in little-endian format.
Below is an illustration of the FSCI packet structure when a virtual interface is used instead :
NOTE : When virtual interfaces are used, the first checksum is decremented with the ID of the interface. The second checksum is used for error detection.
constant definition
The following Macro configurs the FSCI module
#define gFsciIncluded_c 0 /* Enable/Disable FSCI module */
#define gFsciUseDedicatedTask_c 1 /* Enable Fsci task to avoid recursivity in Fsci module (Misra compliant) */
#define gFsciMaxOpGroups_c 8
#define gFsciMaxInterfaces_c 1
#define gFsciMaxVirtualInterfaces_c 0
#define gFsciMaxPayloadLen_c 245 /* bytes */
#define gFsciTimestampSize_c 0 /* bytes */
#define gFsciLenHas2Bytes_c 0 /* boolean */
#define gFsciUseEscapeSeq_c 0 /* boolean */
#define gFsciUseFmtLog_c 0 /* boolean */
#define gFsciUseFileDataLog_c 0 /* boolean */
#define gFsciLoggingInterface_c 1 /* [0..gFsciMaxInterfaces_c) */
#define gFsciHostMacSupport_c 0 /* Host support at MAC layer */
The following provides the OpGroups values reserved by MAC, application, and FSCI.
FSCI Host
FSCI Host is a functionality that allows separation at a certain stack layer between two entities, usually two boards running separate layers of a stack.
Support is provided for functionality at the MAC layer, for example, MAC/PHY layers of a stack are running as a Black Box on a board, and MAC higher layers are running on another. The higher layers send and receive serial commands to and from the MAC Black Box using the FSCI set of operation codes and groups.
The protocol of communication between the two is the same. The current level of support is provided for:
FSCI_MsgResetCPUReqFunc – sends a CPU reset request to black box
FSCI_MsgWriteExtendedAdrReqFunc – configures MAC extended address to the Black Box
FSCI_MsgReadExtendedAdrReqFunc – N/A
The approach on the Host interfacing a Black Box using synchronous primitives is by default the polling of the FSCI_receivePacket function, until the response is received from the Black Box. The calling task polls whenever the task is being scheduled. This is required because a stack synchronous primitive requires that the response of that request is available in the context of the caller right after the SAP call has been executed.
The other option, available for RTOS environments, is using an event mechanism. The calling task blocks waiting for the event that is sent from the Serial Manager task when the response is available from the Black Box. This option is disabled by default. The disadvantage of this option is that the primitive cannot be received from another Black Box through a serial interface because the blocked task is the Serial Manager task, which reaches a deadlock as cannot be released again.
FSCI ACK
ACK transmission is enabled through the gFsciTxAck_c macro definition. Each FSCI valid packet received triggers an FSCI ACK packet transmission on the same FSCI interface that the packet was received on. The serial write call is performed synchronously to send the ACK packet before any other FSCI packet. Only then the registered handler is called to process the received packet. The ACK is represented by the gFSCI_CnfOpcodeGroup_c and mFsciMsgAck_c Opcode. An additional byte is left empty in the payload so that it can be used optionally as a packet identifier to correlate packets and ACKs. ACK reception is the other component that is enabled through gFsciRxAck_c. The behavior is such that every FSCI packet sent through a serial interface triggers an FSCI ACK packet reception on the same interface after the packet is sent. If an ACK packet is received, the transmission is considered successful. Otherwise, the packet is resent a number of times. The ACK wait period is configurable through mFsciRxAckTimeoutMs_c and the number of transmission retries through mFsciTxRetryCnt_c. The ACK mechanism described above can also be coupled with a FSCI packet reception timeout enabled through gFsciRxTimeout_c and configurable through mFsciRxRestartTimeoutMs_c. Whenever there are no more bytes to be read from a serial interface, a timeout is configured at the predefined value if no other bytes are received. If new bytes are received, the timer is stopped and eventually canceled at successful reception. However, if, for any reason, the timeout is triggered, the FSCI module considers that the current packet is invalid, drops it, and searches for a new start marker.
FSCI usage example
Detailed data types and APIs are described in ConnFWK API documentation.
Initialization
/* Configure the number of interfaces and virtual interfaces used */
#define gFsciMaxInterfaces_c 4
#define gFsciMaxVirtualInterfaces_c 2
….
/* Define the interfaces used */
static const gFsciSerialConfig_t myFsciSerials[] = {
/* Baudrate, interface type, channel No, virtual interface */ {gUARTBaudRate115200_c, gSerialMgrUart_c, 1, 0}, {gUARTBaudRate115200_c, gSerialMgrUart_c, 1, 1}, {0 , gSerialMgrIICSlave_c, 1, 0}, {0 , gSerialMgrUSB_c, 0, 0},
};
….
/* Call init function to open all interfaces */
FSCI_Init( (void*)mFsciSerials );
Registering operation groups
myOpGroup = 0x12; // Operation Group used
myParam = NULL; // pointer to a parameter to be passed to the handler function (myHandlerFunc)
myInterface = 1; // index of entry from myFsciSerials
…
FSCI_RegisterOpGroup( myOpGroup, gFsciMonitorMode_c, myHandlerFunc, myParam, myInterface );
Implementing handler function
void fsciMcpsReqHandler(void *pData, void* param, uint32_t interfaceId)
{
clientPacket_t *pClientPacket = ((clientPacket_t*)pData);
fsciLen_t myNewLen;
switch( pClientPacket->structured.header.opCode )
{
case 0x01:
{
/* Reuse packet received over the serial interface The OpCode remains the same. The length of the response must be <= that the length of the received packet */
pClientPacket->structured.header.opGroup = myResponseOpGroup;/* Process packet */
…
pClientPacket->structured.header. len = myNewLen;
FSCI_transmitFormatedPacket(pClientPacket, interfaceId);
return;
}
case 0x02:
{
/* Alocate a new message for the response. The received packet is Freed */
clientPacket_t *pResponsePkt = MEM_BufferAlloc( sizeof(clientPacketHdr_t) + myPayloadSize_d + sizeof(uint8_t) // CRC);
if(pResponsePkt)
{
/* Process received data and fill the response packet */ …
pResponsePkt->structured.header. len = myPayloadSize_d;
FSCI_transmitFormatedPacket(pClientPacket, interfaceId);
}
break;
}
default:
MEM_BufferFree( pData );
FSCI_Error( gFsciUnknownOpcode_c, interfaceId );
return;
}
/* Free message received over the serial interface */
MEM_BufferFree( pData );
}