Skip to content
Permalink
65945b3645
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
352 lines (322 sloc) 10.6 KB
/******************************************************************************
* File Name: shell.c
*
* Description: This is the source code for the XMC MCU: UART Shell Example
* for ModusToolbox. Code derived from fNET Shell
* (https://github.com/butok/FNET/)
*
* Related Document: See README.md
*
******************************************************************************
*
* Copyright (c) 2015-2024, Infineon Technologies AG
* All rights reserved.
*
* Boost Software License - Version 1.0 - August 17th, 2003
*
* Permission is hereby granted, free of charge, to any person or organization
* obtaining a copy of the software and accompanying documentation covered by
* this license (the "Software") to use, reproduce, display, distribute,
* execute, and transmit the Software, and to prepare derivative works of the
* Software, and to permit third-parties to whom the Software is furnished to
* do so, all subject to the following:
*
* The copyright notices in the Software and this entire statement, including
* the above license grant, this restriction and the following disclaimer,
* must be included in all copies of the Software, in whole or in part, and
* all derivative works of the Software, unless such copies or derivative
* works are solely in the form of machine-executable object code generated by
* a source language processor.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include "shell.h"
#include "retarget_io.h"
#include "ring_buffer.h"
/*******************************************************************************
* Typedefs
*******************************************************************************/
/* States of shell state machine */
typedef enum SHELL_STATE
{
SHELL_STATE_INIT, /* The Shell service is initialized to process
next user command. */
SHELL_STATE_GET_USER_INPUT, /* The Shell service is accepting user commands. */
SHELL_STATE_EXEC_CMD, /* The Shell service is executing user commands. */
SHELL_STATE_END_CMD /* The Shell service finished command execution. */
} SHELL_STATE_t;
/*******************************************************************************
* Variables
*******************************************************************************/
static const shell_command_t *shell_cmd_table;
static SHELL_STATE_t shell_state;
static uint32_t shell_cmdline_pos;
static char shell_cmdline[SHELL_CMDLINE_SIZE];
/*******************************************************************************
* Macros
*******************************************************************************/
/* Parameters of shell behaviour */
#define SHELL_ERR_SYNTAX ("Error: Invalid syntax for: %s")
#define SHELL_ERR_CMD ("Error: No such command: %s")
#define SHELL_BACKSPACE ((char)(0x08)) /* Backspace. */
#define SHELL_DELETE ((char)(0x7F)) /* Delete. */
#define SHELL_CTRLC ((char)(0x03)) /* Ctrl + C. */
#define SHELL_CR ((char)(0x0D)) /* CR. */
#define SHELL_LF ((char)(0x0A)) /* LF. */
#define SHELL_ESC ((char)(0x1B)) /* Esc. */
#define SHELL_SPACE ((char)(0x20)) /* Space. */
/*******************************************************************************
* Function Name: shell_println
********************************************************************************
* Summary:
* Wrapping of printf for formatted output including linefeed.
*
* Parameters:
* const char *format: format string
* ...: flexible parameter list for formatted output
*
*
* Return:
* int32_t: number of characters printed
*
*******************************************************************************/
int32_t shell_println(const char *format, ... )
{
int32_t result;
va_list ap;
va_start(ap, format);
result = vprintf(format, ap);
/* Add new line.*/
result += printf("\r\n");
va_end (ap);
return result;
}
/*******************************************************************************
* Function Name: shell_make_argv
********************************************************************************
* Summary:
* Parsing parameters from user input before calling cmd callbacks
*
* Parameters:
* char *cmdline: command input received from terminal
* char *argv[]: parsed array of parameters (output)
*
*
* Return:
* int32_t: count of parsed arguments
*
*******************************************************************************/
static int32_t shell_make_argv(char *cmdline, char *argv[])
{
int32_t argc = 0;
int32_t i;
bool in_text_flag = false;
if ((cmdline != NULL) && (argv != NULL))
{
for (i = 0u; cmdline[i] != '\0'; ++i)
{
if (cmdline[i] == ' ')
{
in_text_flag = false;
cmdline[i] = '\0';
}
else
{
if (argc < SHELL_ARGS_MAX)
{
if (in_text_flag == false)
{
in_text_flag = true;
argv[argc] = &cmdline[i];
argc++;
}
}
else
{
/* Return argc.*/
break;
}
}
}
argv[argc] = 0;
}
return argc;
}
/*******************************************************************************
* Function Name: shell_state_machine
********************************************************************************
* Summary:
* Implementation of the shell internal state-machine.
* see https://github.com/butok/FNET/ for implementation details
*
* Parameters:
* void
*
* Return:
* void
*
*******************************************************************************/
void shell_state_machine(void)
{
/* One extra for 0 terminator.*/
char *argv[SHELL_ARGS_MAX + 1u];
int32_t argc;
int32_t ch;
switch (shell_state)
{
case SHELL_STATE_INIT:
printf("%s", SHELL_PROMPT);
shell_state = SHELL_STATE_GET_USER_INPUT;
break;
case SHELL_STATE_GET_USER_INPUT:
if (ring_buffer_avail(&serial_buffer) > 0)
{
ch = getchar();
if (ch != EOF)
{
/* Check if
* 1. enter was pressed or
* 2. shell_cmdline buffer has only 1 character left, reserved for zero termination
*/
if (((char)ch != SHELL_LF) && (shell_cmdline_pos < (SHELL_CMDLINE_SIZE - 1)))
{
switch(ch)
{
case SHELL_BACKSPACE:
case SHELL_DELETE:
if (shell_cmdline_pos > 0U)
{
shell_cmdline_pos -= 1U;
putchar(SHELL_BACKSPACE);
putchar(' ');
putchar(SHELL_BACKSPACE);
}
break;
default:
if ((shell_cmdline_pos + 1U) < SHELL_CMDLINE_SIZE)
{
/* Only printable characters. */
if (((char)ch >= SHELL_SPACE) && ((char)ch <= SHELL_DELETE))
{
shell_cmdline[shell_cmdline_pos] = (char)ch;
shell_cmdline_pos++;
putchar((char)ch);
}
}
break;
}
}
else
{
/* Append zero termination to command and start execution */
shell_cmdline[shell_cmdline_pos] = '\0';
putchar(SHELL_CR);
putchar(SHELL_LF);
shell_state = SHELL_STATE_EXEC_CMD;
}
}
}
break;
case SHELL_STATE_EXEC_CMD:
argc = shell_make_argv(shell_cmdline, argv);
if (argc != 0)
{
const shell_command_t *cur_command = shell_cmd_table;
while (cur_command->name)
{
/* Command is found. */
if (strcasecmp(cur_command->name, argv[0]) == 0)
{
if (((argc - 1) >= cur_command->min_args) && ((argc - 1) <= cur_command->max_args))
{
if (cur_command->cmd_ptr)
{
((void(*)(int32_t cmd_ptr_argc, char **cmd_ptr_argv))(cur_command->cmd_ptr))(argc, argv);
}
}
else
{
/* Wrong command syntax. */
shell_println(SHELL_ERR_SYNTAX, argv[0]);
}
break;
}
cur_command++;
}
if (cur_command->name == 0)
{
shell_println(SHELL_ERR_CMD, argv[0]);
}
}
shell_state = SHELL_STATE_END_CMD;
break;
case SHELL_STATE_END_CMD:
shell_state = SHELL_STATE_INIT;
shell_cmdline_pos = 0u;
shell_cmdline[0] = 0u;
break;
default:
break;
}
}
/*******************************************************************************
* Function Name: shell_help
********************************************************************************
* Summary:
* Implementation of default command "help" which is parsing all other available
* commands to the terminal.
*
* Parameters:
* void
*
* Return:
* void
*
*******************************************************************************/
void shell_help(void)
{
const shell_command_t *cur_command = shell_cmd_table;
while (cur_command->name)
{
shell_println(">%-7s %-16s- %s", cur_command->name,
cur_command->syntax,
cur_command->description);
cur_command++;
}
}
/*******************************************************************************
* Function Name: shell_init
********************************************************************************
* Summary:
* Initialize printf retarget
*
* Parameters:
* const shell_command_t *const cmd_table: Table to specify shell commands
* void (*init)(void): function ptr which is called at the end of initialization
* e.g. to parse a welcome string to the terminal
*
* Return:
* void
*
*******************************************************************************/
void shell_init(const shell_command_t *const cmd_table, void (*init)(void))
{
setvbuf(stdout, NULL, _IONBF, 0);
shell_state = SHELL_STATE_INIT;
shell_cmdline_pos = 0u;
shell_cmdline[0] = 0u;
shell_cmd_table = cmd_table;
init();
}