Hello jcpacheco,
maybe you or someone else could help me with my little project. I want to control the KW41Z Chip, which is on the FRDM-KW41Z board, from a host system via the UART0 on the PinHeaders.
After some research i found some documentation in the SDK doc-folder, like the Kinetis FSCI Host Application Programming Interface.pdf or the Kinetis Thread Host Control Interface Reference Manual.pdf. But all these examples using host sytems, which are operating systems like Linux, Windows or OpenWRT. What i want to do is to control the KW41Z from another MCU like an STM32 via the UART lines. There could also running a FreeRTOS on the STM32.
Is this not possible right now? Are there plans to do this in the future? Or did i research badly?
Thanks a lot!
Best regards,
Steffen
Hi Steffen,
Consider also the following steps in building your host application using THCI:
1. Start from generic function for UART communcation :
- serial_send_data (uint8_t *pBuffer, uint16_t bufferLen) - to send data via UART interface
- serial_receive_data(uint8_t *pBuffer, uint16_t bufferLen) - to receive data via UART interface
2. define some internal structures:
/* Format of packets exchanged between the external client and THCI. */
typedef struct clientPacketHdr_tag
{
uint8_t startMarker;
uint8_t opGroup;
uint8_t opCode;
uint8_t len[2]; /* Actual length of payload[] */
} clientPacketHdr_t;
typedef struct clientPacketStructured_tag
{
clientPacketHdr_t header;
uint8_t payload[gTHCIMaxPayload_c];
uint8_t checksum;
} clientPacketStructured_t;
/* defines the working packet type */
typedef union clientPacket_tag
{
uint8_t raw[sizeof(clientPacketStructured_t)]; /* The entire packet as unformatted data. */
clientPacketStructured_t structured; /* The packet as header + payload. */
} clientPacket_t;
/* define command status */
typedef enum{
eFsciSuccess_c = 0x00,
...
eFsciTooBig_c = 0xFE,
eFsciError_c = 0xFF /* General catch all error. */
} fsci_Status_t;
#define gTHCIMaxPayload_c 512
3. define THCI handlers:
/* function used to check if the received packet is valid or not */
fsci_packetStatus_t THCI_CheckPacket( clientPacket_t *pData, uint16_t bytes )
{
uint8_t checksum = 0;
uint16_t len;
if((!pData) ||
(pData->raw[0] != gFsciStartMarker_c))
{
return ePacketInvalid_c;
}
if ( bytes < sizeof(clientPacketHdr_t) )
{
return ePacketToShort_c; /* Too short to be valid. */
}
if ( bytes >= sizeof(clientPacket_t) )
{
return eFramingError_c;
}
/* The packet's len field does not count the STX, the opcode group, the */
/* opcode, the len field, or the checksum. */
len = pData->structured.header.len[0] + (pData->structured.header.len[1]<<8);
/* If the length appears to be too long, it might be because the external */
/* client is sending a packet that is too long, or it might be that we're */
/* out of sync with the external client. Assume we're out of sync. */
if ( len > sizeof(pData->structured.payload) )
{
return eFramingError_c;
}
if ( bytes < len + sizeof(clientPacketHdr_t) + sizeof(checksum) )
{
return ePacketToShort_c;
}
/* If the length looks right, make sure that the checksum is correct. */
if( bytes == len + sizeof(clientPacketHdr_t) + sizeof(checksum) )
{
checksum = THCI_ComputeChecksum(pData->raw+1, len + sizeof(clientPacketHdr_t)-1);
if( checksum == pData->structured.payload[len] )
{
return ePacketValid_c;
}
}
return eFramingError_c;
}
/* function used to manage request/response commands */
void THCI_ProcessRxPkt (clientPacket_t* pPacket)
{
fsci_Status_t status;
if(!pPacket){
return;
}
/* Process only FSCI confirms */
if( pPacket->structured.header.opGroup == gFSCI_CnfOpcodeGroup_c )
{
/* receive a confirm for a request.
* At this moment the requests are send from RadioUpgrade module */
//TBD add your handler here
switch(pPacket->structured.header.opCode)
{
case ...
default:
break;
}
}
else if(pPacket->structured.header.opGroup == gFSCI_ReqOpcodeGroup_c)
{
/* receive a request */
//TBD - add your handler here
switch(pPacket->structured.header.opCode)
{
case ...
default:
break;
}
}
}
/* function used to send formatted packets */
void THCI_TransmitFormatedPacket( clientPacket_t *pPacket )
{
uint32_t size;
uint8_t checksum;
uint16_t packetLen = pPacket->structured.header.len[0] + (pPacket->structured.header.len[1]<<8);
pPacket->structured.header.startMarker = gFsciStartMarker_c;
size = sizeof(clientPacketHdr_t) + packetLen + 1 /* CRC */;
/* Compute Checksum */
checksum = THCI_ComputeChecksum( pPacket->raw+1, size - 2);
pPacket->structured.payload[packetLen] = checksum;
/* send message to the serial interface */
serial_send_data(pPacket->raw, size);
}
/* compute checksum */
static uint8_t THCI_ComputeChecksum( uint8_t *pBuffer, uint16_t size )
{
uint16_t index;
uint8_t checksum = 0;
for ( index = 0; index < size; index++ )
{
checksum ^= pBuffer[index];
}
return checksum;
}
4. Update serial receive function to handle THCI packets
void serial_receive_data(uint8_t *pBuffer, uint16_t bufferLen)
{
...
if(THCI_CheckPacket((clientPacket_t *)buffer, bufferLen) == ePacketValid_c)
{
/* THCI Packet received */
THCI_ProcessRxPkt((clientPacket_t *)rx_buf->buf);
}
...
}
Let me know if you need more details,
Ovidiu
hello,
please can i have more details on this host application that you proposed? ovidiu-alexandruusturoi
Can you provide more details on your project?
If you look on our SDK, are two possibilities to communicate via serial line:
1. Shell;
2. THCI (Thread Host controller interface); For more details, please check the documentation folder from the SDK.
Usually, THCI is used for communicating with an external application processor. In the SDK, we have implemented the host SDK in the :. ..\sdk\SDK_2.2.1_FRDM-KW41Z\tools\wireless\host_sdk. There is a python and C language implementation for this protocol, mainly defined for the Linux environment.
What I tried to explain in https://community.nxp.com/thread/464273#comment-963478 is a simple example of how to validate a THCI packet reception and how to transmit. As required pins are only the UART_TX/UART_RX pins are required.
Regards.
Ovidiu
if we want to use THCI, can we use the requests seen in test tool application? like THR_FactoryReset.Request or should we use THCI_FactoryResetReq?
i can't see which one will be suitable for my project between shell and thci.
please can you help me?
As you noted, in our SDK are 2 possibilities for serial communication:
- shell
- THCI.
Shell is let say human-readable format. All the commands are listed using the help command
THCI has been designed for communication with a host processor. The format of the command is containing an opgroup, messageType, CRC... This is what I specified in this comment: https://community.nxp.com/thread/464273#comment-962988
If you want to use THCI, in the project you should enable the following:
#define THREAD_USE_SHELL 0
#define THREAD_USE_THCI 1
All of the THCI commands can be sent from TestTool (https://www.nxp.com/webapp/sps/download/license.jsp?colCode=TESTTOOL_SETUP&appType=file1&location=nu...).
In this case, the TestTool is used to simulate an application processor.
For example, the THCI Factory Reset Command:
As you can see, the format of the command is: 0x02, 0xCE, 0x1F, 0x00, 0x00, 0xD1
where you should map this command to:
STX = 0x02
Opcode Group = 0xCE - used to identify a Thread IP Stack command
Message Type = 0x1F - used to identify the gTHCI_ThrFactoryReset_c command
Lenght = 0x0000;
No Payload
CRC = 0xD1;
Considering the implementation from this comment:https://community.nxp.com/thread/464273#comment-963478
you should use something like:
uint8_t APP_SendResetToFactoryDefault(void)
{
clientPacketHdrr_t header = {
.startMarker = 0x02,
.opGroup = 0xCE,
.opCode = 0x1f,
.len = {0x00, 0x00}
};
clientPacket_t resetToFactoryDefaultCmd;
/* copy the header */
memcpy(&resetToFactoryDefaultCmd.structured.header, &header, sizeof(header));
/* copy the payload if required */
//memcpy(&resetToFactoryDefaultCmd.structured.payload, &payload, payloadLen);
/* call the function to send data via the serial - this function will add the CRC and use the right format for the command*/
THCI_TransmitFormatedPacket(&resetToFactoryDefaultCmd);
}
Let me know if you need more details,
Regards,
Ovidiu
For the need of our project, we want to send all the commands for creating, joining and sending tcp messages from the stm32 acting as a host processor to the KW41Z.
KW41Z will be just like a black box flashed with kinetis thread stack.
stm32 runs freertos.
We have written a program but we are not able to communicate with FRDM-KW41 via UART in order to send our commands.
What can be the problem?
Thank you
Hi Steffen,
I'm not aware for an existing example of using a host uC to control kw41, other than linux examples, but this could be easily build it.
The fist step is to set the UART FRDM header pins:
- in function BOARD_InitLPUART you should enable the following:
PORT_SetPinMux(PORTC, PIN17_IDX, kPORT_MuxAlt4); /* PORTC17 is configured as UART0_RX */
PORT_SetPinMux(PORTC, PIN18_IDX, kPORT_MuxAlt4); /* PORTC18 is configured as UART0_TX */
SIM->SOPT5 = ((SIM->SOPT5 &
(~(SIM_SOPT5_LPUART0RXSRC_MASK))) /* Mask bits to zero which are setting */
| SIM_SOPT5_LPUART0RXSRC(SOPT5_LPUART0RXSRC_LPUART_RX) /* LPUART0 Receive Data Source Select: LPUART_RX pin */
);
- this is used to forward the UART messages from USB to FRDM - UART header (J1 header - pins 6 - UART0_TX, 7 - UART0_RX). Please consider that based on the board Revision, you will need to solder SH12 and SH11 connections.
The next step is to decide what do you want to use: Shell or THCI and implement the same on the Host uC.
For THCI you will need to consider the data transfer format, as below:
where the STX is the synchronization byte, and by default is set to 0x02. The possible values for Opcode and Message type are detailed in the following document: Kinetis Thread Host Control Interface Reference Manual.
Please consider that the delivered sdk items contains also a C implementation for the THCI protocol, that could help you on the host app implementation. This is usually located in sdk at the following location:
...\SDK_2.2_FRDM-KW41Z\tools\wireless\host_sdk\hsdk.
For shell, please consider the Kinetis Thread Stack Shell Interface User's Guide for a complete list of supported commands.
Other considerations are: default UART baud rate = 115200 with no flow control.
Let us know about your progress.
Regards,
Ovidiu
Is this also available for KW40Z? If so, where can I find the implementation?
Hi Steffen,
Let us know about your progress. I will be happy to assist you with any further questions.
Regards,
Ovidiu