diff options
-rw-r--r-- | client/cmd.h | 50 | ||||
-rw-r--r-- | client/i2c.cpp | 4 | ||||
-rw-r--r-- | client/i2c.h | 29 | ||||
-rw-r--r-- | client/parse.h | 14 | ||||
-rw-r--r-- | client/rl.cpp | 15 | ||||
-rw-r--r-- | client/rl.h | 43 | ||||
-rw-r--r-- | client/sock.h | 43 | ||||
-rw-r--r-- | client/xxd.h | 9 |
8 files changed, 187 insertions, 20 deletions
diff --git a/client/cmd.h b/client/cmd.h index 961ef89..a3cc44a 100644 --- a/client/cmd.h +++ b/client/cmd.h @@ -1,17 +1,44 @@ #pragma once +/** + * \ingroup pbc + * \defgroup pbc_cmd cmd + * \brief Commands within \ref pbc + * \{ + */ + #include <stddef.h> -typedef void cmd_handle_t(char *); -typedef char** cmd_complete_t(const char*, int, int); +/** + * \internal + * \brief Command handler function + * + * \param line Remaining text after command name on command line + */ +typedef void cmd_handle_t(char * line); +/** + * \internal + * \brief Command completion function + * + * \param text Current word to complete + * \param start Index in \c rl_line_buffer of cursor position + * \param end End index of \p text in \c rl_line_buffer + * + * \return Array of \c char* with suggestions. The array is terminated by a + * NULL pointer. + */ +typedef char** cmd_complete_t(const char* text, int start, int end); -struct cmd { - cmd_handle_t * handle; - const char* name; - const char* info; - cmd_complete_t * complete; -}; -typedef struct cmd cmd_t; +/** + * \internal + * \brief Command definition struct + */ +typedef struct { + cmd_handle_t * handle; //!< Handler function (required) + const char* name; //!< Command name (required) + const char* info; //!< Command info (shown in help command) (optional = NULL) + cmd_complete_t * complete; //!< Completion function (optional = NULL) +} cmd_t; cmd_handle_t cmd_exit; cmd_handle_t cmd_test; @@ -23,6 +50,7 @@ cmd_handle_t cmd_skip; cmd_handle_t cmd_dump; cmd_complete_t cmd_dump_complete; +//! Commands static const cmd_t cmds[] = { { .handle = cmd_exit, @@ -68,5 +96,9 @@ static const cmd_t cmds[] = { }, #endif }; + +//! Number of commands defined in \c cmds static const size_t cmds_length = sizeof(cmds) / sizeof(cmds[0]); +/// \} + diff --git a/client/i2c.cpp b/client/i2c.cpp index 78e5585..3655191 100644 --- a/client/i2c.cpp +++ b/client/i2c.cpp @@ -35,9 +35,9 @@ void i2c_send(uint16_t addr, const char * data, size_t data_size) { static void i2c_handle_cmd_read(uint16_t, const char *, size_t); -void i2c_recv(uint16_t addr, const char * data, size_t data_size) { +void i2c_recv(const char * data, size_t data_size) { if (i2c_dump_recv) { - printf("[%s] addr(0x%02x) data(0x%02lx):\n", __FUNCTION__, addr, data_size); + printf("[%s] data(0x%02lx):\n", __FUNCTION__, data_size); xxd(data, data_size); } } diff --git a/client/i2c.h b/client/i2c.h index f9f58f9..87f33c9 100644 --- a/client/i2c.h +++ b/client/i2c.h @@ -3,6 +3,33 @@ #include <stdint.h> #include <stddef.h> +/** + * \ingroup pbc + * \defgroup pbc_i2c i2c + * \brief I2C abstraction functions + * \{ + */ + +/** + * \brief Fake I2C send function + * + * This function sends an I2C message to the main controller over TCP using + * \ref i2ctcp. + * + * \param addr I2C address + * \param data Data to send + * \param data_size size of \p data + */ void i2c_send(uint16_t addr, const char * data, size_t data_size); -void i2c_recv(uint16_t addr, const char * data, size_t data_size); +/** + * \brief Fake I2C receive handler + * + * This function is called for I2C messages received by the main controller and + * forwarded to \ref pbc. + * + * \param data Received data + * \param data_size size of \p data + */ +void i2c_recv(const char * data, size_t data_size); +/// \} diff --git a/client/parse.h b/client/parse.h index 94afe70..8b7d235 100644 --- a/client/parse.h +++ b/client/parse.h @@ -2,11 +2,23 @@ #include <stddef.h> +/** + * \ingroup pbc + * \defgroup pbc_parse parse + * \brief Debug send command parser utilities + * \{ + */ + +//! Internal field separator (i.e. whitespace delimiter) #define IFS " \t\n" +//! Octal digit character set #define SET_OCT "01234567" +//! Decimal digit character set #define SET_DEC "0123456789" +//! Hexadecimal digit character set #define SET_HEX SET_DEC"abcdefABCDEF" +//! (Hexadecimal) byte string character set #define SET_HEX_STR SET_HEX":" /** @@ -40,3 +52,5 @@ char* consume_token(char * token, const char * ifs); */ int strtodata(const char * str, char ** data, size_t * size); +/// \} + diff --git a/client/rl.cpp b/client/rl.cpp index fa44bf4..f839d96 100644 --- a/client/rl.cpp +++ b/client/rl.cpp @@ -119,24 +119,25 @@ int rl_word(const char * line, int cursor) { return word; } +/// \internal typedef struct { const char * word; - const char ** suggestions; + const char ** options; } __rl_complete_list_data_t; -char** rl_complete_list(const char * word, const char ** suggestions) { +char** rl_complete_list(const char * word, const char ** options) { __rl_complete_list_data_t data = { .word = word, - .suggestions = suggestions, + .options = options, }; return rl_completion_matches((char *) &data, [](const char * text, int state) -> char * { __rl_complete_list_data_t data = *(__rl_complete_list_data_t *) text; static size_t i = 0; if (state == 0) i = 0; - while (data.suggestions[i] != NULL) { - const char * suggestion = data.suggestions[i++]; - if (strncmp(data.word, suggestion, strlen(data.word)) == 0) - return strdup(suggestion); + while (data.options[i] != NULL) { + const char * option = data.options[i++]; + if (strncmp(data.word, option, strlen(data.word)) == 0) + return strdup(option); } return NULL; }); diff --git a/client/rl.h b/client/rl.h index ab31ddb..d2f8612 100644 --- a/client/rl.h +++ b/client/rl.h @@ -1,12 +1,53 @@ #pragma once +/** + * \ingroup pbc + * \defgroup pbc_rl rl + * \brief GNU Readline related functions + * \{ + */ + +//! Reset color (ANSI sequence) #define COLOR_OFF "\x1b[0m" +//! Set font to bold (ANSI sequence) #define COLOR_BOLD "\x1b[1m" +//! Prompt text #define CLI_PROMPT "(" COLOR_BOLD "pbc" COLOR_OFF ") " +//! CLI entrypoint int cli_main(); + +/** + * \brief Print format string to stdout without disturbing the readline prompt + * + * This function saves and restores the current readline prompt before/after + * calling printf. This function is not required for commands that print output + * synchronously, as the prompt is only shown after a command handler + * completes. + */ void rl_printf(const char * fmt, ...); +/** + * \brief Get the index of the word currently under the cursor + * + * \param line Command line contents + * \param cursor Index of cursor position + * + * This function returns the index of the word from an array made by splitting + * \p line on consecutive occurrences of \c IFS. + * + * \return Index of word + */ int rl_word(const char * line, int cursor); -char ** rl_complete_list(const char * word, const char * suggestions[]); +/** + * \brief Create a completion suggestion string array for readline + * + * \param word Word to complete + * \param options List of possible choices (NULL terminated array of strings) + * + * \return Suggestions matching \p word + */ +char ** rl_complete_list(const char * word, const char * options[]); + +/// \} diff --git a/client/sock.h b/client/sock.h index 0dee09e..c124e45 100644 --- a/client/sock.h +++ b/client/sock.h @@ -3,29 +3,72 @@ #include <cstdint> #include <thread> +/** + * \ingroup pbc + * \defgroup pbc_sock sock + * \brief TCP socket handling + * \{ + */ + +/** + * \brief Asynchronous puzzle box socket connection + * \note Once connected, this class will call \c i2c_recv() when a complete I2C + * message has been received + */ class PBSocket { public: PBSocket(); PBSocket(const char * addr, uint16_t port); virtual ~PBSocket(); + //! Configure target server void set_server(const char * addr, uint16_t port); + //! Attempt to connect to server and start \c sock_task() in a thread void sock_connect(); + /** + * \brief Send data over the TCP connection + * + * \param buf Data to send + * \param buf_sz Size of \p buf in bytes + */ void send(const char * buf, size_t buf_sz); private: + /** + * \brief Continously read from the TCP socket and read \ref i2ctcp messages + * using \c i2ctcp_read(). + * + * Once a complete message has been parsed, \c i2c_recv() is called with the + * complete message. This message is automatically free'd after \c i2c_recv() + * returns. + * + * \note This function is run in a separate thread + */ void sock_task(); + //! Close the socket void sock_close(); + //! Pointer to thread running \c sock_task() std::thread* _thread = nullptr; + /** + * \brief IP address of server to connect to + * + * \note This member must contain an IP address, as no hostname resolution is + * done in pbc. + */ const char * _addr = NULL; + //! Port number of server to connect to uint16_t _port = 0; + //! Unix file descriptor of opened socket int _fd = -1; }; +//! Singleton \c PBSocket instance extern PBSocket* sock; +/// \} + diff --git a/client/xxd.h b/client/xxd.h index fb28bb1..ede9fff 100644 --- a/client/xxd.h +++ b/client/xxd.h @@ -7,10 +7,19 @@ extern "C" { #endif /** + * \ingroup pbc + * \defgroup pbc_xxd xxd + * \brief Utility hexdump + * \{ + */ + +/** * \brief utility function that prints hexdump of data */ void xxd(const char * data, size_t size); +/// \} + #ifdef __cplusplus } #endif |