Pratyush Mallick / Mbed OS nano_dac
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers adi_console_menu.c Source File

adi_console_menu.c

Go to the documentation of this file.
00001 /*!
00002  *****************************************************************************
00003   @file:  adi_console_menu.c
00004 
00005   @brief: A simple console menu manager handler
00006 
00007   @details: A way to define using arrays of structs a set of menus that can
00008             be displayed to a user, easily, with all user interaction handled
00009             by the library, leaving only the implementation of the menu actions
00010             to be done by the library user.
00011  -----------------------------------------------------------------------------
00012  Copyright (c) 2019, 2020 Analog Devices, Inc.
00013  All rights reserved.
00014 
00015  This software is proprietary to Analog Devices, Inc. and its licensors.
00016  By using this software you agree to the terms of the associated
00017  Analog Devices Software License Agreement.
00018 
00019 *****************************************************************************/
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <ctype.h>
00024 #include <string.h>
00025 #include <stdbool.h>
00026 #include <assert.h>
00027 
00028 #include "adi_console_menu.h"
00029 
00030 
00031 #define DIV_STRING "\t=================================================="
00032 
00033 /*!
00034  * @brief      displays the text of a console menu
00035  *
00036  * @details
00037  */
00038 static void adi_display_console_menu(const console_menu * menu)
00039 {
00040     adi_clear_console();
00041 
00042     // call headerItem to allow display of other content
00043     if (menu->headerItem != NULL) {
00044         menu->headerItem();
00045         printf(DIV_STRING EOL);
00046     }
00047 
00048     /*
00049      * Display the menu title and  menuItems
00050      * The shortcutKey is used to display '[A]' before the dispayText
00051      */
00052     printf("\t%s" EOL "\t", menu->title);
00053     // show an underline to distinguish title from item
00054     for (uint8_t i = 0; i < strlen(menu->title); i++) {
00055         putchar('-');
00056     }
00057     // Extend underline past end of string, and then new line
00058     printf("--" EOL);
00059 
00060     // If the shortcutKey is not unique, first found is used
00061     for (uint8_t i = 0; i < menu->itemCount; i ++) {
00062         if (menu->items[i].shortcutKey == '\00') {
00063             // No shortcut key defined, but display item text if available
00064             printf("\t%s" EOL, menu->items[i].text);
00065         } else {
00066             printf("\t[%c] %s" EOL, toupper(menu->items[i].shortcutKey),
00067                    menu->items[i].text);
00068         }
00069     }
00070     if (menu->enableEscapeKey) {
00071         printf(EOL "\t[ESC] Exit Menu" EOL);
00072     }
00073 
00074     printf(EOL "\tPlease make a selection." EOL);
00075 
00076     // call footerItem to allow display of other content
00077     if (menu->footerItem != NULL) {
00078         printf(DIV_STRING EOL);
00079         menu->footerItem();
00080     }
00081 }
00082 
00083 
00084 /*!
00085  * @brief      Display a consoleMenu and handle User interaction
00086  *
00087  * @details    This displays the menuItems defined by the console menu, and
00088  *              handles all user interaction for the menu.
00089  */
00090 int32_t adi_do_console_menu(const console_menu * menu)
00091 {
00092     int32_t itemSelected = MENU_ESCAPED;
00093     bool enableKeyScan = true;
00094 
00095     adi_display_console_menu(menu);
00096 
00097     /*
00098      *  Loop waiting for valid user input. menuItem index is returned if
00099      *  user presses a valid menu option.
00100      */
00101     do {
00102         char keyPressed = toupper(getchar());
00103 
00104         if (menu->enableEscapeKey) {
00105             if (keyPressed == ESCAPE_KEY_CODE) {
00106                 itemSelected = MENU_ESCAPED;
00107                 enableKeyScan = false;
00108                 break;
00109             }
00110         }
00111 
00112         for (uint8_t i = 0; i < menu->itemCount; i ++) {
00113             if (toupper(menu->items[i].shortcutKey) == keyPressed) {
00114                 itemSelected = i;
00115 
00116                 // If the menuAction function pointer is not NULL, call the action
00117                 if (menu->items[i].action != NULL) {
00118                     switch (menu->items[i].action(menu->items[i].id)) {
00119                     case MENU_DONE: {
00120                         enableKeyScan = false;
00121                         break;
00122                     }
00123                     case MENU_CONTINUE:
00124                     default: {
00125                         enableKeyScan = true;
00126                         adi_display_console_menu(menu);
00127                         break;
00128                     }
00129                     }
00130                 }
00131                 break;
00132             }
00133         }
00134     } while (enableKeyScan);
00135 
00136     return (itemSelected);
00137 }
00138 
00139 /*!
00140  * @brief      Reads a decimal string from the user
00141  *
00142  * @param      input_len max number of character to accept from the user
00143  *
00144  * @return      The integer value entered
00145  *
00146  * @details    Allows a user to type in number, echoing back to the user,
00147  *             up to input_len chars
00148  *
00149  *  @note      Only positive integer numbers are supported currently
00150  */
00151 int32_t adi_get_decimal_int(uint8_t input_len)
00152 {
00153     char buf[20] = {0};
00154     uint8_t buf_index = 0;
00155     char ch;
00156     bool loop = true;
00157 
00158     assert(input_len < 19);
00159 
00160     do  {
00161         ch = getchar();
00162         if (isdigit(ch) && buf_index < (input_len)) {
00163             //  echo and store it as buf not full
00164             buf[buf_index++] = ch;
00165             putchar(ch);
00166         }
00167         if ((ch == '\x7F') && (buf_index > 0)) {
00168             //backspace and at least 1 char in buffer
00169             buf[buf_index--] = '\x00';
00170             putchar(ch);
00171         }
00172         if ((ch == '\x0D') || (ch == '\x0A')) {
00173             // return key pressed, all done, null terminate string
00174             buf[buf_index] = '\x00';
00175             loop = false;
00176         }
00177     } while(loop);
00178 
00179     return atoi(buf);
00180 }
00181 
00182 /*!
00183  * @brief      Reads a hexadecimal number from the user
00184  *
00185  * @param      input_len max number of character to accept from the user
00186  *
00187  * @return     The integer value entered
00188  *
00189 * @details     Allows a user to type in a hexnumber, echoing back to the user,
00190  *             up to input_len chars
00191  */
00192 uint32_t adi_get_hex_integer(uint8_t input_len)
00193 {
00194     char buf[9] = {0};
00195     uint8_t buf_index = 0;
00196     char ch;
00197     bool loop = true;
00198 
00199     assert(input_len < 8);
00200 
00201     do  {
00202         ch = getchar();
00203         if (isxdigit(ch) && buf_index < (input_len)) {
00204             //  echo and store it as buf not full
00205             buf[buf_index++] = ch;
00206             putchar(ch);
00207         }
00208         if ((ch == '\x7F') && (buf_index > 0)) {
00209             //backspace and at least 1 char in buffer
00210             buf[buf_index--] = '\x00';
00211             putchar(ch);
00212         }
00213         if ((ch == '\x0D') || (ch == '\x0A')) {
00214             // return key pressed, all done, null terminate string
00215             buf[buf_index] = '\x00';
00216             loop = false;
00217         }
00218     } while(loop);
00219 
00220     return strtol(buf, NULL, 16);
00221 }
00222 
00223 
00224 /*!
00225  * @brief      Reads a floating string from the user
00226  *
00227  * @param      input_len max number of character to accept from the user
00228  *
00229  * @return      The float value entered
00230  *
00231  * @details    Allows a user to type in number, echoing back to the user,
00232  *             up to input_len chars
00233  *
00234  *  @note      Only positive floating point numbers are supported currently
00235  */
00236 float adi_get_decimal_float(uint8_t input_len)
00237 {
00238     char buf[20] = { 0 };
00239     uint8_t buf_index = 0;
00240     char ch;
00241     bool loop = true;
00242 
00243     assert(input_len < 19);
00244 
00245     do {
00246         ch = getchar();
00247         if ((isdigit(ch) || (ch == '.')) && buf_index < (input_len)) {
00248             //  echo and store it as buf not full
00249             buf[buf_index++] = ch;
00250             putchar(ch);
00251         }
00252         if ((ch == '\x7F') && (buf_index > 0)) {
00253             //backspace and at least 1 char in buffer
00254             buf[buf_index--] = '\x00';
00255             putchar(ch);
00256         }
00257         if ((ch == '\x0D') || (ch == '\x0A')) {
00258             // return key pressed, all done, null terminate string
00259             buf[buf_index] = '\x00';
00260             loop = false;
00261         }
00262     } while (loop);
00263 
00264     return atof(buf);
00265 }
00266 
00267 
00268 /*!
00269  * @brief      Clears the console terminal
00270  *
00271  * @details    Clears the console terminal using VT100 escape code, or can be changed to
00272  *             output blank lines if serial link doesn't support VT100.
00273  */
00274 void adi_clear_console(void)
00275 {
00276     /*
00277      * clear console and move cursor to home location, followed by move to home location.
00278      *  Dedicated call to move home is because sometimes first move home doesn't work
00279      *  \r\n required to flush the uart buffer.
00280      */
00281     printf("\x1B[2J\x1B[H\r\n");
00282 
00283     /*
00284      * if VT100 is not supported, this can be enabled instead, but menu display may not work well
00285      */
00286 //    for (uint8_t = 0; i < 100; i++)
00287 //      printf("\r\n\r");
00288 }
00289 
00290 
00291 /*!
00292  * @brief      waits for any key to be pressed, and displays a prompt to the user
00293  *
00294  * @details
00295  */
00296 void adi_press_any_key_to_continue(void)
00297 {
00298     printf("\r\nPress any key to continue...\r\n");
00299     getchar();
00300 }