From b231e9d808f40aef0895787ea09624787b10addd Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Thu, 30 May 2024 15:51:08 +0200 Subject: more client i2c shuffling --- client/i2c.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 client/i2c.cpp (limited to 'client/i2c.cpp') diff --git a/client/i2c.cpp b/client/i2c.cpp new file mode 100644 index 0000000..fd29e1e --- /dev/null +++ b/client/i2c.cpp @@ -0,0 +1,37 @@ +#include +#include + +#include "i2ctcpv1.h" +#include "sock.h" +#include "xxd.h" + +bool i2c_dump_send = false; +bool i2c_dump_recv = true; + +void i2c_send(uint16_t addr, const char * data, size_t data_size) { + i2ctcp_msg_t msg = { + .addr = addr, + .data = (char *) data, + .length = data_size, + }; + + char* packed; + size_t size; + if (!i2ctcp_write(&msg, &packed, &size)) return; + + sock->send(packed, size); + if (i2c_dump_send) { + printf("[%s] addr(0x%02x) data(0x%02lx):\n", __FUNCTION__, addr, data_size); + xxd(data, data_size); + } + + free(packed); +} + +void i2c_recv(uint16_t addr, const char * data, size_t data_size) { + if (i2c_dump_recv) { + printf("[%s] addr(0x%02x) data(0x%02lx):\n", __FUNCTION__, addr, data_size); + xxd(data, data_size); + } +} + -- cgit v1.2.3 From 18d06c79b9f6a625eb218a15c8216556fb99dc02 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Thu, 30 May 2024 18:58:13 +0200 Subject: WIP parsing the connected puzzle module list --- client/i2c.cpp | 30 ++++++++++++++++++++++++++++++ client/readme.md | 10 ++++++++++ shared/pb/mod/main.h | 13 +++++++++++++ shared/pb/moddrv.c | 14 +++++++------- shared/pb/moddrv.h | 8 ++++---- shared/pb/spec.adoc | 20 +++++++++++++------- shared/pb/types.h | 12 +++++++++--- 7 files changed, 86 insertions(+), 21 deletions(-) create mode 100644 shared/pb/mod/main.h (limited to 'client/i2c.cpp') diff --git a/client/i2c.cpp b/client/i2c.cpp index fd29e1e..ee57e20 100644 --- a/client/i2c.cpp +++ b/client/i2c.cpp @@ -5,6 +5,11 @@ #include "sock.h" #include "xxd.h" +#include "pb/bus.h" +#include "pb/types.h" + +#include "pb/mod/main.h" + bool i2c_dump_send = false; bool i2c_dump_recv = true; @@ -28,10 +33,35 @@ void i2c_send(uint16_t addr, const char * data, size_t data_size) { free(packed); } +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) { if (i2c_dump_recv) { printf("[%s] addr(0x%02x) data(0x%02lx):\n", __FUNCTION__, addr, data_size); xxd(data, data_size); } + + if (data_size == 0) return; + enum pb_cmd cmd = (enum pb_cmd) data[0]; + data++; data_size--; + + switch (cmd) { + case PB_CMD_READ: return i2c_handle_cmd_read(addr, data, data_size); + default: return; + } +} + +static void i2c_handle_cmd_read(uint16_t i2c_addr, const char * buf, size_t sz) { + if (sz < 2) return; // require data address + 1 byte of data + pb_cmd_read_t * cmd = (pb_cmd_read_t *) buf; + sz--; // sz now represents size of cmd->data + + if (i2c_addr == BUSADDR_MAIN && cmd->address == 0x01) { + if (sz % 2 != 0) return; // invalid data + for (size_t offset = 0; offset < sz; offset += sizeof(pb_mod_main_mod_t)) { + pb_mod_main_mod_t * mod = (pb_mod_main_mod_t *) (cmd->data + offset); + printf("module at addr 0x%02x with state %d\n", mod->addr, mod->state); + } + } } diff --git a/client/readme.md b/client/readme.md index ea3e034..da48cf1 100644 --- a/client/readme.md +++ b/client/readme.md @@ -7,6 +7,16 @@ 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 diff --git a/shared/pb/mod/main.h b/shared/pb/mod/main.h new file mode 100644 index 0000000..56ccd3d --- /dev/null +++ b/shared/pb/mod/main.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../types.h" + +typedef struct __packed { + const uint8_t addr; + const enum pb_state state; +} pb_mod_main_mod_t; + +enum __packed { + PB_MOD_MAIN_ADDR_MODS = 0x01, //!< connected puzzle modules +}; + diff --git a/shared/pb/moddrv.c b/shared/pb/moddrv.c index 4c897e0..1f7fab8 100644 --- a/shared/pb/moddrv.c +++ b/shared/pb/moddrv.c @@ -4,22 +4,22 @@ #include "moddrv.h" /** \brief [private] placeholder global state variable */ -static pb_state_t _global_state = PB_GS_NOINIT; +static enum pb_state _global_state = PB_GS_NOINIT; /** \brief [private] main controller global state */ -static pb_state_t _main_state = PB_GS_NOINIT; +static enum pb_state _main_state = PB_GS_NOINIT; -__weak pb_state_t pbdrv_hook_mod_state_read() { +__weak enum pb_state pbdrv_hook_mod_state_read() { return _global_state; } -__weak void pbdrv_hook_mod_state_write(pb_state_t state) { +__weak void pbdrv_hook_mod_state_write(enum pb_state state) { _global_state = state; } __weak void pbdrv_i2c_recv(uint16_t i2c_addr, const char * buf, size_t sz) { if (sz == 0) return; - pb_cmd_t cmd = (enum pb_cmd) buf[0]; + enum pb_cmd cmd = (enum pb_cmd) buf[0]; // shift buffer pointer to only contain the puzzle bus message buf buf++; @@ -105,8 +105,8 @@ __weak void pbdrv_handle_sex(uint16_t i2c_addr, const char * buf, size_t sz) { pbdrv_hook_main_state_update(_main_state); } -__weak void pbdrv_hook_main_state_update(pb_state_t state) { } -__weak bool pbdrv_hook_cmd(uint16_t i2c_addr, pb_cmd_t cmd, const char * buf, size_t sz) { +__weak void pbdrv_hook_main_state_update(enum pb_state state) { } +__weak bool pbdrv_hook_cmd(uint16_t i2c_addr, enum pb_state cmd, const char * buf, size_t sz) { return false; } __weak bool pbdrv_hook_read(uint16_t i2c_addr, uint8_t addr) { diff --git a/shared/pb/moddrv.h b/shared/pb/moddrv.h index c4e1167..ecfc13a 100644 --- a/shared/pb/moddrv.h +++ b/shared/pb/moddrv.h @@ -27,9 +27,9 @@ extern "C" { void pbdrv_i2c_recv(uint16_t i2c_addr, const char * buf, size_t sz); void pbdrv_i2c_send(uint16_t i2c_addr, const char * buf, size_t sz); -pb_state_t pbdrv_hook_mod_state_read(); -void pbdrv_hook_mod_state_write(pb_state_t state); -void pbdrv_hook_main_state_update(pb_state_t state); +enum pb_state pbdrv_hook_mod_state_read(); +void pbdrv_hook_mod_state_write(enum pb_state state); +void pbdrv_hook_main_state_update(enum pb_state state); /** * \name hooks @@ -44,7 +44,7 @@ void pbdrv_hook_main_state_update(pb_state_t state); */ /** \brief cmd receive hook */ -bool pbdrv_hook_cmd(uint16_t i2c_addr, pb_cmd_t cmd, const char * buf, size_t sz); +bool pbdrv_hook_cmd(uint16_t i2c_addr, enum pb_state cmd, const char * buf, size_t sz); /** \brief read cmd hook */ bool pbdrv_hook_read(uint16_t i2c_addr, uint8_t addr); /** \brief write cmd hook */ diff --git a/shared/pb/spec.adoc b/shared/pb/spec.adoc index a99497b..3172e84 100644 --- a/shared/pb/spec.adoc +++ b/shared/pb/spec.adoc @@ -10,10 +10,16 @@ puzzle module framework. 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]. -NOTE: Addresses influence the puzzle box's behavior, as 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 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) @@ -46,8 +52,8 @@ default implementations, but this is discouraged. [[sec:state-global]] == Global state -If your puzzle module defines its own ``pb_state_t``, you can tell the driver -to use it by implementing the ``pbdrv_hook_state_read`` and +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). @@ -115,7 +121,7 @@ command(s) that you want to overwrite. Example: ```c -bool pbdrv_hook_cmd(uint16_t i2c_addr, pb_cmd_t cmd, const char * buf, size_t sz) { +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; diff --git a/shared/pb/types.h b/shared/pb/types.h index 7996a19..f2e2078 100644 --- a/shared/pb/types.h +++ b/shared/pb/types.h @@ -29,7 +29,7 @@ enum __packed pb_cmd { PB_CMD_SEX, //!< state exchange PB_CMD_MAGIC, //!< magic message }; -typedef enum pb_cmd pb_cmd_t; +// typedef enum pb_cmd pb_cmd_t; /** \brief magic sent from main controller to puzzle module */ static const char pb_magic_msg[] = { 0x70, 0x75, 0x7a, 0x62, 0x75, 0x73 }; @@ -43,10 +43,16 @@ enum __packed pb_state { PB_GS_PLAYING, //!< puzzle actively being solved PB_GS_SOLVED, //!< puzzle completed }; -typedef enum pb_state pb_state_t; +// typedef enum pb_state pb_state_t; + +typedef struct __packed { + const enum pb_cmd cmd; + const uint8_t data[]; +} pb_cmd_t; typedef struct __packed { const uint8_t address; + const uint8_t data[]; } pb_cmd_read_t; typedef struct __packed { @@ -55,7 +61,7 @@ typedef struct __packed { } pb_cmd_write_t; typedef struct __packed { - const pb_state_t main_state; + const enum pb_state main_state; } pb_cmd_sex_t; enum __packed { -- cgit v1.2.3