From bb63040692c94ffa662b0af7eb14f3c5951aa6e6 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 22 Jun 2024 13:01:42 +0200 Subject: even more doxygen documentation --- lib/pbdrv/drv/arduino/index.dox | 19 ++++++++++ lib/pbdrv/drv/arduino/mod.cpp | 20 ++++++----- lib/pbdrv/drv/index.dox | 32 +++++++++++++++++ lib/pbdrv/ext/freertos/index.dox | 6 ++++ lib/pbdrv/ext/freertos/pb-mem.c | 5 +++ lib/pbdrv/ext/freertos/pb-mod.c | 1 + lib/pbdrv/ext/index.dox | 24 +++++++++++++ lib/pbdrv/ext/stdlib/index.dox | 6 ++++ lib/pbdrv/ext/stdlib/pb-mem.c | 5 +++ lib/pbdrv/index.dox | 64 +++++++++++++++++++++++++-------- lib/pbdrv/pb-mod.h | 13 ++----- lib/pbdrv/pb-msg.h | 3 ++ lib/pbdrv/pb-serial.h | 76 ++++++++++++++++++++++++++++++++++------ main/pbdrv.h | 56 +++++++++++++++++------------ 14 files changed, 262 insertions(+), 68 deletions(-) create mode 100644 lib/pbdrv/drv/arduino/index.dox create mode 100644 lib/pbdrv/drv/index.dox create mode 100644 lib/pbdrv/ext/freertos/index.dox create mode 100644 lib/pbdrv/ext/index.dox create mode 100644 lib/pbdrv/ext/stdlib/index.dox diff --git a/lib/pbdrv/drv/arduino/index.dox b/lib/pbdrv/drv/arduino/index.dox new file mode 100644 index 0000000..4c74222 --- /dev/null +++ b/lib/pbdrv/drv/arduino/index.dox @@ -0,0 +1,19 @@ +// vim:ft=doxygen +/** +\ingroup pb_drv +\defgroup pb_drv_arduino Arduino +\brief Arduino (Arduino-CMake-Toolchain) driver + +This driver is automatically enabled if the variable \c ARDUINO is defined in +your CMakeLists.txt (it is by default when using Arduino-CMake-Toolchain). + +\note This driver automatically includes the +\ref pb_ext_freertos "FreeRTOS extension" for deferring calls to \c +pb_i2c_recv() from the I2C ISR. + +This driver is known to work with the following MCUs: +- ATmega328P (Arduino Uno) +- ATmega2560 (Arduino Mega) + +*/ + diff --git a/lib/pbdrv/drv/arduino/mod.cpp b/lib/pbdrv/drv/arduino/mod.cpp index 9130334..2eef8d5 100644 --- a/lib/pbdrv/drv/arduino/mod.cpp +++ b/lib/pbdrv/drv/arduino/mod.cpp @@ -42,6 +42,7 @@ static void pb_setup() { Wire.onReceive(recv_event); } +/// \ingroup pb_drv_arduino __weak void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { Wire.beginTransmission((int) addr); Wire.write(buf, sz); @@ -64,7 +65,16 @@ void loop_task() { } } -//! Application entrypoint +/** + * \ingroup pb_drv_arduino + * \brief Application entrypoint + * + * \note I should really be able to use Arduino's initVariant function for + * this, but I can't seem to get it to link properly using the CMake setup in + * this repository. Overriding the main() function seems to work, and the + * USBCON thing in the default Arduino main() function isn't needed because + * puzzle modules are likely not using USB. + */ int main(void) { init(); // call arduino internal setup setup(); // call regular arduino setup @@ -74,11 +84,3 @@ int main(void) { return 0; } -/** - * \note I should really be able to use Arduino's initVariant function for - * this, but I can't seem to get it to link properly using the CMake setup in - * this repository. Overriding the main() function seems to work, and the - * USBCON thing in the default Arduino main() function isn't needed because - * puzzle modules are likely not using USB. - */ - diff --git a/lib/pbdrv/drv/index.dox b/lib/pbdrv/drv/index.dox new file mode 100644 index 0000000..1fe09e2 --- /dev/null +++ b/lib/pbdrv/drv/index.dox @@ -0,0 +1,32 @@ +// vim:ft=doxygen +/** +\ingroup pbdrv-mod +\defgroup pb_drv Drivers +\brief Platform-specific \ref pbdrv-mod implementations + +Like \ref pb_ext "extensions", drivers provide platform-specific +implementations for various functions used in \ref pbdrv-mod. + +Drivers are automatically included based on your build configuration, and you +only need to ensure \c pbdrv-mod is linked with your final executable in order +to use one of the available drivers: + +```cmake +# include pbdrv +add_subdirectory(lib/pbdrv) + +# link pbdrv-mod +target_link_libraries(main pbdrv-mod) + +``` + +If there is no existing driver for your target, you may implement the following +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 + +*/ + diff --git a/lib/pbdrv/ext/freertos/index.dox b/lib/pbdrv/ext/freertos/index.dox new file mode 100644 index 0000000..dfa45ff --- /dev/null +++ b/lib/pbdrv/ext/freertos/index.dox @@ -0,0 +1,6 @@ +// vim:ft=doxygen +/** +\ingroup pb_ext +\defgroup pb_ext_freertos FreeRTOS +\brief FreeRTOS memory management and scheduler-based delay +*/ diff --git a/lib/pbdrv/ext/freertos/pb-mem.c b/lib/pbdrv/ext/freertos/pb-mem.c index b18d79f..6647f05 100644 --- a/lib/pbdrv/ext/freertos/pb-mem.c +++ b/lib/pbdrv/ext/freertos/pb-mem.c @@ -3,24 +3,29 @@ #include "../../pb-mem.h" #include "../../pb-types.h" +/// \ingroup pb_ext_freertos inline void * pb_malloc(size_t sz) { return pvPortMalloc(sz); } +/// \ingroup pb_ext_freertos inline void pb_free(void * ptr) { vPortFree(ptr); } +/// \ingroup pb_ext_freertos __weak inline void * pb_realloc(void * ptr, size_t sz) { return NULL; // shit out of luck (don't use mpack_writer_init_growable) } +/// \ingroup pb_ext_freertos __weak void * pb_memcpy(void * dest, const void * src, size_t sz) { for (size_t offset = 0; offset < sz; offset++) *((char*) dest + offset) = *((char*) src + offset); return dest; } +/// \ingroup pb_ext_freertos __weak int pb_memcmp(const void * a, const void * b, size_t sz) { for (size_t offset = 0; offset < sz; offset++) { int diff = *((char*) a + offset) - *((char*) b + offset); diff --git a/lib/pbdrv/ext/freertos/pb-mod.c b/lib/pbdrv/ext/freertos/pb-mod.c index 75495be..5c0aa36 100644 --- a/lib/pbdrv/ext/freertos/pb-mod.c +++ b/lib/pbdrv/ext/freertos/pb-mod.c @@ -3,6 +3,7 @@ #include "../../pb-types.h" +/// \ingroup pb_ext_freertos __weak void pb_mod_blocking_delay_ms(unsigned long ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } diff --git a/lib/pbdrv/ext/index.dox b/lib/pbdrv/ext/index.dox new file mode 100644 index 0000000..f7d2bc6 --- /dev/null +++ b/lib/pbdrv/ext/index.dox @@ -0,0 +1,24 @@ +// vim:ft=doxygen +/** +\ingroup pbdrv +\ingroup pbdrv-mod +\defgroup pb_ext Extensions +\brief Platform-specific \ref pbdrv implementations + +Extensions provide platform-specific implementations for various functions used +in \ref pbdrv, and allows \ref pbdrv to remain completely portable. Extensions +are used in both \ref pbdrv and \ref pbdrv-mod. + +In order to use an extension, include the appropriate CMake lists file for your +target platform after the \ref pbdrv include: + +```cmake +# include pbdrv +add_subdirectory(lib/pbdrv) + +# use stdlib extension (for use with C standard library) +include(lib/pbdrv/ext/stdlib/include.cmake) + +``` + +*/ diff --git a/lib/pbdrv/ext/stdlib/index.dox b/lib/pbdrv/ext/stdlib/index.dox new file mode 100644 index 0000000..756af1e --- /dev/null +++ b/lib/pbdrv/ext/stdlib/index.dox @@ -0,0 +1,6 @@ +// vim:ft=doxygen +/** +\ingroup pb_ext +\defgroup pb_ext_stdlib stdlib +\brief C stdlib memory management +*/ diff --git a/lib/pbdrv/ext/stdlib/pb-mem.c b/lib/pbdrv/ext/stdlib/pb-mem.c index b260c2c..328efbb 100644 --- a/lib/pbdrv/ext/stdlib/pb-mem.c +++ b/lib/pbdrv/ext/stdlib/pb-mem.c @@ -3,22 +3,27 @@ #include "../../pb-mem.h" +/// \ingroup pb_ext_stdlib inline void * pb_malloc(size_t sz) { return malloc(sz); } +/// \ingroup pb_ext_stdlib inline void pb_free(void * ptr) { free(ptr); } +/// \ingroup pb_ext_stdlib inline void * pb_realloc(void * ptr, size_t sz) { return realloc(ptr, sz); } +/// \ingroup pb_ext_stdlib void * pb_memcpy(void * dest, const void * src, size_t sz) { return memcpy(dest, src, sz); } +/// \ingroup pb_ext_stdlib int pb_memcmp(const void * a, const void * b, size_t sz) { return memcmp(a, b, sz); } diff --git a/lib/pbdrv/index.dox b/lib/pbdrv/index.dox index e4a6c5f..eb0fd63 100644 --- a/lib/pbdrv/index.dox +++ b/lib/pbdrv/index.dox @@ -4,28 +4,62 @@ \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. +\ref pbdrv is a standalone portable static library for handling (i.e. +(de)serialization) of puzzle bus messages. \ref pbdrv is meant for use within +applications that handle puzzle bus messages, but are not puzzle modules +themselves. For a complete puzzle module driver, please see \ref pbdrv-mod. -\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. +If you order to use \ref pbdrv, you need to include this folder in your +CMakeLists.txt file, include the \ref pb_ext "extension" for your target +platform, and link the \c pbdrv library with your executable: + +```cmake +# include pbdrv +add_subdirectory(lib/pbdrv) + +# + +# link with executable +target_link_libraries(main pbdrv) +``` -TODO: where to find drivers -TODO: what are extensions -TODO: what to do if there is no driver / extension \defgroup pbdrv-mod pbdrv-mod \brief Puzzle module driver (superset of \ref pbdrv) pbdrv-mod is a superset of \ref 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. +puzzle bus modules. \ref pbdrv-mod compiles to an object file instead of a +static library because it may depend on functions that rely on external +libraries. \ref pbdrv-mod is still considered standalone, but requires either +using an existing \ref pb_drv "driver", or (partially) implementing the driver +functions. + +Like \ref pbdrv, \ref pbdrv-mod can be used by including this folder in your +CMakeLists.txt file and linking the library with your executable. A notable +difference with \ref pbdrv-mod is that you do not need to include an extension. +\ref pb_ext "Extensions" are still used by \ref pbdrv-mod, but they are +included automatically by the target platform's \ref pb_drv "driver". The +appropriate \ref pb_drv "driver" to load is also automatically detected. + +Example: + +```cmake +# include pbdrv +add_subdirectory(lib/pbdrv) + +# link with executable +target_link_libraries(main pbdrv-mod) +``` + +\note In most cases, the \ref pb_hook "hooks" should be sufficient to realize +extensions or custom behavior not provided by \ref pbdrv-mod. + +\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. -\copydetails pbdrv +\see pbdrv \{ @@ -35,7 +69,7 @@ driver, or (partially) implementing the driver functions. Hooks are functions that allow the user to implement custom behavior (i.e. extend or conditionally replace the default handlers), without needing to completely overwrite the built-in handlers or understand the internals of \ref -pbdrv. +pbdrv-mod. \} diff --git a/lib/pbdrv/pb-mod.h b/lib/pbdrv/pb-mod.h index 75fcbec..3869e55 100644 --- a/lib/pbdrv/pb-mod.h +++ b/lib/pbdrv/pb-mod.h @@ -39,20 +39,11 @@ void pb_mod_blocking_delay_ms(unsigned long ms); * \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) + * \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. @@ -67,7 +58,7 @@ void pb_mod_blocking_delay_ms(unsigned long ms); */ void pb_i2c_recv(const uint8_t * buf, size_t sz); /** - * \brief send a message in master-mode on the I2C bus (puzzle bus) + * \brief Send a message in master-mode on the I2C bus (puzzle bus) * * This function sends an I2C message to the address specified by \p i2c_addr. * diff --git a/lib/pbdrv/pb-msg.h b/lib/pbdrv/pb-msg.h index 33b697a..ff5bcde 100644 --- a/lib/pbdrv/pb-msg.h +++ b/lib/pbdrv/pb-msg.h @@ -46,6 +46,9 @@ pb_buf_t pb_msg_write(const pb_msg_t * msg); pb_msg_t * pb_msg_read(const pb_buf_t * buf); /** * \brief Recursively free fields of a \c pb_msg_t + * + * \note The \p msg pointer itself is also free'd by this function. You should + * set it to NULL afterwards to avoid confusion. */ void pb_msg_free(pb_msg_t * msg); diff --git a/lib/pbdrv/pb-serial.h b/lib/pbdrv/pb-serial.h index d3d0007..79f08d7 100644 --- a/lib/pbdrv/pb-serial.h +++ b/lib/pbdrv/pb-serial.h @@ -8,23 +8,77 @@ extern "C" { #endif -#define __pb_cmd(name) \ - pb_ser_r_t pb_ser_r_##name; \ - pb_ser_w_t pb_ser_w_##name; \ - pb_ser_free_t pb_ser_free_##name; +/** + * \ingroup pbdrv + * \ingroup pbdrv-mod + * \defgroup pb_ser Serial + * \internal + * \brief Internal (de)serialization functions using mpack + * + * \{ + */ +/** + * \brief Write (serialize) message fields using mpack + * + * \param writer Pointer to \c mpack_writer_t instance + * \param msg Pointer to message struct to read from + */ typedef void pb_ser_w_t(mpack_writer_t * writer, const pb_msg_t * msg); -pb_ser_w_t pb_ser_w; - +/** + * \brief Read (deserialize) message fields using mpack + * + * \param reader Pointer to \c mpack_reader_t instance + * \param msg Pointer to message struct to write to + */ typedef void pb_ser_r_t(mpack_reader_t * reader, pb_msg_t * msg); -pb_ser_r_t pb_ser_r; - +/** + * \brief Recursively free message struct fields + * + * \param msg Pointer to message struct to free + */ typedef void pb_ser_free_t(pb_msg_t * msg); + +/** + * \brief Write the \ref pb_msg_t header fields and call another function for + * \p msg->cmd. + * \see pb_ser_w_t + */ +pb_ser_w_t pb_ser_w; +/** + * \brief Read the \ref pb_msg_t header fields and call another function for \p + * msg->cmd. + * \see pb_ser_r_t + */ +pb_ser_r_t pb_ser_r; +/** + * \brief Call another function for \p msg->cmd. + * \see pb_ser_free_t + */ pb_ser_free_t pb_ser_free; -__pb_cmd(cmd_prop) -__pb_cmd(cmd_state) -__pb_cmd(cmd_magic) +//! Write the \ref pb_cmd_prop_t fields \see pb_ser_w_t +pb_ser_w_t pb_ser_w_cmd_prop; +//! Read the \ref pb_cmd_prop_t fields \see pb_ser_r_t +pb_ser_r_t pb_ser_r_cmd_prop; +//! Free the \ref pb_cmd_prop_t fields \see pb_ser_free_t +pb_ser_free_t pb_ser_free_cmd_prop; + +//! Write the \ref pb_cmd_state_t fields \see pb_ser_w_t +pb_ser_w_t pb_ser_w_cmd_state; +//! Read the \ref pb_cmd_state_t fields \see pb_ser_r_t +pb_ser_r_t pb_ser_r_cmd_state; +//! Free the \ref pb_cmd_state_t fields \see pb_ser_free_t +pb_ser_free_t pb_ser_free_cmd_state; + +//! Write the \ref pb_cmd_magic_t fields \see pb_ser_w_t +pb_ser_w_t pb_ser_w_cmd_magic; +//! Read the \ref pb_cmd_magic_t fields \see pb_ser_r_t +pb_ser_r_t pb_ser_r_cmd_magic; +//! Free the \ref pb_cmd_magic_t fields \see pb_ser_free_t +pb_ser_free_t pb_ser_free_cmd_magic; + +/// \} #ifdef __cplusplus } diff --git a/main/pbdrv.h b/main/pbdrv.h index a751000..9496aa9 100644 --- a/main/pbdrv.h +++ b/main/pbdrv.h @@ -3,35 +3,41 @@ #include "pb-types.h" /** - * This is the RP2040 puzzle bus driver. This file is no longer inside - * lib/pb//rp2040 as it is tightly coupled to both the pico-sdk and - * freertos functions. I have tried to get FreeRTOS to play nicely with the - * CMake subproject layout, but the pico-sdk and the rp2040 port of freertos - * both rely on CMake's import() functionality, which makes using FreeRTOS in a - * libary context extremely messy. + * \ingroup pb_drv + * \defgroup pb_drv_rp2040 RP2040 + * \brief Raspberry Pi Pico and Pico W driver * - * The workaround implemented in this driver was already kind of messy, and a - * different microcontroller should be used for the main controller instead. + * \note This file is no longer inside `lib/pbdrv/drv/rp2040` as it is tightly + * coupled to both the pico-sdk and FreeRTOS functions. I have tried to get + * FreeRTOS to play nicely with the CMake subproject layout, but the pico-sdk + * and the RP2040 port of FreeRTOS both rely on CMake's import() functionality, + * which makes using FreeRTOS in a libary context extremely messy. + * + * \warning The workaround implemented in this driver was already kind of + * messy, and **a different microcontroller should be used for the main + * controller instead**. Please see the handover document for more details. + * + * \{ */ #ifdef __cplusplus extern "C" { #endif -//! puzzle bus driver setup +//! Puzzle bus driver setup void pb_setup(); /** - * While the RP2040's datasheet claims it supports multi-master configurations - * by implementing bus arbitration, it does not natively support a mode where - * it is configured as a (multi-)master with a slave address, such that it can - * be addressed by other multi-masters. This function includes a hacky - * workaround that teporarily sets the RP2040 to I2C master mode to send a - * message, and then restores it back to slave mode. + * \note While the RP2040's datasheet claims it supports multi-master + * configurations by implementing bus arbitration, it does not natively support + * a mode where it is configured as a (multi-)master with a slave address, such + * that it can be addressed by other multi-masters. This function includes a + * hacky workaround that teporarily sets the RP2040 to I2C master mode to send + * a message, and then restores it back to slave mode. * - * This approach results in some received frames being (partially) dropped in - * the time period between the invocation of this function and the bus becoming - * idle (and the message is sent). + * \warning This approach results in some received frames being (partially) + * dropped in the time period between the invocation of this function and the + * bus becoming idle (and the message is sent). */ void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz); @@ -39,13 +45,19 @@ void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz); * \brief Scan the bus for I2C slaves, and send handshake messages to ACK-ing * slaves. * - * As a result of the RP2040 hardware limitations detailed at the top of this - * file, this function is also implemented in this file, even through it does - * not belong to the puzzle bus driver. In order to not miss any handshake - * responses, the bus should remain busy during the entire scan. + * \note As a result of the RP2040 hardware limitations, this function is also + * implemented in this file, even though it does not belong to the puzzle bus + * driver. + * + * \warning In order to not miss any handshake responses, the bus should remain + * busy during the entire scan. The \c nostop parameter of the \c + * i2c_write_timeout_us() function from the pico-sdk does not seem to keep the + * bus busy. */ void bus_scan(); +/// \} + #ifdef __cplusplus } #endif -- cgit v1.2.3