From 33d17dbab86c1277a1327273fb9753b2c98b7b03 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 22 Jun 2024 14:32:19 +0200 Subject: more documentation --- client/readme.md | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'client') diff --git a/client/readme.md b/client/readme.md index fcde40d..b9e0b09 100644 --- a/client/readme.md +++ b/client/readme.md @@ -1,3 +1,6 @@ +\defgroup pbc pbc +\brief Puzzle box client + # puzzle box client This folder contains the source code for the puzzle box client (pbc). This is a @@ -7,30 +10,21 @@ game operator to control and monitor the state of a puzzle box, but is also a useful debugging tool when developing puzzle modules, as it allows you to send arbitrary data over the puzzle bus. -## WIP TODO - -- cleanup - - separate ../shared/pb/moddrv.c into a puzzle module specific and 'common' bit - - use the common bit in i2c.cpp instead - - cast to structs in ../shared/pb/moddrv.c -- functionality - - print pretty tree of connected puzzle modules - - add enum to string functions in CLIENT ONLY - ## Features - List detected puzzle modules - Reset puzzle modules (individually or all to reset the box) - Skip puzzle modules (individually or all) - Request puzzle box state - -Debug only: -- Send arbitrary messages +- Debug: send arbitrary messages ## Building -PBC is a standard CMake project, but a [makefile](./makefile) is provided for -convenience (still requires CMake and Ninja are installed). +PBC is a standard CMake project. + +## Using + +See ./pbc.1 for usage. ## Send data @@ -45,8 +39,10 @@ send 0x39 68:65:6c:6c:6f 44 0x20 'world' 33 The data is concatenated, and may contain mixed types of literals -## known bugs (TODO) -- tab completion for `dump` seems to print garbage sometimes -- the send command with an address but no data causes a segmentation fault +## WIP TODO + +- add enum to string functions in CLIENT ONLY +- bug: tab completion for `dump` seems to print garbage sometimes +- bug: the send command with an address but no data causes a segmentation fault -- cgit v1.2.3 From 3667d9a9955face0d4a147319cc902cbf8c95299 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 22 Jun 2024 17:00:51 +0200 Subject: more client docs --- client/cmd.h | 50 +++++++++++++++++++++++++++++++++++++++++--------- client/i2c.cpp | 4 ++-- client/i2c.h | 29 ++++++++++++++++++++++++++++- client/parse.h | 14 ++++++++++++++ client/rl.cpp | 15 ++++++++------- client/rl.h | 43 ++++++++++++++++++++++++++++++++++++++++++- client/sock.h | 43 +++++++++++++++++++++++++++++++++++++++++++ client/xxd.h | 9 +++++++++ 8 files changed, 187 insertions(+), 20 deletions(-) (limited to 'client') 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 -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 #include +/** + * \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 +/** + * \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 #include +/** + * \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 @@ -6,11 +6,20 @@ 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 -- cgit v1.2.3 From 3fd5c9e58f2d4ce3cdea41a3f37235ef0de57d39 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sun, 23 Jun 2024 13:39:16 +0200 Subject: fix client compile errors --- client/cmd.cpp | 2 +- client/rl.cpp | 2 +- client/sock.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'client') diff --git a/client/cmd.cpp b/client/cmd.cpp index 10d53e3..062fefa 100644 --- a/client/cmd.cpp +++ b/client/cmd.cpp @@ -28,7 +28,7 @@ void cmd_test(char*) { void cmd_help(char*) { printf("List of available commands:\n"); for (size_t i = 0; i < cmds_length; i++) { - struct cmd cmd = cmds[i]; + cmd_t cmd = cmds[i]; printf(" %-*s", 10, cmd.name); if (cmd.info != NULL) printf(" %s", cmd.info); diff --git a/client/rl.cpp b/client/rl.cpp index f839d96..2e74e5f 100644 --- a/client/rl.cpp +++ b/client/rl.cpp @@ -57,7 +57,7 @@ static char* rl_completion_entries(const char *text, int state) { if (state == 0) i = 0; while (i < cmds_length) { - struct cmd cmd = cmds[i]; + cmd_t cmd = cmds[i]; i++; if (strncmp(text, cmd.name, strlen(text)) == 0) { return strdup(cmd.name); diff --git a/client/sock.cpp b/client/sock.cpp index 3490586..e33a3dc 100644 --- a/client/sock.cpp +++ b/client/sock.cpp @@ -101,7 +101,7 @@ void PBSocket::sock_task() { if (ret > 0) continue; // message read completely! - i2c_recv(input.addr, input.data, input.length); + i2c_recv(input.data, input.length); free(input.data); } -- cgit v1.2.3 From 2528775b34f9c0033027931385a4de866ab2749d Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Mon, 24 Jun 2024 08:31:35 +0200 Subject: add more documentation --- client/cmd.h | 7 ++++++- client/i2c.h | 2 +- client/parse.h | 4 ++-- client/sock.h | 2 +- main/config.def.h | 27 ++++++++++++++++++++++++++- main/index.dox | 6 +++--- main/readme.md | 12 +----------- 7 files changed, 40 insertions(+), 20 deletions(-) (limited to 'client') diff --git a/client/cmd.h b/client/cmd.h index a3cc44a..4f77d50 100644 --- a/client/cmd.h +++ b/client/cmd.h @@ -2,8 +2,13 @@ /** * \ingroup pbc - * \defgroup pbc_cmd cmd + * \defgroup pbc_cmd Commands * \brief Commands within \ref pbc + * + * \note A manpage is available containing end-user usage instructions inside + * the \ref client folder in the source code repository. This page contains the + * internal code documentation for the commands defined in \c pbc. + * * \{ */ diff --git a/client/i2c.h b/client/i2c.h index 87f33c9..d2cfa9a 100644 --- a/client/i2c.h +++ b/client/i2c.h @@ -5,7 +5,7 @@ /** * \ingroup pbc - * \defgroup pbc_i2c i2c + * \defgroup pbc_i2c I2C * \brief I2C abstraction functions * \{ */ diff --git a/client/parse.h b/client/parse.h index 8b7d235..1beb714 100644 --- a/client/parse.h +++ b/client/parse.h @@ -4,8 +4,8 @@ /** * \ingroup pbc - * \defgroup pbc_parse parse - * \brief Debug send command parser utilities + * \defgroup pbc_parse Parse + * \brief Debug \c send command parser utilities * \{ */ diff --git a/client/sock.h b/client/sock.h index c124e45..792123e 100644 --- a/client/sock.h +++ b/client/sock.h @@ -5,7 +5,7 @@ /** * \ingroup pbc - * \defgroup pbc_sock sock + * \defgroup pbc_sock Socket * \brief TCP socket handling * \{ */ diff --git a/main/config.def.h b/main/config.def.h index b3be5ed..cb6e8b4 100644 --- a/main/config.def.h +++ b/main/config.def.h @@ -4,8 +4,33 @@ /** * \ingroup main - * \defgroup main_config config + * \defgroup main_config Config * \brief Configuration options + * + * The main controller firmware is configured statically (i.e. through + * compile-time defined options). Because the configuration is likely to + * contain Wi-Fi credentials, this file is not tracked under version control. + * + * Before compiling the main controller fimrware, a file (`config.h`) must be + * created by the user with the following format: + * + * ```c + * #pragma once + * + * // define non-default options here + * + * #include "config.def.h" + * ``` + * + * \note `config.def.h` contains preprocessor logic that tries to ensure a + * correct configuration. The default configuration has the following settings: + * - Wi-Fi is disabled (prints a warning during compilation because it was not + * explicitly disabled by the user) + * - The TCP server is disabled (due to Wi-Fi being disabled) + * + * \note The exact default values of each configuration option, and all + * available options are listed below. + * * \{ */ diff --git a/main/index.dox b/main/index.dox index 0fee58a..54c5b15 100644 --- a/main/index.dox +++ b/main/index.dox @@ -1,13 +1,13 @@ // vim:ft=doxygen /** \ingroup main -\defgroup main_tasks tasks -\brief Tasks +\defgroup main_tasks Tasks +\brief FreeRTOS tasks */ /** \ingroup main -\defgroup main_pb_override overrides +\defgroup main_pb_override Overrides \brief Override functions from \ref pbdrv-mod */ diff --git a/main/readme.md b/main/readme.md index 85a3fca..97150eb 100644 --- a/main/readme.md +++ b/main/readme.md @@ -8,17 +8,7 @@ This directory contains the software for the main controller of the Puzzle Box. ## building 1. make sure the submodules are initialized -2. create a `config.h` file and define some options (see `config.def.h` for all - options): - ```c - #pragma once - - #define CFG_NET_SSID "network name" - #define CFG_NET_PASS "network password" - #define CFG_NET_AUTH CYW43_AUTH_WPA2_AES_PSK - - #include "config.def.h" - ``` +2. create a `config.h` file (see \ref main_config "config") 3. use CMake to build ## flashing -- cgit v1.2.3