/** * Utilities for console commands * * Created on 2020/03/11. */ #ifndef LIBCONSOLE_UTILS_H #define LIBCONSOLE_UTILS_H #include #include #ifndef STR #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) #endif #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif #ifndef OBC_FIRMWARE #define EXPENDABLE_STRING(x) x #define EXPENDABLE_CODE(x) x #else #define EXPENDABLE_STRING(x) "" #define EXPENDABLE_CODE(x) do {} while(0); #endif /** * Read an argument, or return default if it is empty. * * This works for commands arg_int0 * * Usage: * * \code * static struct { * struct arg_int *foo; * } args; * * args.foo = arg_int0(...); * * int foo = GET_ARG_INT0(args.foo, 1234); * \endcode */ #define GET_ARG_INT0(_arg, _def) ((_arg)->count ? (_arg)->ival[0] : (_def)) /** * Get CSP node ID from an argument table, using own address as default. * * Usage: * * \code * static struct { * struct arg_int *node; * } args; * * args.node = arg_int0(...); * * int node = GET_ARG_CSPADDR0(args.node); * \endcode */ #define GET_ARG_CSPADDR0(_arg) GET_ARG_INT0((_arg), csp_get_address()) /** * Shortcut to get a timeout argument's value, using CSP_DEF_TIMEOUT_MS as default. */ #define GET_ARG_TIMEOUT0(_arg) GET_ARG_INT0((_arg), CONSOLE_CSP_DEF_TIMEOUT_MS) /** * Define an optional CSP node argument */ #define arg_cspaddr0() arg_int0(NULL, NULL, "", EXPENDABLE_STRING("node ID")) /** * Define a mandatory CSP node argument */ #define arg_cspaddr1() arg_int1(NULL, NULL, "", EXPENDABLE_STRING("node ID")) /** * Define an optional timeout argument, with `CSP_DEF_TIMEOUT_MS` * shown as default. Use `GET_ARG_TIMEOUT0()` to retrieve its value. */ #define arg_timeout0() arg_int0("t", "timeout", "", EXPENDABLE_STRING("timeout in ms (default "STR(CONSOLE_CSP_DEF_TIMEOUT_MS)")")) /** * Define a timeout argument with a custom value shown as default. * Use `GET_ARG_INT0()` with the matching default to retrieve its value. */ #define arg_timeout0_def(_def) arg_int0("t", "timeout", "", EXPENDABLE_STRING("timeout in ms (default "STR(_def)")")) #define EMPTY_CMD_SETUP(_helptext) \ (void)ctx; \ static struct { \ struct arg_end *end; \ } args; \ \ if (reg) { \ args.end = arg_end(1); \ \ reg->argtable = &args; \ reg->help = EXPENDABLE_STRING(_helptext); \ return 0; \ } /** * Hexdump a buffer * * @param outf - output file * @param data - data to dump * @param len - data size */ void console_hexdump(const void *data, size_t len); /** * Decode hexa string to binary * * @param hex - hexa string, upper or lower case, must have even length * @param dest - destination buffer * @param capacity - buffer size * @return destination length, or: -1 (bad args), -2 (bad format), -3 (too long) */ int console_base16_decode(const char *hex, void *dest, size_t capacity); #if CONSOLE_USE_MEMSTREAM /** * Data struct for the filecap utilities */ struct console_filecap { char *buf; size_t buf_size; FILE *file; }; typedef struct console_filecap console_filecap_t; /** * Open a temporary in-memory file that can be used to capture the output * of functions taking a FILE * argument. * * @param cap - pointer to a filecap struct (can be on stack) * @return success */ console_err_t console_filecap_init(console_filecap_t *cap); /** * Clean up the capture struct. * * If the buffer is to be used elsewhere, place NULL in the struct to avoid freeing it. * * If the struct itself was allocated on heap, it is the caller's responsibility to free it manually. * * @param cap - pointer to a filecap struct */ void console_filecap_end(console_filecap_t *cap); /** * Print the captured output to console output stream and clean up the struct (calls `console_filecap_end()`) * * @param cap - pointer to a filecap struct */ void console_filecap_print_end(console_filecap_t *cap); #endif // CONSOLE_USE_MEMSTREAM /** * Cross-platform malloc that can be used from console commands. * If CSP is available and the platform is not POSIX, the implementation from there is used (i.e. FreeRTOS alloc) */ void * __attribute__((malloc)) console_malloc(size_t size); /** * Cross-platform realloc that can be used from console commands. * * It is not possible to determine the size of an allocated memory region in a portable way, * that's why this function takes the old size as an argument. On POSIX, the argument is simply ignored. * * If CSP is available and the platform is not POSIX, the implementation from there is used (i.e. FreeRTOS alloc). * NOTE: CSP does not provide realloc, therefore this function allocates a new buffer, copies data, and frees the old buffer. * * Returns the original buffer if the new size is <= old size. */ void * console_realloc(void *ptr, size_t oldsize, size_t newsize); /** * Cross-platform calloc that can be used from console commands. * If CSP is available and the platform is not POSIX, the implementation from there is used (i.e. FreeRTOS alloc) */ void * __attribute__((malloc,alloc_size(1,2))) console_calloc(size_t nmemb, size_t size); /** * `free()` for memory allocated by `console_malloc()` or `console_calloc()` */ void console_free(void *ptr); /** * `strdup()` using `console_malloc()`. Free with `console_free()` */ char * console_strdup(const char *ptr); /** * `strndup()` using `console_malloc()`. Free with `console_free()` */ char * console_strndup(const char *ptr, size_t maxlen); #endif //LIBCONSOLE_UTILS_H