| /**************************************************************************** |
| * apps/system/cfgdata/cfgdata_main.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| #include <nuttx/mtd/mtd.h> |
| #include <nuttx/mtd/configdata.h> |
| #include <sys/ioctl.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <inttypes.h> |
| |
| /**************************************************************************** |
| * Private data |
| ****************************************************************************/ |
| |
| static const char *g_config_dev = "/dev/config"; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Print usage information |
| ****************************************************************************/ |
| |
| static void cfgdatacmd_help(void) |
| { |
| printf("\nUsage: cfgdata <cmd> [arguments]\n"); |
| printf("Where <cmd> is one of:\n\n"); |
| printf(" all: show all config entries\n"); |
| printf(" print: display a specific config entry\n"); |
| printf(" set: set or change a config entry\n"); |
| printf(" unset: delete a config entry\n"); |
| printf(" format: delete all config entries\n\n"); |
| |
| printf("Syntax for 'set' cmd:\n"); |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| printf(" set name [hex_byte,hex_byte,etc.]\n"); |
| printf(" set name \"string\"\n\n"); |
| #else |
| printf(" set id,instance [bytes]\n"); |
| printf(" set id,instance \"string\"\n\n"); |
| #endif |
| |
| printf("Syntax for 'print' cmd:\n"); |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| printf(" print name\n"); |
| #else |
| printf(" print id,instance\n"); |
| #endif |
| |
| printf("Syntax for 'unset' cmd:\n"); |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| printf(" unset name\n"); |
| #else |
| printf(" unset id,instance\n"); |
| #endif |
| } |
| |
| /**************************************************************************** |
| * Parse out the id,inst,name tokens |
| ****************************************************************************/ |
| |
| #ifndef CONFIG_MTD_CONFIG_NAMED |
| static int cfgdatacmd_idtok(int startpos, char *token) |
| { |
| while (token[startpos] != ',' && token[startpos] != '\0') |
| { |
| startpos++; |
| } |
| |
| if (token[startpos] != ',') |
| { |
| /* Error in format */ |
| |
| printf("Expected config identifier in 'id,instance' format\n"); |
| return 0; |
| } |
| |
| /* return, skipping the ',' */ |
| |
| return startpos + 1; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Set a config item value |
| * |
| * config set 1,0,wr_width_cs0 [0x3] |
| * config set 1,1,wr_width_cs1 [0x2] |
| * |
| ****************************************************************************/ |
| |
| static void cfgdatacmd_parse_byte_array(struct config_data_s *cfg, |
| int argc, char *argv[]) |
| { |
| int x; |
| int c; |
| int count; |
| int val; |
| |
| /* Start with arg3 */ |
| |
| x = 3; |
| c = 1; |
| count = 0; |
| |
| /* Loop for all remaining arguments until ']' found */ |
| |
| while (x < argc && argv[x][c] != ']' && argv[x][c] != '\0') |
| { |
| /* Count this item */ |
| |
| count++; |
| |
| /* Skip to next item */ |
| |
| while (argv[x][c] != ',' && argv[x][c] != ']' && argv[x][c] != 0) |
| { |
| c++; |
| } |
| |
| /* Test for comma separator */ |
| |
| if (argv[x][c] == ',') |
| { |
| c++; |
| } |
| |
| /* Test for space separated items */ |
| |
| if (argv[x][c] == 0) |
| { |
| x++; |
| c = 0; |
| } |
| } |
| |
| /* Test if static stack space allocation is big enough for data */ |
| |
| if (count > cfg->len) |
| { |
| /* Perform dynamic memory allocation */ |
| |
| cfg->configdata = (FAR uint8_t *)malloc(count); |
| cfg->len = count; |
| } |
| |
| /* Count determined. Start with arg3 again and parse the bytes */ |
| |
| x = 3; |
| c = 1; |
| count = 0; |
| |
| /* Loop for all remaining arguments until ']' found */ |
| |
| while (x < argc && argv[x][c] != ']' && argv[x][c] != '\0') |
| { |
| /* Parse this item */ |
| |
| if (strncmp(&argv[x][c], "0x", 2) == 0) |
| { |
| /* Hex byte */ |
| |
| sscanf(&argv[x][c + 2], "%x", &val); |
| cfg->configdata[count] = (uint8_t)val; |
| } |
| else |
| { |
| /* Decimal value */ |
| |
| cfg->configdata[count] = (uint8_t)atoi(&argv[x][c]); |
| } |
| |
| /* Increment the count */ |
| |
| count++; |
| |
| /* Skip to next item */ |
| |
| while (argv[x][c] != ',' && argv[x][c] != ']' && argv[x][c] != 0) |
| { |
| c++; |
| } |
| |
| /* Test for comma separator */ |
| |
| if (argv[x][c] == ',') |
| { |
| c++; |
| } |
| |
| /* Test for space separated items */ |
| |
| if (argv[x][c] == 0) |
| { |
| x++; |
| c = 0; |
| } |
| } |
| |
| cfg->len = count; |
| } |
| |
| /**************************************************************************** |
| * Set a config item value |
| * |
| * config set 1,0,wr_width_cs0 [0x3] |
| * config set 1,1,wr_width_cs1 [0x2] |
| * |
| ****************************************************************************/ |
| |
| static void cfgdatacmd_set(int argc, char *argv[]) |
| { |
| int ret; |
| int fd; |
| int x; |
| struct config_data_s cfg; |
| uint8_t data[32]; |
| |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| |
| /* Copy the name to the cfg struct */ |
| |
| strlcpy(cfg.name, argv[2], CONFIG_MTD_CONFIG_NAME_LEN); |
| |
| #else |
| |
| /* Parse the id and instance */ |
| |
| cfg.id = atoi(argv[2]); |
| |
| /* Advance past ',' to instance number */ |
| |
| x = cfgdatacmd_idtok(0, argv[2]); |
| if (x == 0) |
| { |
| return; |
| } |
| |
| /* Convert instance to integer */ |
| |
| cfg.instance = atoi(&argv[2][x]); |
| #endif |
| |
| /* Test if data is an array of bytes or simple string */ |
| |
| if (argv[3][0] == '[') |
| { |
| /* It is an array of bytes. Count the number of bytes */ |
| |
| cfg.configdata = data; |
| cfg.len = sizeof(data); |
| cfgdatacmd_parse_byte_array(&cfg, argc, argv); |
| } |
| else |
| { |
| bool isnumber = true; |
| |
| /* It is a simple string. Test if it looks like a number */ |
| |
| cfg.configdata = data; |
| if (strncmp(argv[3], "0x", 2) == 0) |
| { |
| /* Test for all hex digit values */ |
| |
| for (x = 2; x < strlen(argv[3]); x++) |
| { |
| if (!isxdigit(argv[3][x])) |
| { |
| isnumber = false; |
| break; |
| } |
| } |
| |
| if (isnumber) |
| { |
| sscanf(&argv[3][2], "%" SCNx32, (int32_t *)&cfg.configdata); |
| cfg.len = 4; |
| } |
| } |
| else |
| { |
| /* Test for all hex digit values */ |
| |
| for (x = 0; x < strlen(argv[3]); x++) |
| { |
| if (!isdigit(argv[3][x])) |
| { |
| isnumber = false; |
| break; |
| } |
| } |
| |
| if (isnumber) |
| { |
| int32_t temp = atoi(argv[3]); |
| *((int32_t *)cfg.configdata) = temp; |
| cfg.len = 4; |
| } |
| } |
| |
| if (!isnumber) |
| { |
| /* Point to the string and calculate the length */ |
| |
| cfg.configdata = (FAR uint8_t *)argv[3]; |
| cfg.len = strlen(argv[3]) + 1; |
| } |
| } |
| |
| /* Now open the /dev/config file and set the config item */ |
| |
| if ((fd = open(g_config_dev, 0)) < 2) |
| { |
| /* Display error */ |
| |
| printf("error: unable to open %s\n", g_config_dev); |
| return; |
| } |
| |
| ret = ioctl(fd, CFGDIOC_SETCONFIG, (unsigned long)(uintptr_t)&cfg); |
| |
| /* Close the file and report error if any */ |
| |
| close(fd); |
| if (ret != OK) |
| { |
| printf("Error %d setting config entry\n", errno); |
| } |
| |
| /* Free the cfg.configdata if needed */ |
| |
| if (cfg.configdata != (FAR uint8_t *)argv[3] && |
| cfg.configdata != data) |
| { |
| free(cfg.configdata); |
| } |
| } |
| |
| /**************************************************************************** |
| * Unset a config item value |
| ****************************************************************************/ |
| |
| static void cfgdatacmd_unset(int argc, char *argv[]) |
| { |
| int ret; |
| int fd; |
| struct config_data_s cfg; |
| |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| /* Copy the name to the cfg struct */ |
| |
| strlcpy(cfg.name, argv[2], CONFIG_MTD_CONFIG_NAME_LEN); |
| |
| #else |
| int x; |
| |
| /* Parse the id and instance */ |
| |
| cfg.id = atoi(argv[2]); |
| |
| /* Advance past ',' to instance number */ |
| |
| x = cfgdatacmd_idtok(0, argv[2]); |
| if (x == 0) |
| { |
| return; |
| } |
| |
| /* Convert instance to integer */ |
| |
| cfg.instance = atoi(&argv[2][x]); |
| #endif |
| |
| cfg.configdata = NULL; |
| cfg.len = 0; |
| |
| /* Try to open the /dev/config file */ |
| |
| if ((fd = open(g_config_dev, 0)) < 2) |
| { |
| /* Display error */ |
| |
| printf("error: unable to open %s\n", g_config_dev); |
| return; |
| } |
| |
| /* Delete the config item */ |
| |
| ret = ioctl(fd, CFGDIOC_DELCONFIG, (unsigned long)(uintptr_t)&cfg); |
| close(fd); |
| |
| if (ret != OK) |
| { |
| printf("Error deletign config entry '%s'\n", argv[2]); |
| } |
| } |
| |
| /**************************************************************************** |
| * Print a config item value |
| * |
| * config print 1,1 |
| * config print wr_width_cs0 |
| * |
| ****************************************************************************/ |
| |
| static void cfgdatacmd_print(int argc, char *argv[]) |
| { |
| int ret; |
| int fd; |
| int x; |
| struct config_data_s cfg; |
| bool isstring; |
| |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| |
| /* Copy the name to the cfg struct */ |
| |
| strlcpy(cfg.name, argv[2], CONFIG_MTD_CONFIG_NAME_LEN); |
| |
| #else |
| |
| /* Parse the id and instance */ |
| |
| cfg.id = atoi(argv[2]); |
| |
| /* Advance past ',' to instance number */ |
| |
| x = cfgdatacmd_idtok(0, argv[2]); |
| if (x == 0) |
| { |
| return; |
| } |
| |
| /* Convert instance to integer */ |
| |
| cfg.instance = atoi(&argv[2][x]); |
| #endif |
| |
| /* Try to open the /dev/config file */ |
| |
| if ((fd = open(g_config_dev, O_RDONLY)) < 2) |
| { |
| /* Display error */ |
| |
| printf("error: unable to open %s\n", g_config_dev); |
| return; |
| } |
| |
| cfg.configdata = (FAR uint8_t *)malloc(256); |
| cfg.len = 256; |
| if (cfg.configdata == NULL) |
| { |
| printf("Error allocating buffer\n"); |
| return; |
| } |
| |
| /* Get the config item */ |
| |
| ret = ioctl(fd, CFGDIOC_GETCONFIG, (unsigned long)(uintptr_t)&cfg); |
| close(fd); |
| |
| if (ret != OK) |
| { |
| printf("Error reading config entry '%s'\n", argv[2]); |
| free(cfg.configdata); |
| return; |
| } |
| |
| /* Display the data */ |
| |
| isstring = cfg.configdata[cfg.len - 1] == 0; |
| for (x = 0; x < cfg.len - 1; x++) |
| { |
| /* Test for all ascii characters */ |
| |
| if (cfg.configdata[x] < ' ' || cfg.configdata[x] > '~') |
| { |
| isstring = false; |
| break; |
| } |
| } |
| |
| /* Display the data */ |
| |
| if (isstring) |
| { |
| printf("%s\n", cfg.configdata); |
| } |
| else |
| { |
| /* Loop though all bytes and display them */ |
| |
| for (x = 0; x < cfg.len; x++) |
| { |
| /* Print the next byte */ |
| |
| printf("0x%02X ", cfg.configdata[x]); |
| |
| if (((x + 1) & 7) == 0 && x + 1 != cfg.len) |
| { |
| printf("\n"); |
| } |
| } |
| |
| printf("\n"); |
| } |
| |
| free(cfg.configdata); |
| } |
| |
| /**************************************************************************** |
| * Enumerate and display all config items |
| ****************************************************************************/ |
| |
| static void cfgdatacmd_show_all_config_items(void) |
| { |
| int ret; |
| int fd; |
| int x; |
| struct config_data_s cfg; |
| char fmtstr[24]; |
| bool isstring; |
| |
| /* Try to open the /dev/config file */ |
| |
| if ((fd = open(g_config_dev, 0)) < 2) |
| { |
| /* Display error */ |
| |
| printf("error: unable to open %s\n", g_config_dev); |
| return; |
| } |
| |
| /* Print header */ |
| |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| snprintf(fmtstr, sizeof(fmtstr), |
| "%%-%ds%%-6sData\n", CONFIG_MTD_CONFIG_NAME_LEN); |
| printf(fmtstr, "Name", "Len"); |
| snprintf(fmtstr, sizeof(fmtstr), |
| "%%-%ds%%-6d", CONFIG_MTD_CONFIG_NAME_LEN); |
| #else |
| strlcpy(fmtstr, "%-6s%-6s%-6sData\n", sizeof(fmtstr)); |
| printf(fmtstr, "ID", "Inst", "Len"); |
| strlcpy(fmtstr, "%-6d%-6d%-6d", sizeof(fmtstr)); |
| #endif |
| |
| /* Get the first config item */ |
| |
| cfg.configdata = (FAR uint8_t *)malloc(256); |
| cfg.len = 256; |
| if (cfg.configdata == NULL) |
| { |
| printf("Error allocating buffer\n"); |
| return; |
| } |
| |
| ret = ioctl(fd, CFGDIOC_FIRSTCONFIG, (unsigned long)(uintptr_t)&cfg); |
| |
| while (ret != -1) |
| { |
| /* Print this entry */ |
| |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| printf(fmtstr, cfg.name, cfg.len); |
| #else |
| printf(fmtstr, cfg.id, cfg.instance, cfg.len); |
| #endif |
| |
| /* Test if data is a string */ |
| |
| isstring = cfg.configdata[cfg.len - 1] == 0; |
| for (x = 0; x < cfg.len - 1; x++) |
| { |
| /* Test for all ascii characters */ |
| |
| if (cfg.configdata[x] < ' ' || cfg.configdata[x] > '~') |
| { |
| isstring = false; |
| break; |
| } |
| } |
| |
| /* Display the data */ |
| |
| if (isstring) |
| { |
| printf("%s\n", cfg.configdata); |
| } |
| else |
| { |
| char fmtstr2[10]; |
| |
| #ifdef CONFIG_MTD_CONFIG_NAMED |
| snprintf(fmtstr2, sizeof(fmtstr2), |
| "\n%ds", CONFIG_MTD_CONFIG_NAME_LEN + 6); |
| #else |
| strlcpy(fmtstr2, "\n%18s", sizeof(fmtstr2)); |
| #endif |
| /* Loop though all bytes and display them */ |
| |
| for (x = 0; x < cfg.len; x++) |
| { |
| /* Print the next byte */ |
| |
| printf("0x%02X ", cfg.configdata[x]); |
| |
| if (((x + 1) & 7) == 0 && x + 1 != cfg.len) |
| { |
| printf(fmtstr2, " "); |
| } |
| } |
| |
| printf("\n"); |
| } |
| |
| /* Get the next config item */ |
| |
| cfg.len = 256; |
| ret = ioctl(fd, CFGDIOC_NEXTCONFIG, (unsigned long)(uintptr_t)&cfg); |
| } |
| |
| close(fd); |
| free(cfg.configdata); |
| } |
| |
| /**************************************************************************** |
| * Erase all config items |
| ****************************************************************************/ |
| |
| static void cfgdatacmd_format(void) |
| { |
| int fd; |
| int ret; |
| |
| /* Try to open the /dev/config file */ |
| |
| if ((fd = open(g_config_dev, 0)) < 2) |
| { |
| /* Display error */ |
| |
| printf("error: unable to open %s\n", g_config_dev); |
| return; |
| } |
| |
| ret = ioctl(fd, MTDIOC_BULKERASE, 0); |
| close(fd); |
| |
| if (ret != OK) |
| { |
| printf("Error %d config format\n", errno); |
| } |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| int main(int argc, FAR char *argv[]) |
| { |
| /* Argument given? */ |
| |
| if (argc == 1) |
| { |
| /* Show usage info and exit */ |
| |
| cfgdatacmd_help(); |
| return 0; |
| } |
| |
| /* Test for "all" cmd */ |
| |
| if (strcmp(argv[1], "all") == 0) |
| { |
| /* Print the existing config items */ |
| |
| cfgdatacmd_show_all_config_items(); |
| return 0; |
| } |
| |
| /* Test for "set" cmd */ |
| |
| if (strcmp(argv[1], "set") == 0) |
| { |
| if (argc < 4) |
| { |
| printf("At least 2 arguments needed for 'set' command\n"); |
| return 0; |
| } |
| |
| /* Call the routine to set a config item */ |
| |
| cfgdatacmd_set(argc, argv); |
| return 0; |
| } |
| |
| /* Test for "print" cmd */ |
| |
| if (strcmp(argv[1], "print") == 0) |
| { |
| /* Test for print all */ |
| |
| if (strcmp(argv[2], "all") == 0) |
| { |
| cfgdatacmd_show_all_config_items(); |
| } |
| else |
| { |
| /* Call the routine to print a config item */ |
| |
| cfgdatacmd_print(argc, argv); |
| } |
| |
| return 0; |
| } |
| |
| /* Test for "unset" cmd */ |
| |
| if (strcmp(argv[1], "unset") == 0) |
| { |
| if (argc < 3) |
| { |
| printf("Need 1 argument for 'unset' command\n"); |
| return 0; |
| } |
| |
| /* Call the routine to set a config item */ |
| |
| cfgdatacmd_unset(argc, argv); |
| return 0; |
| } |
| |
| /* Test for "format" cmd */ |
| |
| if (strcmp(argv[1], "format") == 0) |
| { |
| /* Call the routine to erase all config items */ |
| |
| cfgdatacmd_format(); |
| return 0; |
| } |
| |
| /* Unknown cmd */ |
| |
| printf("Unknown config command: %s\n", argv[1]); |
| |
| return 0; |
| } |