From d57d0cdb11451283fffbc3ac4b4deaacf188e94a Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Fri, 21 Jun 2024 10:51:19 +0200 Subject: add puzzle module init hook + weak implementation --- lib/pbdrv/pb-route.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib/pbdrv/pb-route.c') diff --git a/lib/pbdrv/pb-route.c b/lib/pbdrv/pb-route.c index ee47700..df00cd3 100644 --- a/lib/pbdrv/pb-route.c +++ b/lib/pbdrv/pb-route.c @@ -56,8 +56,12 @@ __weak void pb_route_cmd_prop_req(pb_msg_t * msg) {} __weak void pb_route_cmd_prop_res(pb_msg_t * msg) {} __weak void pb_route_cmd_prop_set(pb_msg_t * msg) {} +//! last known global state of last STATE REQ sender (i.e. main controller) static pb_global_state_t _main_state = PB_GS_NOINIT; __weak void pb_hook_main_state_update(pb_global_state_t state) {} +__weak void pb_hook_module_init() { + pb_hook_mod_state_write(PB_GS_IDLE); +} __weak void pb_route_cmd_state_req(pb_msg_t * msg) { pb_global_state_t own_state = pb_hook_mod_state_read(); pb_buf_t buf = pb_send_state_res(own_state); @@ -66,8 +70,11 @@ __weak void pb_route_cmd_state_req(pb_msg_t * msg) { // notify of new global state variable pb_cmd_state_t * cmd = msg->cmd; - if (cmd->state != _main_state) + if (cmd->state != _main_state) { + // first STATE REQ = module init OK + if (_main_state == PB_GS_NOINIT) pb_hook_module_init(); pb_hook_main_state_update(cmd->state); + } _main_state = cmd->state; } -- cgit v1.2.3 From 6da66e5356eb367e4b766484eab3a94cb009fb9c Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Fri, 21 Jun 2024 10:56:20 +0200 Subject: fix dumb mistake in pbdrv --- lib/pbdrv/pb-route.c | 7 ++++--- lib/pbdrv/pb-send.c | 4 ++-- lib/pbdrv/pb-send.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'lib/pbdrv/pb-route.c') diff --git a/lib/pbdrv/pb-route.c b/lib/pbdrv/pb-route.c index df00cd3..709fb7f 100644 --- a/lib/pbdrv/pb-route.c +++ b/lib/pbdrv/pb-route.c @@ -64,9 +64,6 @@ __weak void pb_hook_module_init() { } __weak void pb_route_cmd_state_req(pb_msg_t * msg) { pb_global_state_t own_state = pb_hook_mod_state_read(); - pb_buf_t buf = pb_send_state_res(own_state); - pb_send_reply(msg, &buf); - pb_buf_free(&buf); // notify of new global state variable pb_cmd_state_t * cmd = msg->cmd; @@ -76,6 +73,10 @@ __weak void pb_route_cmd_state_req(pb_msg_t * msg) { pb_hook_main_state_update(cmd->state); } _main_state = cmd->state; + + pb_buf_t buf = pb_send_state_res(); + pb_send_reply(msg, &buf); + pb_buf_free(&buf); } __weak void pb_route_cmd_state_res(pb_msg_t * msg) {} diff --git a/lib/pbdrv/pb-send.c b/lib/pbdrv/pb-send.c index 66c43c1..29d81ed 100644 --- a/lib/pbdrv/pb-send.c +++ b/lib/pbdrv/pb-send.c @@ -64,9 +64,9 @@ pb_buf_t pb_send_state_req() { return pb_msg_write(&msg); } -pb_buf_t pb_send_state_res(pb_global_state_t state) { +pb_buf_t pb_send_state_res() { pb_cmd_state_t cmd = { - .state = state, + .state = pb_hook_mod_state_read(), }; pb_msg_t msg = { .type = PB_CMD_STATE, diff --git a/lib/pbdrv/pb-send.h b/lib/pbdrv/pb-send.h index 2f8be1e..679df29 100644 --- a/lib/pbdrv/pb-send.h +++ b/lib/pbdrv/pb-send.h @@ -13,7 +13,7 @@ pb_buf_t pb_send_read_req(uint8_t propid); pb_buf_t pb_send_read_res(uint8_t propid, uint8_t * value, size_t size); pb_buf_t pb_send_write_req(uint8_t propid, uint8_t * value, size_t size); pb_buf_t pb_send_state_req(); -pb_buf_t pb_send_state_res(pb_global_state_t state); +pb_buf_t pb_send_state_res(); pb_buf_t pb_send_state_set(pb_global_state_t state); pb_buf_t pb_send_magic_req(); pb_buf_t pb_send_magic_res(); -- cgit v1.2.3 From 2187c3d6196f2a25bc0b74365358c9874dde3a46 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 22 Jun 2024 10:39:01 +0200 Subject: more code documentation --- Doxyfile | 2 + lib/pbdrv/index.dox | 29 +++++----- lib/pbdrv/pb-buf.h | 2 +- lib/pbdrv/pb-mod.h | 11 +++- lib/pbdrv/pb-route.c | 8 +-- lib/pbdrv/pb-route.h | 161 ++++++++++++++++++++++++++++++++++++++++++++++++--- lib/pbdrv/pb-types.h | 58 ++++++++++++++----- 7 files changed, 228 insertions(+), 43 deletions(-) (limited to 'lib/pbdrv/pb-route.c') diff --git a/Doxyfile b/Doxyfile index 53e75c2..ea9692a 100644 --- a/Doxyfile +++ b/Doxyfile @@ -25,3 +25,5 @@ INPUT_FILTER = "sed -e 's/\\|\2<\/sup>C\>/\\I2C/g'" USE_MDFILE_AS_MAINPAGE = readme.md +INTERNAL_DOCS = YES + diff --git a/lib/pbdrv/index.dox b/lib/pbdrv/index.dox index ad05078..e4a6c5f 100644 --- a/lib/pbdrv/index.dox +++ b/lib/pbdrv/index.dox @@ -7,15 +7,6 @@ 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 @@ -25,14 +16,26 @@ 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. + +\copydetails pbdrv + \{ -\defgroup hook +\defgroup pb_hook 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. +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. \} diff --git a/lib/pbdrv/pb-buf.h b/lib/pbdrv/pb-buf.h index 049f516..9ff53fe 100644 --- a/lib/pbdrv/pb-buf.h +++ b/lib/pbdrv/pb-buf.h @@ -10,7 +10,7 @@ extern "C" { * \ingroup pbdrv * \ingroup pbdrv-mod * \defgroup pb_buf Buffer - * \brief Binary data buffer type used in pbdrv + * \brief Binary data buffer type used in \ref pbdrv * \{ */ diff --git a/lib/pbdrv/pb-mod.h b/lib/pbdrv/pb-mod.h index 2ff1908..ef2cd77 100644 --- a/lib/pbdrv/pb-mod.h +++ b/lib/pbdrv/pb-mod.h @@ -80,7 +80,7 @@ void pb_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz); /// \} -/// \ingroup hook +/// \ingroup pb_hook /// \{ /** @@ -89,8 +89,7 @@ void pb_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz); * * 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. + * are also used internally by the driver. * * \{ */ @@ -98,11 +97,17 @@ 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 + * + * 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 + * + * The default implementation of this function uses an internal global state + * variable in \ref pbdrv. */ void pb_hook_mod_state_write(pb_global_state_t state); diff --git a/lib/pbdrv/pb-route.c b/lib/pbdrv/pb-route.c index 709fb7f..f5c32d6 100644 --- a/lib/pbdrv/pb-route.c +++ b/lib/pbdrv/pb-route.c @@ -58,8 +58,8 @@ __weak void pb_route_cmd_prop_set(pb_msg_t * msg) {} //! last known global state of last STATE REQ sender (i.e. main controller) static pb_global_state_t _main_state = PB_GS_NOINIT; -__weak void pb_hook_main_state_update(pb_global_state_t state) {} -__weak void pb_hook_module_init() { +__weak void pb_hook_ev_main_state_update(pb_global_state_t state) {} +__weak void pb_hook_ev_module_init() { pb_hook_mod_state_write(PB_GS_IDLE); } __weak void pb_route_cmd_state_req(pb_msg_t * msg) { @@ -69,8 +69,8 @@ __weak void pb_route_cmd_state_req(pb_msg_t * msg) { pb_cmd_state_t * cmd = msg->cmd; if (cmd->state != _main_state) { // first STATE REQ = module init OK - if (_main_state == PB_GS_NOINIT) pb_hook_module_init(); - pb_hook_main_state_update(cmd->state); + if (_main_state == PB_GS_NOINIT) pb_hook_ev_module_init(); + pb_hook_ev_main_state_update(cmd->state); } _main_state = cmd->state; diff --git a/lib/pbdrv/pb-route.h b/lib/pbdrv/pb-route.h index 233a087..b80e4ec 100644 --- a/lib/pbdrv/pb-route.h +++ b/lib/pbdrv/pb-route.h @@ -6,40 +6,185 @@ extern "C" { #endif +/** + * \ingroup pbdrv-mod + * \defgroup pb_route Routing + * \internal + * \brief Parsed message handler routing + * + * These functions form a tree-shaped call graph, and are used to handle + * specific commands received from \c pb_i2c_recv(). + * + * \{ + */ + +/** + * \brief Handle a message with type {\ref PB_CMD_PROP "PROP", \ref + * PB_CMD_STATE "STATE", \ref PB_CMD_MAGIC "MAGIC"} + * + * Calls the next handler depending on \c msg->type. + */ void pb_route_msg(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_PROP "PROP" message with action {\ref + * pb_route_cmd_prop_req "REQ", \ref pb_route_cmd_prop_res "RES", \ref + * pb_route_cmd_prop_set "SET"} + * + * Calls the next handler depending on \c msg->action. + */ void pb_route_cmd_prop(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_STATE "STATE" message with action {\ref + * pb_route_cmd_state_req "REQ", \ref pb_route_cmd_state_res "RES", \ref + * pb_route_cmd_state_set "SET"} + * + * Calls the next handler depending on \c msg->action. + */ void pb_route_cmd_state(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_MAGIC "MAGIC" message with action {\ref + * pb_route_cmd_magic_req "REQ", \ref pb_route_cmd_magic_res "RES"} + * + * Calls the next handler depending on \c msg->action. + * + * \note Messages with type \c MAGIC and action \c SET will be silently + * ignored, as there is no such command. + */ void pb_route_cmd_magic(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_PROP "PROP" message with action \ref + * PB_ACTION_REQ "REQ" + * + * The default implementation of this function is empty, as puzzle module + * properties are user-defined. + */ void pb_route_cmd_prop_req(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_PROP "PROP" message with action \ref + * PB_ACTION_RES "RES" + * + * The default implementation of this function is empty, as puzzle module + * properties are user-defined. + */ void pb_route_cmd_prop_res(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_PROP "PROP" message with action \ref + * PB_ACTION_SET "SET" + * + * The default implementation of this function is empty, as puzzle module + * properties are user-defined. + */ void pb_route_cmd_prop_set(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_STATE "STATE" message with action \ref + * PB_ACTION_REQ "REQ" + * + * The default implementation of this function does the following: + * - Call \c pb_hook_ev_module_init() if this is the first received \c STATE \c + * REQ command. + * - Call \c pb_hook_ev_main_state_update() if the main controller state has + * changed. + * - Reply with a \c STATE \c RES message. + */ void pb_route_cmd_state_req(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_STATE "STATE" message with action \ref + * PB_ACTION_RES "RES" + * + * The default implementation of this function is empty, as only the main + * controller handles this type of command. + */ void pb_route_cmd_state_res(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_STATE "STATE" message with action \ref + * PB_ACTION_SET "SET" + * + * The default implementation of this function does the following: + * - Write the global state variable using \c pb_hook_mod_state_write(). + */ void pb_route_cmd_state_set(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_MAGIC "MAGIC" message with action \ref + * PB_ACTION_REQ "REQ" + * + * The default implementation of this function does the following: + * - Verify the size of the magic string + * - Verify the content of the magic string + * - Reply with a \c MAGIC \c RES message. + */ void pb_route_cmd_magic_req(pb_msg_t * msg); +/** + * \brief Handle a \ref PB_CMD_MAGIC "MAGIC" message with action \ref + * PB_ACTION_RES "RES" + * + * The default implementation of this function is empty, as only the main + * controller handles this type of command. + */ void pb_route_cmd_magic_res(pb_msg_t * msg); -/// \ingroup hook -/// \{ - -/// \defgroup hook_route Routing -/// \brief Use a custom message handler -/// \{ +/// \} +/** + * \ingroup pb_hook + * \defgroup pb_hook_route Routing + * \brief Conditionally use substitute or extend the built-in message handlers + * \{ + */ + +/** + * \brief \c pb_route_msg() hook + * + * The default implementation of this function immediately returns 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). + */ bool pb_hook_route_msg(pb_msg_t * msg); +//! \c pb_route_cmd_prop() hook \copydetails pb_hook_route_msg bool pb_hook_route_cmd_prop(pb_msg_t * msg); +//! \c pb_route_cmd_state() hook \copydetails pb_hook_route_msg bool pb_hook_route_cmd_state(pb_msg_t * msg); +//! \c pb_route_cmd_magic() hook \copydetails pb_hook_route_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(); +/** + * \ingroup pb_hook + * \defgroup pb_hook_ev Events + * \brief Functions called on puzzle bus-related events + * \{ + */ + +/** + * \brief Main controller state update hook + * + * The default implementation of this function is empty. + * + * \param state New state of main controller + * + * \note This function is also called when the first \c STATE \c REQ command is + * received, as the main controller state variable used to check if the state + * actually changed is initialized to \ref PB_GS_NOINIT. In this case, this + * function is called *after* \c pb_hook_ev_module_init(). + */ +void pb_hook_ev_main_state_update(pb_global_state_t state); +/** + * \brief Module initialized hook + * + * The default implementation of this function calls \c + * pb_hook_mod_state_write() with \ref PB_GS_IDLE. + * + * This function is called when the first \c STATE \c REQ command is received, + * indicating this puzzle module has been registered successfully by the main + * controller, and is now part of an active play session. + */ +void pb_hook_ev_module_init(); /// \} diff --git a/lib/pbdrv/pb-types.h b/lib/pbdrv/pb-types.h index f5fbb74..dfd5da9 100644 --- a/lib/pbdrv/pb-types.h +++ b/lib/pbdrv/pb-types.h @@ -8,7 +8,17 @@ extern "C" { #endif +/** + * \ingroup pbdrv + * \ingroup pbdrv-mod + * \defgroup pb_types Types + * \brief Datatypes used within \ref pbdrv + * + * \{ + */ + #ifdef __GNUC__ +//! Mark function as weak (allow user to override implementation) #define __weak __attribute__((weak)) #endif #ifndef __weak @@ -21,15 +31,33 @@ typedef uint16_t i2c_addr_t; //! puzzle bus command types enum pb_cmd_id { - /** \brief puzzle module property (REQ, RES, SET) */ + /** + * \brief puzzle module property (\ref pb_route_cmd_prop_req "REQ", \ref + * pb_route_cmd_prop_res "RES", \ref pb_route_cmd_prop_set "SET") + * + * The \c PROP command type is used for exchanging arbitrary data between + * puzzle modules and/or the puzzle box client (pbc) over the TCP bridge. + * These properties are not used by the puzzle framework. + */ PB_CMD_PROP, - /** \brief puzzle module global state variable (REQ, RES, SET) */ + /** + * \brief puzzle module global state variable (\ref pb_route_cmd_state_req + * "REQ", \ref pb_route_cmd_state_res "RES", \ref pb_route_cmd_state_set + * "SET") + * + * The \c STATE command is used by puzzle modules to inform the main + * controller about their global state. The main controller aggregates the + * states of all connected puzzle modules and exchanges this aggregated state + * with the puzzle modules to indicate when the entire puzzle box is solved. + */ PB_CMD_STATE, /** - * \brief magic (handshake) (REQ, RES) + * \brief magic (handshake) (\ref pb_route_cmd_magic_req "REQ", \ref + * pb_route_cmd_magic_res "RES") * - * This message is used to distinguish between puzzle modules and regular I2C - * slaves on the puzzle bus. + * The \c MAGIC command effectively serves as a 'secret handshake' (using a + * _magic_ value) which is used to distinguish between puzzle modules and + * unrelated I2C devices. */ PB_CMD_MAGIC, }; @@ -57,16 +85,16 @@ static const char pb_cmd_magic_req[] = { 0x70, 0x75, 0x7a, 0x62, 0x75, 0x73 }; //! magic reply from puzzle module back to main controller static const char pb_cmd_magic_res[] = { 0x67, 0x61, 0x6d, 0x69, 0x6e, 0x67 }; -//! puzzle bus message header (shared by all commands) +//! puzzle bus message header / container (shared by all commands) typedef struct { /** - * \brief command type + * \brief Command type (see \ref pb_cmd_id_t) * * This is used to identify what the message is about. */ pb_cmd_id_t type; /** - * \brief command action + * \brief Command action (see \ref pb_action_t) * * This is used to specify what should happen as a result of this message. */ @@ -79,31 +107,33 @@ typedef struct { */ i2c_addr_t sender; /** - * \brief command data (type dependent) + * \brief Command data (dependent on \p type) * * Struct containing command type-specific data. */ void * cmd; } pb_msg_t; -//! PB_CMD_PROP data +//! \ref PB_CMD_PROP data typedef struct { uint8_t propid; //!< id of state property uint8_t * value; //!< new or current value - size_t _value_size; //!< [META] size of \p value + size_t _value_size; //!< size of \p value } pb_cmd_prop_t; -//! PB_CMD_STATE data +//! \ref PB_CMD_STATE data typedef struct { pb_global_state_t state; //!< global state } pb_cmd_state_t; -//! PB_CMD_MAGIC data +//! \ref PB_CMD_MAGIC data typedef struct { char * magic; //!< magic value - size_t _magic_size; //!< [META] size of \p magic + size_t _magic_size; //!< size of \p magic } pb_cmd_magic_t; +/// \} + #ifdef __cplusplus } #endif -- cgit v1.2.3 From ccdcf5001c47820c41e9b962d8498602870289b5 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 22 Jun 2024 18:32:06 +0200 Subject: WIP RP2040 I2C workaround code --- lib/pbdrv/pb-route.c | 3 --- main/config.def.h | 20 ++++++++++++++------ main/i2c.c | 16 ++++++++++++---- main/init.c | 12 ++++++++---- main/pbdrv.c | 36 +++++++++++------------------------- main/pbdrv.h | 15 --------------- 6 files changed, 45 insertions(+), 57 deletions(-) (limited to 'lib/pbdrv/pb-route.c') diff --git a/lib/pbdrv/pb-route.c b/lib/pbdrv/pb-route.c index f5c32d6..5a7bd67 100644 --- a/lib/pbdrv/pb-route.c +++ b/lib/pbdrv/pb-route.c @@ -93,9 +93,6 @@ __weak void pb_route_cmd_magic_req(pb_msg_t * msg) { // // return early if magic doesn't match if (pb_memcmp(cmd->magic, pb_cmd_magic_req, sizeof(pb_cmd_magic_req)) != 0) return; - // FIXME: this should be removed (see handover: RP2040 I2C limitations) - pb_mod_blocking_delay_ms(2000); - pb_buf_t buf = pb_send_magic_res(); pb_send_reply(msg, &buf); pb_buf_free(&buf); diff --git a/main/config.def.h b/main/config.def.h index 0dae608..b3be5ed 100644 --- a/main/config.def.h +++ b/main/config.def.h @@ -72,13 +72,21 @@ * \name I2C configuration * \{ */ -#ifndef CFG_SDA_PIN -//! I2C SDA pin -#define CFG_SDA_PIN 16 +#ifndef CFG_SDA0_PIN +//! I2C 0 SDA pin +#define CFG_SDA0_PIN 16 #endif -#ifndef CFG_SCL_PIN -//! I2C SCL pin -#define CFG_SCL_PIN 17 +#ifndef CFG_SCL0_PIN +//! I2C 0 SCL pin +#define CFG_SCL0_PIN 17 +#endif +#ifndef CFG_SDA1_PIN +//! I2C 1 SDA pin +#define CFG_SDA1_PIN 18 +#endif +#ifndef CFG_SCL1_PIN +//! I2C 1 SCL pin +#define CFG_SCL1_PIN 19 #endif /// \} diff --git a/main/i2c.c b/main/i2c.c index 2503560..0f23a13 100644 --- a/main/i2c.c +++ b/main/i2c.c @@ -16,6 +16,18 @@ i2c_addr_t modules[CFG_PB_MOD_MAX]; size_t modules_size = 0; +static void bus_scan() { + pb_buf_t buf = pb_send_magic_req(); + + // check for all 7-bit addresses + uint16_t addr_max = 1 << 7; + for (uint16_t addr = 0x00; addr < addr_max; addr++) { + pb_i2c_send(addr, (uint8_t *) buf.data, buf.size); + } + + pb_buf_free(&buf); +} + static void state_exchange() { for (size_t i = 0; i < modules_size; i++) { pb_buf_t buf = pb_send_state_req(); @@ -28,10 +40,6 @@ void bus_task() { // do a scan of the bus bus_scan(); - // FIXME: this should be removed (see handover: RP2040 I2C limitations) - // wait for 5 seconds until all handshake responses are received - pb_mod_blocking_delay_ms(5e3); - while(1) { // send my state to all puzzle modules state_exchange(); diff --git a/main/init.c b/main/init.c index 6d29d19..d85c94d 100644 --- a/main/init.c +++ b/main/init.c @@ -29,11 +29,15 @@ static void init_wifi() { } static void init_i2c() { - gpio_set_function(CFG_SDA_PIN, GPIO_FUNC_I2C); - gpio_set_function(CFG_SCL_PIN, GPIO_FUNC_I2C); + gpio_set_function(CFG_SDA0_PIN, GPIO_FUNC_I2C); + gpio_set_function(CFG_SCL0_PIN, GPIO_FUNC_I2C); + gpio_set_function(CFG_SDA1_PIN, GPIO_FUNC_I2C); + gpio_set_function(CFG_SCL1_PIN, GPIO_FUNC_I2C); - gpio_pull_up(CFG_SDA_PIN); - gpio_pull_up(CFG_SCL_PIN); + gpio_pull_up(CFG_SDA0_PIN); + gpio_pull_up(CFG_SCL0_PIN); + gpio_pull_up(CFG_SDA1_PIN); + gpio_pull_up(CFG_SCL1_PIN); pb_setup(); } diff --git a/main/pbdrv.c b/main/pbdrv.c index 0624897..6a89253 100644 --- a/main/pbdrv.c +++ b/main/pbdrv.c @@ -14,7 +14,9 @@ #include #include -#define PB_I2C i2c0 +#define PB_I2C_S i2c0 +#define PB_I2C_M i2c1 + #define BUF_SIZE 256 #define MSGS_MAX 4 @@ -32,6 +34,8 @@ static void async_pb_i2c_recv(void * _msg, uint32_t _) { } static void msg_complete(i2c_msg_buf_t * msg) { + return pb_i2c_recv(msg->data, msg->size); + // defer pb_i2c_recv call to FreeRTOS scheduler as pb_i2c_recv takes // too long to return from an ISR xTimerPendFunctionCallFromISR(async_pb_i2c_recv, msg, 0, NULL); @@ -48,7 +52,7 @@ static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) { switch (event) { case I2C_SLAVE_RECEIVE: { if (msg->size == BUF_SIZE) return; - msg->data[msg->size++] = i2c_read_byte_raw(PB_I2C); + msg->data[msg->size++] = i2c_read_byte_raw(PB_I2C_S); break; } case I2C_SLAVE_FINISH: { @@ -60,33 +64,15 @@ static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) { } void pb_setup() { - i2c_init(PB_I2C, PB_CLOCK_SPEED_HZ); - i2c_slave_init(PB_I2C, PB_MOD_ADDR, &recv_event); + i2c_init(PB_I2C_S, PB_CLOCK_SPEED_HZ); + i2c_init(PB_I2C_M, PB_CLOCK_SPEED_HZ); + + i2c_slave_init(PB_I2C_S, PB_MOD_ADDR, &recv_event); } __weak void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { - i2c_set_slave_mode(PB_I2C, false, PB_MOD_ADDR); - // false to write stop condition to i2c bus - i2c_write_timeout_us(PB_I2C, addr, buf, sz, false, PB_TIMEOUT_US); - - i2c_set_slave_mode(PB_I2C, true, PB_MOD_ADDR); -} - -void bus_scan() { - i2c_set_slave_mode(PB_I2C, false, PB_MOD_ADDR); - - pb_buf_t buf = pb_send_magic_req(); - - // check for all 7-bit addresses - uint16_t addr_max = 1 << 7; - for (uint16_t addr = 0x00; addr < addr_max; addr++) { - i2c_write_timeout_us(PB_I2C, addr, (uint8_t *) buf.data, buf.size, false, PB_TIMEOUT_US); - } - - pb_buf_free(&buf); - - i2c_set_slave_mode(PB_I2C, true, PB_MOD_ADDR); + i2c_write_timeout_us(PB_I2C_M, addr, buf, sz, false, PB_TIMEOUT_US); } void pb_mod_blocking_delay_ms(unsigned long ms) { diff --git a/main/pbdrv.h b/main/pbdrv.h index 9496aa9..89a4870 100644 --- a/main/pbdrv.h +++ b/main/pbdrv.h @@ -41,21 +41,6 @@ void pb_setup(); */ 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. - * - * \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 -- cgit v1.2.3