diff options
-rw-r--r-- | Doxyfile | 12 | ||||
-rw-r--r-- | client/cmd.h | 140 | ||||
-rw-r--r-- | client/pbc.1 | 90 | ||||
-rw-r--r-- | client/readme.md | 23 | ||||
-rw-r--r-- | client/rl.cpp | 7 | ||||
-rw-r--r-- | client/sock.h | 1 | ||||
-rw-r--r-- | lib/pbdrv/drv/arduino/mod.cpp | 6 | ||||
-rw-r--r-- | lib/pbdrv/drv/index.dox | 7 | ||||
-rw-r--r-- | lib/pbdrv/index.dox | 5 | ||||
-rw-r--r-- | lib/pbdrv/mod/main/pb-mod-main.h | 13 | ||||
-rw-r--r-- | lib/pbdrv/pb-mod.h | 24 | ||||
-rw-r--r-- | lib/pbdrv/pb-route.h | 6 | ||||
-rw-r--r-- | main/config.def.h | 2 | ||||
-rw-r--r-- | main/i2c.c | 1 |
14 files changed, 191 insertions, 146 deletions
@@ -4,10 +4,15 @@ PROJECT_NAME = "puzzlebox" OUTPUT_DIRECTORY = doxygen LAYOUT_FILE = docs/doxygen-layout.xml +# read these files first (fixes broken links) INPUT += readme.md +INPUT += lib/pbdrv/pb-mod.h +INPUT += client/cmd.h + +# find remaining files +INPUT += lib/pbdrv INPUT += lib/mpack INPUT += lib/i2ctcp -INPUT += lib/pbdrv INPUT += client INPUT += main INPUT += puzzle @@ -15,6 +20,7 @@ INPUT += puzzle EXCLUDE = lib/mpack/src EXCLUDE_PATTERNS = **/build EXCLUDE_SYMLINKS = YES +EXCLUDE_SYMBOLS = _* FILE_PATTERNS = *.c *.cpp *.h *.hpp *.md *.dox RECURSIVE = YES @@ -24,10 +30,12 @@ GENERATE_LATEX = NO ALIASES += I2C="I²C" INPUT_FILTER = "sed -e 's/\<I2C\>\|\<I<sup>2<\/sup>C\>/\\I2C/g'" -USE_MDFILE_AS_MAINPAGE = readme.md +USE_MDFILE_AS_MAINPAGE = ./readme.md HTML_INDEX_NUM_ENTRIES = 1 # collapse trees by default REPEAT_BRIEF = NO INTERNAL_DOCS = YES EXTRACT_STATIC = YES +QUIET = YES + diff --git a/client/cmd.h b/client/cmd.h index e2c412a..eac9834 100644 --- a/client/cmd.h +++ b/client/cmd.h @@ -5,10 +5,6 @@ * \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. - * * \{ */ @@ -45,13 +41,149 @@ typedef struct { cmd_complete_t * complete; //!< Completion function (optional = NULL) } cmd_t; +/** + * \anchor pbc_cmd_usage + * \name Command usage + * \{ + */ + +/** + * \brief \c exit command + * + * ``` + * (pbc) exit + * ``` + * + * Disconnect from the puzzle box and exit \c pbc. This command takes no + * arguments. + */ cmd_handle_t cmd_exit; +/** + * \brief \c test command + * + * ``` + * (pbc) test + * ``` + * + * Send a test command containing the ASCII string "Hello world!" to I2C + * address 0x39. This command takes no arguments. + */ cmd_handle_t cmd_test; +/** + * \brief \c help command + * + * ``` + * (pbc) help + * ``` + * + * Print a list of available commands with descriptions. This command takes no + * arguments. + */ cmd_handle_t cmd_help; +/** + * \brief \c reset command + * + * ``` + * (pbc) reset <mod> + * ``` + * + * Set a specific puzzle module's global state to *idle*. *mod* is the I2C + * address of the puzzle module to reset. This parameter may be specified in + * hexadecimal using a *0x* prefix or decimal. + * + */ cmd_handle_t cmd_reset; +/** + * \brief \c send command + * + * ``` + * (pbc) send <addr> <data> + * ``` + * + * Send arbitrary data specified by *data* to the I2C address specified by + * *addr*. *data* may consist of multiple arguments separated by \ref IFS, in + * which case the arguments are concatenated. + * + * The main controller will initiate an I2C write command if the address + * specified in *addr* does not match that of the main controller. If the + * addresses do match, the main controller interprets the message as if it were + * being addressed by another I2C controller. + * + * \par Example + * ``` + * ADDRESS DATA + * v~~~ v~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * (pbc) send 0x39 68:65:6c:6c:6f 44 0x20 'world' 33 + * ^~~~~~~~~~~~~~ ^~ ^~~~ ^~~~~~~ ^~ + * HEXSTR NUMBER NUMBER STRING NUMBER + * (binary) (dec) (hex) (literal) (dec) + * ``` + * + * \par Datatypes + * \parblock + * - **NUMBER** + * + * Numbers can be specified as decimal or hexadecimal using a "0x" prefix. + * All numbers are unsigned. Decimal literals are always cast to 8-bit + * integers, while hexadecimal literals are cast to the smallest type that + * will fit the specified number. Numbers are always sent as little endian. + * + * Examples: `0` `123` `255` `0x10` `0x1245` `0xdeadBEEF` + * + * - **HEXSTR** + * + * Hexadecimal string literals are specified by hexadecimal bytes separated + * by colons. Each byte must be exactly 2 hexadecimal characters long and + * followed by a colon (except for the last byte). The minimum length of a + * hexstr is 2 bytes, as it must include at least a single colon. + * + * Examples: `de:ad:be:ef` `00:00` + * + * - **STRING** + * + * A string literal starts and ends with a single quote. All characters within + * this literal are sent as-is, and no escaping is possible. + * + * Examples: <code>'Hello world!'</code> <code>'string'</code> <code>' hello + * '</code> + * + * When double quotes are used instead of single quotes, the following escape + * sequences are recognised and replaced with special characters: + * |input|replacement|meaning| + * |-|-|-| + * |`\0`|0x00|null| + * |`\t`|0x09|tab| + * |`\n`|0x0a|newline| + * |`\r`|0x0d|carriage return| + * |`\\`|0x5c|backslash| + * |`\"`|0x22|double quote| + * |<code>\'</code>|0x27|single quote| + * + * Examples: `"Hello world!\\0"` `"foo\\nbar"` + * \endparblock + */ cmd_handle_t cmd_send; +/** + * \brief \c skip command + * + * ``` + * (pbc) skip <mod> + * ``` + * + * Set a specific puzzle module's global state to *solved*. *mod* is the I2C + * address of the puzzle module to skip. This parameter may be specified in + * hexadecimal using a *0x* prefix or decimal. + * + */ cmd_handle_t cmd_skip; +/** + * \brief \c dump command + */ cmd_handle_t cmd_dump; + +/// \} + +//! \c dump completion function cmd_complete_t cmd_dump_complete; //! Commands diff --git a/client/pbc.1 b/client/pbc.1 deleted file mode 100644 index a85b03a..0000000 --- a/client/pbc.1 +++ /dev/null @@ -1,90 +0,0 @@ -\# vim: ft=groff -.de I2C -I\*{2\*}C -.. -.TH pbc 1 -.SH NAME -pbc \- puzzle box client -.SH SYNPOSIS -pbc <addr> [port] -.SH DESCRIPTION -Connect to a puzzle box at the IPv4 address specified by \fIaddr\fP and -optionally port specified by \fIport\fP. The default port is 9191. Once -connected, a -.MR readline 3 -based -CLI is started, and commands can be sent. -.SH COMMANDS -.TP -exit -Disconnect from the puzzle box and exit pbc. This command takes no arguments. -.TP -help -Print a list of available commands with descriptions. This command takes no -arguments. -.TP -reset [mod ...] -Set the main controller or specific puzzle module's global state to \fIidle\fP. -If no modules are specified, the main controller's state is updated. One or -more modules can be specified to update them at once. -.TP -skip [mod ...] -Set the main controller or specific puzzle module's global state to -\fIsolved\fP. If no modules are specified, the main controller's state is -updated. One or more modules can be specified to update them at once. -.SH DEBUG COMMANDS -The commands detailed under this section are only available in version of pbc -compiled with debug support. -.TP -send <addr> <data> -Send arbitrary data specified by \fIdata\fP to the -.I2C -address specified by \fIaddr\fP. \fIdata\fP may consist of multiple arguments -separated by IFS, in which case the arguments are concatenated. -.TP -test -Send a test command containing the ASCII string "Hello world!" to -.I2C -address 0x39. This command takes no arguments. -.SH DATA FORMATS -.TP -number -Numbers can be specified as decimal or hexadecimal using a "0x" prefix. All -numbers are unsigned. Decimal literals are always cast to 8-bit integers, while -hexadecimal literals are cast to the smallest type that will fit the specified -number. Numbers are always sent as little endian. - -Examples: 0 123 255 0x10 0x1245 0xdeadBEEF -.TP -hexstr -Hexadecimal string literals are specified by hexadecimal bytes separated by -colons. Each byte must be exactly 2 hexadecimal characters long and followed by -a colon (except for the last byte). The minimum length of a hexstr is 2 bytes, -as it must include at least a single colon. - -Examples: de:ad:be:ef 00:00 -.TP -string -A string literal starts and ends with a single quote. All characters within -this literal are sent as-is, and no escaping is possible. - -Examples: 'Hello world!' 'string' ' hello ' - -When double quotes are used instead of single quotes, the following escape -sequences are recognised and replaced with special characters: - -\\0 -> 0x00 (null) -.br -\\t -> 0x09 (tab) -.br -\\n -> 0x0a (newline) -.br -\\r -> 0x0d (carriage return) -.br -\\\\ -> 0x5c (backslash) -.br -\\" -> 0x22 (double quote) -.br -\\' -> 0x27 (single quote) - -Examples: "Hello world!\\0" "foo\\nbar" - diff --git a/client/readme.md b/client/readme.md index b9e0b09..d99991f 100644 --- a/client/readme.md +++ b/client/readme.md @@ -18,31 +18,12 @@ arbitrary data over the puzzle bus. - Request puzzle box state - Debug: send arbitrary messages -## Building - -PBC is a standard CMake project. - -## Using - -See ./pbc.1 for usage. - -## Send data - -``` - ADDRESS DATA - v~~~ v~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -send 0x39 68:65:6c:6c:6f 44 0x20 'world' 33 - ^~~~~~~~~~~~~~ ^~ ^~~~ ^~~~~~~ ^~ - HEXSTR NUMBER NUMBER STRING NUMBER - (binary) (dec) (hex) (literal) (dec) -``` - -The data is concatenated, and may contain mixed types of literals +## Usage +See \ref pbc_cmd_usage "command usage" for individual command usage. ## 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 diff --git a/client/rl.cpp b/client/rl.cpp index 493f753..82d1412 100644 --- a/client/rl.cpp +++ b/client/rl.cpp @@ -128,18 +128,17 @@ int rl_word(const char * line, int cursor) { return word; } -/// \internal typedef struct { const char * word; const char ** options; -} __rl_complete_list_data_t; +} _rl_complete_list_data_t; char** rl_complete_list(const char * word, const char ** options) { - __rl_complete_list_data_t data = { + _rl_complete_list_data_t data = { .word = word, .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; + _rl_complete_list_data_t data = *(_rl_complete_list_data_t *) text; static size_t i = 0; if (state == 0) i = 0; diff --git a/client/sock.h b/client/sock.h index 792123e..5b62861 100644 --- a/client/sock.h +++ b/client/sock.h @@ -18,6 +18,7 @@ class PBSocket { public: PBSocket(); + //! Constructor that immediately calls \c set_server() PBSocket(const char * addr, uint16_t port); virtual ~PBSocket(); diff --git a/lib/pbdrv/drv/arduino/mod.cpp b/lib/pbdrv/drv/arduino/mod.cpp index 581b80a..81735af 100644 --- a/lib/pbdrv/drv/arduino/mod.cpp +++ b/lib/pbdrv/drv/arduino/mod.cpp @@ -47,11 +47,11 @@ static void pb_setup() { * with 2 Uno's, but ran into issues while integrating the Arduino's with the * RP2040. */ -__weak void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { - if (pb_hook_i2c_send(addr, buf, sz)) return; +__weak void pb_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz) { + if (pb_hook_i2c_send(i2c_addr, buf, sz)) return; vTaskDelay(10 / portTICK_PERIOD_MS); // prevent bus collisions - Wire.beginTransmission((int) addr); + Wire.beginTransmission((int) i2c_addr); Wire.write(buf, sz); Wire.endTransmission(true); Wire.setWireTimeout(PB_TIMEOUT_US, true); diff --git a/lib/pbdrv/drv/index.dox b/lib/pbdrv/drv/index.dox index 89b9247..c0c1b76 100644 --- a/lib/pbdrv/drv/index.dox +++ b/lib/pbdrv/drv/index.dox @@ -8,12 +8,17 @@ Like \ref pb_ext "extensions", drivers provide platform-specific implementations for various functions used in \ref pbdrv-mod. If there is no existing driver for your target, you may implement the following -in order to use \ref pbdrv-mod: +in order to use \ref "pbdrv-mod": - The \c pb_i2c_recv() function must be **called** for every received I2C message - The \c pb_i2c_send() function must be **implemented** using the platform/device-specific I2C write function + \note The \c pb_i2c_send() function should immediately call \c + pb_hook_i2c_send() before doing any further processing: + ```c + if (pb_hook_i2c_send(i2c_addr, buf, sz)) return; + ``` */ diff --git a/lib/pbdrv/index.dox b/lib/pbdrv/index.dox index 8ddcb6a..0be5f33 100644 --- a/lib/pbdrv/index.dox +++ b/lib/pbdrv/index.dox @@ -68,6 +68,11 @@ extend or conditionally replace the default handlers), without needing to completely overwrite the built-in handlers or understand the internals of \ref pbdrv-mod. +The boolean value returned by some hooks (e.g. those under \ref pb_hook_route +or \ref pb_hook_i2c) represents if the default handler should run after the +hook returns. This allow you to conditionally 'catch' calls to their respective +base functions by returning \c true. + \} */ diff --git a/lib/pbdrv/mod/main/pb-mod-main.h b/lib/pbdrv/mod/main/pb-mod-main.h deleted file mode 100644 index 9c69c1d..0000000 --- a/lib/pbdrv/mod/main/pb-mod-main.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "../../pb-types.h" - -typedef struct { - i2c_addr_t mod_addr; - pb_global_state_t mod_state; -} pb_mod_main_prop_mod_t; - -enum { - PB_MOD_MAIN_PROP_MODS = 0x00, //!< structured list of connected puzzle modules -}; - diff --git a/lib/pbdrv/pb-mod.h b/lib/pbdrv/pb-mod.h index 7069b32..21e8100 100644 --- a/lib/pbdrv/pb-mod.h +++ b/lib/pbdrv/pb-mod.h @@ -75,16 +75,16 @@ void pb_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz); */ /** - * \brief global state read hook - * \return current value of global state enum + * \brief Global state read hook + * \return Current value of global state enum * * The default implementation of this function uses an internal global state * variable in \ref pbdrv. */ pb_global_state_t pb_hook_mod_state_read(); /** - * \brief global state write hook - * \param state new value of global state enum + * \brief Global state write hook + * \param state New value of global state enum * * The default implementation of this function uses an internal global state * variable in \ref pbdrv. @@ -101,7 +101,23 @@ void pb_hook_mod_state_write(pb_global_state_t state); * \{ */ +/** + * \brief \c pb_i2c_recv() hook + * + * The default implementation of this function immediately returns \c false. + * + * \return \c false if execution should continue to the default handler, or \c + * true if it should stop (i.e. the message was handled). + */ bool pb_hook_i2c_recv(const uint8_t * buf, size_t sz); +/** + * \brief \c pb_i2c_send() hook + * + * The default implementation of this function immediately returns \c false. + * + * \return \c false if execution should continue to the default handler, or \c + * true if it should stop (i.e. the message was handled). + */ bool pb_hook_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz); /// \} diff --git a/lib/pbdrv/pb-route.h b/lib/pbdrv/pb-route.h index 2a28c0b..8b7bba5 100644 --- a/lib/pbdrv/pb-route.h +++ b/lib/pbdrv/pb-route.h @@ -140,10 +140,10 @@ void pb_route_cmd_magic_res(pb_msg_t * msg); /** * \brief \c pb_route_msg() hook * - * The default implementation of this function immediately returns false. + * The default implementation of this function immediately returns \c false. * - * \return \c true if execution should continue to the default handler, or \c - * false if it should stop (i.e. the message was handled). + * \return \c false if execution should continue to the default handler, or \c + * true if it should stop (i.e. the message was handled). */ bool pb_hook_route_msg(pb_msg_t * msg); diff --git a/main/config.def.h b/main/config.def.h index cb6e8b4..1ec8a5c 100644 --- a/main/config.def.h +++ b/main/config.def.h @@ -71,10 +71,10 @@ #ifdef CFG_NET_DISABLE #undef CFG_NET_COUNTRY +//! Radio communications country #define CFG_NET_COUNTRY CYW43_COUNTRY_WORLDWIDE #endif #ifndef CFG_NET_COUNTRY -//! Radio communications country #define CFG_NET_COUNTRY CYW43_COUNTRY_NETHERLANDS #endif /// \} @@ -12,6 +12,7 @@ #include "pb-buf.h" #include "pb-send.h" +//! Puzzle module handle typedef struct { i2c_addr_t sender; //!< I2C address of sender pb_global_state_t state; //!< global state |