diff options
author | Dominik Sliwa <dominik.sliwa@toradex.com> | 2016-06-27 13:46:01 +0200 |
---|---|---|
committer | Dominik Sliwa <dominik.sliwa@toradex.com> | 2017-01-25 16:39:29 +0100 |
commit | 8d59942da073513104a2c89ed0c9514198187dbe (patch) | |
tree | 3c8e786b1774f828da3ba788daeb37f560673cff /utilities |
apalis_tk1_k20: Initial commit
Diffstat (limited to 'utilities')
-rw-r--r-- | utilities/fsl_debug_console.c | 1806 | ||||
-rw-r--r-- | utilities/fsl_debug_console.h | 193 | ||||
-rw-r--r-- | utilities/fsl_notifier.c | 182 | ||||
-rw-r--r-- | utilities/fsl_notifier.h | 259 | ||||
-rw-r--r-- | utilities/fsl_sbrk.c | 66 | ||||
-rw-r--r-- | utilities/fsl_shell.c | 621 | ||||
-rw-r--r-- | utilities/fsl_shell.h | 204 |
7 files changed, 3331 insertions, 0 deletions
diff --git a/utilities/fsl_debug_console.c b/utilities/fsl_debug_console.c new file mode 100644 index 0000000..10c64a4 --- /dev/null +++ b/utilities/fsl_debug_console.c @@ -0,0 +1,1806 @@ +/* + * This is a modified version of the file printf.c, which was distributed + * by Motorola as part of the M5407C3BOOT.zip package used to initialize + * the M5407C3 evaluation board. + * + * Copyright: + * 1999-2000 MOTOROLA, INC. All Rights Reserved. + * You are hereby granted a copyright license to use, modify, and + * distribute the SOFTWARE so long as this entire notice is + * retained without alteration in any modified and/or redistributed + * versions, and that such modified versions are clearly identified + * as such. No licenses are granted by implication, estoppel or + * otherwise under any patents or trademarks of Motorola, Inc. This + * software is provided on an "AS IS" basis and without warranty. + * + * To the maximum extent permitted by applicable law, MOTOROLA + * DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR + * PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH REGARD TO THE + * SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) AND ANY + * ACCOMPANYING WRITTEN MATERIALS. + * + * To the maximum extent permitted by applicable law, IN NO EVENT + * SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING + * WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS + * INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY + * LOSS) ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. + * + * Motorola assumes no responsibility for the maintenance and support + * of this software + + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdarg.h> +#include <stdlib.h> +#if defined(__CC_ARM) +#include <stdio.h> +#endif +#include <math.h> +#include "fsl_debug_console.h" + +#if defined(FSL_FEATURE_SOC_UART_COUNT) && (FSL_FEATURE_SOC_UART_COUNT > 0) +#include "fsl_uart.h" +#endif /* FSL_FEATURE_SOC_UART_COUNT */ + +#if defined(FSL_FEATURE_SOC_LPSCI_COUNT) && (FSL_FEATURE_SOC_LPSCI_COUNT > 0) +#include "fsl_lpsci.h" +#endif /* FSL_FEATURE_SOC_LPSCI_COUNT */ + +#if defined(FSL_FEATURE_SOC_LPUART_COUNT) && (FSL_FEATURE_SOC_LPUART_COUNT > 0) +#include "fsl_lpuart.h" +#endif /* FSL_FEATURE_SOC_LPUART_COUNT */ + +#if defined(FSL_FEATURE_SOC_USB_COUNT) && (FSL_FEATURE_SOC_USB_COUNT > 0) && defined(BOARD_USE_VIRTUALCOM) +#include "usb_device_config.h" +#include "usb.h" +#include "usb_device_cdc_acm.h" +#include "usb_device_ch9.h" +#include "virtual_com.h" +#endif + +/*! @brief Keil: suppress ellipsis warning in va_arg usage below. */ +#if defined(__CC_ARM) +#pragma diag_suppress 1256 +#endif /* __CC_ARM */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief This definition is maximum line that debugconsole can scanf each time.*/ +#define IO_MAXLINE 20U + +/*! @brief The overflow value.*/ +#ifndef HUGE_VAL +#define HUGE_VAL (99.e99) +#endif /* HUGE_VAL */ + +#if SCANF_FLOAT_ENABLE +static double fnum = 0.0; +#endif /* SCANF_FLOAT_ENABLE */ + +/*! @brief Operation functions definitions for debug console. */ +typedef struct DebugConsoleOperationFunctions +{ + union + { + void (*PutChar)(void *base, const uint8_t *buffer, size_t length); +#if defined(FSL_FEATURE_SOC_UART_COUNT) && (FSL_FEATURE_SOC_UART_COUNT > 0) + void (*UART_PutChar)(UART_Type *base, const uint8_t *buffer, size_t length); +#endif /* FSL_FEATURE_SOC_UART_COUNT */ +#if defined(FSL_FEATURE_SOC_LPSCI_COUNT) && (FSL_FEATURE_SOC_LPSCI_COUNT > 0) + void (*LPSCI_PutChar)(UART0_Type *base, const uint8_t *buffer, size_t length); +#endif /* FSL_FEATURE_SOC_LPSCI_COUNT */ +#if defined(FSL_FEATURE_SOC_LPUART_COUNT) && (FSL_FEATURE_SOC_LPUART_COUNT > 0) + void (*LPUART_PutChar)(LPUART_Type *base, const uint8_t *buffer, size_t length); +#endif /* FSL_FEATURE_SOC_LPUART_COUNT */ +#if defined(FSL_FEATURE_SOC_USB_COUNT) && (FSL_FEATURE_SOC_USB_COUNT > 0) && defined(BOARD_USE_VIRTUALCOM) + void (*USB_PutChar)(usb_device_handle base, const uint8_t *buf, size_t count); +#endif /* FSL_FEATURE_SOC_USB_COUNT && BOARD_USE_VIRTUALCOM*/ + } tx_union; + union + { + void (*GetChar)(void *base, const uint8_t *buffer, size_t length); +#if defined(FSL_FEATURE_SOC_UART_COUNT) && (FSL_FEATURE_SOC_UART_COUNT > 0) + status_t (*UART_GetChar)(UART_Type *base, uint8_t *buffer, size_t length); +#endif /* FSL_FEATURE_SOC_UART_COUNT */ +#if defined(FSL_FEATURE_SOC_LPSCI_COUNT) && (FSL_FEATURE_SOC_LPSCI_COUNT > 0) + status_t (*LPSCI_GetChar)(UART0_Type *base, uint8_t *buffer, size_t length); +#endif /* FSL_FEATURE_SOC_LPSCI_COUNT */ +#if defined(FSL_FEATURE_SOC_LPUART_COUNT) && (FSL_FEATURE_SOC_LPUART_COUNT > 0) + status_t (*LPUART_GetChar)(LPUART_Type *base, uint8_t *buffer, size_t length); +#endif /* FSL_FEATURE_SOC_LPUART_COUNT */ +#if defined(FSL_FEATURE_SOC_USB_COUNT) && (FSL_FEATURE_SOC_USB_COUNT > 0) && defined(BOARD_USE_VIRTUALCOM) + status_t (*USB_GetChar)(usb_device_handle base, uint8_t *buf, size_t count); +#endif /* FSL_FEATURE_SOC_USB_COUNT && BOARD_USE_VIRTUALCOM*/ + } rx_union; +} debug_console_ops_t; + +/*! @brief State structure storing debug console. */ +typedef struct DebugConsoleState +{ + uint8_t type; /*!< Indicator telling whether the debug console is initialized. */ + void *base; /*!< Base of the IP register. */ + debug_console_ops_t ops; /*!< Operation function pointers for debug UART operations. */ +} debug_console_state_t; + +/*! @brief Type of KSDK printf function pointer. */ +typedef int (*PUTCHAR_FUNC)(int a); + +#if PRINTF_ADVANCED_ENABLE +/*! @brief Specification modifier flags for printf. */ +enum _debugconsole_printf_flag +{ + kPRINTF_Minus = 0x01U, /*!< Minus FLag. */ + kPRINTF_Plus = 0x02U, /*!< Plus Flag. */ + kPRINTF_Space = 0x04U, /*!< Space Flag. */ + kPRINTF_Zero = 0x08U, /*!< Zero Flag. */ + kPRINTF_Pound = 0x10U, /*!< Pound Flag. */ + kPRINTF_LengthChar = 0x20U, /*!< Length: Char Flag. */ + kPRINTF_LengthShortInt = 0x40U, /*!< Length: Short Int Flag. */ + kPRINTF_LengthLongInt = 0x80U, /*!< Length: Long Int Flag. */ + kPRINTF_LengthLongLongInt = 0x100U, /*!< Length: Long Long Int Flag. */ +}; +#endif /* PRINTF_ADVANCED_ENABLE */ + +/*! @brief Specification modifier flags for scanf. */ +enum _debugconsole_scanf_flag +{ + kSCANF_Suppress = 0x2U, /*!< Suppress Flag. */ + kSCANF_DestMask = 0x7cU, /*!< Destination Mask. */ + kSCANF_DestChar = 0x4U, /*!< Destination Char Flag. */ + kSCANF_DestString = 0x8U, /*!< Destination String FLag. */ + kSCANF_DestSet = 0x10U, /*!< Destination Set Flag. */ + kSCANF_DestInt = 0x20U, /*!< Destination Int Flag. */ + kSCANF_DestFloat = 0x30U, /*!< Destination Float Flag. */ + kSCANF_LengthMask = 0x1f00U, /*!< Length Mask Flag. */ +#if SCANF_ADVANCED_ENABLE + kSCANF_LengthChar = 0x100U, /*!< Length Char Flag. */ + kSCANF_LengthShortInt = 0x200U, /*!< Length ShortInt Flag. */ + kSCANF_LengthLongInt = 0x400U, /*!< Length LongInt Flag. */ + kSCANF_LengthLongLongInt = 0x800U, /*!< Length LongLongInt Flag. */ +#endif /* SCANF_ADVANCED_ENABLE */ +#if PRINTF_FLOAT_ENABLE + kSCANF_LengthLongLongDouble = 0x1000U, /*!< Length LongLongDuoble Flag. */ +#endif /*PRINTF_FLOAT_ENABLE */ + kSCANF_TypeSinged = 0x2000U, /*!< TypeSinged Flag. */ +}; + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Debug UART state information. */ +static debug_console_state_t s_debugConsole = {.type = DEBUG_CONSOLE_DEVICE_TYPE_NONE, .base = NULL, .ops = {{0}, {0}}}; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +#if SDK_DEBUGCONSOLE +static int DbgConsole_PrintfFormattedData(PUTCHAR_FUNC func_ptr, const char *fmt, va_list ap); +static int DbgConsole_ScanfFormattedData(const char *line_ptr, char *format, va_list args_ptr); +double modf(double input_dbl, double *intpart_ptr); +#endif /* SDK_DEBUGCONSOLE */ + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*************Code for DbgConsole Init, Deinit, Printf, Scanf *******************************/ + +/* See fsl_debug_console.h for documentation of this function. */ +status_t DbgConsole_Init(uint32_t baseAddr, uint32_t baudRate, uint8_t device, uint32_t clkSrcFreq) +{ + if (s_debugConsole.type != DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return kStatus_Fail; + } + + /* Set debug console to initialized to avoid duplicated initialized operation. */ + s_debugConsole.type = device; + + /* Switch between different device. */ + switch (device) + { +#if defined(FSL_FEATURE_SOC_UART_COUNT) && (FSL_FEATURE_SOC_UART_COUNT > 0) + case DEBUG_CONSOLE_DEVICE_TYPE_UART: + { + uart_config_t uart_config; + s_debugConsole.base = (UART_Type *)baseAddr; + UART_GetDefaultConfig(&uart_config); + uart_config.baudRate_Bps = baudRate; + /* Enable clock and initial UART module follow user configure structure. */ + UART_Init(s_debugConsole.base, &uart_config, clkSrcFreq); + UART_EnableTx(s_debugConsole.base, true); + UART_EnableRx(s_debugConsole.base, true); + /* Set the function pointer for send and receive for this kind of device. */ + s_debugConsole.ops.tx_union.UART_PutChar = UART_WriteBlocking; + s_debugConsole.ops.rx_union.UART_GetChar = UART_ReadBlocking; + } + break; +#endif /* FSL_FEATURE_SOC_UART_COUNT */ +#if defined(FSL_FEATURE_SOC_LPSCI_COUNT) && (FSL_FEATURE_SOC_LPSCI_COUNT > 0) + case DEBUG_CONSOLE_DEVICE_TYPE_LPSCI: + { + lpsci_config_t lpsci_config; + s_debugConsole.base = (UART0_Type *)baseAddr; + LPSCI_GetDefaultConfig(&lpsci_config); + lpsci_config.baudRate_Bps = baudRate; + /* Enable clock and initial UART module follow user configure structure. */ + LPSCI_Init(s_debugConsole.base, &lpsci_config, clkSrcFreq); + LPSCI_EnableTx(s_debugConsole.base, true); + LPSCI_EnableRx(s_debugConsole.base, true); + /* Set the function pointer for send and receive for this kind of device. */ + s_debugConsole.ops.tx_union.LPSCI_PutChar = LPSCI_WriteBlocking; + s_debugConsole.ops.rx_union.LPSCI_GetChar = LPSCI_ReadBlocking; + } + break; +#endif /* FSL_FEATURE_SOC_LPSCI_COUNT */ +#if defined(FSL_FEATURE_SOC_LPUART_COUNT) && (FSL_FEATURE_SOC_LPUART_COUNT > 0) + case DEBUG_CONSOLE_DEVICE_TYPE_LPUART: + { + lpuart_config_t lpuart_config; + s_debugConsole.base = (LPUART_Type *)baseAddr; + LPUART_GetDefaultConfig(&lpuart_config); + lpuart_config.baudRate_Bps = baudRate; + /* Enable clock and initial UART module follow user configure structure. */ + LPUART_Init(s_debugConsole.base, &lpuart_config, clkSrcFreq); + LPUART_EnableTx(s_debugConsole.base, true); + LPUART_EnableRx(s_debugConsole.base, true); + /* Set the function pointer for send and receive for this kind of device. */ + s_debugConsole.ops.tx_union.LPUART_PutChar = LPUART_WriteBlocking; + s_debugConsole.ops.rx_union.LPUART_GetChar = LPUART_ReadBlocking; + } + break; +#endif /* FSL_FEATURE_SOC_LPUART_COUNT */ +#if defined(FSL_FEATURE_SOC_USB_COUNT) && (FSL_FEATURE_SOC_USB_COUNT > 0) && defined(BOARD_USE_VIRTUALCOM) + case DEBUG_CONSOLE_DEVICE_TYPE_USBCDC: + { + s_debugConsole.base = USB_VcomInit(); + s_debugConsole.ops.tx_union.USB_PutChar = USB_VcomWriteBlocking; + s_debugConsole.ops.rx_union.USB_GetChar = USB_VcomReadBlocking; + } + break; +#endif /* FSL_FEATURE_SOC_USB_COUNT && BOARD_USE_VIRTUALCOM*/ + /* If new device is required as the low level device for debug console, + * Add the case branch and add the preprocessor macro to judge whether + * this kind of device exist in this SOC. */ + default: + /* Device identified is invalid, return invalid device error code. */ + return kStatus_InvalidArgument; + } + + return kStatus_Success; +} + +/* See fsl_debug_console.h for documentation of this function. */ +status_t DbgConsole_Deinit(void) +{ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return kStatus_Success; + } + + switch (s_debugConsole.type) + { +#if defined(FSL_FEATURE_SOC_UART_COUNT) && (FSL_FEATURE_SOC_UART_COUNT > 0) + case DEBUG_CONSOLE_DEVICE_TYPE_UART: + /* Disable UART module. */ + UART_Deinit(s_debugConsole.base); + break; +#endif /* FSL_FEATURE_SOC_UART_COUNT */ +#if defined(FSL_FEATURE_SOC_LPSCI_COUNT) && (FSL_FEATURE_SOC_LPSCI_COUNT > 0) + case DEBUG_CONSOLE_DEVICE_TYPE_LPSCI: + /* Disable LPSCI module. */ + LPSCI_Deinit(s_debugConsole.base); + break; +#endif /* FSL_FEATURE_SOC_LPSCI_COUNT */ +#if defined(FSL_FEATURE_SOC_LPUART_COUNT) && (FSL_FEATURE_SOC_LPUART_COUNT > 0) + case DEBUG_CONSOLE_DEVICE_TYPE_LPUART: + /* Disable LPUART module. */ + LPUART_Deinit(s_debugConsole.base); + break; +#endif /* FSL_FEATURE_SOC_LPUART_COUNT */ +#if defined(FSL_FEATURE_SOC_USB_COUNT) && (FSL_FEATURE_SOC_USB_COUNT > 0) && defined(BOARD_USE_VIRTUALCOM) + case DEBUG_CONSOLE_DEVICE_TYPE_USBCDC: + /* Disable USBCDC module. */ + USB_VcomDeinit(s_debugConsole.base); + break; +#endif /* FSL_FEATURE_SOC_USB_COUNT && BOARD_USE_VIRTUALCOM*/ + default: + /* Device identified is invalid, return invalid device error code. */ + s_debugConsole.type = DEBUG_CONSOLE_DEVICE_TYPE_NONE; + return kStatus_InvalidArgument; + } + s_debugConsole.type = DEBUG_CONSOLE_DEVICE_TYPE_NONE; + return kStatus_Success; +} + +#if SDK_DEBUGCONSOLE +/* See fsl_debug_console.h for documentation of this function. */ +int DbgConsole_Printf(const char *fmt_s, ...) +{ + va_list ap; + int result; + + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return -1; + } + va_start(ap, fmt_s); + result = DbgConsole_PrintfFormattedData(DbgConsole_Putchar, fmt_s, ap); + va_end(ap); + + return result; +} + +/* See fsl_debug_console.h for documentation of this function. */ +int DbgConsole_Putchar(int ch) +{ + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return -1; + } + s_debugConsole.ops.tx_union.PutChar(s_debugConsole.base, (uint8_t *)(&ch), 1); + + return 1; +} + +/* See fsl_debug_console.h for documentation of this function. */ +int DbgConsole_Scanf(char *fmt_ptr, ...) +{ + /* Plus one to store end of string char */ + char temp_buf[IO_MAXLINE + 1]; + va_list ap; + int32_t i; + char result; + + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return -1; + } + va_start(ap, fmt_ptr); + temp_buf[0] = '\0'; + + for (i = 0; i < IO_MAXLINE; i++) + { + temp_buf[i] = result = DbgConsole_Getchar(); + + if ((result == '\r') || (result == '\n')) + { + /* End of Line. */ + if(i == 0) + { + temp_buf[i] = '\0'; + i = -1; + } + else + { + break; + } + } + } + + if ((i == IO_MAXLINE)) + { + temp_buf[i] = '\0'; + } + else + { + temp_buf[i+1] = '\0'; + } + result = DbgConsole_ScanfFormattedData(temp_buf, fmt_ptr, ap); + va_end(ap); + + return result; +} + +/* See fsl_debug_console.h for documentation of this function. */ +int DbgConsole_Getchar(void) +{ + char ch; + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return -1; + } + s_debugConsole.ops.rx_union.GetChar(s_debugConsole.base, (uint8_t *)(&ch), 1); + + return ch; +} + +/*************Code for process formatted data*******************************/ +/*! + * @brief Scanline function which ignores white spaces. + * + * @param[in] s The address of the string pointer to update. + * @return String without white spaces. + */ +static uint32_t DbgConsole_ScanIgnoreWhiteSpace(const char **s) +{ + uint8_t count = 0; + uint8_t c; + + c = **s; + while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\v') || (c == '\f')) + { + count++; + (*s)++; + c = **s; + } + return count; +} + +/*! + * @brief This function puts padding character. + * + * @param[in] c Padding character. + * @param[in] curlen Length of current formatted string . + * @param[in] width Width of expected formatted string. + * @param[in] count Number of characters. + * @param[in] func_ptr Function to put character out. + */ +static void DbgConsole_PrintfPaddingCharacter( + char c, int32_t curlen, int32_t width, int32_t *count, PUTCHAR_FUNC func_ptr) +{ + int32_t i; + + for (i = curlen; i < width; i++) + { + func_ptr(c); + (*count)++; + } +} + +/*! + * @brief Converts a radix number to a string and return its length. + * + * @param[in] numstr Converted string of the number. + * @param[in] nump Pointer to the number. + * @param[in] neg Polarity of the number. + * @param[in] radix The radix to be converted to. + * @param[in] use_caps Used to identify %x/X output format. + + * @return Length of the converted string. + */ +static int32_t DbgConsole_ConvertRadixNumToString(char *numstr, void *nump, int32_t neg, int32_t radix, bool use_caps) +{ +#if PRINTF_ADVANCED_ENABLE + int64_t a; + int64_t b; + int64_t c; + + uint64_t ua; + uint64_t ub; + uint64_t uc; +#else + int32_t a; + int32_t b; + int32_t c; + + uint32_t ua; + uint32_t ub; + uint32_t uc; +#endif /* PRINTF_ADVANCED_ENABLE */ + + int32_t nlen; + char *nstrp; + + nlen = 0; + nstrp = numstr; + *nstrp++ = '\0'; + + if (neg) + { +#if PRINTF_ADVANCED_ENABLE + a = *(int64_t *)nump; +#else + a = *(int32_t *)nump; +#endif /* PRINTF_ADVANCED_ENABLE */ + if (a == 0) + { + *nstrp = '0'; + ++nlen; + return nlen; + } + while (a != 0) + { +#if PRINTF_ADVANCED_ENABLE + b = (int64_t)a / (int64_t)radix; + c = (int64_t)a - ((int64_t)b * (int64_t)radix); + if (c < 0) + { + uc = (uint64_t)c; + c = (int64_t)(~uc) + 1 + '0'; + } +#else + b = a / radix; + c = a - (b * radix); + if (c < 0) + { + uc = (uint32_t)c; + c = (uint32_t)(~uc) + 1 + '0'; + } +#endif /* PRINTF_ADVANCED_ENABLE */ + else + { + c = c + '0'; + } + a = b; + *nstrp++ = (char)c; + ++nlen; + } + } + else + { +#if PRINTF_ADVANCED_ENABLE + ua = *(uint64_t *)nump; +#else + ua = *(uint32_t *)nump; +#endif /* PRINTF_ADVANCED_ENABLE */ + if (ua == 0) + { + *nstrp = '0'; + ++nlen; + return nlen; + } + while (ua != 0) + { +#if PRINTF_ADVANCED_ENABLE + ub = (uint64_t)ua / (uint64_t)radix; + uc = (uint64_t)ua - ((uint64_t)ub * (uint64_t)radix); +#else + ub = ua / (uint32_t)radix; + uc = ua - (ub * (uint32_t)radix); +#endif /* PRINTF_ADVANCED_ENABLE */ + + if (uc < 10) + { + uc = uc + '0'; + } + else + { + uc = uc - 10 + (use_caps ? 'A' : 'a'); + } + ua = ub; + *nstrp++ = (char)uc; + ++nlen; + } + } + return nlen; +} + +#if PRINTF_FLOAT_ENABLE +/*! + * @brief Converts a floating radix number to a string and return its length. + * + * @param[in] numstr Converted string of the number. + * @param[in] nump Pointer to the number. + * @param[in] radix The radix to be converted to. + * @param[in] precision_width Specify the precision width. + + * @return Length of the converted string. + */ +static int32_t DbgConsole_ConvertFloatRadixNumToString(char *numstr, + void *nump, + int32_t radix, + uint32_t precision_width) +{ + int32_t a; + int32_t b; + int32_t c; + int32_t i; + uint32_t uc; + double fa; + double dc; + double fb; + double r; + double fractpart; + double intpart; + + int32_t nlen; + char *nstrp; + nlen = 0; + nstrp = numstr; + *nstrp++ = '\0'; + r = *(double *)nump; + if (!r) + { + *nstrp = '0'; + ++nlen; + return nlen; + } + fractpart = modf((double)r, (double *)&intpart); + /* Process fractional part. */ + for (i = 0; i < precision_width; i++) + { + fractpart *= radix; + } + if (r >= 0) + { + fa = fractpart + (double)0.5; + if (fa >= pow(10, precision_width)) + { + intpart++; + } + } + else + { + fa = fractpart - (double)0.5; + if (fa <= -pow(10, precision_width)) + { + intpart--; + } + } + for (i = 0; i < precision_width; i++) + { + fb = fa / (int32_t)radix; + dc = (fa - (int64_t)fb * (int32_t)radix); + c = (int32_t)dc; + if (c < 0) + { + uc = (uint32_t)c; + c = (int32_t)(~uc) + 1 + '0'; + } + else + { + c = c + '0'; + } + fa = fb; + *nstrp++ = (char)c; + ++nlen; + } + *nstrp++ = (char)'.'; + ++nlen; + a = (int32_t)intpart; + if (a == 0) + { + *nstrp++ = '0'; + ++nlen; + } + else + { + while (a != 0) + { + b = (int32_t)a / (int32_t)radix; + c = (int32_t)a - ((int32_t)b * (int32_t)radix); + if (c < 0) + { + uc = (uint32_t)c; + c = (int32_t)(~uc) + 1 + '0'; + } + else + { + c = c + '0'; + } + a = b; + *nstrp++ = (char)c; + ++nlen; + } + } + return nlen; +} +#endif /* PRINTF_FLOAT_ENABLE */ + +/*! + * @brief This function outputs its parameters according to a formatted string. + * + * @note I/O is performed by calling given function pointer using following + * (*func_ptr)(c); + * + * @param[in] func_ptr Function to put character out. + * @param[in] fmt_ptr Format string for printf. + * @param[in] args_ptr Arguments to printf. + * + * @return Number of characters + */ +static int DbgConsole_PrintfFormattedData(PUTCHAR_FUNC func_ptr, const char *fmt, va_list ap) +{ + /* va_list ap; */ + char *p; + int32_t c; + + char vstr[33]; + char *vstrp = NULL; + int32_t vlen = 0; + + int32_t done; + int32_t count = 0; + + uint32_t field_width; + uint32_t precision_width; + char *sval; + int32_t cval; + bool use_caps; + uint8_t radix = 0; + +#if PRINTF_ADVANCED_ENABLE + uint32_t flags_used; + int32_t schar, dschar; + int64_t ival; + uint64_t uval = 0; +#else + int32_t ival; + uint32_t uval = 0; +#endif /* PRINTF_ADVANCED_ENABLE */ + +#if PRINTF_FLOAT_ENABLE + double fval; +#endif /* PRINTF_FLOAT_ENABLE */ + + /* Start parsing apart the format string and display appropriate formats and data. */ + for (p = (char *)fmt; (c = *p) != 0; p++) + { + /* + * All formats begin with a '%' marker. Special chars like + * '\n' or '\t' are normally converted to the appropriate + * character by the __compiler__. Thus, no need for this + * routine to account for the '\' character. + */ + if (c != '%') + { + func_ptr(c); + count++; + /* By using 'continue', the next iteration of the loop is used, skipping the code that follows. */ + continue; + } + + use_caps = true; + +#if PRINTF_ADVANCED_ENABLE + /* First check for specification modifier flags. */ + flags_used = 0; + done = false; + while (!done) + { + switch (*++p) + { + case '-': + flags_used |= kPRINTF_Minus; + break; + case '+': + flags_used |= kPRINTF_Plus; + break; + case ' ': + flags_used |= kPRINTF_Space; + break; + case '0': + flags_used |= kPRINTF_Zero; + break; + case '#': + flags_used |= kPRINTF_Pound; + break; + default: + /* We've gone one char too far. */ + --p; + done = true; + break; + } + } +#endif /* PRINTF_ADVANCED_ENABLE */ + + /* Next check for minimum field width. */ + field_width = 0; + done = false; + while (!done) + { + c = *++p; + if ((c >= '0') && (c <= '9')) + { + field_width = (field_width * 10) + (c - '0'); + } + else + { + /* We've gone one char too far. */ + --p; + done = true; + } + } + /* Next check for the width and precision field separator. */ + precision_width = 6; + if (*++p == '.') + { + /* Must get precision field width, if present. */ + precision_width = 0; + done = false; + while (!done) + { + c = *++p; + if ((c >= '0') && (c <= '9')) + { + precision_width = (precision_width * 10) + (c - '0'); + } + else + { + /* We've gone one char too far. */ + --p; + done = true; + } + } + } + else + { + /* We've gone one char too far. */ + --p; + } +#if PRINTF_ADVANCED_ENABLE + /* + * Check for the length modifier. + */ + switch (/* c = */ *++p) + { + case 'h': + if (*++p != 'h') + { + flags_used |= kPRINTF_LengthShortInt; + --p; + } + else + { + flags_used |= kPRINTF_LengthChar; + } + break; + case 'l': + if (*++p != 'l') + { + flags_used |= kPRINTF_LengthLongInt; + --p; + } + else + { + flags_used |= kPRINTF_LengthLongLongInt; + } + break; + default: + /* we've gone one char too far */ + --p; + break; + } +#endif /* PRINTF_ADVANCED_ENABLE */ + /* Now we're ready to examine the format. */ + c = *++p; + { + if ((c == 'd') || (c == 'i') || (c == 'f') || (c == 'F') || (c == 'x') || (c == 'X') || (c == 'o') || + (c == 'b') || (c == 'p') || (c == 'u')) + { + if ((c == 'd') || (c == 'i')) + { +#if PRINTF_ADVANCED_ENABLE + if (flags_used & kPRINTF_LengthLongLongInt) + { + ival = (int64_t)va_arg(ap, int64_t); + } + else +#endif /* PRINTF_ADVANCED_ENABLE */ + { + ival = (int32_t)va_arg(ap, int32_t); + } + vlen = DbgConsole_ConvertRadixNumToString(vstr, &ival, true, 10, use_caps); + vstrp = &vstr[vlen]; +#if PRINTF_ADVANCED_ENABLE + if (ival < 0) + { + schar = '-'; + ++vlen; + } + else + { + if (flags_used & kPRINTF_Plus) + { + schar = '+'; + ++vlen; + } + else + { + if (flags_used & kPRINTF_Space) + { + schar = ' '; + ++vlen; + } + else + { + schar = 0; + } + } + } + dschar = false; + /* Do the ZERO pad. */ + if (flags_used & kPRINTF_Zero) + { + if (schar) + { + func_ptr(schar); + count++; + } + dschar = true; + + DbgConsole_PrintfPaddingCharacter('0', vlen, field_width, &count, func_ptr); + vlen = field_width; + } + else + { + if (!(flags_used & kPRINTF_Minus)) + { + DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr); + if (schar) + { + func_ptr(schar); + count++; + } + dschar = true; + } + } + /* The string was built in reverse order, now display in correct order. */ + if ((!dschar) && schar) + { + func_ptr(schar); + count++; + } +#endif /* PRINTF_ADVANCED_ENABLE */ + } + +#if PRINTF_FLOAT_ENABLE + if ((c == 'f') || (c == 'F')) + { + fval = (double)va_arg(ap, double); + vlen = DbgConsole_ConvertFloatRadixNumToString(vstr, &fval, 10, precision_width); + vstrp = &vstr[vlen]; + +#if PRINTF_ADVANCED_ENABLE + if (fval < 0) + { + schar = '-'; + ++vlen; + } + else + { + if (flags_used & kPRINTF_Plus) + { + schar = '+'; + ++vlen; + } + else + { + if (flags_used & kPRINTF_Space) + { + schar = ' '; + ++vlen; + } + else + { + schar = 0; + } + } + } + dschar = false; + if (flags_used & kPRINTF_Zero) + { + if (schar) + { + func_ptr(schar); + count++; + } + dschar = true; + DbgConsole_PrintfPaddingCharacter('0', vlen, field_width, &count, func_ptr); + vlen = field_width; + } + else + { + if (!(flags_used & kPRINTF_Minus)) + { + DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr); + if (schar) + { + func_ptr(schar); + count++; + } + dschar = true; + } + } + if ((!dschar) && schar) + { + func_ptr(schar); + count++; + } +#endif /* PRINTF_ADVANCED_ENABLE */ + } +#endif /* PRINTF_FLOAT_ENABLE */ + if ((c == 'X') || (c == 'x')) + { + if (c == 'x') + { + use_caps = false; + } +#if PRINTF_ADVANCED_ENABLE + if (flags_used & kPRINTF_LengthLongLongInt) + { + uval = (uint64_t)va_arg(ap, uint64_t); + } + else +#endif /* PRINTF_ADVANCED_ENABLE */ + { + uval = (uint32_t)va_arg(ap, uint32_t); + } + vlen = DbgConsole_ConvertRadixNumToString(vstr, &uval, false, 16, use_caps); + vstrp = &vstr[vlen]; + +#if PRINTF_ADVANCED_ENABLE + dschar = false; + if (flags_used & kPRINTF_Zero) + { + if (flags_used & kPRINTF_Pound) + { + func_ptr('0'); + func_ptr((use_caps ? 'X' : 'x')); + count += 2; + /*vlen += 2;*/ + dschar = true; + } + DbgConsole_PrintfPaddingCharacter('0', vlen, field_width, &count, func_ptr); + vlen = field_width; + } + else + { + if (!(flags_used & kPRINTF_Minus)) + { + if (flags_used & kPRINTF_Pound) + { + vlen += 2; + } + DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr); + if (flags_used & kPRINTF_Pound) + { + func_ptr('0'); + func_ptr(use_caps ? 'X' : 'x'); + count += 2; + + dschar = true; + } + } + } + + if ((flags_used & kPRINTF_Pound) && (!dschar)) + { + func_ptr('0'); + func_ptr(use_caps ? 'X' : 'x'); + count += 2; + vlen += 2; + } +#endif /* PRINTF_ADVANCED_ENABLE */ + } + if (c == 'o') + { + uval = (uint32_t)va_arg(ap, uint32_t); + radix = 8; + } + if (c == 'b') + { + uval = (uint32_t)va_arg(ap, uint32_t); + radix = 2; + vstrp = &vstr[vlen]; + } + if (c == 'p') + { + uval = (uint32_t)va_arg(ap, void *); + radix = 16; + vstrp = &vstr[vlen]; + } + if (c == 'u') + { + uval = (uint32_t)va_arg(ap, uint32_t); + radix = 10; + vstrp = &vstr[vlen]; + } + if ((c == 'o') || (c == 'b') || (c == 'p') || (c == 'u')) + { + vlen = DbgConsole_ConvertRadixNumToString(vstr, &uval, false, radix, use_caps); + vstrp = &vstr[vlen]; +#if PRINTF_ADVANCED_ENABLE + if (flags_used & kPRINTF_Zero) + { + DbgConsole_PrintfPaddingCharacter('0', vlen, field_width, &count, func_ptr); + vlen = field_width; + } + else + { + if (!(flags_used & kPRINTF_Minus)) + { + DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr); + } + } +#endif /* PRINTF_ADVANCED_ENABLE */ + } +#if !PRINTF_ADVANCED_ENABLE + DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr); +#endif /* !PRINTF_ADVANCED_ENABLE */ + if (vstrp != NULL) + { + while (*vstrp) + { + func_ptr(*vstrp--); + count++; + } + } +#if PRINTF_ADVANCED_ENABLE + if (flags_used & kPRINTF_Minus) + { + DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr); + } +#endif /* PRINTF_ADVANCED_ENABLE */ + } + else if (c == 'c') + { + cval = (char)va_arg(ap, uint32_t); + func_ptr(cval); + count++; + } + else if (c == 's') + { + sval = (char *)va_arg(ap, char *); + if (sval) + { + vlen = strlen(sval); +#if PRINTF_ADVANCED_ENABLE + if (!(flags_used & kPRINTF_Minus)) +#endif /* PRINTF_ADVANCED_ENABLE */ + { + DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr); + } + while (*sval) + { + func_ptr(*sval++); + count++; + } +#if PRINTF_ADVANCED_ENABLE + if (flags_used & kPRINTF_Minus) + { + DbgConsole_PrintfPaddingCharacter(' ', vlen, field_width, &count, func_ptr); + } +#endif /* PRINTF_ADVANCED_ENABLE */ + } + } + else + { + func_ptr(c); + count++; + } + } + } + return count; +} + +/*! + * @brief Converts an input line of ASCII characters based upon a provided + * string format. + * + * @param[in] line_ptr The input line of ASCII data. + * @param[in] format Format first points to the format string. + * @param[in] args_ptr The list of parameters. + * + * @return Number of input items converted and assigned. + * @retval IO_EOF When line_ptr is empty string "". + */ +static int DbgConsole_ScanfFormattedData(const char *line_ptr, char *format, va_list args_ptr) +{ + uint8_t base; + int8_t neg; + /* Identifier for the format string. */ + char *c = format; + char temp; + char *buf; + /* Flag telling the conversion specification. */ + uint32_t flag = 0; + /* Filed width for the matching input streams. */ + uint32_t field_width; + /* How many arguments are assigned except the suppress. */ + uint32_t nassigned = 0; + /* How many characters are read from the input streams. */ + uint32_t n_decode = 0; + + int32_t val; + + const char *s; + /* Identifier for the input string. */ + const char *p = line_ptr; + + /* Return EOF error before any conversion. */ + if (*p == '\0') + { + return -1; + } + + /* Decode directives. */ + while ((*c) && (*p)) + { + /* Ignore all white-spaces in the format strings. */ + if (DbgConsole_ScanIgnoreWhiteSpace((const char **)&c)) + { + n_decode += DbgConsole_ScanIgnoreWhiteSpace(&p); + } + else if ((*c != '%') || ((*c == '%') && (*(c + 1) == '%'))) + { + /* Ordinary characters. */ + c++; + if (*p == *c) + { + n_decode++; + p++; + c++; + } + else + { + /* Match failure. Misalignment with C99, the unmatched characters need to be pushed back to stream. + * However, it is deserted now. */ + break; + } + } + else + { + /* convernsion specification */ + c++; + /* Reset. */ + flag = 0; + field_width = 0; + base = 0; + + /* Loop to get full conversion specification. */ + while ((*c) && (!(flag & kSCANF_DestMask))) + { + switch (*c) + { +#if SCANF_ADVANCED_ENABLE + case '*': + if (flag & kSCANF_Suppress) + { + /* Match failure. */ + return nassigned; + } + flag |= kSCANF_Suppress; + c++; + break; + case 'h': + if (flag & kSCANF_LengthMask) + { + /* Match failure. */ + return nassigned; + } + + if (c[1] == 'h') + { + flag |= kSCANF_LengthChar; + c++; + } + else + { + flag |= kSCANF_LengthShortInt; + } + c++; + break; + case 'l': + if (flag & kSCANF_LengthMask) + { + /* Match failure. */ + return nassigned; + } + + if (c[1] == 'l') + { + flag |= kSCANF_LengthLongLongInt; + c++; + } + else + { + flag |= kSCANF_LengthLongInt; + } + c++; + break; +#endif /* SCANF_ADVANCED_ENABLE */ +#if SCANF_FLOAT_ENABLE + case 'L': + if (flag & kSCANF_LengthMask) + { + /* Match failure. */ + return nassigned; + } + flag |= kSCANF_LengthLongLongDouble; + c++; + break; +#endif /* SCANF_FLOAT_ENABLE */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (field_width) + { + /* Match failure. */ + return nassigned; + } + do + { + field_width = field_width * 10 + *c - '0'; + c++; + } while ((*c >= '0') && (*c <= '9')); + break; + case 'd': + base = 10; + flag |= kSCANF_TypeSinged; + flag |= kSCANF_DestInt; + c++; + break; + case 'u': + base = 10; + flag |= kSCANF_DestInt; + c++; + break; + case 'o': + base = 8; + flag |= kSCANF_DestInt; + c++; + break; + case 'x': + case 'X': + base = 16; + flag |= kSCANF_DestInt; + c++; + break; + case 'i': + base = 0; + flag |= kSCANF_DestInt; + c++; + break; +#if SCANF_FLOAT_ENABLE + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + flag |= kSCANF_DestFloat; + c++; + break; +#endif /* SCANF_FLOAT_ENABLE */ + case 'c': + flag |= kSCANF_DestChar; + if (!field_width) + { + field_width = 1; + } + c++; + break; + case 's': + flag |= kSCANF_DestString; + c++; + break; + default: + return nassigned; + } + } + + if (!(flag & kSCANF_DestMask)) + { + /* Format strings are exhausted. */ + return nassigned; + } + + if (!field_width) + { + /* Large than length of a line. */ + field_width = 99; + } + + /* Matching strings in input streams and assign to argument. */ + switch (flag & kSCANF_DestMask) + { + case kSCANF_DestChar: + s = (const char *)p; + buf = va_arg(args_ptr, char *); + while ((field_width--) && (*p)) + { + if (!(flag & kSCANF_Suppress)) + { + *buf++ = *p++; + } + else + { + p++; + } + n_decode++; + } + + if ((!(flag & kSCANF_Suppress)) && (s != p)) + { + nassigned++; + } + break; + case kSCANF_DestString: + n_decode += DbgConsole_ScanIgnoreWhiteSpace(&p); + s = p; + buf = va_arg(args_ptr, char *); + while ((field_width--) && (*p != '\0') && (*p != ' ') && (*p != '\t') && (*p != '\n') && + (*p != '\r') && (*p != '\v') && (*p != '\f')) + { + if (flag & kSCANF_Suppress) + { + p++; + } + else + { + *buf++ = *p++; + } + n_decode++; + } + + if ((!(flag & kSCANF_Suppress)) && (s != p)) + { + /* Add NULL to end of string. */ + *buf = '\0'; + nassigned++; + } + break; + case kSCANF_DestInt: + n_decode += DbgConsole_ScanIgnoreWhiteSpace(&p); + s = p; + val = 0; + if ((base == 0) || (base == 16)) + { + if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) + { + base = 16; + if (field_width >= 1) + { + p += 2; + n_decode += 2; + field_width -= 2; + } + } + } + + if (base == 0) + { + if (s[0] == '0') + { + base = 8; + } + else + { + base = 10; + } + } + + neg = 1; + switch (*p) + { + case '-': + neg = -1; + n_decode++; + p++; + field_width--; + break; + case '+': + neg = 1; + n_decode++; + p++; + field_width--; + break; + default: + break; + } + + while ((*p) && (field_width--)) + { + if ((*p <= '9') && (*p >= '0')) + { + temp = *p - '0'; + } + else if ((*p <= 'f') && (*p >= 'a')) + { + temp = *p - 'a' + 10; + } + else if ((*p <= 'F') && (*p >= 'A')) + { + temp = *p - 'A' + 10; + } + else + { + temp = base; + } + + if (temp >= base) + { + break; + } + else + { + val = base * val + temp; + } + p++; + n_decode++; + } + val *= neg; + if (!(flag & kSCANF_Suppress)) + { +#if SCANF_ADVANCED_ENABLE + switch (flag & kSCANF_LengthMask) + { + case kSCANF_LengthChar: + if (flag & kSCANF_TypeSinged) + { + *va_arg(args_ptr, signed char *) = (signed char)val; + } + else + { + *va_arg(args_ptr, unsigned char *) = (unsigned char)val; + } + break; + case kSCANF_LengthShortInt: + if (flag & kSCANF_TypeSinged) + { + *va_arg(args_ptr, signed short *) = (signed short)val; + } + else + { + *va_arg(args_ptr, unsigned short *) = (unsigned short)val; + } + break; + case kSCANF_LengthLongInt: + if (flag & kSCANF_TypeSinged) + { + *va_arg(args_ptr, signed long int *) = (signed long int)val; + } + else + { + *va_arg(args_ptr, unsigned long int *) = (unsigned long int)val; + } + break; + case kSCANF_LengthLongLongInt: + if (flag & kSCANF_TypeSinged) + { + *va_arg(args_ptr, signed long long int *) = (signed long long int)val; + } + else + { + *va_arg(args_ptr, unsigned long long int *) = (unsigned long long int)val; + } + break; + default: + /* The default type is the type int. */ + if (flag & kSCANF_TypeSinged) + { + *va_arg(args_ptr, signed int *) = (signed int)val; + } + else + { + *va_arg(args_ptr, unsigned int *) = (unsigned int)val; + } + break; + } +#else + /* The default type is the type int. */ + if (flag & kSCANF_TypeSinged) + { + *va_arg(args_ptr, signed int *) = (signed int)val; + } + else + { + *va_arg(args_ptr, unsigned int *) = (unsigned int)val; + } +#endif /* SCANF_ADVANCED_ENABLE */ + nassigned++; + } + break; +#if SCANF_FLOAT_ENABLE + case kSCANF_DestFloat: + n_decode += DbgConsole_ScanIgnoreWhiteSpace(&p); + fnum = strtod(p, (char **)&s); + + if ((fnum >= HUGE_VAL) || (fnum <= -HUGE_VAL)) + { + break; + } + + n_decode += (int)(s) - (int)(p); + p = s; + if (!(flag & kSCANF_Suppress)) + { + if (flag & kSCANF_LengthLongLongDouble) + { + *va_arg(args_ptr, double *) = fnum; + } + else + { + *va_arg(args_ptr, float *) = (float)fnum; + } + nassigned++; + } + break; +#endif /* SCANF_FLOAT_ENABLE */ + default: + return nassigned; + } + } + } + return nassigned; +} +#endif /* SDK_DEBUGCONSOLE */ +/*************Code to support toolchain's printf, scanf *******************************/ +/* These function __write and __read is used to support IAR toolchain to printf and scanf*/ +#if (defined(__ICCARM__)) +#pragma weak __write +size_t __write(int handle, const unsigned char *buffer, size_t size) +{ + if (buffer == 0) + { + /* + * This means that we should flush internal buffers. Since we don't we just return. + * (Remember, "handle" == -1 means that all handles should be flushed.) + */ + return 0; + } + + /* This function only writes to "standard out" and "standard err" for all other file handles it returns failure. */ + if ((handle != 1) && (handle != 2)) + { + return ((size_t)-1); + } + + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return ((size_t)-1); + } + + /* Send data. */ + s_debugConsole.ops.tx_union.PutChar(s_debugConsole.base, buffer, 1); + return size; +} + +#pragma weak __read +size_t __read(int handle, unsigned char *buffer, size_t size) +{ + /* This function only reads from "standard in", for all other file handles it returns failure. */ + if (handle != 0) + { + return ((size_t)-1); + } + + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return ((size_t)-1); + } + + /* Receive data. */ + s_debugConsole.ops.rx_union.GetChar(s_debugConsole.base, buffer, size); + + return size; +} +/* These function __write and __read is used to support ARM_GCC, KDS, Atollic toolchains to printf and scanf*/ +#elif(defined(__GNUC__)) +#pragma weak __write +int _write(int handle, char *buffer, int size) +{ + if (buffer == 0) + { + /* return -1 if error. */ + return -1; + } + + /* This function only writes to "standard out" and "standard err" for all other file handles it returns failure. */ + if ((handle != 1) && (handle != 2)) + { + return -1; + } + + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return -1; + } + + /* Send data. */ + s_debugConsole.ops.tx_union.PutChar(s_debugConsole.base, (uint8_t *)buffer, size); + return size; +} + +#pragma weak __read +int _read(int handle, char *buffer, int size) +{ + /* This function only reads from "standard in", for all other file handles it returns failure. */ + if (handle != 0) + { + return -1; + } + + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return -1; + } + + /* Receive data. */ + s_debugConsole.ops.rx_union.GetChar(s_debugConsole.base, (uint8_t *)buffer, size); + return size; +} +/* These function fputc and fgetc is used to support KEIL toolchain to printf and scanf*/ +#elif defined(__CC_ARM) +struct __FILE +{ + int handle; + /* + * Whatever you require here. If the only file you are using is standard output using printf() for debugging, + * no file handling is required. + */ +}; + +/* FILE is typedef in stdio.h. */ +#pragma weak __stdout +FILE __stdout; +FILE __stdin; + +#pragma weak fputc +int fputc(int ch, FILE *f) +{ + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return -1; + } + + /* Send data. */ + s_debugConsole.ops.tx_union.PutChar(s_debugConsole.base, (uint8_t *)(&ch), 1); + return 1; +} + +#pragma weak fgetc +int fgetc(FILE *f) +{ + char ch; + /* Do nothing if the debug UART is not initialized. */ + if (s_debugConsole.type == DEBUG_CONSOLE_DEVICE_TYPE_NONE) + { + return -1; + } + + /* Receive data. */ + s_debugConsole.ops.rx_union.GetChar(s_debugConsole.base, (uint8_t *)(&ch), 1); + return ch; +} +#endif /* __ICCARM__ */ diff --git a/utilities/fsl_debug_console.h b/utilities/fsl_debug_console.h new file mode 100644 index 0000000..3ef50cf --- /dev/null +++ b/utilities/fsl_debug_console.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2013 - 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Debug console shall provide input and output functions to scan and print formatted data. + * o Support a format specifier for PRINTF follows this prototype "%[flags][width][.precision][length]specifier" + * - [flags] :'-', '+', '#', ' ', '0' + * - [width]: number (0,1...) + * - [.precision]: number (0,1...) + * - [length]: do not support + * - [specifier]: 'd', 'i', 'f', 'F', 'x', 'X', 'o', 'p', 'u', 'c', 's', 'n' + * o Support a format specifier for SCANF follows this prototype " %[*][width][length]specifier" + * - [*]: is supported. + * - [width]: number (0,1...) + * - [length]: 'h', 'hh', 'l','ll','L'. ignore ('j','z','t') + * - [specifier]: 'd', 'i', 'u', 'f', 'F', 'e', 'E', 'g', 'G', 'a', 'A', 'o', 'c', 's' + */ + +#ifndef _FSL_DEBUGCONSOLE_H_ +#define _FSL_DEBUGCONSOLE_H_ + +#include "fsl_common.h" + +/* + * @addtogroup debugconsole + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Definition to select sdk or toolchain printf, scanf. */ +#ifndef SDK_DEBUGCONSOLE +#define SDK_DEBUGCONSOLE 1U +#endif + +#if defined(SDK_DEBUGCONSOLE) && !(SDK_DEBUGCONSOLE) +#include <stdio.h> +#endif + +/*! @brief Definition to printf float number. */ +#ifndef PRINTF_FLOAT_ENABLE +#define PRINTF_FLOAT_ENABLE 0U +#endif /* PRINTF_FLOAT_ENABLE */ + +/*! @brief Definition to scanf float number. */ +#ifndef SCANF_FLOAT_ENABLE +#define SCANF_FLOAT_ENABLE 0U +#endif /* SCANF_FLOAT_ENABLE */ + +/*! @brief Definition to support advanced format specifier for printf. */ +#ifndef PRINTF_ADVANCED_ENABLE +#define PRINTF_ADVANCED_ENABLE 0U +#endif /* PRINTF_ADVANCED_ENABLE */ + +/*! @brief Definition to support advanced format specifier for scanf. */ +#ifndef SCANF_ADVANCED_ENABLE +#define SCANF_ADVANCED_ENABLE 0U +#endif /* SCANF_ADVANCED_ENABLE */ + +#if SDK_DEBUGCONSOLE /* Select printf, scanf, putchar, getchar of SDK version. */ +#define PRINTF DbgConsole_Printf +#define SCANF DbgConsole_Scanf +#define PUTCHAR DbgConsole_Putchar +#define GETCHAR DbgConsole_Getchar +#else /* Select printf, scanf, putchar, getchar of toolchain. */ +#define PRINTF printf +#define SCANF scanf +#define PUTCHAR putchar +#define GETCHAR getchar +#endif /* SDK_DEBUGCONSOLE */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +/*! @name Initialization*/ +/* @{ */ + +/*! + * @brief Initialize the the peripheral used for debug messages. + * + * Call this function to enable debug log messages to be output via the specified peripheral, + * frequency of peripheral source clock, base address at the specified baud rate. + * After this function has returned, stdout and stdin will be connected to the selected peripheral. + * + * @param baseAddr Which address of peripheral is used to send debug messages. + * @param baudRate The desired baud rate in bits per second. + * @param device Low level device type for the debug console, could be one of: + * @arg DEBUG_CONSOLE_DEVICE_TYPE_UART, + * @arg DEBUG_CONSOLE_DEVICE_TYPE_LPUART, + * @arg DEBUG_CONSOLE_DEVICE_TYPE_LPSCI, + * @arg DEBUG_CONSOLE_DEVICE_TYPE_USBCDC. + * @param clkSrcFreq Frequency of peripheral source clock. + * + * @return Whether initialization was successful or not. + * @retval kStatus_Success Execution successfully + * @retval kStatus_Fail Execution failure + * @retval kStatus_InvalidArgument Invalid argument existed + */ +status_t DbgConsole_Init(uint32_t baseAddr, uint32_t baudRate, uint8_t device, uint32_t clkSrcFreq); + +/*! + * @brief De-initialize the peripheral used for debug messages. + * + * Call this function to disable debug log messages to be output via the specified peripheral + * base address and at the specified baud rate. + * + * @return Whether de-initialization was successful or not. + */ +status_t DbgConsole_Deinit(void); + +#if SDK_DEBUGCONSOLE +/*! + * @brief Writes formatted output to the standard output stream. + * + * Call this function to Writes formatted output to the standard output stream. + * + * @param fmt_s Format control string. + * @return Returns the number of characters printed, or a negative value if an error occurs. + */ +int DbgConsole_Printf(const char *fmt_s, ...); + +/*! + * @brief Writes a character to stdout. + * + * Call this function to write a character to stdout. + * + * @param ch Character to be written. + * @return Returns the character written. + */ +int DbgConsole_Putchar(int ch); + +/*! + * @brief Reads formatted data from the standard input stream. + * + * Call this function to read formatted data from the standard input stream. + * + * @param fmt_ptr Format control string. + * @return Returns the number of fields successfully converted and assigned. + */ +int DbgConsole_Scanf(char *fmt_ptr, ...); + +/*! + * @brief Reads a character from standard input. + * + * Call this function to read a character from standard input. + * + * @return Returns the character read. + */ +int DbgConsole_Getchar(void); + +#endif /* SDK_DEBUGCONSOLE */ + +/*! @} */ + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +/*! @} */ + +#endif /* _FSL_DEBUGCONSOLE_H_ */ diff --git a/utilities/fsl_notifier.c b/utilities/fsl_notifier.c new file mode 100644 index 0000000..3e2744f --- /dev/null +++ b/utilities/fsl_notifier.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsl_notifier.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t NOTIFIER_CreateHandle(notifier_handle_t *notifierHandle, + notifier_user_config_t **configs, + uint8_t configsNumber, + notifier_callback_config_t *callbacks, + uint8_t callbacksNumber, + notifier_user_function_t userFunction, + void *userData) +{ + /* Check input parameter - at least one configuration is required and userFunction must exist */ + if ((configs == NULL) || (configsNumber == 0U) || (userFunction == NULL)) + { + return kStatus_Fail; + } + /* Initialize handle structure */ + memset(notifierHandle, 0, sizeof(notifier_handle_t)); + /* Store references to user-defined configurations */ + notifierHandle->configsTable = configs; + notifierHandle->configsNumber = configsNumber; + /* Store references to user-defined callback configurations */ + if (callbacks != NULL) + { + notifierHandle->callbacksTable = callbacks; + notifierHandle->callbacksNumber = callbacksNumber; + /* If all callbacks return success, then the errorCallbackIndex is callbacksNumber */ + notifierHandle->errorCallbackIndex = callbacksNumber; + } + notifierHandle->userFunction = userFunction; + notifierHandle->userData = userData; + + return kStatus_Success; +} + +status_t NOTIFIER_SwitchConfig(notifier_handle_t *notifierHandle, uint8_t configIndex, notifier_policy_t policy) +{ + uint8_t currentStaticCallback = 0U; /* Index to array of statically registered call-backs */ + status_t returnCode = kStatus_Success; /* Function return */ + + notifier_notification_block_t notifyBlock; /* Callback notification block */ + notifier_callback_config_t *callbackConfig; /* Pointer to callback configuration */ + + /* Set errorcallbackindex as callbacksNumber, which means no callback error now */ + notifierHandle->errorCallbackIndex = notifierHandle->callbacksNumber; + + /* Requested configuration availability check */ + if (configIndex >= notifierHandle->configsNumber) + { + return kStatus_OutOfRange; + } + + /* Initialization of local variables from the Notifier handle structure */ + + notifyBlock.policy = policy; + notifyBlock.targetConfig = notifierHandle->configsTable[configIndex]; + notifyBlock.notifyType = kNOTIFIER_NotifyBefore; + + /* From all statically registered call-backs... */ + for (currentStaticCallback = 0U; currentStaticCallback < notifierHandle->callbacksNumber; currentStaticCallback++) + { + callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]); + /* ...notify only those which asked to be called before the configuration switch */ + if (((uint32_t)callbackConfig->callbackType) & kNOTIFIER_CallbackBefore) + { + /* In case that call-back returned error code mark it, store the call-back handle and eventually cancel + * the configuration switch */ + if (callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData) != kStatus_Success) + { + returnCode = kStatus_NOTIFIER_ErrorNotificationBefore; + notifierHandle->errorCallbackIndex = currentStaticCallback; + /* If not forcing configuration switch, call all already notified call-backs to revert their state + * as the switch is canceled */ + if (policy != kNOTIFIER_PolicyForcible) + { + break; + } + } + } + } + + /* Set configuration */ + + /* In case that any call-back returned error code and policy doesn't force the configuration set, go to after + * switch call-backs */ + if ((policy == kNOTIFIER_PolicyForcible) || (returnCode == kStatus_Success)) + { + returnCode = notifierHandle->userFunction(notifierHandle->configsTable[configIndex], notifierHandle->userData); + if (returnCode != kStatus_Success) + { + return returnCode; + } + /* Update current configuration index */ + notifierHandle->currentConfigIndex = configIndex; + notifyBlock.notifyType = kNOTIFIER_NotifyAfter; + /* From all statically registered call-backs... */ + for (currentStaticCallback = 0U; currentStaticCallback < notifierHandle->callbacksNumber; + currentStaticCallback++) + { + callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]); + /* ...notify only those which asked to be called after the configruation switch */ + if (((uint32_t)callbackConfig->callbackType) & kNOTIFIER_CallbackAfter) + { + /* In case that call-back returned error code mark it and store the call-back handle */ + if (callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData) != kStatus_Success) + { + returnCode = kStatus_NOTIFIER_ErrorNotificationAfter; + notifierHandle->errorCallbackIndex = currentStaticCallback; + if (policy != kNOTIFIER_PolicyForcible) + { + break; + } + } + } + } + } + else + { + /* End of unsuccessful switch */ + notifyBlock.notifyType = kNOTIFIER_NotifyRecover; + while (currentStaticCallback--) + { + callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]); + if (((uint32_t)callbackConfig->callbackType) & kNOTIFIER_CallbackBefore) + { + callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData); + } + } + } + + return returnCode; +} + +uint8_t NOTIFIER_GetErrorCallbackIndex(notifier_handle_t *notifierHandle) +{ + return notifierHandle->errorCallbackIndex; +} diff --git a/utilities/fsl_notifier.h b/utilities/fsl_notifier.h new file mode 100644 index 0000000..1d39134 --- /dev/null +++ b/utilities/fsl_notifier.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSL_NOTIFIER_H_ +#define _FSL_NOTIFIER_H_ + +#include "fsl_common.h" +/*! + * @addtogroup notifier + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @brief Notifier error codes. + * + * Used as return value of Notifier functions. + */ +enum _notifier_status +{ + kStatus_NOTIFIER_ErrorNotificationBefore = + MAKE_STATUS(kStatusGroup_NOTIFIER, 0), /*!< Error occurs during send "BEFORE" notification. */ + kStatus_NOTIFIER_ErrorNotificationAfter = + MAKE_STATUS(kStatusGroup_NOTIFIER, 1), /*!< Error occurs during send "AFTER" notification. */ +}; + +/*! + * @brief Notifier policies. + * + * Defines whether user function execution is forced or not. + * For kNOTIFIER_PolicyForcible, the user function is executed regardless of the callback results, + * while kNOTIFIER_PolicyAgreement policy is used to exit NOTIFIER_SwitchConfig() + * when any of the callbacks returns error code. + * See also NOTIFIER_SwitchConfig() description. + */ +typedef enum _notifier_policy +{ + kNOTIFIER_PolicyAgreement, /*!< NOTIFIER_SwitchConfig() method is exited when any of the callbacks returns error + code. */ + kNOTIFIER_PolicyForcible, /*!< user function is executed regardless of the results. */ +} notifier_policy_t; + +/*! @brief Notification type. Used to notify registered callbacks */ +typedef enum _notifier_notification_type +{ + kNOTIFIER_NotifyRecover = 0x00U, /*!< Notify IP to recover to previous work state. */ + kNOTIFIER_NotifyBefore = 0x01U, /*!< Notify IP that configuration setting is going to change. */ + kNOTIFIER_NotifyAfter = 0x02U, /*!< Notify IP that configuration setting has been changed. */ +} notifier_notification_type_t; + +/*! + * @brief The callback type, indicates what kinds of notification the callback handles. + * + * Used in the callback configuration structure (notifier_callback_config_t) + * to specify when the registered callback is called during configuration switch initiated by + * NOTIFIER_SwitchConfig(). + * Callback can be invoked in following situations: + * - before the configuration switch (Callback return value can affect NOTIFIER_SwitchConfig() + * execution. See the NOTIFIER_SwitchConfig() and notifier_policy_t documentation). + * - after unsuccessful attempt to switch configuration + * - after successful configuration switch + */ +typedef enum _notifier_callback_type +{ + kNOTIFIER_CallbackBefore = 0x01U, /*!< Callback handles BEFORE notification. */ + kNOTIFIER_CallbackAfter = 0x02U, /*!< Callback handles AFTER notification. */ + kNOTIFIER_CallbackBeforeAfter = 0x03U, /*!< Callback handles BEFORE and AFTER notification. */ +} notifier_callback_type_t; + +/*! @brief Notifier user configuration type. + * + * Reference of user defined configuration is stored in an array; the notifier switches between these configurations + * based on this array. + */ +typedef void notifier_user_config_t; + +/*! @brief Notifier user function prototype + * Use this function to execute specific operations in configuration switch. + * Before and after this function execution, different notification is sent to registered callbacks. + * If this function returns any error code, NOTIFIER_SwitchConfig() exits. + * + * @param targetConfig target Configuration. + * @param userData Refers to other specific data passed to user function. + * @return An error code or kStatus_Success. + */ +typedef status_t (*notifier_user_function_t)(notifier_user_config_t *targetConfig, void *userData); + +/*! @brief notification block passed to the registered callback function. */ +typedef struct _notifier_notification_block +{ + notifier_user_config_t *targetConfig; /*!< Pointer to target configuration. */ + notifier_policy_t policy; /*!< Configure transition policy. */ + notifier_notification_type_t notifyType; /*!< Configure notification type. */ +} notifier_notification_block_t; + +/*! + * @brief Callback prototype. + * + * Declaration of callback. It is common for registered callbacks. + * Reference to function of this type is part of notifier_callback_config_t callback configuration structure. + * Depending on callback type, function of this prototype is called (see NOTIFIER_SwitchConfig()) + * before configuration switch, after it or in both use cases to notify about + * the switch progress (see notifier_callback_type_t). When called, type of the notification + * is passed as parameter along with reference to the target configuration structure (see notifier_notification_block_t) + * and any data passed during the callback registration. + * When notified before configuration switch, depending on the configuration switch policy (see + * notifier_policy_t) the callback may deny the execution of user function by returning any error code different + * from kStatus_Success (see NOTIFIER_SwitchConfig()). + * + * @param notify Notification block. + * @param data Callback data. Refers to the data passed during callback registration. Intended to + * pass any driver or application data such as internal state information. + * @return An error code or kStatus_Success. + */ +typedef status_t (*notifier_callback_t)(notifier_notification_block_t *notify, void *data); + +/*! + * @brief Callback configuration structure + * + * This structure holds configuration of callbacks. + * Callbacks of this type are expected to be statically allocated. + * This structure contains following application-defined data: + * callback - pointer to the callback function + * callbackType - specifies when the callback is called + * callbackData - pointer to the data passed to the callback. + */ +typedef struct _notifier_callback_config +{ + notifier_callback_t callback; /*!< Pointer to the callback function. */ + notifier_callback_type_t callbackType; /*!< Callback type. */ + void *callbackData; /*!< Pointer to the data passed to the callback. */ +} notifier_callback_config_t; + +/*! + * @brief Notifier handle structure. + * + * Notifier handle structure. Contains data necessary for Notifier proper function. + * Stores references to registered configurations, callbacks, information about their numbers, + * user function, user data and other internal data. + * NOTIFIER_CreateHandle() must be called to initialize this handle. + */ +typedef struct _notifier_handle +{ + notifier_user_config_t **configsTable; /*!< Pointer to configure table. */ + uint8_t configsNumber; /*!< Number of configurations. */ + notifier_callback_config_t *callbacksTable; /*!< Pointer to callback table. */ + uint8_t callbacksNumber; /*!< Maximum number of callback configurations. */ + uint8_t errorCallbackIndex; /*!< Index of callback returns error. */ + uint8_t currentConfigIndex; /*!< Index of current configuration. */ + notifier_user_function_t userFunction; /*!< user function. */ + void *userData; /*!< user data passed to user function. */ +} notifier_handle_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Create Notifier handle. + * + * @param notifierHandle A pointer to notifier handle + * @param configs A pointer to an array with references to all configurations which is handled by the Notifier. + * @param configsNumber Number of configurations. Size of the configuration array. + * @param callbacks A pointer to an array of callback configurations. + * If there are no callbacks to register during Notifier initialization, use NULL value. + * @param callbacksNumber Number of registered callbacks. Size of callbacks array. + * @param userFunction user function. + * @param userData user data passed to user function. + * @return An error code or kStatus_Success. + */ +status_t NOTIFIER_CreateHandle(notifier_handle_t *notifierHandle, + notifier_user_config_t **configs, + uint8_t configsNumber, + notifier_callback_config_t *callbacks, + uint8_t callbacksNumber, + notifier_user_function_t userFunction, + void *userData); + +/*! + * @brief Switch configuration according to a pre-defined structure. + * + * This function sets the system to the target configuration. Before transition, + * the Notifier sends notifications to all callbacks registered to the callback table. + * Callbacks are invoked in the following order: All registered callbacks are notified + * ordered by index in the callbacks array. The same order is used for before and after switch notifications. + * The notifications before the configuration switch can be used to obtain confirmation about + * the change from registered callbacks. If any registered callback denies the + * configuration change, further execution of this function depends on the notifier policy: the + * configuration change is either forced (kNOTIFIER_PolicyForcible) or exited (kNOTIFIER_PolicyAgreement). + * When configuration change is forced, the result of the before switch notifications are ignored. If + * agreement is required, if any callback returns an error code then further notifications + * before switch notifications are cancelled and all already notified callbacks are re-invoked + * The index of the callback which returned error code during pre-switch notifications is stored + * (any error codes during callbacks re-invocation are ignored) and NOTIFIER_GetErrorCallback() can be used to get it. + * Regardless of the policies, if any callback returned an error code, an error code denoting in which phase + * the error occurred is returned when NOTIFIER_SwitchConfig() exits. + * @param notifierHandle pointer to notifier handle + * @param configIndex Index of the target configuration. + * @param policy Transaction policy, kNOTIFIER_PolicyAgreement or kNOTIFIER_PolicyForcible. + * + * @return An error code or kStatus_Success. + * + */ +status_t NOTIFIER_SwitchConfig(notifier_handle_t *notifierHandle, uint8_t configIndex, notifier_policy_t policy); + +/*! + * @brief This function returns the last failed notification callback. + * + * This function returns index of the last callback that failed during the configuration switch while + * the last NOTIFIER_SwitchConfig() was called. If the last NOTIFIER_SwitchConfig() call ended successfully + * value equal to callbacks number is returned. Returned value represents index in the array of + * static call-backs. + * + * @param notifierHandle pointer to notifier handle + * @return Callback index of last failed callback or value equal to callbacks count. + */ +uint8_t NOTIFIER_GetErrorCallbackIndex(notifier_handle_t *notifierHandle); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +/*! @}*/ + +#endif /* _FSL_NOTIFIER_H_ */ diff --git a/utilities/fsl_sbrk.c b/utilities/fsl_sbrk.c new file mode 100644 index 0000000..aae6b1e --- /dev/null +++ b/utilities/fsl_sbrk.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#if defined(__GNUC__) +#include <stdio.h> +#include <errno.h> +#endif + +#if defined(__GNUC__) +/*! + * @brief Function to override ARMGCC default function _sbrk + * + * _sbrk is called by malloc. ARMGCC default _sbrk compares "SP" register and + * heap end, if heap end is larger than "SP", then _sbrk returns error and + * memory allocation failed. This function changes to compare __HeapLimit with + * heap end. + */ +caddr_t _sbrk(int incr) +{ + extern char end __asm("end"); + extern char heap_limit __asm("__HeapLimit"); + static char *heap_end; + char *prev_heap_end; + + if (heap_end == NULL) + heap_end = &end; + + prev_heap_end = heap_end; + + if (heap_end + incr > &heap_limit) + { + errno = ENOMEM; + return (caddr_t)-1; + } + + heap_end += incr; + + return (caddr_t)prev_heap_end; +} +#endif diff --git a/utilities/fsl_shell.c b/utilities/fsl_shell.c new file mode 100644 index 0000000..75ce7e8 --- /dev/null +++ b/utilities/fsl_shell.c @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * POSIX getopt for Windows + * Code given out at the 1985 UNIFORUM conference in Dallas. + * + * From std-unix@ut-sally.UUCP (Moderator, John Quarterman) Sun Nov 3 14:34:15 1985 + * Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site gatech.CSNET + * Posting-Version: version B 2.10.2 9/18/84; site ut-sally.UUCP + * Path: gatech!akgua!mhuxv!mhuxt!mhuxr!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!seismo!ut-sally!std-unix + * From: std-unix@ut-sally.UUCP (Moderator, John Quarterman) + * Newsgroups: mod.std.unix + * Subject: public domain AT&T getopt source + * Message-ID: <3352@ut-sally.UUCP> + * Date: 3 Nov 85 19:34:15 GMT + * Date-Received: 4 Nov 85 12:25:09 GMT + * Organization: IEEE/P1003 Portable Operating System Environment Committee + * Lines: 91 + * Approved: jsq@ut-sally.UUC + * Here's something you've all been waiting for: the AT&T public domain + * source for getopt(3). It is the code which was given out at the 1985 + * UNIFORUM conference in Dallas. I obtained it by electronic mail + * directly from AT&T. The people there assure me that it is indeed + * in the public domain + * There is no manual page. That is because the one they gave out at + * UNIFORUM was slightly different from the current System V Release 2 + * manual page. The difference apparently involved a note about the + * famous rules 5 and 6, recommending using white space between an option + * and its first argument, and not grouping options that have arguments. + * Getopt itself is currently lenient about both of these things White + * space is allowed, but not mandatory, and the last option in a group can + * have an argument. That particular version of the man page evidently + * has no official existence, and my source at AT&T did not send a copy. + * The current SVR2 man page reflects the actual behavor of this getopt. + * However, I am not about to post a copy of anything licensed by AT&T. + */ + +#include <assert.h> +#include "fsl_shell.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define KEY_ESC (0x1BU) +#define KET_DEL (0x7FU) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static int32_t HelpCommand(p_shell_context_t context, int32_t argc, char **argv); /*!< help command */ + +static int32_t ExitCommand(p_shell_context_t context, int32_t argc, char **argv); /*!< exit command */ + +static int32_t ParseLine(const char *cmd, uint32_t len, char *argv[SHELL_MAX_ARGS]); /*!< parse line command */ + +static int32_t StrCompare(const char *str1, const char *str2, int32_t count); /*!< compare string command */ + +static void ProcessCommand(p_shell_context_t context, const char *cmd); /*!< process a command */ + +static void GetHistoryCommand(p_shell_context_t context, uint8_t hist_pos); /*!< get commands history */ + +static void AutoComplete(p_shell_context_t context); /*!< auto complete command */ + +static uint8_t GetChar(p_shell_context_t context); /*!< get a char from communication interface */ + +static int32_t StrLen(const char *str); /*!< get string length */ + +static char *StrCopy(char *dest, const char *src, int32_t count); /*!< string copy */ + +/******************************************************************************* + * Variables + ******************************************************************************/ +static const shell_command_context_t xHelpCommand = {"help", "\r\n\"help\": Lists all the registered commands\r\n", + HelpCommand, 0}; + +static const shell_command_context_t xExitCommand = {"exit", "\r\n\"exit\": Exit program\r\n", ExitCommand, 0}; + +static shell_command_context_list_t g_RegisteredCommands; + +static char g_paramBuffer[SHELL_BUFFER_SIZE]; + +/******************************************************************************* + * Code + ******************************************************************************/ +void SHELL_Init( + p_shell_context_t context, send_data_cb_t send_cb, recv_data_cb_t recv_cb, printf_data_t shell_printf, char *prompt) +{ + assert(send_cb != NULL); + assert(recv_cb != NULL); + assert(prompt != NULL); + assert(shell_printf != NULL); + + /* Memset for context */ + memset(context, 0, sizeof(shell_context_struct)); + context->send_data_func = send_cb; + context->recv_data_func = recv_cb; + context->printf_data_func = shell_printf; + context->prompt = prompt; + + SHELL_RegisterCommand(&xHelpCommand); + SHELL_RegisterCommand(&xExitCommand); +} + +int32_t SHELL_Main(p_shell_context_t context) +{ + uint8_t ch; + int32_t i; + + if (!context) + { + return -1; + } + + context->exit = false; + context->printf_data_func("\r\nSHELL (build: %s)\r\n", __DATE__); + context->printf_data_func("Copyright (c) 2015 Freescale Semiconductor\r\n"); + context->printf_data_func(context->prompt); + + while (1) + { + if (context->exit) + { + break; + } + ch = GetChar(context); + /* Special key */ + if (ch == KEY_ESC) + { + context->stat = kSHELL_Special; + continue; + } + else if (context->stat == kSHELL_Special) + { + /* Function key */ + if (ch == '[') + { + context->stat = kSHELL_Function; + continue; + } + context->stat = kSHELL_Normal; + } + else if (context->stat == kSHELL_Function) + { + context->stat = kSHELL_Normal; + + switch ((uint8_t)ch) + { + /* History operation here */ + case 'A': /* Up key */ + GetHistoryCommand(context, context->hist_current); + if (context->hist_current < (context->hist_count - 1)) + { + context->hist_current++; + } + break; + case 'B': /* Down key */ + GetHistoryCommand(context, context->hist_current); + if (context->hist_current > 0) + { + context->hist_current--; + } + break; + case 'D': /* Left key */ + if (context->c_pos) + { + context->printf_data_func("\b"); + context->c_pos--; + } + break; + case 'C': /* Right key */ + if (context->c_pos < context->l_pos) + { + context->printf_data_func("%c", context->line[context->c_pos]); + context->c_pos++; + } + break; + default: + break; + } + continue; + } + /* Handle tab key */ + else if (ch == '\t') + { +#if SHELL_AUTO_COMPLETE + /* Move the cursor to the beginning of line */ + for (i = 0; i < context->c_pos; i++) + { + context->printf_data_func("\b"); + } + /* Do auto complete */ + AutoComplete(context); + /* Move position to end */ + context->c_pos = context->l_pos = StrLen(context->line); +#endif + continue; + } +#if SHELL_SEARCH_IN_HIST + /* Search command in history */ + else if ((ch == '`') && (context->l_pos == 0) && (context->line[0] == 0x00)) + { + } +#endif + /* Handle backspace key */ + else if ((ch == KET_DEL) || (ch == '\b')) + { + /* There must be at last one char */ + if (context->c_pos == 0) + { + continue; + } + + context->l_pos--; + context->c_pos--; + + if (context->l_pos > context->c_pos) + { + memmove(&context->line[context->c_pos], &context->line[context->c_pos + 1], + context->l_pos - context->c_pos); + context->line[context->l_pos] = 0; + context->printf_data_func("\b%s \b", &context->line[context->c_pos]); + + /* Reset position */ + for (i = context->c_pos; i <= context->l_pos; i++) + { + context->printf_data_func("\b"); + } + } + else /* Normal backspace operation */ + { + context->printf_data_func("\b \b"); + context->line[context->l_pos] = 0; + } + continue; + } + else + { + } + + /* Input too long */ + if (context->l_pos >= (SHELL_BUFFER_SIZE - 1)) + { + context->l_pos = 0; + } + + /* Handle end of line, break */ + if ((ch == '\r') || (ch == '\n')) + { + context->printf_data_func("\r\n"); + ProcessCommand(context, context->line); + /* Reset all params */ + context->c_pos = context->l_pos = 0; + context->hist_current = 0; + context->printf_data_func(context->prompt); + memset(context->line, 0, sizeof(context->line)); + continue; + } + + /* Normal character */ + if (context->c_pos < context->l_pos) + { + memmove(&context->line[context->c_pos + 1], &context->line[context->c_pos], + context->l_pos - context->c_pos); + context->line[context->c_pos] = ch; + context->printf_data_func("%s", &context->line[context->c_pos]); + /* Move the cursor to new position */ + for (i = context->c_pos; i < context->l_pos; i++) + { + context->printf_data_func("\b"); + } + } + else + { + context->line[context->l_pos] = ch; + context->printf_data_func("%c", ch); + } + + ch = 0; + context->l_pos++; + context->c_pos++; + } + return 0; +} + +static int32_t HelpCommand(p_shell_context_t context, int32_t argc, char **argv) +{ + uint8_t i = 0; + + for (i = 0; i < g_RegisteredCommands.numberOfCommandInList; i++) + { + context->printf_data_func(g_RegisteredCommands.CommandList[i]->pcHelpString); + } + return 0; +} + +static int32_t ExitCommand(p_shell_context_t context, int32_t argc, char **argv) +{ + /* Skip warning */ + context->printf_data_func("\r\nSHELL exited\r\n"); + context->exit = true; + return 0; +} + +static void ProcessCommand(p_shell_context_t context, const char *cmd) +{ + static const shell_command_context_t *tmpCommand = NULL; + static const char *tmpCommandString; + int32_t argc; + char *argv[SHELL_BUFFER_SIZE]; + uint8_t flag = 1; + uint8_t tmpCommandLen; + uint8_t tmpLen; + uint8_t i = 0; + + tmpLen = StrLen(cmd); + argc = ParseLine(cmd, tmpLen, argv); + + if ((tmpCommand == NULL) && (argc > 0)) + { + for (i = 0; i < g_RegisteredCommands.numberOfCommandInList; i++) + { + tmpCommand = g_RegisteredCommands.CommandList[i]; + tmpCommandString = tmpCommand->pcCommand; + tmpCommandLen = StrLen(tmpCommandString); + /* Compare with space or end of string */ + if ((cmd[tmpCommandLen] == ' ') || (cmd[tmpCommandLen] == 0x00)) + { + if (StrCompare(tmpCommandString, argv[0], tmpCommandLen) == 0) + { + if ((tmpCommand->cExpectedNumberOfParameters == 0) && (argc == 1)) + { + flag = 0; + } + else if (tmpCommand->cExpectedNumberOfParameters > 0) + { + if ((argc - 1) == tmpCommand->cExpectedNumberOfParameters) + { + flag = 0; + } + } + else + { + flag = 1; + } + break; + } + } + } + } + + if ((tmpCommand != NULL) && (flag == 1U)) + { + context->printf_data_func( + "\r\nIncorrect command parameter(s). Enter \"help\" to view a list of available commands.\r\n\r\n"); + tmpCommand = NULL; + } + else if (tmpCommand != NULL) + { + tmpLen = StrLen(cmd); + /* Compare with last command. Push back to history buffer if different */ + if (tmpLen != StrCompare(cmd, context->hist_buf[0], StrLen(cmd))) + { + for (i = SHELL_HIST_MAX - 1; i > 0; i--) + { + memset(context->hist_buf[i], '\0', SHELL_BUFFER_SIZE); + tmpLen = StrLen(context->hist_buf[i - 1]); + StrCopy(context->hist_buf[i], context->hist_buf[i - 1], tmpLen); + } + memset(context->hist_buf[0], '\0', SHELL_BUFFER_SIZE); + tmpLen = StrLen(cmd); + StrCopy(context->hist_buf[0], cmd, tmpLen); + if (context->hist_count < SHELL_HIST_MAX) + { + context->hist_count++; + } + } + tmpCommand->pFuncCallBack(context, argc, argv); + tmpCommand = NULL; + } + else + { + context->printf_data_func( + "\r\nCommand not recognised. Enter 'help' to view a list of available commands.\r\n\r\n"); + tmpCommand = NULL; + } +} + +static void GetHistoryCommand(p_shell_context_t context, uint8_t hist_pos) +{ + uint8_t i; + uint32_t tmp; + + if (context->hist_buf[0][0] == '\0') + { + context->hist_current = 0; + return; + } + if (hist_pos > SHELL_HIST_MAX) + { + hist_pos = SHELL_HIST_MAX - 1; + } + tmp = StrLen(context->line); + /* Clear current if have */ + if (tmp > 0) + { + memset(context->line, '\0', tmp); + for (i = 0; i < tmp; i++) + { + context->printf_data_func("\b \b"); + } + } + + context->l_pos = StrLen(context->hist_buf[hist_pos]); + context->c_pos = context->l_pos; + StrCopy(context->line, context->hist_buf[hist_pos], context->l_pos); + context->printf_data_func(context->hist_buf[hist_pos]); +} + +static void AutoComplete(p_shell_context_t context) +{ + int32_t len; + int32_t minLen; + uint8_t i = 0; + const shell_command_context_t *tmpCommand = NULL; + const char *namePtr; + const char *cmdName; + + minLen = 0; + namePtr = NULL; + + if (!StrLen(context->line)) + { + return; + } + context->printf_data_func("\r\n"); + /* Empty tab, list all commands */ + if (context->line[0] == '\0') + { + HelpCommand(context, 0, NULL); + return; + } + /* Do auto complete */ + for (i = 0; i < g_RegisteredCommands.numberOfCommandInList; i++) + { + tmpCommand = g_RegisteredCommands.CommandList[i]; + cmdName = tmpCommand->pcCommand; + if (StrCompare(context->line, cmdName, StrLen(context->line)) == 0) + { + if (minLen == 0) + { + namePtr = cmdName; + minLen = StrLen(namePtr); + /* Show possible matches */ + context->printf_data_func("%s\r\n", cmdName); + continue; + } + len = StrCompare(namePtr, cmdName, StrLen(namePtr)); + if (len < 0) + { + len = len * (-1); + } + if (len < minLen) + { + minLen = len; + } + } + } + /* Auto complete string */ + if (namePtr) + { + StrCopy(context->line, namePtr, minLen); + } + context->printf_data_func("%s%s", context->prompt, context->line); + return; +} + +static char *StrCopy(char *dest, const char *src, int32_t count) +{ + char *ret = dest; + int32_t i = 0; + + for (i = 0; i < count; i++) + { + dest[i] = src[i]; + } + + return ret; +} + +static int32_t StrLen(const char *str) +{ + int32_t i = 0; + + while (*str) + { + str++; + i++; + } + return i; +} + +static int32_t StrCompare(const char *str1, const char *str2, int32_t count) +{ + while (count--) + { + if (*str1++ != *str2++) + { + return *(unsigned char *)(str1 - 1) - *(unsigned char *)(str2 - 1); + } + } + return 0; +} + +static int32_t ParseLine(const char *cmd, uint32_t len, char *argv[SHELL_MAX_ARGS]) +{ + uint32_t argc; + char *p; + uint32_t position; + + /* Init params */ + memset(g_paramBuffer, '\0', len + 1); + StrCopy(g_paramBuffer, cmd, len); + + p = g_paramBuffer; + position = 0; + argc = 0; + + while (position < len) + { + /* Skip all blanks */ + while (((char)(*p) == ' ') && (position < len)) + { + *p = '\0'; + p++; + position++; + } + /* Process begin of a string */ + if (*p == '"') + { + p++; + position++; + argv[argc] = p; + argc++; + /* Skip this string */ + while ((*p != '"') && (position < len)) + { + p++; + position++; + } + /* Skip '"' */ + *p = '\0'; + p++; + position++; + } + else /* Normal char */ + { + argv[argc] = p; + argc++; + while (((char)*p != ' ') && ((char)*p != '\t') && (position < len)) + { + p++; + position++; + } + } + } + return argc; +} + +int32_t SHELL_RegisterCommand(const shell_command_context_t *command_context) +{ + int32_t result = 0; + + /* If have room in command list */ + if (g_RegisteredCommands.numberOfCommandInList < SHELL_MAX_CMD) + { + g_RegisteredCommands.CommandList[g_RegisteredCommands.numberOfCommandInList++] = command_context; + } + else + { + result = -1; + } + return result; +} + +static uint8_t GetChar(p_shell_context_t context) +{ + uint8_t ch; + +#if SHELL_USE_FILE_STREAM + ch = fgetc(context->STDIN); +#else + context->recv_data_func(&ch, 1U); +#endif + return ch; +} diff --git a/utilities/fsl_shell.h b/utilities/fsl_shell.h new file mode 100644 index 0000000..c1472d9 --- /dev/null +++ b/utilities/fsl_shell.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FSL_SHELL_H_ +#define _FSL_SHELL_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup SHELL + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief Macro to set on/off history feature. */ +#ifndef SHELL_USE_HISTORY +#define SHELL_USE_HISTORY (0U) +#endif + +/*! @brief Macro to set on/off history feature. */ +#ifndef SHELL_SEARCH_IN_HIST +#define SHELL_SEARCH_IN_HIST (1U) +#endif + +/*! @brief Macro to select method stream. */ +#ifndef SHELL_USE_FILE_STREAM +#define SHELL_USE_FILE_STREAM (0U) +#endif + +/*! @brief Macro to set on/off auto-complete feature. */ +#ifndef SHELL_AUTO_COMPLETE +#define SHELL_AUTO_COMPLETE (1U) +#endif + +/*! @brief Macro to set console buffer size. */ +#ifndef SHELL_BUFFER_SIZE +#define SHELL_BUFFER_SIZE (64U) +#endif + +/*! @brief Macro to set maximum arguments in command. */ +#ifndef SHELL_MAX_ARGS +#define SHELL_MAX_ARGS (8U) +#endif + +/*! @brief Macro to set maximum count of history commands. */ +#ifndef SHELL_HIST_MAX +#define SHELL_HIST_MAX (3U) +#endif + +/*! @brief Macro to set maximum count of commands. */ +#ifndef SHELL_MAX_CMD +#define SHELL_MAX_CMD (6U) +#endif + +/*! @brief Shell user send data callback prototype.*/ +typedef void (*send_data_cb_t)(uint8_t *buf, uint32_t len); + +/*! @brief Shell user receiver data callback prototype.*/ +typedef void (*recv_data_cb_t)(uint8_t *buf, uint32_t len); + +/*! @brief Shell user printf data prototype.*/ +typedef int (*printf_data_t)(const char *format, ...); + +/*! @brief A type for the handle special key. */ +typedef enum _fun_key_status +{ + kSHELL_Normal = 0U, /*!< Normal key */ + kSHELL_Special = 1U, /*!< Special key */ + kSHELL_Function = 2U, /*!< Function key */ +} fun_key_status_t; + +/*! @brief Data structure for Shell environment. */ +typedef struct _shell_context_struct +{ + char *prompt; /*!< Prompt string */ + enum _fun_key_status stat; /*!< Special key status */ + char line[SHELL_BUFFER_SIZE]; /*!< Consult buffer */ + uint8_t cmd_num; /*!< Number of user commands */ + uint8_t l_pos; /*!< Total line position */ + uint8_t c_pos; /*!< Current line position */ +#if SHELL_USE_FILE_STREAM + FILE *STDOUT, *STDIN, *STDERR; +#else + send_data_cb_t send_data_func; /*!< Send data interface operation */ + recv_data_cb_t recv_data_func; /*!< Receive data interface operation */ + printf_data_t printf_data_func; +#endif + uint16_t hist_current; /*!< Current history command in hist buff*/ + uint16_t hist_count; /*!< Total history command in hist buff*/ + char hist_buf[SHELL_HIST_MAX][SHELL_BUFFER_SIZE]; /*!< History buffer*/ + bool exit; /*!< Exit Flag*/ +} shell_context_struct, *p_shell_context_t; + +/*! @brief User command function prototype. */ +typedef int32_t (*cmd_function_t)(p_shell_context_t context, int32_t argc, char **argv); + +/*! @brief User command data structure. */ +typedef struct _shell_command_context +{ + const char *pcCommand; /*!< The command that is executed. For example "help". It must be all lower case. */ + char *pcHelpString; /*!< String that describes how to use the command. It should start with the command itself, + and end with "\r\n". For example "help: Returns a list of all the commands\r\n". */ + const cmd_function_t + pFuncCallBack; /*!< A pointer to the callback function that returns the output generated by the command. */ + uint8_t cExpectedNumberOfParameters; /*!< Commands expect a fixed number of parameters, which may be zero. */ +} shell_command_context_t; + +/*! @brief Structure list command. */ +typedef struct _shell_command_context_list +{ + const shell_command_context_t *CommandList[SHELL_MAX_CMD]; /*!< The command table list */ + uint8_t numberOfCommandInList; /*!< The total command in list */ +} shell_command_context_list_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* _cplusplus */ + +/*! + * @name Shell functional Operation + * @{ + */ + +/*! +* @brief Enables the clock gate and configure the Shell module according to the configuration structure. +* +* This function must be called before calling all other Shell functions. +* Call operation the Shell commands with user-defined settings. +* The example below shows how to set up the middleware Shell and +* how to call the SHELL_Init function by passing in these parameters: +* Example: +* @code +* shell_context_struct user_context; +* SHELL_Init(&user_context, SendDataFunc, ReceiveDataFunc, "SHELL>> "); +* @endcode +* @param context The pointer to the Shell environment and runtime states. +* @param send_cb The pointer to call back send data function. +* @param recv_cb The pointer to call back receive data function. +* @param prompt The string prompt of Shell +*/ +void SHELL_Init(p_shell_context_t context, + send_data_cb_t send_cb, + recv_data_cb_t recv_cb, + printf_data_t shell_printf, + char *prompt); + +/*! + * @brief Shell register command. + * @param command_context The pointer to the command data structure. + * @return -1 if error or 0 if success + */ +int32_t SHELL_RegisterCommand(const shell_command_context_t *command_context); + +/*! + * @brief Main loop for Shell. + * Main loop for Shell; After this function is called, Shell begins to initialize the basic variables and starts to + * work. + * @param context The pointer to the Shell environment and runtime states. + * @return this function does not return until Shell command exit was called. + */ +int32_t SHELL_Main(p_shell_context_t context); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_SHELL_H_ */ |