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  |