aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/i2c.cpp30
-rw-r--r--client/readme.md10
-rw-r--r--shared/pb/mod/main.h13
-rw-r--r--shared/pb/moddrv.c14
-rw-r--r--shared/pb/moddrv.h8
-rw-r--r--shared/pb/spec.adoc20
-rw-r--r--shared/pb/types.h12
7 files changed, 86 insertions, 21 deletions
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 {