Skip to content

Commit

Permalink
[Silabs] Add Uart log output (#25809)
Browse files Browse the repository at this point in the history
* [Silabs] Add Uart log output

* fix CI
  • Loading branch information
jepenven-silabs authored and pull[bot] committed Oct 5, 2023
1 parent adfd7e7 commit 0651b5c
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 33 deletions.
5 changes: 5 additions & 0 deletions examples/platform/silabs/efr32/efr32_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ void appError(int err);
#ifdef __cplusplus
}

// Output logs to RTT by defaults
#ifndef SILABS_LOG_OUT_UART
#define SILABS_LOG_OUT_UART 0
#endif

#include <lib/core/CHIPError.h>
void appError(CHIP_ERROR error);
#endif
7 changes: 6 additions & 1 deletion examples/platform/silabs/efr32/init_efrPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ extern "C" {
#include "sl_component_catalog.h"
#include "sl_mbedtls.h"
#include "sl_system_init.h"
#if SILABS_LOG_OUT_UART || ENABLE_CHIP_SHELL || CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI
#include "uart.h"
#endif

#if SL_SYSTEM_VIEW
#include "SEGGER_SYSVIEW.h"
Expand All @@ -80,7 +83,9 @@ void init_efrPlatform(void)
SEGGER_SYSVIEW_Conf();
SEGGER_SYSVIEW_Start();
#endif

#if SILABS_LOG_OUT_UART || ENABLE_CHIP_SHELL || CHIP_DEVICE_CONFIG_THREAD_ENABLE_CLI
uartConsoleInit();
#endif
#if SILABS_LOG_ENABLED
silabsInitLog();
#endif
Expand Down
177 changes: 152 additions & 25 deletions examples/platform/silabs/efr32/uart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
* limitations under the License.
*/
#include "AppConfig.h"
#include "FreeRTOS.h"
#include "event_groups.h"
#include "matter_shell.h"
#include "semphr.h"
#include "task.h"

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -96,11 +100,47 @@ static uint8_t sRxDmaBuffer[MAX_DMA_BUFFER_SIZE];
static uint8_t sRxDmaBuffer2[MAX_DMA_BUFFER_SIZE];
static uint16_t lastCount; // Nb of bytes already processed from the active dmaBuffer

// uart transmit
#if SILABS_LOG_OUT_UART
#define UART_MAX_QUEUE_SIZE 125
#else
#define UART_MAX_QUEUE_SIZE 25
#endif
#define UART_TASK_SIZE 256
#define UART_TASK_NAME "UART"
#define UART_TX_COMPLETE_BIT (1 << 0)

#ifdef CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE
#define UART_TX_MAX_BUF_LEN (CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE + 2) // \r\n
#else
#define UART_TX_MAX_BUF_LEN (258)
#endif

TaskHandle_t sUartTaskHandle;
StackType_t uartStack[UART_TASK_SIZE * sizeof(StackType_t)];
StaticTask_t uartTaskStruct;

typedef struct
{
uint8_t data[UART_TX_MAX_BUF_LEN];
uint16_t length = 0;
} UartTxStruct_t;

uint8_t sUartTxQueueBuffer[UART_MAX_QUEUE_SIZE * sizeof(UartTxStruct_t)];
StaticQueue_t sUartTxQueueStruct;
QueueHandle_t sUartTxQueue;

EventGroupHandle_t sUartEventGroup;
StaticEventGroup_t sUartEventGroupStruct;

// Rx buffer for the receive Fifo
static uint8_t sRxFifoBuffer[MAX_BUFFER_SIZE];
static Fifo_t sReceiveFifo;

static void UART_rx_callback(UARTDRV_Handle_t handle, Ecode_t transferStatus, uint8_t * data, UARTDRV_Count_t transferCount);
static void UART_tx_callback(struct UARTDRV_HandleData * handle, Ecode_t transferStatus, uint8_t * data,
UARTDRV_Count_t transferCount);
static void uartSendBytes(uint8_t * buffer, uint16_t nbOfBytes);

static bool InitFifo(Fifo_t * fifo, uint8_t * pDataBuffer, uint16_t bufferSize)
{
Expand Down Expand Up @@ -180,7 +220,7 @@ static void WriteToFifo(Fifo_t * fifo, uint8_t * pDataToWrite, uint16_t SizeToWr
* @param Ptr to the fifo, ptr to contain the data to process, nb of bytes to pull from the fifo
* @return Nb of bytes that were retrieved.
*/
static uint8_t RetrieveFromFifo(Fifo_t * fifo, uint8_t * pData, uint16_t SizeToRead)
static uint16_t RetrieveFromFifo(Fifo_t * fifo, uint8_t * pData, uint16_t SizeToRead)
{
assert(fifo);
assert(pData);
Expand Down Expand Up @@ -217,7 +257,6 @@ void uartConsoleInit(void)
InitFifo(&sReceiveFifo, sRxFifoBuffer, MAX_BUFFER_SIZE);

// Activate 2 dma queues to always have one active

UARTDRV_Receive(vcom_handle, sRxDmaBuffer, MAX_DMA_BUFFER_SIZE, UART_rx_callback);
UARTDRV_Receive(vcom_handle, sRxDmaBuffer2, MAX_DMA_BUFFER_SIZE, UART_rx_callback);

Expand All @@ -237,6 +276,19 @@ void uartConsoleInit(void)
#else
USART_IntEnable(SL_UARTDRV_USART_VCOM_PERIPHERAL, USART_IF_RXDATAV);
#endif // EFR32MG24

uint32_t struct_size = sizeof(UartTxStruct_t);

sUartTxQueue = xQueueCreateStatic(UART_MAX_QUEUE_SIZE, struct_size, sUartTxQueueBuffer, &sUartTxQueueStruct);

sUartEventGroup = xEventGroupCreateStatic(&sUartEventGroupStruct);

// Start App task.
sUartTaskHandle = xTaskCreateStatic(uartMainLoop, UART_TASK_NAME, UART_TASK_SIZE, nullptr, 30, uartStack, &uartTaskStruct);

assert(sUartTaskHandle);
assert(sUartEventGroup);
assert(sUartTxQueue);
}

void USART_IRQHandler(void)
Expand All @@ -255,6 +307,24 @@ void USART_IRQHandler(void)
#endif
}

/**
* @brief Transmit complete callback
*
* @param handle
* @param transferStatus
* @param data
* @param transferCount
*/
void UART_tx_callback(struct UARTDRV_HandleData * handle, Ecode_t transferStatus, uint8_t * data, UARTDRV_Count_t transferCount)
{
BaseType_t xHigherPriorityTaskWoken;
/* Was the message posted successfully? */
if (xEventGroupSetBitsFromISR(sUartEventGroup, UART_TX_COMPLETE_BIT, &xHigherPriorityTaskWoken) == pdPASS)
{
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}

/*
* @brief Callback triggered when a UARTDRV DMA buffer is full
*/
Expand All @@ -281,42 +351,57 @@ static void UART_rx_callback(UARTDRV_Handle_t handle, Ecode_t transferStatus, ui
#endif
}

/*
* @brief Read the data available from the console Uart
* @param Buffer that contains the data to write, number bytes to write.
* @return Amount of bytes written or ERROR (-1)
/**
* @brief Read the data available from the console Uart
*
* @param Buf Buffer that contains the data to write
* @param BufLength number bytes to write
* @return int16_t Amount of bytes written or ERROR (-1)
*/
int16_t uartConsoleWrite(const char * Buf, uint16_t BufLength)
{
if (Buf == NULL || BufLength < 1)
if (Buf == NULL || BufLength < 1 || BufLength > UART_TX_MAX_BUF_LEN)
{
return UART_CONSOLE_ERR;
}
// Do NOT wait for logs. Better to lost some logging than block
// an unknow task that might be critical.
UartTxStruct_t workBuffer;
memcpy(workBuffer.data, Buf, BufLength);
workBuffer.length = BufLength;

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
#endif

#if (defined(EFR32MG24) && defined(WF200_WIFI))
pre_uart_transfer();
#endif /* EFR32MG24 && WF200_WIFI */
if (pdTRUE == xQueueSend(sUartTxQueue, &workBuffer, 0))
{
return BufLength;
}

// Use of ForceTransmit here. Transmit with DMA was causing errors with PW_RPC
// TODO: Use DMA and find/fix what causes the issue with PW
Ecode_t ecode_status = UARTDRV_ForceTransmit(vcom_handle, (uint8_t *) Buf, BufLength);
return UART_CONSOLE_ERR;
}

#if (defined(EFR32MG24) && defined(WF200_WIFI))
post_uart_transfer();
#endif /* EFR32MG24 && WF200_WIFI */
/**
* @brief Write Logs to the Uart. Appends a return character
*
* @param log pointer to the logs
* @param length number of bytes to write
* @return int16_t Amount of bytes written or ERROR (-1)
*/
int16_t uartLogWrite(const char * log, uint16_t length)
{
if (log == NULL || length < 1 || (length + 2) > UART_TX_MAX_BUF_LEN)
{
return UART_CONSOLE_ERR;
}

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
#endif
UartTxStruct_t workBuffer;
memcpy(workBuffer.data, log, length);
memcpy(workBuffer.data + length, "\r\n", 2);
workBuffer.length = length + 2;

if (ECODE_EMDRV_UARTDRV_OK == ecode_status)
if (pdTRUE == xQueueSend(sUartTxQueue, &workBuffer, 0))
{
return BufLength;
return length;
}

return UART_CONSOLE_ERR;
}

Expand Down Expand Up @@ -348,6 +433,48 @@ int16_t uartConsoleRead(char * Buf, uint16_t NbBytesToRead)
return (int16_t) RetrieveFromFifo(&sReceiveFifo, (uint8_t *) Buf, NbBytesToRead);
}

void uartMainLoop(void * args)
{
UartTxStruct_t workBuffer;

while (1)
{
while (pdTRUE == xQueueReceive(sUartTxQueue, &workBuffer, portMAX_DELAY))
{
uartSendBytes(workBuffer.data, workBuffer.length);
}
}
}

/**
* @brief Send Bytes to UART. This blocks the UART task.
*
* @param buffer pointer to the buffer containing the data
* @param nbOfBytes number of bytes to send
*/
void uartSendBytes(uint8_t * buffer, uint16_t nbOfBytes)
{
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
#endif

#if (defined(EFR32MG24) && defined(WF200_WIFI))
pre_uart_transfer();
#endif /* EFR32MG24 && WF200_WIFI */

UARTDRV_Transmit(vcom_handle, (uint8_t *) buffer, nbOfBytes, UART_tx_callback);

#if (defined(EFR32MG24) && defined(WF200_WIFI))
post_uart_transfer();
#endif /* EFR32MG24 && WF200_WIFI */

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
#endif

xEventGroupWaitBits(sUartEventGroup, UART_TX_COMPLETE_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
}

#ifdef __cplusplus
}
#endif
3 changes: 3 additions & 0 deletions examples/platform/silabs/efr32/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ extern "C" {

void uartConsoleInit(void);
int16_t uartConsoleWrite(const char * Buf, uint16_t BufLength);
int16_t uartLogWrite(const char * log, uint16_t length);
int16_t uartConsoleRead(char * Buf, uint16_t NbBytesToRead);

void uartMainLoop(void * args);

// Implemented by in openthread code
#ifndef PW_RPC_ENABLED
extern void otPlatUartReceived(const uint8_t * aBuf, uint16_t aBufLength);
Expand Down
6 changes: 6 additions & 0 deletions scripts/examples/gn_efr32_example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ if [ "$#" == "0" ]; then
Remove all logs and debugs features (including the LCD). Yield the smallest image size possible
--docker
Change GSDK root for docker builds
--uart_log
Forward Logs to Uart instead of RTT
"
elif [ "$#" -lt "2" ]; then
Expand Down Expand Up @@ -203,6 +205,10 @@ else
USE_DOCKER=true
shift
;;
--uart_log)
optArgs+="sl_uart_log_output=true "
shift
;;

*"sl_matter_version_str="*)
optArgs+="$1 "
Expand Down
30 changes: 25 additions & 5 deletions src/platform/silabs/Logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,20 @@
#define LOG_RTT_BUFFER_SIZE 256
#endif

// FreeRTOS includes
#if SILABS_LOG_OUT_UART
#include "uart.h"
#endif

// Enable RTT by default
#ifndef SILABS_LOG_OUT_RTT
#define SILABS_LOG_OUT_RTT 1
#endif

// SEGGER_RTT includes
#if SILABS_LOG_OUT_RTT
#include "SEGGER_RTT.h"
#include "SEGGER_RTT_Conf.h"
#endif

#define LOG_ERROR "[error ]"
#define LOG_WARN "[warn ]"
Expand Down Expand Up @@ -131,16 +142,23 @@ static void PrintLog(const char * msg)
{
size_t sz;
sz = strlen(msg);
SEGGER_RTT_WriteNoLock(LOG_RTT_BUFFER_INDEX, msg, sz);
#ifdef PW_RPC_ENABLED

#if SILABS_LOG_OUT_UART
uartLogWrite(msg, sz);
#elif PW_RPC_ENABLED
PigweedLogger::putString(msg, sz);
#else
SEGGER_RTT_WriteNoLock(LOG_RTT_BUFFER_INDEX, msg, sz);
#endif

#if SILABS_LOG_OUT_RTT || PW_RPC_ENABLED
const char * newline = "\r\n";
sz = strlen(newline);
SEGGER_RTT_WriteNoLock(LOG_RTT_BUFFER_INDEX, newline, sz);
#ifdef PW_RPC_ENABLED
#if PW_RPC_ENABLED
PigweedLogger::putString(newline, sz);
#else
SEGGER_RTT_WriteNoLock(LOG_RTT_BUFFER_INDEX, newline, sz);
#endif // PW_RPC_ENABLED
#endif
}
}
Expand All @@ -152,6 +170,7 @@ static void PrintLog(const char * msg)
extern "C" void silabsInitLog(void)
{
#if SILABS_LOG_ENABLED
#if SILABS_LOG_OUT_RTT
#if LOG_RTT_BUFFER_INDEX != 0
SEGGER_RTT_ConfigUpBuffer(LOG_RTT_BUFFER_INDEX, LOG_RTT_BUFFER_NAME, sLogBuffer, LOG_RTT_BUFFER_SIZE,
SEGGER_RTT_MODE_NO_BLOCK_TRIM);
Expand All @@ -161,6 +180,7 @@ extern "C" void silabsInitLog(void)
#else
SEGGER_RTT_SetFlagsUpBuffer(LOG_RTT_BUFFER_INDEX, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
#endif
#endif // SILABS_LOG_OUT_RTT

#ifdef PW_RPC_ENABLED
PigweedLogger::init();
Expand Down
2 changes: 1 addition & 1 deletion src/platform/silabs/efr32/ThreadStackManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ extern "C" otError otPlatUartEnable(void)
#ifdef PW_RPC_ENABLED
return OT_ERROR_NOT_IMPLEMENTED;
#else
uartConsoleInit();
// Uart Init is handled in init_efrPlatform.cpp
return OT_ERROR_NONE;
#endif
}
Expand Down
Loading

0 comments on commit 0651b5c

Please sign in to comment.