639 lines
20 KiB
C
639 lines
20 KiB
C
/** \file
|
|
* \brief This file implements a simple serial debug console and command interpreter.
|
|
*/
|
|
|
|
/** \defgroup CONSOLE Console
|
|
*
|
|
* \brief Serial debug console command interpreter.
|
|
*
|
|
* \todo Describe the command interpreter.
|
|
*
|
|
* @{
|
|
* @}
|
|
*/
|
|
|
|
/* Include Files */
|
|
#include "KTag.h"
|
|
|
|
/* Local Definitions and Constants */
|
|
|
|
//! Text representations of numeric digits, used by COMM_Console_Print_UInt32().
|
|
static const char8 DIGITS[] = "0123456789ABCDEF";
|
|
|
|
#if (CONFIG__FEATURE_COMM_CONSOLE == CONFIG__FEATURE_ENABLED)
|
|
|
|
//! Maximum number of characters (save one) able to be printed by COMM_Console_Print_String().
|
|
#define MAX_CONSOLE_STRING_LENGTH 81
|
|
|
|
//! States in the COMM_Console_Task() state machine.
|
|
typedef enum
|
|
{
|
|
COMM_STATE_INITIALIZING = 0,
|
|
COMM_STATE_DISPLAY_POWERUP_INFO,
|
|
COMM_STATE_IDLE,
|
|
COMM_STATE_COMMAND_TOO_LONG,
|
|
COMM_STATE_IDENTIFY_COMMAND,
|
|
COMM_STATE_EXECUTE_COMMAND,
|
|
COMM_STATE_UNKNOWN_COMMAND
|
|
} COMM_Console_State_T;
|
|
|
|
/* Public Variables */
|
|
char8 Command_Buffer[COMM_CONSOLE_COMMAND_MAX_LENGTH];
|
|
uint_fast16_t Command_Buffer_Index = 0;
|
|
TaskHandle_t COMM_Console_Task_Handle;
|
|
|
|
/* Private Variables */
|
|
|
|
//! Current state of the COMM_Console_Task() state machine.
|
|
static COMM_Console_State_T Current_State = COMM_STATE_INITIALIZING;
|
|
|
|
//! Next state of the COMM_Console_Task() state machine.
|
|
static COMM_Console_State_T Next_State = COMM_STATE_INITIALIZING;
|
|
|
|
//! Index into the #COMM_Console_Command_Table for the command currently being handled.
|
|
/*!
|
|
* If #Current_Command is set to UINT_FAST16_MAX, the command being handled is unknown, or no command is being handled.
|
|
*/
|
|
static uint_fast16_t Current_Command = 0;
|
|
|
|
/* Private Function Prototypes */
|
|
|
|
static void ConsoleISR(void);
|
|
static bool ConsoleCommandMatches(const char8 * const command_name);
|
|
static void ReverseString(char8 * value, uint32_t length);
|
|
|
|
/* Inline Functions */
|
|
|
|
//! Swaps the characters in x and y.
|
|
static inline void Swap_Char8(char8 * x, char8 * y)
|
|
{
|
|
uint8_t temp = *x;
|
|
*x = *y;
|
|
*y = temp;
|
|
}
|
|
|
|
static inline void Reset_Command_Buffer()
|
|
{
|
|
taskENTER_CRITICAL();
|
|
for (uint_fast16_t i = 0; i < COMM_CONSOLE_COMMAND_MAX_LENGTH; i++)
|
|
{
|
|
Command_Buffer[i] = COMM_CONSOLE_STRING_TERMINATOR;
|
|
}
|
|
Command_Buffer_Index = 0;
|
|
taskEXIT_CRITICAL();
|
|
}
|
|
|
|
/* Public Functions */
|
|
|
|
//! Initializes the console.
|
|
/*!
|
|
* \ingroup CONSOLE
|
|
*/
|
|
void COMM_Console_Init(void)
|
|
{
|
|
// Enable the pullup on the Rx pin to keep the noise down.
|
|
Cy_GPIO_SetDrivemode(UART_Console_rx_PORT, UART_Console_rx_NUM, CY_GPIO_DM_PULLUP);
|
|
UART_Console_Start();
|
|
|
|
/// Unmask only the RX FIFO not empty interrupt bit.
|
|
UART_Console_HW->INTR_RX_MASK = SCB_INTR_RX_MASK_NOT_EMPTY_Msk;
|
|
Cy_SysInt_Init(&Int_UART_Console_cfg, ConsoleISR);
|
|
NVIC_ClearPendingIRQ(Int_UART_Console_cfg.intrSrc);
|
|
NVIC_EnableIRQ(Int_UART_Console_cfg.intrSrc);
|
|
}
|
|
|
|
//! Parses and handle console commands in the background.
|
|
/*!
|
|
* \ingroup CONSOLE
|
|
*
|
|
* The [UML State Machine Diagram](http://www.uml-diagrams.org/state-machine-diagrams.html) below
|
|
* shows how the console messages processed by this code. Note that all of the *Character Rx'd*
|
|
* transitions occur in the #UART_Console_SPI_UART_ISR_EntryCallback() itself on the PSoC4, in
|
|
* #ConsoleRxISR() on the PSoC5, and in #ConsoleISR() on the PSoC6, to improve overall performance.
|
|
*
|
|
* \startuml{COMM_Console_Task.png} "Console Task"
|
|
*
|
|
* skinparam headerFontSize 18
|
|
* skinparam state {
|
|
* BackgroundColor #eeeeee
|
|
* BackgroundColor<<Error>> #ffaaaa
|
|
* FontName Impact
|
|
* FontSize 18
|
|
* }
|
|
* skinparam note {
|
|
* FontName "Comic Sans MS"
|
|
* FontStyle italic
|
|
* }
|
|
*
|
|
* state "Initializing" as STATE_INITIALIZING
|
|
* [*] --> STATE_INITIALIZING
|
|
* note left of STATE_INITIALIZING : Wait for the rest of the system to come online.
|
|
* state "Display Powerup Info" as STATE_DISPLAY_POWERUP_INFO
|
|
* STATE_DISPLAY_POWERUP_INFO : do/ print OS version
|
|
* STATE_DISPLAY_POWERUP_INFO : do/ print configuration (debug or release)
|
|
* STATE_INITIALIZING --> STATE_DISPLAY_POWERUP_INFO : after(100ms)
|
|
* state "Idle" as STATE_IDLE
|
|
* STATE_IDLE : do/ RTOS_Sleep()
|
|
* STATE_DISPLAY_POWERUP_INFO --> STATE_IDLE
|
|
* state STATE_IS_EOM <<choice>>
|
|
* note top of STATE_IS_EOM : This happens in\nUART_Console_SPI_UART_ISR_ExitCallback() on PSoC4,\nConsoleRxISR() on PSoC5,\nand ConsoleISR() on PSoC6.
|
|
* STATE_IDLE --> STATE_IS_EOM : character rx'd
|
|
* state STATE_IS_COMMAND_BUFFER_FULL <<choice>>
|
|
* note top of STATE_IS_COMMAND_BUFFER_FULL : This happens in\nUART_Console_SPI_UART_ISR_ExitCallback() on PSoC4,\nConsoleRxISR() on PSoC5,\nand ConsoleISR() on PSoC6.
|
|
* STATE_IS_EOM --> STATE_IS_COMMAND_BUFFER_FULL : [else]
|
|
* state "Identify Command" as STATE_IDENTIFY_COMMAND
|
|
* STATE_IDENTIFY_COMMAND : do/ look for command in the COMM_Console_Command_Table[]
|
|
* STATE_IS_EOM --> STATE_IDENTIFY_COMMAND : [rx'd character is EOM]
|
|
* STATE_IDLE --> STATE_IDENTIFY_COMMAND : COMM_Console_Execute_Internal_Command()
|
|
* state "Command Too Long" as STATE_COMMAND_TOO_LONG
|
|
* STATE_COMMAND_TOO_LONG : do/ print error message
|
|
* STATE_COMMAND_TOO_LONG : do/ reset command buffer
|
|
* STATE_IS_COMMAND_BUFFER_FULL --> STATE_COMMAND_TOO_LONG : [command buffer is full]
|
|
* STATE_IS_COMMAND_BUFFER_FULL --> STATE_IDLE : [else]/\nAppend received character to command buffer
|
|
* STATE_COMMAND_TOO_LONG --> STATE_IDLE
|
|
* state "Execute Command" as STATE_EXECUTE_COMMAND
|
|
* STATE_EXECUTE_COMMAND : do/ execute console command
|
|
* STATE_EXECUTE_COMMAND : exit/ reset command buffer
|
|
* STATE_EXECUTE_COMMAND --> STATE_IDLE
|
|
* STATE_IDENTIFY_COMMAND --> STATE_EXECUTE_COMMAND : [command matched]
|
|
* state "Unknown Command" as STATE_UNKNOWN_COMMAND
|
|
* STATE_UNKNOWN_COMMAND : do/ print error message
|
|
* STATE_UNKNOWN_COMMAND : do/ reset command buffer
|
|
* STATE_IDENTIFY_COMMAND --> STATE_UNKNOWN_COMMAND : [else]
|
|
* STATE_UNKNOWN_COMMAND --> STATE_IDLE
|
|
*
|
|
* left footer Key: UML 2.5\nLast modified 2020-12-14
|
|
* \enduml
|
|
*
|
|
* \return None (infinite loop)
|
|
*/
|
|
void COMM_Console_Task(void * pvParameters)
|
|
{
|
|
static TickType_t xTicksToWait = pdMS_TO_TICKS(10);
|
|
static uint32_t * NotificationValue;
|
|
|
|
while(true)
|
|
{
|
|
(void) xTaskNotifyWait(0, 0, (uint32_t *)&NotificationValue, xTicksToWait);
|
|
|
|
// Change to the next state atomically.
|
|
taskENTER_CRITICAL();
|
|
Current_State = Next_State;
|
|
taskEXIT_CRITICAL();
|
|
|
|
switch (Current_State)
|
|
{
|
|
default:
|
|
case COMM_STATE_INITIALIZING:
|
|
Next_State = COMM_STATE_DISPLAY_POWERUP_INFO;
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
xTicksToWait = 1;
|
|
break;
|
|
|
|
case COMM_STATE_DISPLAY_POWERUP_INFO:
|
|
COMM_Console_Print_String("[COMM] ");
|
|
COMM_RTOS_HandleConsoleVersion(NULL, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
COMM_Console_Print_String("[COMM] Console ready (awaiting commands).\n");
|
|
Next_State = COMM_STATE_IDLE;
|
|
xTicksToWait = 1;
|
|
break;
|
|
|
|
case COMM_STATE_IDLE:
|
|
xTicksToWait = pdMS_TO_TICKS(100);
|
|
break;
|
|
|
|
case COMM_STATE_COMMAND_TOO_LONG:
|
|
COMM_Console_Print_String("[COMM] ERROR: Command \"");
|
|
COMM_Console_Print_String(Command_Buffer);
|
|
COMM_Console_Print_String("\" too long!\n");
|
|
Reset_Command_Buffer();
|
|
Next_State = COMM_STATE_IDLE;
|
|
xTicksToWait = 1;
|
|
break;
|
|
|
|
case COMM_STATE_IDENTIFY_COMMAND:
|
|
Current_Command = UINT_FAST16_MAX;
|
|
|
|
for (uint_fast16_t i = 0; i < COMM_N_CONSOLE_COMMANDS; i++)
|
|
{
|
|
if (ConsoleCommandMatches(COMM_Console_Command_Table[i].Command_Name) == true)
|
|
{
|
|
Current_Command = i;
|
|
Next_State = COMM_STATE_EXECUTE_COMMAND;
|
|
xTicksToWait = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Current_Command == UINT_FAST16_MAX)
|
|
{
|
|
// No matching command was found.
|
|
Next_State = COMM_STATE_UNKNOWN_COMMAND;
|
|
xTicksToWait = 1;
|
|
}
|
|
break;
|
|
|
|
case COMM_STATE_EXECUTE_COMMAND:
|
|
if (COMM_Console_Command_Table[Current_Command].Execute_Command != NULL)
|
|
{
|
|
COMM_Console_Command_Result_T result = COMM_Console_Command_Table[Current_Command].Execute_Command(Command_Buffer, Command_Buffer_Index);
|
|
|
|
if (result == COMM_CONSOLE_CMD_RESULT_PARAMETER_ERROR)
|
|
{
|
|
COMM_Console_Print_String("ERROR: Parameter error!\n");
|
|
}
|
|
}
|
|
Reset_Command_Buffer();
|
|
Next_State = COMM_STATE_IDLE;
|
|
xTicksToWait = 1;
|
|
break;
|
|
|
|
case COMM_STATE_UNKNOWN_COMMAND:
|
|
COMM_Console_Print_String("ERROR: Command \"");
|
|
COMM_Console_Print_String(Command_Buffer);
|
|
COMM_Console_Print_String("\" not recognized! Try '?' for help.\n");
|
|
Reset_Command_Buffer();
|
|
Next_State = COMM_STATE_IDLE;
|
|
xTicksToWait = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SystemKResult_T HW_Execute_Console_Command(const uint8_t * const command)
|
|
{
|
|
COMM_Console_Execute_Internal_Command(command);
|
|
|
|
return SYSTEMK_RESULT_SUCCESS;
|
|
}
|
|
|
|
//! Executes a (potentially cross-task) console command.
|
|
/*!
|
|
* This function is used to initiate a console command from a software source internal to this
|
|
* CPU. This provides a way to use preexisting console commands on TX-only consoles.
|
|
*
|
|
* \note If two calls to this function are made back-to-back (before the COMM_Console_Task() has an
|
|
* opportunity to run), only the second command will be executed, as it will have overwritten the
|
|
* first. Allow time for the console commands to execute between calls to this function.
|
|
*
|
|
* \param command String containing the command to be executed.
|
|
*/
|
|
void COMM_Console_Execute_Internal_Command(const uint8_t * const command)
|
|
{
|
|
bool finished = false;
|
|
uint_fast16_t i = 0;
|
|
|
|
taskENTER_CRITICAL();
|
|
while ( (finished == false) &&
|
|
(i < COMM_CONSOLE_COMMAND_MAX_LENGTH) &&
|
|
(command[i] != COMM_CONSOLE_END_OF_MESSAGE ) &&
|
|
(command[i] != COMM_CONSOLE_STRING_TERMINATOR )
|
|
)
|
|
{
|
|
Command_Buffer[i] = command[i];
|
|
i++;
|
|
}
|
|
Command_Buffer_Index = i;
|
|
|
|
// If there is still room, terminate the command.
|
|
if (i < COMM_CONSOLE_COMMAND_MAX_LENGTH)
|
|
{
|
|
Command_Buffer[i] = COMM_CONSOLE_END_OF_MESSAGE;
|
|
}
|
|
taskEXIT_CRITICAL();
|
|
|
|
Next_State = COMM_STATE_IDENTIFY_COMMAND;
|
|
xTaskNotifyGive(COMM_Console_Task_Handle);
|
|
}
|
|
|
|
//! Prints a NULL-terminated string to the serial console.
|
|
void COMM_Console_Print_String(const char8 * const text)
|
|
{
|
|
for (size_t i = 0; i < MAX_CONSOLE_STRING_LENGTH; i++)
|
|
{
|
|
// Check for the end of the string. If there is no NULL terminator, up to
|
|
// MAX_CONSOLE_STRING_LENGTH characters of randomness will be printed.
|
|
if (text[i] == COMM_CONSOLE_STRING_TERMINATOR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Send out the string, one character at a time.
|
|
COMM_Console_PutChar(text[i]);
|
|
}
|
|
}
|
|
|
|
//! Prints a 32-bit unsigned integer to the serial console.
|
|
void COMM_Console_Print_UInt32(uint32_t value)
|
|
{
|
|
// The largest string for a unit32_t is 10 characters (4294967296).
|
|
char8 buffer[10+1];
|
|
uint_fast8_t buffer_index = 0;
|
|
|
|
while (value > 9)
|
|
{
|
|
uint8_t digit_index = value % 10;
|
|
buffer[buffer_index] = DIGITS[digit_index];
|
|
value = value / 10;
|
|
buffer_index++;
|
|
}
|
|
buffer[buffer_index] = DIGITS[value];
|
|
buffer_index++;
|
|
ReverseString(buffer, buffer_index);
|
|
|
|
// NULL-terminate the string.
|
|
buffer[buffer_index] = 0;
|
|
|
|
COMM_Console_Print_String(buffer);
|
|
}
|
|
|
|
//! Prints a 32-bit signed integer to the serial console.
|
|
void COMM_Console_Print_SInt32(int32_t value)
|
|
{
|
|
if (value < 0)
|
|
{
|
|
value *= -1;
|
|
COMM_Console_PutChar('-');
|
|
}
|
|
|
|
COMM_Console_Print_UInt32(value);
|
|
}
|
|
|
|
//! Prints a 32-bit unsigned integer to the serial console using a hexadecimal representation.
|
|
void COMM_Console_Print_UInt32AsHex(uint32_t value)
|
|
{
|
|
// The largest hexadecimal string for a unit32_t is 8 characters (FFFFFFFF).
|
|
char8 buffer[8+1];
|
|
uint_fast8_t buffer_index = 0;
|
|
|
|
while (value > 15)
|
|
{
|
|
uint8_t digit_index = value % 16;
|
|
buffer[buffer_index] = DIGITS[digit_index];
|
|
value = value / 16;
|
|
buffer_index++;
|
|
}
|
|
buffer[buffer_index] = DIGITS[value];
|
|
buffer_index++;
|
|
ReverseString(buffer, buffer_index);
|
|
|
|
// NULL-terminate the string.
|
|
buffer[buffer_index] = 0;
|
|
|
|
COMM_Console_PutChar('0');
|
|
COMM_Console_PutChar('x');
|
|
COMM_Console_Print_String(buffer);
|
|
}
|
|
|
|
//! Prints a 64-bit unsigned integer to the serial console.
|
|
void COMM_Console_Print_UInt64(uint64_t value)
|
|
{
|
|
// The largest string for a unit64_t is 20 characters (18446744073709551615).
|
|
char8 buffer[20+1];
|
|
uint_fast8_t buffer_index = 0;
|
|
|
|
while (value > 9)
|
|
{
|
|
uint8_t digit_index = value % 10;
|
|
buffer[buffer_index] = DIGITS[digit_index];
|
|
value = value / 10;
|
|
buffer_index++;
|
|
}
|
|
buffer[buffer_index] = DIGITS[value];
|
|
buffer_index++;
|
|
ReverseString(buffer, buffer_index);
|
|
|
|
// NULL-terminate the string.
|
|
buffer[buffer_index] = 0;
|
|
|
|
COMM_Console_Print_String(buffer);
|
|
}
|
|
|
|
//! Prints a 64-bit unsigned integer to the serial console using a hexadecimal representation.
|
|
void COMM_Console_Print_UInt64AsHex(uint64_t value)
|
|
{
|
|
// The largest hexadecimal string for a unit64_t is 16 characters (FFFFFFFFFFFFFFFF).
|
|
char8 buffer[16+1];
|
|
uint_fast8_t buffer_index = 0;
|
|
|
|
while (value > 15)
|
|
{
|
|
uint8_t digit_index = value % 16;
|
|
buffer[buffer_index] = DIGITS[digit_index];
|
|
value = value / 16;
|
|
buffer_index++;
|
|
}
|
|
buffer[buffer_index] = DIGITS[value];
|
|
buffer_index++;
|
|
ReverseString(buffer, buffer_index);
|
|
|
|
// NULL-terminate the string.
|
|
buffer[buffer_index] = 0;
|
|
|
|
COMM_Console_PutChar('0');
|
|
COMM_Console_PutChar('x');
|
|
COMM_Console_Print_String(buffer);
|
|
}
|
|
|
|
//! Prints a floating-point number to the serial console.
|
|
/*!
|
|
* With thanks to Rick Regan and his [Quick and Dirty Floating-Point to Decimal Conversion](https://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal-conversion/).
|
|
*/
|
|
void COMM_Console_Print_Float(float value)
|
|
{
|
|
#define MAX_INTEGRAL_DIGITS 12
|
|
#define MAX_FRACTIONAL_DIGITS 6
|
|
#define BUFFER_SIZE (MAX_INTEGRAL_DIGITS + MAX_FRACTIONAL_DIGITS + 2)
|
|
|
|
char8 buffer[BUFFER_SIZE];
|
|
char8 integral_buffer_reversed[MAX_INTEGRAL_DIGITS];
|
|
uint16_t buffer_index = 0;
|
|
double integral_value;
|
|
double fractional_value;
|
|
bool overflow = false;
|
|
|
|
if (value < 0.0)
|
|
{
|
|
COMM_Console_Print_String("-");
|
|
value *= -1.0;
|
|
}
|
|
|
|
// Break the given value into fractional and integral parts.
|
|
fractional_value = modf(value, &integral_value);
|
|
|
|
if (integral_value > 0)
|
|
{
|
|
// Convert the integral part.
|
|
while ((integral_value > 0) && (buffer_index < MAX_INTEGRAL_DIGITS))
|
|
{
|
|
integral_buffer_reversed[buffer_index++] = '0' + (int)fmod(integral_value, 10);
|
|
integral_value = floor(integral_value / 10);
|
|
}
|
|
|
|
// If there is still an integral part remaining, and overflow has occurred.
|
|
if (integral_value > 0)
|
|
{
|
|
overflow = true;
|
|
}
|
|
|
|
// Reverse and append the integral part.
|
|
for (uint16_t i = 0; i < buffer_index; i++)
|
|
{
|
|
buffer[i] = integral_buffer_reversed[buffer_index-i-1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Append a leading zero.
|
|
buffer[buffer_index++] = '0';
|
|
}
|
|
|
|
// Append the decimal point.
|
|
buffer[buffer_index++] = '.';
|
|
|
|
// Convert the fractional part, even if it is zero, and leave room for the NULL terminator.
|
|
while (buffer_index < (BUFFER_SIZE - 1))
|
|
{
|
|
fractional_value *= 10;
|
|
buffer[buffer_index++] = '0' + (int)fractional_value;
|
|
fractional_value = modf(fractional_value, &integral_value);
|
|
}
|
|
|
|
// Append the NULL terminator.
|
|
buffer[buffer_index] = 0;
|
|
|
|
if (overflow == true)
|
|
{
|
|
COMM_Console_Print_String("OVERFLOW");
|
|
}
|
|
else
|
|
{
|
|
COMM_Console_Print_String(buffer);
|
|
}
|
|
}
|
|
|
|
#endif // (CONFIG__FEATURE_COMM_CONSOLE == CONFIG__FEATURE_ENABLED)
|
|
|
|
//! Converts a byte to a two-character hexadecimal representation.
|
|
/*!
|
|
* \param buffer Buffer into which to place the resulting sting. It needs to be at least three
|
|
* characters wide.
|
|
* \param byte The byte to be converted.
|
|
*/
|
|
void COMM_Console_ByteToHex(char8 * buffer, uint8_t byte)
|
|
{
|
|
if (byte < 16)
|
|
{
|
|
buffer[0] = '0';
|
|
buffer[1] = DIGITS[byte];
|
|
buffer[2] = 0;
|
|
}
|
|
else
|
|
{
|
|
buffer[0] = DIGITS[byte / 16];
|
|
buffer[1] = DIGITS[byte % 16];
|
|
buffer[2] = 0;
|
|
}
|
|
}
|
|
|
|
#if (CONFIG__FEATURE_COMM_CONSOLE == CONFIG__FEATURE_ENABLED)
|
|
|
|
/* Private Functions */
|
|
|
|
static void ConsoleISR(void)
|
|
{
|
|
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
|
|
|
// Check for the "Rx FIFO not empty" interrput.
|
|
if ((UART_Console_HW->INTR_RX_MASKED & SCB_INTR_RX_MASKED_NOT_EMPTY_Msk ) != 0)
|
|
{
|
|
// Clear the "Rx FIFO not empty" interrput.
|
|
UART_Console_HW->INTR_RX = UART_Console_HW->INTR_RX & SCB_INTR_RX_NOT_EMPTY_Msk;
|
|
|
|
// Get the character.
|
|
uint32_t value = UART_Console_Get();
|
|
|
|
// Check if there is actually data. Sometimes the flag is set when there is no data (why?).
|
|
if (value != CY_SCB_UART_RX_NO_DATA)
|
|
{
|
|
char8 rx_data = (char8) value;
|
|
|
|
// Determine what to do with it.
|
|
if (Command_Buffer_Index < COMM_CONSOLE_COMMAND_MAX_LENGTH)
|
|
{
|
|
if (rx_data == COMM_CONSOLE_END_OF_MESSAGE)
|
|
{
|
|
Command_Buffer[Command_Buffer_Index] = COMM_CONSOLE_STRING_TERMINATOR;
|
|
Next_State = COMM_STATE_IDENTIFY_COMMAND;
|
|
vTaskNotifyGiveFromISR(COMM_Console_Task_Handle, &xHigherPriorityTaskWoken);
|
|
}
|
|
else
|
|
{
|
|
Command_Buffer[Command_Buffer_Index] = rx_data;
|
|
Command_Buffer_Index++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Next_State = COMM_STATE_COMMAND_TOO_LONG;
|
|
vTaskNotifyGiveFromISR(COMM_Console_Task_Handle, &xHigherPriorityTaskWoken);
|
|
}
|
|
}
|
|
}
|
|
|
|
NVIC_ClearPendingIRQ(Int_UART_Console_cfg.intrSrc);
|
|
|
|
// If the state needs to change, a context switch might be required.
|
|
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
|
|
}
|
|
|
|
static bool ConsoleCommandMatches(const char8 * const command_name)
|
|
{
|
|
uint32_t i = 0;
|
|
bool is_match = false;
|
|
|
|
if (Command_Buffer[i] == command_name[i])
|
|
{
|
|
is_match = true;
|
|
i++;
|
|
}
|
|
|
|
while ( (is_match == true) &&
|
|
(i < COMM_CONSOLE_COMMAND_MAX_LENGTH) &&
|
|
(Command_Buffer[i] != COMM_CONSOLE_PARAMETER_DELIMITER) &&
|
|
(Command_Buffer[i] != COMM_CONSOLE_END_OF_MESSAGE ) &&
|
|
(Command_Buffer[i] != COMM_CONSOLE_STRING_TERMINATOR )
|
|
)
|
|
{
|
|
if ( Command_Buffer[i] != command_name[i] )
|
|
{
|
|
is_match = false;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return is_match;
|
|
}
|
|
|
|
//! Reverses a string in place.
|
|
/*!
|
|
* \param value Pointer to the string to be reversed.
|
|
* \param length Length of the string, including the NULL terminator.
|
|
*/
|
|
static void ReverseString(char8 * value, uint32_t length)
|
|
{
|
|
if (length > 1)
|
|
{
|
|
uint_fast32_t start = 0;
|
|
uint_fast32_t end = length - 1;
|
|
while (start < end)
|
|
{
|
|
Swap_Char8(value + start, value + end);
|
|
start++;
|
|
end--;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // (CONFIG__FEATURE_COMM_CONSOLE == CONFIG__FEATURE_ENABLED)
|