/* * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may * not use this file except in compliance with the License. A copy of the * License is located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file 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. */ /** @file * EC2 F1 CLI parsing and associated help text. */ #include #include #include #include #include #include #include #include #include #include #include #include "fpga_local_cmd.h" #include "virtual_jtag.h" #define MSEC_PER_SEC 1000 /** * Usage defines for use with print_usage. */ static const char *opcode_str_usage[] = { " SYNOPSIS", " fpga-local-cmd [GENERAL OPTIONS] [-h]", " DESCRIPTION", " This program is normally executed via the wrapper scripts.", " See fpga-load-local-image, fpga-clear-local-image,", " fpga-describe-local-image, fpga-describe-local-image-slots.", " fpga-start-virtual-jtag, fpga-get-virtual-led", " fpga-get-virtual-dip-switch, fpga-set-virtual-dip-switch", " GENERAL OPTIONS", " LoadFpgaImage, ClearFpgaImage, DescribeFpgaImage,", " DescribeFpgaImageSlots, StartVirtualJtag, GetVirtualLED,", " GetVirtualDIP, SetVirtualDIP", }; static const char *describe_afi_slots_usage[] = { " SYNOPSIS", " fpga-describe-local-image-slots [GENERAL OPTIONS] [-h]", " Example: fpga-describe-local-image-slots", " DESCRIPTION", " Returns the FPGA image slot numbers and device mappings to use for", " the fpga-load-local-image, fpga-clear-local-image, and", " fpga-describe-local-image commands.", " GENERAL OPTIONS", " -h, --help", " Display this help.", " -H, --headers", " Display column headers.", " -V, --version", " Display version number of this program.", " --request-timeout TIMEOUT", " Specify a request timeout TIMEOUT (in seconds).", " -M, --show-mbox", " Show the mbox physical function in the list of devices." }; static const char *describe_afi_usage[] = { " SYNOPSIS", " fpga-describe-local-image [GENERAL OPTIONS] [-h]", " Example: fpga-describe-local-image -S 0", " DESCRIPTION", " Returns the status of the FPGA image for a specified FPGA image", " slot number. The fpga-image-slot parameter is a logical index that", " represents a given FPGA within an instance.", " Use fpga-describe-local-image-slots to return the available FPGA", " image slots for the instance.", " GENERAL OPTIONS", " -S, --fpga-image-slot", " The logical slot number for the FPGA image.", " Constraints: Positive integer from 0 to the total slots minus 1.", " -M --metrics", " Return FPGA image hardware metrics.", " Examples: FPGA PCI and DDR metrics.", " -C --clear-metrics", " Return FPGA image hardware metrics (clear on read).", " Examples: FPGA PCI and DDR metrics.", " -R --rescan", " Rescan the AFIDEVICE to update the per-AFI PCI VendorId and", " DeviceId that may be dynamically modified due to a", " fpga-load-local-image or fpga-clear-local-image command.", " NOTE1: this option removes the AFIDEVICE from the sysfs PCI", " subsystem and then rescans the PCI subsystem in order for", " the modified AFI PCI IDs to be refreshed.", " NOTE2: it is the developer's responsibility to remove any", " driver previously installed on the older PCIe VendorId", " and DeviceId before fpga-clear-local-image,", " fpga-load-local-image, or re-scan.", " -h, --help", " Display this help.", " -H, --headers", " Display column headers.", " -V, --version", " Display version number of this program.", " --request-timeout TIMEOUT", " Specify a request timeout TIMEOUT (in seconds).", }; static const char *load_afi_usage[] = { " SYNOPSIS", " fpga-load-local-image [GENERAL OPTIONS] [-h]", " Example: fpga-load-local-image -S 0 -I ", " DESCRIPTION", " Loads the specified FPGA image to the specified slot number, and", " returns the status of the command. The fpga-image-slot parameter", " is a logical index that represents a given FPGA within an instance.", " Use fpga-describe-local-image to return the FPGA image status, and", " fpga-describe-local-image-slots to return the available FPGA image", " slots for the instance.", " NOTE: By default, this command automatically rescans the AFIDEVICE", " to update the per-AFI PCI VendorId and DeviceId that may be", " dynamically modified during each FPGA image load.", " The rescan operation removes the AFIDEVICE from the sysfs PCI", " subsystem and then rescans the PCI subsystem in order for", " the modified AFI PCI IDs to be refreshed.", " It is the developer's responsibility to remove any", " driver previously installed on the older PCIe VendorId", " and DeviceId before the FPGA image is loaded.", " GENERAL OPTIONS", " -S, --fpga-image-slot", " The logical slot number for the FPGA image", " Constraints: Positive integer from 0 to the total slots minus 1.", " -I, --fpga-image-id", " The ID of the FPGA image. agfi-", " -A, --async", " The default mode of operation is synchronous FPGA image load", " with automatic rescan. The --async option may be specfied", " for asynchronous FPGA image load completion, which may be", " polled for completion using fpga-describe-local-image.", " -h, --help", " Display this help.", " -H, --headers", " Display column headers.", " -V, --version", " Display version number of this program.", " --request-timeout TIMEOUT", " Specify a request timeout TIMEOUT (in seconds).", " --sync-timeout TIMEOUT", " Specify a timeout TIMEOUT (in seconds) for the sequence", " of operations that are performed in the synchronous (blocking)", " mode.", " -F, --force-shell-reload", " Reload the FPGA shell on AFI load, even if the next AFI", " doesn't require it.", " -a, --clock-a0-freq", " Request the clock a0 frequency be set to this value in Mhz or less,", " setting other frequencies in clock group a much slower.", " -b, --clock-b0-freq", " Request the clock b0 frequency be set to this value in Mhz or less,", " setting other frequencies in clock group b much slower.", " -c, --clock-c0-freq", " Request the clock c0 frequency be set to this value in Mhz or less,", " setting other frequencies in clock group c much slower.", " -D, --dram-data-retention", " Request that dram data retention be performed for this afi load.", " This will try to detect if retention is possible and reject the", " load if it is not. To use, call load with another afi already", " loaded.", " -P, --prefetch-image", " Prefetch the indicated AFI and store it in the cache for faster loading.", " Fastest load times can be achieved by using cached AFIs and enabling data retention (-D).", " See Reducing AFI load times documentation.", }; static const char *clear_afi_usage[] = { " SYNOPSIS", " fpga-clear-local-image [GENERAL OPTIONS] [-h]", " Example: fpga-clear-local-image -S 0", " DESCRIPTION", " Clears the specified FPGA image slot, including FPGA internal and", " external memories that are used by the slot. The fpga-image-slot", " parameter is a logical index that represents a given FPGA within", " an instance.", " Use fpga-describe-local-image to return the FPGA image status, and", " fpga-describe-local-image-slots to return the available FPGA image", " slots for the instance.", " NOTE: By default, this command automatically rescans the AFIDEVICE", " to update the default AFI PCI VendorId and DeviceId that are", " dynamically modified during each FPGA image clear.", " The rescan operation removes the AFIDEVICE from the sysfs PCI", " subsystem and then rescans the PCI subsystem in order for", " the modified AFI PCI IDs to be refreshed.", " It is the developer's responsibility to remove any", " driver previously installed on the older PCIe VendorId", " and DeviceId before the FPGA image is cleared.", " GENERAL OPTIONS", " -S, --fpga-image-slot", " The logical slot number for the FPGA image.", " Constraints: Positive integer from 0 to the total slots minus 1.", " -A, --async", " The default mode of operation is synchronous FPGA image clear", " with automatic rescan. The --async option may be specfied", " for asynchronous FPGA image clear completion, which may be", " polled for completion using fpga-describe-local-image.", " -h, --help", " Display this help.", " -H, --headers", " Display column headers.", " -V, --version", " Display version number of this program.", " --request-timeout TIMEOUT", " Specify a request timeout TIMEOUT (in seconds).", " --sync-timeout TIMEOUT", " Specify a timeout TIMEOUT (in seconds) for the sequence", " of operations that are performed in the synchronous (blocking)", " mode", }; static const char *start_virtual_jtag_usage[] = { " SYNOPSIS", " fpga-start-virtual-jtag [GENERAL OPTIONS] [-h]", " Example: fpga-start-virtual-jtag -S 0 [-P ]", " DESCRIPTION", " Start Virtual JTAG spplication server, running Xilinx's Virtual", " Cable (XVC) service, which listens incoming command over TCP", " port that is set by -P option (Default TCP port is 10201).", " The fpga-image-slot parameter is a logical index that represents", " a given FPGA within an instance.", " This command will work only if AFI is in READY state:", " Use fpga-describe-local-image to return the FPGA image status, and", " fpga-describe-local-image-slots to return the AFI state.", " The AFI should have included Xilinx's VIO/LIA debug cores", " and AWS CL Debug Bridge inside the CustomLogic (CL)", " Concurrent debug of multiple FPGA slots is possible as long as", " different values are used for each slot.", " Linux firewall and/or EC2 Network Security Group rules may", " need to change for enabling inbound access to the TCP port.", " GENERAL OPTIONS", " -S, --fpga-image-slot", " The logical slot number for the FPGA image", " Constraints: Positive integer from 0 to the total slots minus 1.", " -P, --tcp-port", " The TCP port number to use for virtual jtag server, default", " TCP port is 10201. Remember to use different TCP port for", " different slot if debugging multiple slots concurrently", " -h, --help", " Display this help.", " -H, --headers", " Display column headers.", " -V, --version", " Display version number of this program.", }; static const char *get_virtual_led_usage[] = { " SYNOPSIS", " fpga-get-virtual-led [GENERAL OPTIONS] [-h]", " Example: fpga-get-virtual-led -S 0", " DESCRIPTION", " Returns the current status of the virtual LED exposed by the AFI, a", " series of 0 (zeros) and 1 (ones), first digit from the righti maps", " to cl_sh_vled[0]. For example, a return value 0000000001000000", " indicates that cl_sh_vled[6] is set(on)", " GENERAL OPTIONS", " -S, --fpga-image-slot", " The logical slot number for the FPGA image", " Constraints: Positive integer from 0 to the total slots minus 1.", " -h, --help", " Display this help.", " -H, --headers", " Display column headers.", " -V, --version", " Display version number of this program.", }; static const char *get_virtual_dip_usage[] = { " SYNOPSIS", " fpga-get-virtual-dip-switch [GENERAL OPTIONS] [-h]", " Example: fpga-get-virtual-dip-switch -S 0", " DESCRIPTION", " Returns the current status of the virtual DIP Switches by", " driven to the AFI. A series of 0 (Zeros) and 1 (ones)", " First digit from the right maps to sh_cl_vdip[0]", " For example, a return value 0000000001000000", " indicates that sh_cl_vdip[6] is set(on)", " GENERAL OPTIONS", " -S, --fpga-image-slot", " The logical slot number for the FPGA image", " Constraints: Positive integer from 0 to the total slots minus 1.", " -h, --help", " Display this help.", " -H, --headers", " Display column headers.", " -V, --version", " Display version number of this program.", }; static const char *set_virtual_dip_usage[] = { " SYNOPSIS", " fpga-set-virtual-dip-switch [GENERAL OPTIONS] [-h]", " Example: fpga-set-virtual-dip-switch -S 0 -D 0101000011000000", " DESCRIPTION", " Drive the AFI in a given slot with the specified virtual DIP Switches", " A 16 digit value is require: a series of 0 (zeros) and 1 (ones)", " First digit from the right maps to sh_cl_vdip[0]", " For example, a value 0101000011000000", " indicates that sh_cl_vdip[6], [7], [12], and [14] is set/on", " GENERAL OPTIONS", " -S, --fpga-image-slot", " The logical slot number for the FPGA image", " Constraints: Positive integer from 0 to the total slots minus 1.", " -D, --virtual-dip", " A 16 digit bitmap representation of the desired setting for Virtual DIP Switches", " This argument is mandatory and must be 16 digits made of any combinations of ", " zeros or ones.", " -h, --help", " Display this help.", " -H, --headers", " Display column headers.", " -V, --version", " Display version number of this program.", }; /** * Generic usage printing engine. * * @param[in] prog_name program name * @param[in] usage usage array of strings * @param[in] num_entries number of entries in the usage array of strings */ static void print_usage(const char *prog_name, const char *usage[], size_t num_entries) { (void)prog_name; size_t i; for (i = 0; i < num_entries; i++) { printf("%s\n", usage[i]); } } /** * Print the version number of this program. */ static void print_version(void) { printf("AFI Management Tools Version: %s\n", CLI_VERSION); } /** * Check the given option and set the f1.parser_completed flag. * * -parser_completed is set when the parser will complete the option * (help or version output) and no further command processing is necessary, * though a non-zero return value is still returned from parse_args. * -the parser_completed flag may then be used to skip the "Error" output * that is generically used for parsing or other errors beyond the parsing * stage. * * @param[in] opt the option to check */ static void get_parser_completed(char opt) { if ((opt == 'h') || (opt == 'V')) { f1.parser_completed = true; } } /** * Configure the request timeout * * @param[in] timeout timeout in seconds * * @returns * 0 on success * -1 on failure */ static int config_request_timeout(uint32_t timeout) { size_t timeout_tmp = CLI_REQUEST_TIMEOUT_DFLT * CLI_REQUEST_DELAY_MSEC_DFLT / MSEC_PER_SEC; size_t timeout_max = ((size_t)(uint32_t)-1) * CLI_REQUEST_DELAY_MSEC_DFLT / MSEC_PER_SEC; /** Check min and max values */ fail_on_user((timeout < timeout_tmp) || (timeout > timeout_max), err, "Error: The timeout must be between %zu and %zu seconds", timeout_tmp, timeout_max); timeout_tmp = ((size_t)timeout) * MSEC_PER_SEC / CLI_REQUEST_DELAY_MSEC_DFLT; if (timeout_tmp > (uint32_t)-1) { /** Sanity check: Max out at ((1 << 32) - 1) * CLI_REQUEST_DELAY_MSEC_DFLT */ timeout_tmp = (uint32_t)-1; } f1.request_timeout = timeout_tmp; f1.request_delay_msec = CLI_REQUEST_DELAY_MSEC_DFLT; log_debug("Setting timeout to %u secs, request_timeout=%u, request_delay_msec=%u", timeout, f1.request_timeout, f1.request_delay_msec); return 0; err: return -EINVAL; } /** * Configure the synchronous operation timeout * * @param[in] timeout timeout in seconds * * @returns * 0 on success * -1 on failure */ static int config_sync_timeout(uint32_t timeout) { size_t timeout_tmp = CLI_SYNC_TIMEOUT_DFLT * CLI_SYNC_DELAY_MSEC_DFLT / MSEC_PER_SEC; size_t timeout_max = ((size_t)(uint32_t)-1) * CLI_SYNC_DELAY_MSEC_DFLT / MSEC_PER_SEC; /** Check min and max values */ fail_on_user((timeout < timeout_tmp) || (timeout > timeout_max), err, "Error: The timeout must be between %zu and %zu seconds", timeout_tmp, timeout_max); timeout_tmp = ((size_t)timeout) * MSEC_PER_SEC / CLI_SYNC_DELAY_MSEC_DFLT; if (timeout_tmp > (uint32_t)-1) { /** Sanity check: Max out at ((1 << 32) - 1) * CLI_SYNC_DELAY_MSEC_DFLT */ timeout_tmp = (uint32_t)-1; } f1.sync_timeout = timeout_tmp; f1.sync_delay_msec = CLI_SYNC_DELAY_MSEC_DFLT; log_debug("Setting timeout to %u secs, sync_timeout=%u, sync_delay_msec=%u", timeout, f1.sync_timeout, f1.sync_delay_msec); return 0; err: return -EINVAL; } /** * Parse load-fpga-image command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ static int parse_args_load_afi(int argc, char *argv[]) { int opt = 0; static struct option long_options[] = { {"fpga-image-slot", required_argument, 0, 'S' }, {"fpga-image-id", required_argument, 0, 'I' }, {"clock-a0-freq", required_argument, 0, 'a' }, {"clock-b0-freq", required_argument, 0, 'b' }, {"clock-c0-freq", required_argument, 0, 'c' }, {"request-timeout", required_argument, 0, 'r' }, {"sync-timeout", required_argument, 0, 's' }, {"async", no_argument, 0, 'A' }, {"headers", no_argument, 0, 'H' }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'V' }, {"force-shell-reload", no_argument, 0, 'F' }, {"dram-data-retention", no_argument, 0, 'D' }, {"prefetch-image", no_argument, 0, 'P' }, {0, 0, 0, 0 }, }; int long_index = 0; while ((opt = getopt_long(argc, argv, "S:I:r:s:a:b:c:AH?hVFDP", long_options, &long_index)) != -1) { switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } case 'I': { fail_on_user(strnlen(optarg, AFI_ID_STR_MAX) == AFI_ID_STR_MAX, err, "fpga-image-id must be less than %u bytes", AFI_ID_STR_MAX); strncpy(f1.afi_id, optarg, sizeof(f1.afi_id)); f1.afi_id[sizeof(f1.afi_id) - 1] = 0; break; } case 'a': { string_to_uint(&f1.clock_a0_freq, optarg); fail_on_user(f1.clock_a0_freq == 0, err, "Requested frequency must be positive"); break; } case 'b': { string_to_uint(&f1.clock_b0_freq, optarg); fail_on_user(f1.clock_b0_freq == 0, err, "Requested frequency must be positive"); break; } case 'c': { string_to_uint(&f1.clock_c0_freq, optarg); fail_on_user(f1.clock_c0_freq == 0, err, "Requested frequency must be positive"); break; } case 'r': { uint32_t value32; string_to_uint(&value32, optarg); int ret = config_request_timeout(value32); fail_on(ret != 0, err, "Could not configure the request-timeout"); break; } case 's': { uint32_t value32; string_to_uint(&value32, optarg); int ret = config_sync_timeout(value32); fail_on(ret != 0, err, "Could not configure the sync-timeout"); break; } case 'A': { f1.async = true; break; } case 'H': { f1.show_headers = true; break; } case 'F': { f1.force_shell_reload = true; break; } case 'V': { print_version(); get_parser_completed(opt); goto out_ver; } case 'D': { f1.dram_data_retention = true; break; } case 'P': { f1.prefetch = true; f1.async = true; break; } default: { get_parser_completed(opt); goto err; } } } if ((f1.afi_slot == (uint32_t) -1) || (f1.afi_id[0] == 0)) { goto err; } return 0; err: print_usage(argv[0], load_afi_usage, sizeof_array(load_afi_usage)); out_ver: return -EINVAL; } /** * Parse clear-fpga-image command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ static int parse_args_clear_afi(int argc, char *argv[]) { int opt = 0; static struct option long_options[] = { {"fpga-image-slot", required_argument, 0, 'S' }, {"request-timeout", required_argument, 0, 'r' }, {"sync-timeout", required_argument, 0, 's' }, {"async", no_argument, 0, 'A' }, {"headers", no_argument, 0, 'H' }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'V' }, {0, 0, 0, 0 }, }; int long_index = 0; while ((opt = getopt_long(argc, argv, "S:r:s:AH?hV", long_options, &long_index)) != -1) { switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } case 'r': { uint32_t value32; string_to_uint(&value32, optarg); int ret = config_request_timeout(value32); fail_on(ret != 0, err, "Could not configure the request-timeout"); break; } case 's': { uint32_t value32; string_to_uint(&value32, optarg); int ret = config_sync_timeout(value32); fail_on(ret != 0, err, "Could not configure the sync-timeout"); break; } case 'A': { f1.async = true; break; } case 'H': { f1.show_headers = true; break; } case 'V': { print_version(); get_parser_completed(opt); goto out_ver; } default: { get_parser_completed(opt); goto err; } } } if (f1.afi_slot == (uint32_t) -1) { goto err; } return 0; err: print_usage(argv[0], clear_afi_usage, sizeof_array(clear_afi_usage)); out_ver: return -EINVAL; } /** * Parse describe-fpga-image command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ static int parse_args_describe_afi(int argc, char *argv[]) { int opt = 0; static struct option long_options[] = { {"fpga-image-slot", required_argument, 0, 'S' }, {"metrics", no_argument, 0, 'M' }, {"clear-metrics", no_argument, 0, 'C' }, {"request-timeout", required_argument, 0, 'r' }, {"rescan", no_argument, 0, 'R' }, {"headers", no_argument, 0, 'H' }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'V' }, {0, 0, 0, 0 }, }; int long_index = 0; while ((opt = getopt_long(argc, argv, "S:MCr:RH?hV", long_options, &long_index)) != -1) { switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } case 'M': { f1.get_hw_metrics = true; break; } case 'C': { f1.get_hw_metrics = true; f1.clear_hw_metrics = true; break; } case 'r': { uint32_t value32; string_to_uint(&value32, optarg); int ret = config_request_timeout(value32); fail_on(ret != 0, err, "Could not configure the request-timeout"); break; } case 'R': { f1.rescan = true; break; } case 'H': { f1.show_headers = true; break; } case 'V': { print_version(); get_parser_completed(opt); goto out_ver; } default: { get_parser_completed(opt); goto err; } } } if (f1.afi_slot == (uint32_t) -1) { goto err; } return 0; err: print_usage(argv[0], describe_afi_usage, sizeof_array(describe_afi_usage)); out_ver: return -EINVAL; } /** * Parse describe-fpga-image-slots command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ static int parse_args_describe_afi_slots(int argc, char *argv[]) { int opt = 0; static struct option long_options[] = { {"request-timeout", required_argument, 0, 'r' }, {"headers", no_argument, 0, 'H' }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'V' }, {"show-mbox", no_argument, 0, 'M' }, {0, 0, 0, 0 }, }; int long_index = 0; while ((opt = getopt_long(argc, argv, "r:H?hVM", long_options, &long_index)) != -1) { switch (opt) { case 'r': { uint32_t value32; string_to_uint(&value32, optarg); int ret = config_request_timeout(value32); fail_on(ret != 0, err, "Could not configure the request-timeout"); break; } case 'H': { f1.show_headers = true; break; } case 'V': { print_version(); get_parser_completed(opt); goto out_ver; } case 'M': { f1.show_mbox_device = true; break; } default: { get_parser_completed(opt); goto err; } } } return 0; err: print_usage(argv[0], describe_afi_slots_usage, sizeof_array(describe_afi_slots_usage)); out_ver: return -EINVAL; } static char default_tcp_port[5] = "10201"; /** * Parse fpga-start-virtual-jtag command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ static int parse_args_start_virtual_jtag(int argc, char *argv[]) { int opt = 0; uint32_t temp_int = 0; char* tcp_port; static struct option long_options[] = { {"fpga-image-slot", required_argument, 0, 'S' }, {"tcp-port", required_argument, 0, 'P' }, {"headers", no_argument, 0, 'H' }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'V' }, {0, 0, 0, 0 }, }; int long_index = 0; f1.tcp_port=(char*) default_tcp_port; while ((opt = getopt_long(argc, argv, "S:P:RH?hV", long_options, &long_index)) != -1) { switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } case 'P': { // FIXME tcp_port = optarg; string_to_uint(&temp_int, tcp_port); fail_on_user(temp_int >= (64*1024-1), err, "tcp-port must be less than %u", 64*1024-1); fail_on_user(temp_int <= (1024), err, "tcp-port must be larger than %u",1024); f1.tcp_port = optarg; break; } case 'H': { f1.show_headers = true; break; } case 'V': { print_version(); get_parser_completed(opt); goto out_ver; } default: { get_parser_completed(opt); goto err; } } } if (f1.afi_slot == (uint32_t) -1) { printf("Error: Invalid Slot Id !"); goto err; } return 0; err: print_usage(argv[0], start_virtual_jtag_usage, sizeof_array(start_virtual_jtag_usage)); out_ver: return -EINVAL; } /** * Parse fpga-get-virtual-led command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ static int parse_args_get_virtual_led(int argc, char *argv[]) { int opt; static struct option long_options[] = { {"fpga-image-slot", required_argument, 0, 'S' }, {"headers", no_argument, 0, 'H' }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'V' }, {0, 0, 0, 0 }, }; int long_index = 0; while ((opt = getopt_long(argc, argv, "S:RH?hV", long_options, &long_index)) != -1) { switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } case 'H': { f1.show_headers = true; break; } case 'V': { print_version(); get_parser_completed(opt); goto out_ver; } default: { get_parser_completed(opt); goto err; } } } if (f1.afi_slot == (uint32_t) -1) { printf("Error: Invalid Slot Id !"); goto err; } return 0; err: print_usage(argv[0], get_virtual_led_usage, sizeof_array(get_virtual_led_usage)); out_ver: return -EINVAL; } /** * Parse fpga-get-virtual-dip-switch command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ static int parse_args_get_virtual_dip(int argc, char *argv[]) { int opt; static struct option long_options[] = { {"fpga-image-slot", required_argument, 0, 'S' }, {"headers", no_argument, 0, 'H' }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'V' }, {0, 0, 0, 0 }, }; int long_index = 0; while ((opt = getopt_long(argc, argv, "S:RH?hV", long_options, &long_index)) != -1) { switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } case 'H': { f1.show_headers = true; break; } case 'V': { print_version(); get_parser_completed(opt); goto out_ver; } default: { get_parser_completed(opt); goto err; } } } if (f1.afi_slot == (uint32_t) -1) { printf("Error: Invalid Slot Id !"); goto err; } return 0; err: print_usage(argv[0], get_virtual_dip_usage, sizeof_array(get_virtual_dip_usage)); out_ver: return -EINVAL; } /** * Parse fpga-set-virtual-dip-switch command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ static int parse_args_set_virtual_dip(int argc, char *argv[]) { int opt; uint16_t status=0; int i; int vdip_arg_found=0; static struct option long_options[] = { {"fpga-image-slot", required_argument, 0, 'S' }, {"virtual-dip", required_argument, 0, 'D' }, {"headers", no_argument, 0, 'H' }, {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'V' }, {0, 0, 0, 0 }, }; int long_index = 0; while ((opt = getopt_long(argc, argv, "S:D:RH?hV", long_options, &long_index)) != -1) { switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } case 'D': { fail_on_user(strlen(optarg) != 16, err, "virtual-dip must be 16 digits of zero or one"); for (i=0;i<16;i++) { if (optarg[i] == '1') status = status | 0x1; else if (optarg[i] == '0') status = status; else fail_on_user(1, err, "illegal digit for virtual-dip %c", optarg[i]); if (i!=15) status = status << 1; } vdip_arg_found=1; f1.v_dip_switch=status; break; } case 'H': { f1.show_headers = true; break; } case 'V': { print_version(); get_parser_completed(opt); goto out_ver; } default: { get_parser_completed(opt); goto err; } } } if (f1.afi_slot == (uint32_t) -1) { printf("Error: Invalid Slot Id !"); goto err; } if (!vdip_arg_found) { printf("Error: Missing DIP Switch values !"); goto err; } return 0; err: print_usage(argv[0], set_virtual_dip_usage, sizeof_array(set_virtual_dip_usage)); out_ver: return -EINVAL; } typedef int (*parse_args_func_t)(int argc, char *argv[]); struct parse_args_str2func { char *str; uint32_t opcode; parse_args_func_t func; }; /** * Parse command line arguments. * * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ int parse_args(int argc, char *argv[]) { fail_on(argc < 2, err, "Error: opcode string must be specified"); fail_on_user(!argv[0] || !argv[1], err, "Error: program name or opcode string is NULL"); static struct parse_args_str2func str2func[] = { {"LoadFpgaImage", CLI_CMD_LOAD, parse_args_load_afi}, {"ClearFpgaImage", CLI_CMD_CLEAR, parse_args_clear_afi}, {"DescribeFpgaImageSlots", CLI_CMD_DESCRIBE_SLOTS, parse_args_describe_afi_slots}, {"DescribeFpgaImage", CLI_CMD_DESCRIBE, parse_args_describe_afi}, {"StartVirtualJtag", CLI_CMD_START_VJTAG, parse_args_start_virtual_jtag}, {"GetVirtualLED", CLI_CMD_GET_LED, parse_args_get_virtual_led}, {"GetVirtualDIP", CLI_CMD_GET_DIP, parse_args_get_virtual_dip}, {"SetVirtualDIP", CLI_CMD_SET_DIP, parse_args_set_virtual_dip}, }; char *opcode_str = argv[1]; size_t i; int ret = -EINVAL; for (i = 0; i < sizeof_array(str2func); i++) { struct parse_args_str2func *entry = &str2func[i]; if (!strncmp(entry->str, opcode_str, strlen(entry->str))) { f1.opcode = entry->opcode; ret = entry->func(argc, argv); break; } } if (f1.opcode == (uint32_t)-1) { goto err; } return ret; err: print_usage(argv[0], opcode_str_usage, sizeof_array(opcode_str_usage)); return -EINVAL; }