acassis commented on code in PR #2820: URL: https://github.com/apache/nuttx-apps/pull/2820#discussion_r1957442025
########## examples/spislv_test/spislv_test.c: ########## @@ -22,81 +22,558 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <fcntl.h> -#include <unistd.h> #include <errno.h> -#include <string.h> -#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/select.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Define buffer sizes */ +#define RX_BUFFER_SIZE 64 +#define TX_BUFFER_SIZE 64 +#define SOURCE_FILE "dev/spislv2" /* SPI device path */ + +/* Enumeration for operation modes */ -#define SOURCE_FILE "/dev/spislv2" -#define BUFFER_SIZE 256 +typedef enum +{ + MODE_WRITE, + MODE_LISTEN, + MODE_ECHO, + MODE_INVALID +} operation_mode_t; /**************************************************************************** - * Public Functions + * Structure to hold program configurations ****************************************************************************/ +typedef struct +{ + operation_mode_t mode; + int num_bytes; /* Applicable for write mode */ + int timeout_seconds; /* Applicable for all modes */ + unsigned char tx_buffer[TX_BUFFER_SIZE]; +} program_config_t; + /**************************************************************************** - * spislv_test + * Private Functions ****************************************************************************/ -int main(int argc, FAR char *argv[]) +/** + * @brief Converts a single hexadecimal character to its byte value. + * + * @param c The hexadecimal character. + * @return The byte value of the hexadecimal character, or -1 if invalid. + */ + +static int hexchar_to_byte(char c) { - int fd; - char buffer[BUFFER_SIZE]; - ssize_t bytes_read; - ssize_t i; + if (c >= '0' && c <= '9') + { + return c - '0'; + } - printf("Slave started!!\n"); - fd = open(SOURCE_FILE, O_RDWR); + c = tolower(c); - if (fd < 0) + if (c >= 'a' && c <= 'f') { - printf("Failed to open %s: %s\n", SOURCE_FILE, strerror(errno)); - return 0; + return c - 'a' + 10; } - while (1) + return -1; +} + +/** + * @brief Converts a hexadecimal string to a byte array. + * + * @param hexstr The input hexadecimal string. + * @param bytes The output byte array. + * @param max_bytes The maximum number of bytes to convert. + * @return The number of bytes converted, or -1 on error. + */ + +static int hexstr_to_bytes(const char *hexstr, unsigned char *bytes, + size_t max_bytes) +{ + size_t len = strlen(hexstr); + + if (len % 2 != 0 || len / 2 > max_bytes) { - /* Read the number from the source file */ + return -1; + } - printf("Slave: Reading from %s\n", SOURCE_FILE); - bytes_read = read(fd, buffer, BUFFER_SIZE - 1); + for (size_t i = 0; i < len / 2; i++) + { + int high = hexchar_to_byte(hexstr[2 * i]); + int low = hexchar_to_byte(hexstr[2 * i + 1]); - if (bytes_read < 0) + if (high == -1 || low == -1) { - printf("Failed to read from %s: %s\n", - SOURCE_FILE, strerror(errno)); - close(fd); - return 0; + return -1; } - else if (bytes_read > 0) + + bytes[i] = (high << 4) | low; + } + + return len / 2; +} + +/** + * @brief Parses and validates command-line arguments. + * + * @param argc Argument count. + * @param argv Argument vector. + * @param config Pointer to the program configuration structure. + * @return 0 on success, -1 on failure. + */ + +static int parse_arguments(int argc, char *argv[], + program_config_t *config) +{ + int opt; + + /* Set default configurations */ + + config->mode = MODE_INVALID; + config->num_bytes = 0; + config->timeout_seconds = 10; /* Default timeout */ + + /* Parse command-line options */ + + while ((opt = getopt(argc, argv, "x:t:le")) != -1) + { + switch (opt) + { + case 'x': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_WRITE; + config->num_bytes = atoi(optarg); + if (config->num_bytes <= 0 || + config->num_bytes > TX_BUFFER_SIZE) + { + fprintf(stderr, + "Error: Invalid number of bytes for write mode.\n"); + return -1; + } + + break; + + case 't': + config->timeout_seconds = atoi(optarg); + if (config->timeout_seconds <= 0) + { + fprintf(stderr, + "Error: Timeout must be a positive integer.\n"); + return -1; + } + break; + + case 'l': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_LISTEN; + break; + + case 'e': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_ECHO; + break; + + default: + fprintf(stderr, "Usage:\n"); + fprintf(stderr, + " %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + fprintf(stderr, + " %s -l [-t <timeout_seconds>]\n", argv[0]); + fprintf(stderr, + " %s -e [-t <timeout_seconds>]\n", argv[0]); + printf("Examples:\n"); + printf(" spislv -x 2 abba\n"); + printf(" spislv -l -t 5\n"); + printf(" spislv -e -t 10\n\n"); + return -1; + } + } + + /* Validate mutual exclusivity and required arguments */ + + if (config->mode == MODE_WRITE) + { + if (optind >= argc) + { + fprintf(stderr, + "Error: Missing hexadecimal bytes to send.\n"); + fprintf(stderr, + "Usage: %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + return -1; + } + + char *hex_input = argv[optind]; + + /* Verify the hexadecimal string length */ + + if (strlen(hex_input) != (size_t)(config->num_bytes * 2)) { - buffer[bytes_read] = '\0'; + fprintf(stderr, + "Error: Hex string length must be %d characters\n" + "for %d bytes.\n", + config->num_bytes * 2, config->num_bytes); + return -1; + } + + /* Convert hexadecimal string to byte array */ + + int converted = hexstr_to_bytes(hex_input, config->tx_buffer, + TX_BUFFER_SIZE); + if (converted != config->num_bytes) + { + fprintf(stderr, "Error: Invalid hexadecimal string.\n"); + return -1; + } + } + + else if (config->mode == MODE_INVALID) + { + fprintf(stderr, "Error: No operation mode specified.\n"); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, + " %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + fprintf(stderr, + " %s -l [-t <timeout_seconds>]\n", argv[0]); + fprintf(stderr, + " %s -e [-t <timeout_seconds>]\n", argv[0]); + printf("Examples:\n"); + printf(" spislv -x 2 abba\n"); + printf(" spislv -l -t 5\n"); + printf(" spislv -e -t 10\n"); + return -1; + } + + return 0; +} + +/** + * @brief Executes the write mode: sends specified bytes to the master. + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure. + */ + +static int write_mode(program_config_t *config, int fd) +{ + ssize_t bytes_written; + char data_str[3 * TX_BUFFER_SIZE + 1]; /* Buffer for debug string */ + char *ptr = data_str; + + for (int i = 0; i < config->num_bytes; i++) + { + int len = snprintf(ptr, + sizeof(data_str) - (ptr - data_str), + "%02X ", + config->tx_buffer[i]); + if (len < 0 || len >= (int)(sizeof(data_str) - (ptr - data_str))) + { + break; + } + + ptr += len; + } - /* Print buffer in hexadecimal format */ + *ptr = '\0'; - printf("Slave: Read value in hex: "); - for (i = 0; i < bytes_read; ++i) + printf("Slave: Queuing %d bytes for sending to master: %s\n", + config->num_bytes, data_str); + + bytes_written = write(fd, config->tx_buffer, config->num_bytes); + if (bytes_written < 0) + { + fprintf(stderr, "Error: Failed to write to %s: %s\n", + SOURCE_FILE, strerror(errno)); + return -1; + } + + else if (bytes_written != config->num_bytes) + { + fprintf(stderr, "Error: Incomplete write. Expected %d, got %zd\n", + config->num_bytes, bytes_written); + return -1; + } + + return 0; +} + +/** + * @brief Executes the listen-only mode: waits for data from the master. + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure. + */ + +static int listen_mode(program_config_t *config, int fd) +{ + printf("Slave: Listen-only mode activated. Waiting for data\n" + " from master.\n"); + + return 0; +} + +/** + * @brief Executes the echo mode: continuously echoes received data to + * the master. + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure. + */ + +static int echo_mode_func(program_config_t *config, int fd) +{ + printf("Slave: Echo mode activated. Will echo received data until\n" + " timeout.\n"); + + return 0; +} + +/** + * @brief Reads data from the SPI device with a specified timeout. + * Depending on the mode, it either exits after the first read or + * continues (echo mode). + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure or timeout. + */ + +static int read_with_timeout(program_config_t *config, int fd) +{ + unsigned char buffer_rx[RX_BUFFER_SIZE]; + ssize_t bytes_read; + ssize_t bytes_written; + int select_ret; + + while (1) + { + fd_set read_fds; + struct timeval timeout; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + timeout.tv_sec = config->timeout_seconds; + timeout.tv_usec = 0; + + select_ret = select(fd + 1, &read_fds, + NULL, NULL, &timeout); + if (select_ret == -1) + { + fprintf(stderr, "Error: Select failed: %s\n", + strerror(errno)); + return -1; + } + Review Comment: Please remove empty line ########## examples/spislv_test/spislv_test.c: ########## @@ -22,81 +22,558 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <fcntl.h> -#include <unistd.h> #include <errno.h> -#include <string.h> -#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/select.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Define buffer sizes */ +#define RX_BUFFER_SIZE 64 +#define TX_BUFFER_SIZE 64 +#define SOURCE_FILE "dev/spislv2" /* SPI device path */ + +/* Enumeration for operation modes */ -#define SOURCE_FILE "/dev/spislv2" -#define BUFFER_SIZE 256 +typedef enum +{ + MODE_WRITE, + MODE_LISTEN, + MODE_ECHO, + MODE_INVALID +} operation_mode_t; /**************************************************************************** - * Public Functions + * Structure to hold program configurations ****************************************************************************/ +typedef struct +{ + operation_mode_t mode; + int num_bytes; /* Applicable for write mode */ + int timeout_seconds; /* Applicable for all modes */ + unsigned char tx_buffer[TX_BUFFER_SIZE]; +} program_config_t; + /**************************************************************************** - * spislv_test + * Private Functions ****************************************************************************/ -int main(int argc, FAR char *argv[]) +/** + * @brief Converts a single hexadecimal character to its byte value. + * + * @param c The hexadecimal character. + * @return The byte value of the hexadecimal character, or -1 if invalid. + */ + +static int hexchar_to_byte(char c) { - int fd; - char buffer[BUFFER_SIZE]; - ssize_t bytes_read; - ssize_t i; + if (c >= '0' && c <= '9') + { + return c - '0'; + } - printf("Slave started!!\n"); - fd = open(SOURCE_FILE, O_RDWR); + c = tolower(c); - if (fd < 0) + if (c >= 'a' && c <= 'f') { - printf("Failed to open %s: %s\n", SOURCE_FILE, strerror(errno)); - return 0; + return c - 'a' + 10; } - while (1) + return -1; +} + +/** + * @brief Converts a hexadecimal string to a byte array. + * + * @param hexstr The input hexadecimal string. + * @param bytes The output byte array. + * @param max_bytes The maximum number of bytes to convert. + * @return The number of bytes converted, or -1 on error. + */ + +static int hexstr_to_bytes(const char *hexstr, unsigned char *bytes, + size_t max_bytes) +{ + size_t len = strlen(hexstr); + + if (len % 2 != 0 || len / 2 > max_bytes) { - /* Read the number from the source file */ + return -1; + } - printf("Slave: Reading from %s\n", SOURCE_FILE); - bytes_read = read(fd, buffer, BUFFER_SIZE - 1); + for (size_t i = 0; i < len / 2; i++) + { + int high = hexchar_to_byte(hexstr[2 * i]); + int low = hexchar_to_byte(hexstr[2 * i + 1]); - if (bytes_read < 0) + if (high == -1 || low == -1) { - printf("Failed to read from %s: %s\n", - SOURCE_FILE, strerror(errno)); - close(fd); - return 0; + return -1; } - else if (bytes_read > 0) + + bytes[i] = (high << 4) | low; + } + + return len / 2; +} + +/** + * @brief Parses and validates command-line arguments. + * + * @param argc Argument count. + * @param argv Argument vector. + * @param config Pointer to the program configuration structure. + * @return 0 on success, -1 on failure. + */ + +static int parse_arguments(int argc, char *argv[], + program_config_t *config) +{ + int opt; + + /* Set default configurations */ + + config->mode = MODE_INVALID; + config->num_bytes = 0; + config->timeout_seconds = 10; /* Default timeout */ + + /* Parse command-line options */ + + while ((opt = getopt(argc, argv, "x:t:le")) != -1) + { + switch (opt) + { + case 'x': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_WRITE; + config->num_bytes = atoi(optarg); + if (config->num_bytes <= 0 || + config->num_bytes > TX_BUFFER_SIZE) + { + fprintf(stderr, + "Error: Invalid number of bytes for write mode.\n"); + return -1; + } + + break; + + case 't': + config->timeout_seconds = atoi(optarg); + if (config->timeout_seconds <= 0) + { + fprintf(stderr, + "Error: Timeout must be a positive integer.\n"); + return -1; + } + break; + + case 'l': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_LISTEN; + break; + + case 'e': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_ECHO; + break; + + default: + fprintf(stderr, "Usage:\n"); + fprintf(stderr, + " %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + fprintf(stderr, + " %s -l [-t <timeout_seconds>]\n", argv[0]); + fprintf(stderr, + " %s -e [-t <timeout_seconds>]\n", argv[0]); + printf("Examples:\n"); + printf(" spislv -x 2 abba\n"); + printf(" spislv -l -t 5\n"); + printf(" spislv -e -t 10\n\n"); + return -1; + } + } + + /* Validate mutual exclusivity and required arguments */ + + if (config->mode == MODE_WRITE) + { + if (optind >= argc) + { + fprintf(stderr, + "Error: Missing hexadecimal bytes to send.\n"); + fprintf(stderr, + "Usage: %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + return -1; + } + + char *hex_input = argv[optind]; + + /* Verify the hexadecimal string length */ + + if (strlen(hex_input) != (size_t)(config->num_bytes * 2)) { - buffer[bytes_read] = '\0'; + fprintf(stderr, + "Error: Hex string length must be %d characters\n" + "for %d bytes.\n", + config->num_bytes * 2, config->num_bytes); + return -1; + } + + /* Convert hexadecimal string to byte array */ + + int converted = hexstr_to_bytes(hex_input, config->tx_buffer, + TX_BUFFER_SIZE); + if (converted != config->num_bytes) + { + fprintf(stderr, "Error: Invalid hexadecimal string.\n"); + return -1; + } + } + + else if (config->mode == MODE_INVALID) + { + fprintf(stderr, "Error: No operation mode specified.\n"); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, + " %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + fprintf(stderr, + " %s -l [-t <timeout_seconds>]\n", argv[0]); + fprintf(stderr, + " %s -e [-t <timeout_seconds>]\n", argv[0]); + printf("Examples:\n"); + printf(" spislv -x 2 abba\n"); + printf(" spislv -l -t 5\n"); + printf(" spislv -e -t 10\n"); + return -1; + } + + return 0; +} + +/** + * @brief Executes the write mode: sends specified bytes to the master. + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure. + */ + +static int write_mode(program_config_t *config, int fd) +{ + ssize_t bytes_written; + char data_str[3 * TX_BUFFER_SIZE + 1]; /* Buffer for debug string */ + char *ptr = data_str; + + for (int i = 0; i < config->num_bytes; i++) + { + int len = snprintf(ptr, + sizeof(data_str) - (ptr - data_str), + "%02X ", + config->tx_buffer[i]); + if (len < 0 || len >= (int)(sizeof(data_str) - (ptr - data_str))) + { + break; + } + + ptr += len; + } - /* Print buffer in hexadecimal format */ + *ptr = '\0'; - printf("Slave: Read value in hex: "); - for (i = 0; i < bytes_read; ++i) + printf("Slave: Queuing %d bytes for sending to master: %s\n", + config->num_bytes, data_str); + + bytes_written = write(fd, config->tx_buffer, config->num_bytes); + if (bytes_written < 0) + { + fprintf(stderr, "Error: Failed to write to %s: %s\n", + SOURCE_FILE, strerror(errno)); + return -1; + } + + else if (bytes_written != config->num_bytes) + { + fprintf(stderr, "Error: Incomplete write. Expected %d, got %zd\n", + config->num_bytes, bytes_written); + return -1; + } + + return 0; +} + +/** + * @brief Executes the listen-only mode: waits for data from the master. + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure. + */ + +static int listen_mode(program_config_t *config, int fd) +{ + printf("Slave: Listen-only mode activated. Waiting for data\n" + " from master.\n"); + + return 0; +} + +/** + * @brief Executes the echo mode: continuously echoes received data to + * the master. + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure. + */ + +static int echo_mode_func(program_config_t *config, int fd) +{ + printf("Slave: Echo mode activated. Will echo received data until\n" + " timeout.\n"); + + return 0; +} + +/** + * @brief Reads data from the SPI device with a specified timeout. + * Depending on the mode, it either exits after the first read or + * continues (echo mode). + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure or timeout. + */ + +static int read_with_timeout(program_config_t *config, int fd) +{ + unsigned char buffer_rx[RX_BUFFER_SIZE]; + ssize_t bytes_read; + ssize_t bytes_written; + int select_ret; + + while (1) + { + fd_set read_fds; + struct timeval timeout; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + timeout.tv_sec = config->timeout_seconds; + timeout.tv_usec = 0; + + select_ret = select(fd + 1, &read_fds, + NULL, NULL, &timeout); + if (select_ret == -1) + { + fprintf(stderr, "Error: Select failed: %s\n", + strerror(errno)); + return -1; + } + + else if (select_ret == 0) + { + if (config->mode == MODE_ECHO) + { + printf("Communication timeout after %d seconds. No more\n" + "data received from master.\n", + config->timeout_seconds); + } + Review Comment: Ditto ########## examples/spislv_test/spislv_test.c: ########## @@ -22,81 +22,558 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <fcntl.h> -#include <unistd.h> #include <errno.h> -#include <string.h> -#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/select.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Define buffer sizes */ +#define RX_BUFFER_SIZE 64 +#define TX_BUFFER_SIZE 64 +#define SOURCE_FILE "dev/spislv2" /* SPI device path */ + +/* Enumeration for operation modes */ -#define SOURCE_FILE "/dev/spislv2" -#define BUFFER_SIZE 256 +typedef enum +{ + MODE_WRITE, + MODE_LISTEN, + MODE_ECHO, + MODE_INVALID +} operation_mode_t; /**************************************************************************** - * Public Functions + * Structure to hold program configurations ****************************************************************************/ +typedef struct +{ + operation_mode_t mode; + int num_bytes; /* Applicable for write mode */ + int timeout_seconds; /* Applicable for all modes */ + unsigned char tx_buffer[TX_BUFFER_SIZE]; +} program_config_t; + /**************************************************************************** - * spislv_test + * Private Functions ****************************************************************************/ -int main(int argc, FAR char *argv[]) +/** + * @brief Converts a single hexadecimal character to its byte value. + * + * @param c The hexadecimal character. + * @return The byte value of the hexadecimal character, or -1 if invalid. + */ + +static int hexchar_to_byte(char c) { - int fd; - char buffer[BUFFER_SIZE]; - ssize_t bytes_read; - ssize_t i; + if (c >= '0' && c <= '9') + { + return c - '0'; + } - printf("Slave started!!\n"); - fd = open(SOURCE_FILE, O_RDWR); + c = tolower(c); - if (fd < 0) + if (c >= 'a' && c <= 'f') { - printf("Failed to open %s: %s\n", SOURCE_FILE, strerror(errno)); - return 0; + return c - 'a' + 10; } - while (1) + return -1; +} + +/** + * @brief Converts a hexadecimal string to a byte array. + * + * @param hexstr The input hexadecimal string. + * @param bytes The output byte array. + * @param max_bytes The maximum number of bytes to convert. + * @return The number of bytes converted, or -1 on error. + */ + +static int hexstr_to_bytes(const char *hexstr, unsigned char *bytes, + size_t max_bytes) +{ + size_t len = strlen(hexstr); + + if (len % 2 != 0 || len / 2 > max_bytes) { - /* Read the number from the source file */ + return -1; + } - printf("Slave: Reading from %s\n", SOURCE_FILE); - bytes_read = read(fd, buffer, BUFFER_SIZE - 1); + for (size_t i = 0; i < len / 2; i++) + { + int high = hexchar_to_byte(hexstr[2 * i]); + int low = hexchar_to_byte(hexstr[2 * i + 1]); - if (bytes_read < 0) + if (high == -1 || low == -1) { - printf("Failed to read from %s: %s\n", - SOURCE_FILE, strerror(errno)); - close(fd); - return 0; + return -1; } - else if (bytes_read > 0) + + bytes[i] = (high << 4) | low; + } + + return len / 2; +} + +/** + * @brief Parses and validates command-line arguments. + * + * @param argc Argument count. + * @param argv Argument vector. + * @param config Pointer to the program configuration structure. + * @return 0 on success, -1 on failure. + */ + +static int parse_arguments(int argc, char *argv[], + program_config_t *config) +{ + int opt; + + /* Set default configurations */ + + config->mode = MODE_INVALID; + config->num_bytes = 0; + config->timeout_seconds = 10; /* Default timeout */ + + /* Parse command-line options */ + + while ((opt = getopt(argc, argv, "x:t:le")) != -1) + { + switch (opt) + { + case 'x': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_WRITE; + config->num_bytes = atoi(optarg); + if (config->num_bytes <= 0 || + config->num_bytes > TX_BUFFER_SIZE) + { + fprintf(stderr, + "Error: Invalid number of bytes for write mode.\n"); + return -1; + } + + break; + + case 't': + config->timeout_seconds = atoi(optarg); + if (config->timeout_seconds <= 0) + { + fprintf(stderr, + "Error: Timeout must be a positive integer.\n"); + return -1; + } + break; + + case 'l': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_LISTEN; + break; + + case 'e': + if (config->mode != MODE_INVALID) + { + fprintf(stderr, + "Error: Multiple operation modes specified.\n"); + return -1; + } + + config->mode = MODE_ECHO; + break; + + default: + fprintf(stderr, "Usage:\n"); + fprintf(stderr, + " %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + fprintf(stderr, + " %s -l [-t <timeout_seconds>]\n", argv[0]); + fprintf(stderr, + " %s -e [-t <timeout_seconds>]\n", argv[0]); + printf("Examples:\n"); + printf(" spislv -x 2 abba\n"); + printf(" spislv -l -t 5\n"); + printf(" spislv -e -t 10\n\n"); + return -1; + } + } + + /* Validate mutual exclusivity and required arguments */ + + if (config->mode == MODE_WRITE) + { + if (optind >= argc) + { + fprintf(stderr, + "Error: Missing hexadecimal bytes to send.\n"); + fprintf(stderr, + "Usage: %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + return -1; + } + + char *hex_input = argv[optind]; + + /* Verify the hexadecimal string length */ + + if (strlen(hex_input) != (size_t)(config->num_bytes * 2)) { - buffer[bytes_read] = '\0'; + fprintf(stderr, + "Error: Hex string length must be %d characters\n" + "for %d bytes.\n", + config->num_bytes * 2, config->num_bytes); + return -1; + } + + /* Convert hexadecimal string to byte array */ + + int converted = hexstr_to_bytes(hex_input, config->tx_buffer, + TX_BUFFER_SIZE); + if (converted != config->num_bytes) + { + fprintf(stderr, "Error: Invalid hexadecimal string.\n"); + return -1; + } + } + + else if (config->mode == MODE_INVALID) + { + fprintf(stderr, "Error: No operation mode specified.\n"); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, + " %s -x <num_bytes> [-t <timeout_seconds>] <hex_bytes>\n", + argv[0]); + fprintf(stderr, + " %s -l [-t <timeout_seconds>]\n", argv[0]); + fprintf(stderr, + " %s -e [-t <timeout_seconds>]\n", argv[0]); + printf("Examples:\n"); + printf(" spislv -x 2 abba\n"); + printf(" spislv -l -t 5\n"); + printf(" spislv -e -t 10\n"); + return -1; + } + + return 0; +} + +/** + * @brief Executes the write mode: sends specified bytes to the master. + * + * @param config Pointer to the program configuration structure. + * @param fd File descriptor for the SPI device. + * @return 0 on success, -1 on failure. + */ + +static int write_mode(program_config_t *config, int fd) +{ + ssize_t bytes_written; + char data_str[3 * TX_BUFFER_SIZE + 1]; /* Buffer for debug string */ + char *ptr = data_str; + + for (int i = 0; i < config->num_bytes; i++) + { + int len = snprintf(ptr, + sizeof(data_str) - (ptr - data_str), + "%02X ", + config->tx_buffer[i]); Review Comment: Please simplify it in two lines -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org