diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-06-21 19:29:44 +0200 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-06-21 19:29:44 +0200 |
commit | 8a80226e9dce394573e95d68fc9fe04592ad5907 (patch) | |
tree | 05686bd0674f6fa33cd319cec803c791551ef0f7 | |
parent | 79e60b430143b2acc4b93f62e23770e6bcbd7861 (diff) |
more doxygen documentationg
-rw-r--r-- | Doxyfile | 8 | ||||
-rw-r--r-- | lib/pbdrv/index.dox | 39 | ||||
-rw-r--r-- | lib/pbdrv/pb-buf.h | 16 | ||||
-rw-r--r-- | lib/pbdrv/pb-mem.h | 55 | ||||
-rw-r--r-- | lib/pbdrv/pb-mod.h | 83 | ||||
-rw-r--r-- | lib/pbdrv/pb-msg.h | 40 | ||||
-rw-r--r-- | lib/pbdrv/pb-route.h | 27 | ||||
-rw-r--r-- | lib/pbdrv/pb.h | 9 | ||||
-rw-r--r-- | lib/pbdrv/spec.adoc | 133 |
9 files changed, 248 insertions, 162 deletions
@@ -3,6 +3,7 @@ DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "puzzlebox" OUTPUT_DIRECTORY = doxygen +INPUT += readme.md INPUT += client INPUT += lib/mpack INPUT += lib/i2ctcp @@ -14,8 +15,13 @@ EXCLUDE = lib/mpack/src EXCLUDE_PATTERNS = **/build EXCLUDE_SYMLINKS = YES -FILE_PATTERNS = *.c *.cpp *.h *.hpp *.md +FILE_PATTERNS = *.c *.cpp *.h *.hpp *.md *.dox RECURSIVE = YES 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 + diff --git a/lib/pbdrv/index.dox b/lib/pbdrv/index.dox new file mode 100644 index 0000000..ad05078 --- /dev/null +++ b/lib/pbdrv/index.dox @@ -0,0 +1,39 @@ +// vim:ft=doxygen +/** + +\defgroup pbdrv pbdrv +\brief Standalone puzzle bus driver + +pbdrv is a standalone portable static library for handling (i.e. +(de)serialization) of puzzle bus messages. + +\defgroup pbdrv-mod pbdrv-mod +\brief Puzzle module driver (superset of \ref pbdrv) + +pbdrv-mod is a superset of pbdrv, and includes functions specific to puzzle bus +modules. pbdrv-mod compiles to an object file instead of a static library +because it may depend on functions that rely on external libraries. pbdrv-mod +is still considered standalone, but requires either using an existing driver, +or (partially) implementing the driver functions. + +\note Most \c pb_* functions have a weak implementation, which may be +overwritten by a custom implementation. This allows you to use the default +implementation where possible, and only implement extensions required for your +puzzle module. + +TODO: where to find drivers +TODO: what are extensions +TODO: what to do if there is no driver / extension + +\{ + +\defgroup hook +\brief Functions for (partially) overriding default behavior + +Hooks are functions with a default (weak) implementation in pbdrv. These +functions can be overwritten by the user to implement custom behavior, without +needing to understand the internals of pbdrv. + +\} + +*/ diff --git a/lib/pbdrv/pb-buf.h b/lib/pbdrv/pb-buf.h index 78ee380..049f516 100644 --- a/lib/pbdrv/pb-buf.h +++ b/lib/pbdrv/pb-buf.h @@ -6,14 +6,30 @@ extern "C" { #endif +/** + * \ingroup pbdrv + * \ingroup pbdrv-mod + * \defgroup pb_buf Buffer + * \brief Binary data buffer type used in pbdrv + * \{ + */ + //! binary buffer struct typedef struct { char * data; //! pointer to data size_t size; //! size of data } pb_buf_t; +/** + * \brief free a \c pb_buf_t + * + * This function calls \c pb_free() on the \c data member of a \c pb_buf_t + * struct if it is not equal to \c NULL. + */ void pb_buf_free(pb_buf_t * buf); +/// \} + #ifdef __cplusplus } #endif diff --git a/lib/pbdrv/pb-mem.h b/lib/pbdrv/pb-mem.h index 72be214..4d0f995 100644 --- a/lib/pbdrv/pb-mem.h +++ b/lib/pbdrv/pb-mem.h @@ -6,13 +6,68 @@ extern "C" { #endif +/** + * \ingroup pbdrv + * \ingroup pbdrv-mod + * \defgroup pb_mem Memory + * \brief Platform-specific memory management functions + * + * \note This header only declares the memory management functions, and it is + * up to \ref pb_ext "extensions" to implement the underlying memory management + * functions. + * + * TODO: ref to extensions + * + * \{ + */ + +/** + * \brief Allocate a contiguous chunk of memory + * \param sz Requested size of memory area + * \return Pointer to memory area, or \c NULL on failure + * \note The allocated memory must be free'd again using \c pb_free() + */ void * pb_malloc(size_t sz); +/** + * \brief Free a chunk of memory previously allocated with \c pb_malloc() + * \param ptr Pointer to memory area + */ void pb_free(void * ptr); +/** + * \brief Resize the memory area \c ptr to size \c sz + * \param ptr Pointer to allocated memory area + * \param sz Requested new size of memory area + * \return Pointer to memory area, or \c NULL on failure + * \warning This function is not available on FreeRTOS, and should be avoided + * if possible. MPack's \c mpack_writer_init_growable() is known to use \c + * realloc(), and should not be used for this reason. + */ void * pb_realloc(void * ptr, size_t sz); +/** + * \brief copy a memory region + * \param dest Pointer to destination memory + * \param src Pointer to source memory + * \param sz Number of bytes to copy + * \return Pointer to \c dest + * + * This function has a portable implementation, and is always available. + */ void * pb_memcpy(void * dest, const void * src, size_t sz); +/** + * \brief compare two memory regions + * \param a Pointer to first memory region + * \param b Pointer to second memory region + * \param sz Number of bytes to compare + * \return 0 if the memory regions are identical, or the difference between the + * first non-matching byte + * + * This function has a portable implementation, and is always available. + */ int pb_memcmp(const void * a, const void * b, size_t sz); +/// \} + #ifdef __cplusplus } #endif diff --git a/lib/pbdrv/pb-mod.h b/lib/pbdrv/pb-mod.h index c4629a6..2ff1908 100644 --- a/lib/pbdrv/pb-mod.h +++ b/lib/pbdrv/pb-mod.h @@ -1,31 +1,63 @@ #pragma once -/** - * \file puzzle bus driver implementation - * - * Most \c pb_* functions have a weak implementation, which may be overwritten - * by a custom implementation. This allows you to use the default - * implementation where possible, and only implement extensions required for - * your puzzle module. Please see spec.adoc for more information about how to - * use the puzzle bus driver library. - */ - #include "pb-types.h" #ifdef __cplusplus extern "C" { #endif -//! puzzle module name (optional, default = "???") +/** + * \ingroup pbdrv-mod + * \defgroup pb_mod Module + * \brief Metadata and auxiliary utility functions + * \{ + */ + +/** + * \brief Puzzle module name + * + * Optional to define, default value is "???" + */ extern const char * PB_MOD_NAME; -//! puzzle module bus address (required) +/** + * \brief Puzzle module bus address + * + * **Required** to define + */ extern const i2c_addr_t PB_MOD_ADDR; /** + * \brief Platform-specific blocking delay function + * + * FIXME: this should be removed (see handover: RP2040 I2C limitations) + */ +void pb_mod_blocking_delay_ms(unsigned long ms); + +/// \} + +/** + * \ingroup pbdrv-mod + * \defgroup pb_i2c I2C + * \brief I2C send/receive handlers + * + * If there is no existing \ref pb_drv "driver" for the microcontroller on + * which you want to use the puzzle bus driver, you may implement the following + * in order to use pbdrv: + * + * - 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 + * + * \{ + */ + +/** * \brief handle a received message from the I2C bus (puzzle bus) * * This function attempts to parse an I2C message as a puzzle bus message, and * calls the appropriate handler for the message if it is considered valid. + * Invalid messages are silently ignored. * * \param buf pointer to message content * \param sz size of \p buf @@ -46,25 +78,36 @@ void pb_i2c_recv(const uint8_t * buf, size_t sz); */ void pb_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz); +/// \} + +/// \ingroup hook +/// \{ + +/** + * \defgroup pb_hook_mod_state State + * \brief Provide your own global state variable + * + * If your puzzle module defines its own global \c pb_global_state_t, you can + * tell the driver to use it by implementing these functions. These functions + * are also used internally by the driver when creating \c STATE \c REQ and \c + * STATE \c RES commands. + * + * \{ + */ + /** * \brief global state read hook - * \ingroup hook * \return current value of global state enum */ pb_global_state_t pb_hook_mod_state_read(); /** * \brief global state write hook - * \ingroup hook * \param state new value of global state enum */ void pb_hook_mod_state_write(pb_global_state_t state); -/** - * \brief platform-specific blocking delay function - * - * FIXME: this should be removed (see handover: RP2040 I2C limitations) - */ -void pb_mod_blocking_delay_ms(unsigned long ms); +/// \} +/// \} #ifdef __cplusplus } diff --git a/lib/pbdrv/pb-msg.h b/lib/pbdrv/pb-msg.h index f27d4c4..33b697a 100644 --- a/lib/pbdrv/pb-msg.h +++ b/lib/pbdrv/pb-msg.h @@ -7,10 +7,50 @@ extern "C" { #endif +/** + * \ingroup pbdrv + * \ingroup pbdrv-mod + * \defgroup pb_msg Message + * \brief Message (de)serialization + * \{ + */ + +/** + * \brief Serialize a message into a binary buffer + * + * \note This function allocates a \c pb_buf_t that should be free'd using \c + * pb_buf_free() + * + * \param msg Message to serialize + * + * \warning The type of \c msg->cmd is inferred from \c msg->type. If the + * message is not correctly formatted, this function may cause undefined + * behavior. If possible, use functions from \ref pb_send instead. + * + * \return \c pb_buf_t containing the serialized message, or an empty struct if + * serialization failed + */ pb_buf_t pb_msg_write(const pb_msg_t * msg); +/** + * \brief Read a binary buffer and attempt to deserialize it as a puzzle bus + * message + * + * \note This function allocates a \c pb_msg_t pointer that should be free'd + * using \c pb_msg_free() + * + * \param buf Binary data to interpret as puzzle bus message + * + * \return \c pb_msg_t pointer containing the deserialized message, or NULL if + * serialization failed + */ pb_msg_t * pb_msg_read(const pb_buf_t * buf); +/** + * \brief Recursively free fields of a \c pb_msg_t + */ void pb_msg_free(pb_msg_t * msg); +/// \} + #ifdef __cplusplus } #endif diff --git a/lib/pbdrv/pb-route.h b/lib/pbdrv/pb-route.h index 967c4a9..233a087 100644 --- a/lib/pbdrv/pb-route.h +++ b/lib/pbdrv/pb-route.h @@ -8,16 +8,10 @@ extern "C" { void pb_route_msg(pb_msg_t * msg); -bool pb_hook_route_msg(pb_msg_t * msg); - void pb_route_cmd_prop(pb_msg_t * msg); void pb_route_cmd_state(pb_msg_t * msg); void pb_route_cmd_magic(pb_msg_t * msg); -bool pb_hook_route_cmd_prop(pb_msg_t * msg); -bool pb_hook_route_cmd_state(pb_msg_t * msg); -bool pb_hook_route_cmd_magic(pb_msg_t * msg); - void pb_route_cmd_prop_req(pb_msg_t * msg); void pb_route_cmd_prop_res(pb_msg_t * msg); void pb_route_cmd_prop_set(pb_msg_t * msg); @@ -26,11 +20,28 @@ void pb_route_cmd_state_req(pb_msg_t * msg); void pb_route_cmd_state_res(pb_msg_t * msg); void pb_route_cmd_state_set(pb_msg_t * msg); +void pb_route_cmd_magic_req(pb_msg_t * msg); +void pb_route_cmd_magic_res(pb_msg_t * msg); + +/// \ingroup hook +/// \{ + +/// \defgroup hook_route Routing +/// \brief Use a custom message handler +/// \{ + +bool pb_hook_route_msg(pb_msg_t * msg); + +bool pb_hook_route_cmd_prop(pb_msg_t * msg); +bool pb_hook_route_cmd_state(pb_msg_t * msg); +bool pb_hook_route_cmd_magic(pb_msg_t * msg); + +/// \} + void pb_hook_main_state_update(pb_global_state_t state); void pb_hook_module_init(); -void pb_route_cmd_magic_req(pb_msg_t * msg); -void pb_route_cmd_magic_res(pb_msg_t * msg); +/// \} #ifdef __cplusplus } diff --git a/lib/pbdrv/pb.h b/lib/pbdrv/pb.h index e8037ae..cef04d8 100644 --- a/lib/pbdrv/pb.h +++ b/lib/pbdrv/pb.h @@ -1,5 +1,13 @@ #pragma once +/** + * \ingroup pbdrv + * \ingroup pbdrv-mod + * \defgroup pb Bus + * \brief Constants for the puzzle bus hardware + * \{ + */ + //! I2C bus speed in hertz (100 KHz) #define PB_CLOCK_SPEED_HZ 100000 //! I2C bus timeout delay in milliseconds @@ -32,3 +40,4 @@ //! Dummy puzzle module I2C address #define PB_ADDR_MOD_DUMMY 0x69 +/// \} diff --git a/lib/pbdrv/spec.adoc b/lib/pbdrv/spec.adoc deleted file mode 100644 index 3172e84..0000000 --- a/lib/pbdrv/spec.adoc +++ /dev/null @@ -1,133 +0,0 @@ -= Puzzle module specification - -This folder contains an implementation of the puzzle bus protocol -specification, and is targeted at puzzle module developers. This document -describes the required implementation steps for integrating a new game into the -puzzle module framework. - -== The bus - -The puzzle bus carries data over a standard I^2^C bus. Additional details about -this bus can be found in the link:../../docs/design.adoc[Design document]. - -The following details are important to puzzle module developers, as they may -cause unexpected behavior: - -- *Addresses influence the puzzle box's behavior*. The order of puzzles is - determined by the puzzle module address. Two puzzle modules may use the same - address, but this will mean that they cannot be used simultaniously in the - same puzzle box. Known addresses are documented in link:bus.h[]. -- *The read/write bit of an I^2^C frame determines how it's handled*. I^2^C - *read* frames are treated as requests, while *write* frames are treated as - responses. - -== Puzzle bus driver (pbdrv) - -The library in this folder is a partial implementation of the puzzle bus -specification *for puzzle modules*. Most functions in the driver are marked -with the 'weak' attribute, which allows you to override them by providing an -implementation. - -In order to utilize this driver, the following must be done: - -- The ``pbdrv_i2c_recv`` function must be *called* for every received *I^2^C - read* frame -- The ``pbdrv_i2c_send`` function must be *implemented* with the - platform-specific *I^2^C write* function - -This is enough to get the puzzle module registered. You may also want to -implement some of the following integrations: - -- If your game uses the global state variable, you should implement the - <<sec:state-global,global state hooks>> to point the driver to your own - global state variable, and be notified of reads/writes to it. -- If you want to expose additional game state variables over the puzzle bus, - you should implement the <<sec:state-aux,auxiliary state hooks>>. -- If you want to implement custom puzzle bus commands, you can implement the - <<sec:cmd,command hook>>. - -All other kinds of integrations/hooks can likely be realized by overriding the -default implementations, but this is discouraged. - -[[sec:state-global]] -== Global state - -If your puzzle module defines its own global ``enum pb_state``, you can tell -the driver to use it by implementing the ``pbdrv_hook_state_read`` and -``pbdrv_hook_state_write`` functions. These functions are also used by the -default implementation of the read/write commands to address 0 (global state). - -Example: - -```c -pb_state_t global_state = PB_GS_NOINIT; - -pb_state_t pbdrv_hook_mod_state_read() { - return global_state; -} - -void pbdrv_hook_mod_state_write(pb_state_t state) { - global_state = state; -} -``` - -[[sec:state-aux]] -== Auxiliary state - -You can expose additional state variables by implementing the -``pbdrv_hook_read`` and ``pbdrv_hook_write`` functions. These functions should -return ``true`` for state addresses you want to override. - -Example: - -```c -#define CUSTOM_VAR_ADDR 0x01 -uint8_t my_custom_variable = 10; - -bool pbdrv_hook_read(uint16_t i2c_addr, uint8_t addr) { - switch (addr) { - case CUSTOM_VAR_ADDR: { - char res[] = { PB_CMD_READ, addr, my_custom_variable }; - pbdrv_i2c_send(i2c_addr, res, sizeof(res)); - break; - } - default: return false; - } - - return true; -} - -bool pbdrv_hook_write(uint16_t i2c_addr, uint8_t addr, const char * buf, size_t sz) { - switch (addr) { - case CUSTOM_VAR_ADDR: { - if (sz != 1) return false; - my_custom_variable = buf[0]; - break; - } - default: return false; - } - - return true; -} -``` - -[[sec:cmd]] -== Custom commands - -Similar to the auxiliary state, custom commands can be added by implementing -the ``pbdrv_hook_cmd`` function, which should return ``true`` for the -command(s) that you want to overwrite. - -Example: - -```c -bool pbdrv_hook_cmd(uint16_t i2c_addr, enum pb_cmd cmd, const char * buf, size_t sz) { - if (cmd == 0x54) { - printf("custom command received!\n"); - return true; - } - - return false; -} -``` - |