aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mpack/CMakeLists.txt4
-rw-r--r--lib/mpack/read-remaining.c4
-rw-r--r--lib/pbdrv/CMakeLists.txt30
-rw-r--r--lib/pbdrv/drv/arduino/cfg.cmake7
-rw-r--r--lib/pbdrv/drv/arduino/include.cmake11
-rw-r--r--lib/pbdrv/drv/arduino/mod.cpp67
-rw-r--r--lib/pbdrv/drv/arduino/mod.h17
-rw-r--r--lib/pbdrv/drv/rp2040/cfg.cmake7
-rw-r--r--lib/pbdrv/drv/rp2040/mod.c73
-rw-r--r--lib/pbdrv/drv/rp2040/mod.h13
-rw-r--r--lib/pbdrv/ext/freertos/include.cmake9
-rw-r--r--lib/pbdrv/ext/freertos/pb-mem.c31
-rw-r--r--lib/pbdrv/ext/freertos/pb-mod.c9
-rw-r--r--lib/pbdrv/ext/stdlib/include.cmake2
-rw-r--r--lib/pbdrv/ext/stdlib/pb-mem.c25
-rw-r--r--lib/pbdrv/mod/main.h2
-rw-r--r--lib/pbdrv/mpack-config.h23
-rw-r--r--lib/pbdrv/pb-buf.c9
-rw-r--r--lib/pbdrv/pb-buf.h20
-rw-r--r--lib/pbdrv/pb-mem.h19
-rw-r--r--lib/pbdrv/pb-mod.c36
-rw-r--r--lib/pbdrv/pb-mod.h24
-rw-r--r--lib/pbdrv/pb-msg.c46
-rw-r--r--lib/pbdrv/pb-msg.h17
-rw-r--r--lib/pbdrv/pb-read.c3
-rw-r--r--lib/pbdrv/pb-read.h10
-rw-r--r--lib/pbdrv/pb-route.c97
-rw-r--r--lib/pbdrv/pb-route.h37
-rw-r--r--lib/pbdrv/pb-send.c120
-rw-r--r--lib/pbdrv/pb-send.h24
-rw-r--r--lib/pbdrv/pb-serial.c111
-rw-r--r--lib/pbdrv/pb-serial.h32
-rw-r--r--lib/pbdrv/pb-types.h83
-rw-r--r--lib/pbdrv/pb-write.c35
-rw-r--r--lib/pbdrv/pb-write.h26
-rw-r--r--lib/pbdrv/pb.h17
36 files changed, 805 insertions, 295 deletions
diff --git a/lib/mpack/CMakeLists.txt b/lib/mpack/CMakeLists.txt
index 0e4359d..4badc7b 100644
--- a/lib/mpack/CMakeLists.txt
+++ b/lib/mpack/CMakeLists.txt
@@ -7,6 +7,8 @@ cmake_minimum_required(VERSION 3.29)
set(CMAKE_C_STANDARD 11)
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
+# set(CMAKE_BUILD_TYPE Debug)
+
project(mpack C)
add_library(mpack STATIC
@@ -24,5 +26,5 @@ target_include_directories(mpack SYSTEM INTERFACE
)
# causes some wild crashes, please leave off
-add_compile_definitions(MPACK_READ_TRACKING=0)
+target_compile_definitions(mpack PRIVATE MPACK_READ_TRACKING=0)
diff --git a/lib/mpack/read-remaining.c b/lib/mpack/read-remaining.c
index ebc9b56..46b5815 100644
--- a/lib/mpack/read-remaining.c
+++ b/lib/mpack/read-remaining.c
@@ -1,10 +1,10 @@
#include "mpack.h"
size_t mpack_read_remaining_bytes(mpack_reader_t * reader, char * p, size_t count) {
- size_t limit =mpack_reader_remaining(reader, NULL);
+ size_t limit = mpack_reader_remaining(reader, NULL);
if (0 < count && count < limit)
limit = count;
- memcpy(p, reader->data, limit);
+ MPACK_MEMCPY(p, reader->data, limit);
return limit;
}
diff --git a/lib/pbdrv/CMakeLists.txt b/lib/pbdrv/CMakeLists.txt
index ca85b2b..998ed4d 100644
--- a/lib/pbdrv/CMakeLists.txt
+++ b/lib/pbdrv/CMakeLists.txt
@@ -12,17 +12,29 @@ project(pbdrv C CXX)
add_subdirectory(lib/mpack)
-# generic puzzle bus (de)serializer library
-add_library(pbdrv STATIC pb-read.c pb-write.c)
-target_link_libraries(pbdrv mpack)
+# mpack-config.h
+target_compile_definitions(mpack PRIVATE MPACK_HAS_CONFIG=1)
+target_include_directories(mpack PRIVATE .)
+
+# generic puzzle bus message handling library functions
+add_library(pbdrv STATIC
+ pb-msg.c
+ pb-serial.c
+ pb-buf.c
+ )
target_include_directories(pbdrv SYSTEM INTERFACE .)
+target_link_libraries(pbdrv mpack)
-# puzzle bus module specific code (superset of pbdrv)
-add_library(pbdrv-mod STATIC pb-mod.c)
-target_link_libraries(pbdrv-mod pbdrv)
+# puzzle bus *module* specific code
+add_library(pbdrv-mod OBJECT
+ pb-mod.c
+ pb-send.c
+ pb-route.c
+ )
target_include_directories(pbdrv-mod SYSTEM INTERFACE .)
+target_link_libraries(pbdrv-mod pbdrv)
-# supported puzzle bus drivers
-include(drv/arduino/cfg.cmake)
-include(drv/rp2040/cfg.cmake)
+# puzzle bus drivers
+include(drv/arduino/include.cmake)
+# include(drv/rp2040/include.cmake) # please see /main/pbdrv.h
diff --git a/lib/pbdrv/drv/arduino/cfg.cmake b/lib/pbdrv/drv/arduino/cfg.cmake
deleted file mode 100644
index 36716e3..0000000
--- a/lib/pbdrv/drv/arduino/cfg.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-if(NOT DEFINED ARDUINO)
- return()
-endif()
-
-target_sources(pbdrv-mod PRIVATE "${CMAKE_CURRENT_LIST_DIR}/mod.cpp")
-target_link_arduino_libraries(pbdrv-mod core Wire)
-
diff --git a/lib/pbdrv/drv/arduino/include.cmake b/lib/pbdrv/drv/arduino/include.cmake
new file mode 100644
index 0000000..1e2ff08
--- /dev/null
+++ b/lib/pbdrv/drv/arduino/include.cmake
@@ -0,0 +1,11 @@
+if(NOT DEFINED ARDUINO)
+ return()
+endif()
+
+target_sources(pbdrv-mod PRIVATE "${CMAKE_CURRENT_LIST_DIR}/mod.cpp")
+target_link_arduino_libraries(pbdrv-mod core Wire)
+
+# freertos is used to defer the handling of i2c messages outside the receive
+# interrupt service routine
+include("${CMAKE_CURRENT_LIST_DIR}/../../ext/freertos/include.cmake")
+
diff --git a/lib/pbdrv/drv/arduino/mod.cpp b/lib/pbdrv/drv/arduino/mod.cpp
index 8a38a5b..9130334 100644
--- a/lib/pbdrv/drv/arduino/mod.cpp
+++ b/lib/pbdrv/drv/arduino/mod.cpp
@@ -4,34 +4,81 @@
#include <Arduino.h>
#include <Wire.h>
+#include <avr/delay.h>
-#include <stdlib.h>
-#include <stdint.h>
+#include <FreeRTOS.h>
+#include <timers.h>
+#include <task.h>
#include "../../pb.h"
#include "../../pb-mod.h"
-#include "mod.h"
+#include "../../pb-types.h"
+#include "../../pb-buf.h"
+#include "../../pb-mem.h"
+
+static void async_pb_i2c_recv(void * _msg, uint32_t _) {
+ pb_buf_t * msg = (pb_buf_t *) _msg;
+ pb_i2c_recv((uint8_t *) msg->data, msg->size);
+ pb_buf_free(msg);
+ pb_free(msg);
+}
static void recv_event(int bytes) {
- uint8_t * data = (uint8_t *) malloc(bytes);
- size_t size = 0;
+ pb_buf_t * msg = (pb_buf_t *) pb_malloc(sizeof(pb_buf_t));
+ msg->data = (char *) pb_malloc(bytes);
+ msg->size = 0;
while (Wire.available())
- data[size++] = Wire.read();
+ msg->data[msg->size++] = Wire.read();
- pbdrv_i2c_recv(data, size);
+ // defer pb_i2c_recv call
+ xTimerPendFunctionCallFromISR(async_pb_i2c_recv, msg, 0, NULL);
}
-void pbdrv_setup() {
- Wire.begin((int) PBDRV_MOD_ADDR);
+static void pb_setup() {
+ Wire.begin((int) PB_MOD_ADDR);
Wire.setWireTimeout(PB_TIMEOUT_US, true);
Wire.setClock(PB_CLOCK_SPEED_HZ);
+ // TODO: check if onReceive replaces or appends a handler function
Wire.onReceive(recv_event);
}
-__weak void pbdrv_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) {
+__weak void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) {
Wire.beginTransmission((int) addr);
Wire.write(buf, sz);
Wire.endTransmission(true);
Wire.setWireTimeout(PB_TIMEOUT_US, true);
}
+//! Arduino setup function
+extern void setup(void);
+//! Arduino loop function
+extern void loop(void);
+//! Arduino internal initialization
+void init(void);
+
+//! FreeRTOS loop task
+void loop_task() {
+ for(;;) {
+ loop();
+ if (serialEventRun) serialEventRun();
+ }
+}
+
+//! Application entrypoint
+int main(void) {
+ init(); // call arduino internal setup
+ setup(); // call regular arduino setup
+ pb_setup(); // call pbdrv-mod setup
+ xTaskCreate((TaskFunction_t) loop_task, "loop", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
+ vTaskStartScheduler(); // start freertos scheduler
+ 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/arduino/mod.h b/lib/pbdrv/drv/arduino/mod.h
deleted file mode 100644
index 079941a..0000000
--- a/lib/pbdrv/drv/arduino/mod.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \brief puzzle bus driver setup
- *
- * This function should be called from the Arduino \c setup() function.
- */
-void pbdrv_setup();
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/lib/pbdrv/drv/rp2040/cfg.cmake b/lib/pbdrv/drv/rp2040/cfg.cmake
deleted file mode 100644
index 0fbad18..0000000
--- a/lib/pbdrv/drv/rp2040/cfg.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-if(NOT PICO_PLATFORM STREQUAL "rp2040")
- return()
-endif()
-
-target_sources(pbdrv-mod PRIVATE "${CMAKE_CURRENT_LIST_DIR}/mod.c")
-target_link_libraries(pbdrv-mod hardware_i2c pico_i2c_slave)
-
diff --git a/lib/pbdrv/drv/rp2040/mod.c b/lib/pbdrv/drv/rp2040/mod.c
deleted file mode 100644
index 6becdee..0000000
--- a/lib/pbdrv/drv/rp2040/mod.c
+++ /dev/null
@@ -1,73 +0,0 @@
-#include "mod.h"
-
-#include "../../pb.h"
-#include "../../pb-types.h"
-#include "../../pb-mod.h"
-
-#include <hardware/i2c.h>
-#include <hardware/gpio.h>
-#include <pico/i2c_slave.h>
-
-#define PBDRV_I2C i2c0
-#define BUF_SIZE 256
-
-static volatile bool pbdrv_i2c_msg_avail = false;
-static uint8_t data[BUF_SIZE];
-static size_t size = 0;
-
-// TODO: create event group instead of pbdrv_i2c_msg_avail
-// TODO: create freertos task that monitors the pbdrv_i2c_msg_avail flag and
-// calls pbdrv_i2c_recv when a message is received
-
-
-/**
- * \note this function is called from the I2C ISR, and should return as quickly
- * as possible.
- */
-static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) {
- // message needs to be handled first
- if (pbdrv_i2c_msg_avail) return;
-
- switch (event) {
- case I2C_SLAVE_RECEIVE: {
- if (size == BUF_SIZE) return;
- data[size++] = i2c_read_byte_raw(PBDRV_I2C);
- break;
- }
- case I2C_SLAVE_FINISH: {
- // TODO: handle this w/ queue mechanism instead?
- // pbdrv_i2c_recv(data, size);
- pbdrv_i2c_msg_avail = true;
- size = 0;
- break;
- }
- default: break;
- }
-}
-
-void pbdrv_setup() {
- i2c_init(PBDRV_I2C, PB_CLOCK_SPEED_HZ);
- i2c_slave_init(PBDRV_I2C, PBDRV_MOD_ADDR, &recv_event);
-}
-
-/**
- * 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).
- */
-__weak void pbdrv_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) {
- i2c_set_slave_mode(PBDRV_I2C, false, PBDRV_MOD_ADDR);
-
- // false to write stop condition to i2c bus
- i2c_write_timeout_us(PBDRV_I2C, addr, buf, sz, false, PB_TIMEOUT_US);
-
- i2c_set_slave_mode(PBDRV_I2C, true, PBDRV_MOD_ADDR);
-}
-
diff --git a/lib/pbdrv/drv/rp2040/mod.h b/lib/pbdrv/drv/rp2040/mod.h
deleted file mode 100644
index 0cf2e63..0000000
--- a/lib/pbdrv/drv/rp2040/mod.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//! puzzle bus driver setup
-void pbdrv_setup();
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/lib/pbdrv/ext/freertos/include.cmake b/lib/pbdrv/ext/freertos/include.cmake
new file mode 100644
index 0000000..e7ab7fd
--- /dev/null
+++ b/lib/pbdrv/ext/freertos/include.cmake
@@ -0,0 +1,9 @@
+target_sources(pbdrv PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pb-mem.c")
+target_link_libraries(pbdrv
+ freertos_kernel
+ freertos_kernel_include
+ freertos_config
+ )
+
+target_sources(pbdrv-mod PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pb-mod.c")
+
diff --git a/lib/pbdrv/ext/freertos/pb-mem.c b/lib/pbdrv/ext/freertos/pb-mem.c
new file mode 100644
index 0000000..b18d79f
--- /dev/null
+++ b/lib/pbdrv/ext/freertos/pb-mem.c
@@ -0,0 +1,31 @@
+#include <FreeRTOS.h>
+
+#include "../../pb-mem.h"
+#include "../../pb-types.h"
+
+inline void * pb_malloc(size_t sz) {
+ return pvPortMalloc(sz);
+}
+
+inline void pb_free(void * ptr) {
+ vPortFree(ptr);
+}
+
+__weak inline void * pb_realloc(void * ptr, size_t sz) {
+ return NULL; // shit out of luck (don't use mpack_writer_init_growable)
+}
+
+__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;
+}
+
+__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);
+ if (diff != 0) return diff;
+ }
+ return 0;
+}
+
diff --git a/lib/pbdrv/ext/freertos/pb-mod.c b/lib/pbdrv/ext/freertos/pb-mod.c
new file mode 100644
index 0000000..75495be
--- /dev/null
+++ b/lib/pbdrv/ext/freertos/pb-mod.c
@@ -0,0 +1,9 @@
+#include <FreeRTOS.h>
+#include <task.h>
+
+#include "../../pb-types.h"
+
+__weak void pb_mod_blocking_delay_ms(unsigned long ms) {
+ vTaskDelay(ms / portTICK_PERIOD_MS);
+}
+
diff --git a/lib/pbdrv/ext/stdlib/include.cmake b/lib/pbdrv/ext/stdlib/include.cmake
new file mode 100644
index 0000000..67fe80e
--- /dev/null
+++ b/lib/pbdrv/ext/stdlib/include.cmake
@@ -0,0 +1,2 @@
+target_sources(pbdrv PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pb-mem.c")
+
diff --git a/lib/pbdrv/ext/stdlib/pb-mem.c b/lib/pbdrv/ext/stdlib/pb-mem.c
new file mode 100644
index 0000000..b260c2c
--- /dev/null
+++ b/lib/pbdrv/ext/stdlib/pb-mem.c
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../pb-mem.h"
+
+inline void * pb_malloc(size_t sz) {
+ return malloc(sz);
+}
+
+inline void pb_free(void * ptr) {
+ free(ptr);
+}
+
+inline void * pb_realloc(void * ptr, size_t sz) {
+ return realloc(ptr, sz);
+}
+
+void * pb_memcpy(void * dest, const void * src, size_t sz) {
+ return memcpy(dest, src, sz);
+}
+
+int pb_memcmp(const void * a, const void * b, size_t sz) {
+ return memcmp(a, b, sz);
+}
+
diff --git a/lib/pbdrv/mod/main.h b/lib/pbdrv/mod/main.h
index 535ce06..ec48acd 100644
--- a/lib/pbdrv/mod/main.h
+++ b/lib/pbdrv/mod/main.h
@@ -1,6 +1,6 @@
#pragma once
-#include "../types.h"
+#include "../pb-types.h"
typedef struct {
const i2c_addr_t mod_addr;
diff --git a/lib/pbdrv/mpack-config.h b/lib/pbdrv/mpack-config.h
new file mode 100644
index 0000000..994d9b7
--- /dev/null
+++ b/lib/pbdrv/mpack-config.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "pb-mem.h"
+
+// use pb_* functions
+#define MPACK_STDLIB 0
+
+// pb_* memory management functions
+#define MPACK_FREE pb_free
+#define MPACK_MALLOC pb_malloc
+#define MPACK_REALLOC pb_realloc
+#define MPACK_MEMCPY pb_memcpy
+#define MPACK_MEMCMP pb_memcmp
+
+// more reasonable buffer size (all messages are small)
+#define MPACK_BUFFER_SIZE 256
+#define MPACK_STACK_SIZE MPACK_BUFFER_SIZE
+#define MPACK_PAGE_SIZE MPACK_BUFFER_SIZE
+
+// disable unused features (causes errors?)
+#define MPACK_NODE 0
+#define MPACK_BUILDER 0
+
diff --git a/lib/pbdrv/pb-buf.c b/lib/pbdrv/pb-buf.c
new file mode 100644
index 0000000..3d6cb8a
--- /dev/null
+++ b/lib/pbdrv/pb-buf.c
@@ -0,0 +1,9 @@
+#include "pb-buf.h"
+#include "pb-mem.h"
+
+void pb_buf_free(pb_buf_t * buf) {
+ if (buf->data == NULL) return;
+ pb_free(buf->data);
+ buf->data = NULL;
+}
+
diff --git a/lib/pbdrv/pb-buf.h b/lib/pbdrv/pb-buf.h
new file mode 100644
index 0000000..78ee380
--- /dev/null
+++ b/lib/pbdrv/pb-buf.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "pb-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//! binary buffer struct
+typedef struct {
+ char * data; //! pointer to data
+ size_t size; //! size of data
+} pb_buf_t;
+
+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
new file mode 100644
index 0000000..72be214
--- /dev/null
+++ b/lib/pbdrv/pb-mem.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "pb-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void * pb_malloc(size_t sz);
+void pb_free(void * ptr);
+void * pb_realloc(void * ptr, size_t sz);
+
+void * pb_memcpy(void * dest, const void * src, size_t sz);
+int pb_memcmp(const void * a, const void * b, size_t sz);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/lib/pbdrv/pb-mod.c b/lib/pbdrv/pb-mod.c
index 740f2a5..c27194e 100644
--- a/lib/pbdrv/pb-mod.c
+++ b/lib/pbdrv/pb-mod.c
@@ -1,26 +1,34 @@
+#include "pb-buf.h"
+#include "pb-msg.h"
#include "pb-types.h"
-#include "pb.h"
+#include "pb-mod.h"
+#include "pb-route.h"
//! fallback module name
-__weak const char * PBDRV_MOD_NAME = "???";
+__weak const char * PB_MOD_NAME = "???";
//! [private] placeholder global state variable
static pb_global_state_t _global_state = PB_GS_NOINIT;
-//! [private] main controller global state
-static pb_global_state_t _main_state = PB_GS_NOINIT;
+__weak pb_global_state_t pb_hook_mod_state_read() {
+ return _global_state;
+}
-// __weak enum pb_state pbdrv_hook_mod_state_read() {
-// return _global_state;
-// }
+__weak void pb_hook_mod_state_write(pb_global_state_t state) {
+ _global_state = state;
+}
-// __weak void pbdrv_hook_mod_state_write(enum pb_state state) {
-// _global_state = state;
-// }
+__weak void pb_i2c_recv(const uint8_t * data, size_t sz) {
+ pb_buf_t buf = {
+ .data = (char *) data,
+ .size = sz,
+ };
+ pb_msg_t * msg = pb_msg_read(&buf);
+ if (msg == NULL) return; // invalid message
+ if (msg->cmd == NULL) return; // invalid message
+
+ pb_route_msg(msg);
-__weak void pbdrv_i2c_recv(const uint8_t * buf, size_t sz) {
- return;
+ pb_msg_free(msg);
}
-
-__weak void pbdrv_hook_main_state_update(pb_global_state_t state) { }
diff --git a/lib/pbdrv/pb-mod.h b/lib/pbdrv/pb-mod.h
index fa290bf..ae36d22 100644
--- a/lib/pbdrv/pb-mod.h
+++ b/lib/pbdrv/pb-mod.h
@@ -3,17 +3,13 @@
/**
* \file puzzle bus driver implementation
*
- * Most \c pbdrv_* functions have a weak implementation, which may be
+ * 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 <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-
#include "pb-types.h"
#ifdef __cplusplus
@@ -21,12 +17,22 @@ extern "C" {
#endif
//! puzzle module name (optional, default = "???")
-extern const char * PBDRV_MOD_NAME;
+extern const char * PB_MOD_NAME;
//! puzzle module bus address (required)
-extern const i2c_addr_t PBDRV_MOD_ADDR;
+extern const i2c_addr_t PB_MOD_ADDR;
+
+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);
+
+pb_global_state_t pb_hook_mod_state_read();
+void pb_hook_mod_state_write(pb_global_state_t state);
-void pbdrv_i2c_recv(const uint8_t * buf, size_t sz);
-void pbdrv_i2c_send(i2c_addr_t i2c_addr, const uint8_t * buf, size_t sz);
+/**
+ * \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.c b/lib/pbdrv/pb-msg.c
new file mode 100644
index 0000000..7fd6662
--- /dev/null
+++ b/lib/pbdrv/pb-msg.c
@@ -0,0 +1,46 @@
+#include "mpack-config.h"
+
+#include <mpack.h>
+
+#include "pb-msg.h"
+#include "pb-serial.h"
+#include "pb-mem.h"
+
+pb_buf_t pb_msg_write(const pb_msg_t * msg) {
+ pb_buf_t buf = { 0 };
+ if (msg == NULL) return buf;
+
+ buf.data = pb_malloc(MPACK_BUFFER_SIZE);
+ if (buf.data == NULL) return buf;
+ buf.size = MPACK_BUFFER_SIZE;
+
+ mpack_writer_t writer;
+ mpack_writer_init(&writer, buf.data, buf.size);
+
+ pb_ser_w(&writer, msg);
+
+ buf.size = mpack_writer_buffer_used(&writer);
+ mpack_writer_destroy(&writer);
+ return buf;
+}
+
+pb_msg_t * pb_msg_read(const pb_buf_t * buf) {
+ mpack_reader_t reader;
+ mpack_reader_init_data(&reader, buf->data, buf->size);
+
+ pb_msg_t * msg = pb_malloc(sizeof(pb_msg_t));
+
+ pb_ser_r(&reader, msg);
+
+ mpack_reader_destroy(&reader);
+ return msg;
+}
+
+void pb_msg_free(pb_msg_t * msg) {
+ // free message fields recursively
+ pb_ser_free(msg);
+
+ // free message container that was created in \p pb_msg_read
+ pb_free(msg);
+}
+
diff --git a/lib/pbdrv/pb-msg.h b/lib/pbdrv/pb-msg.h
new file mode 100644
index 0000000..f27d4c4
--- /dev/null
+++ b/lib/pbdrv/pb-msg.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "pb-types.h"
+#include "pb-buf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+pb_buf_t pb_msg_write(const pb_msg_t * msg);
+pb_msg_t * pb_msg_read(const pb_buf_t * buf);
+void pb_msg_free(pb_msg_t * msg);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/lib/pbdrv/pb-read.c b/lib/pbdrv/pb-read.c
deleted file mode 100644
index 843420d..0000000
--- a/lib/pbdrv/pb-read.c
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "pb-read.h"
-
-
diff --git a/lib/pbdrv/pb-read.h b/lib/pbdrv/pb-read.h
deleted file mode 100644
index 7a6f0df..0000000
--- a/lib/pbdrv/pb-read.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/lib/pbdrv/pb-route.c b/lib/pbdrv/pb-route.c
new file mode 100644
index 0000000..ee47700
--- /dev/null
+++ b/lib/pbdrv/pb-route.c
@@ -0,0 +1,97 @@
+#include "pb-route.h"
+#include "pb-mod.h"
+#include "pb-send.h"
+#include "pb-types.h"
+#include "pb-mem.h"
+
+__weak bool pb_hook_route_msg(pb_msg_t * msg) { return false; }
+__weak void pb_route_msg(pb_msg_t * msg) {
+ if (pb_hook_route_msg(msg)) return;
+
+ switch (msg->type) {
+ case PB_CMD_PROP: return pb_route_cmd_prop(msg);
+ case PB_CMD_STATE: return pb_route_cmd_state(msg);
+ case PB_CMD_MAGIC: return pb_route_cmd_magic(msg);
+ default: return;
+ }
+}
+
+__weak bool pb_hook_route_cmd_prop(pb_msg_t * msg) { return false; }
+__weak void pb_route_cmd_prop(pb_msg_t * msg) {
+ if (pb_hook_route_cmd_prop(msg)) return;
+
+ switch (msg->action) {
+ case PB_ACTION_REQ: return pb_route_cmd_prop_req(msg);
+ case PB_ACTION_RES: return pb_route_cmd_prop_res(msg);
+ case PB_ACTION_SET: return pb_route_cmd_prop_set(msg);
+ default: return;
+ }
+}
+
+__weak bool pb_hook_route_cmd_state(pb_msg_t * msg) { return false; }
+__weak void pb_route_cmd_state(pb_msg_t * msg) {
+ if (pb_hook_route_cmd_state(msg)) return;
+
+ switch (msg->action) {
+ case PB_ACTION_REQ: return pb_route_cmd_state_req(msg);
+ case PB_ACTION_RES: return pb_route_cmd_state_res(msg);
+ case PB_ACTION_SET: return pb_route_cmd_state_set(msg);
+ default: return;
+ }
+}
+
+__weak bool pb_hook_route_cmd_magic(pb_msg_t * msg) { return false; }
+__weak void pb_route_cmd_magic(pb_msg_t * msg) {
+ if (pb_hook_route_cmd_magic(msg)) return;
+
+ switch (msg->action) {
+ case PB_ACTION_REQ: return pb_route_cmd_magic_req(msg);
+ case PB_ACTION_RES: return pb_route_cmd_magic_res(msg);
+ default: return;
+ }
+}
+
+// all properties are user-defined
+__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) {}
+
+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_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;
+ if (cmd->state != _main_state)
+ pb_hook_main_state_update(cmd->state);
+ _main_state = cmd->state;
+}
+
+__weak void pb_route_cmd_state_res(pb_msg_t * msg) {}
+
+__weak void pb_route_cmd_state_set(pb_msg_t * msg) {
+ pb_cmd_state_t * cmd = msg->cmd;
+ pb_hook_mod_state_write(cmd->state);
+}
+
+__weak void pb_route_cmd_magic_req(pb_msg_t * msg) {
+ pb_cmd_magic_t * cmd = msg->cmd;
+ // return early if magic has wrong size
+ if (cmd->_magic_size != sizeof(pb_cmd_magic_req)) return;
+ // // 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);
+}
+
+__weak void pb_route_cmd_magic_res(pb_msg_t * msg) { }
+
diff --git a/lib/pbdrv/pb-route.h b/lib/pbdrv/pb-route.h
new file mode 100644
index 0000000..41c009a
--- /dev/null
+++ b/lib/pbdrv/pb-route.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "pb-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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);
+
+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_hook_main_state_update(pb_global_state_t state);
+
+void pb_route_cmd_magic_req(pb_msg_t * msg);
+void pb_route_cmd_magic_res(pb_msg_t * msg);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/lib/pbdrv/pb-send.c b/lib/pbdrv/pb-send.c
new file mode 100644
index 0000000..66c43c1
--- /dev/null
+++ b/lib/pbdrv/pb-send.c
@@ -0,0 +1,120 @@
+#include "pb-send.h"
+#include "pb-mod.h"
+#include "pb-msg.h"
+
+__weak void pb_send_reply(pb_msg_t * msg, pb_buf_t * reply) {
+ return pb_i2c_send(msg->sender, (uint8_t *) reply->data, reply->size);
+}
+
+pb_buf_t pb_send_read_req(uint8_t propid) {
+ pb_cmd_prop_t cmd = {
+ .propid = propid,
+ .value = NULL,
+ ._value_size = 0,
+ };
+ pb_msg_t msg = {
+ .type = PB_CMD_PROP,
+ .action = PB_ACTION_REQ,
+ .sender = PB_MOD_ADDR,
+ .cmd = &cmd,
+ };
+ return pb_msg_write(&msg);
+}
+
+pb_buf_t pb_send_read_res(uint8_t propid, uint8_t * value, size_t size) {
+ pb_cmd_prop_t cmd = {
+ .propid = propid,
+ .value = value,
+ ._value_size = size,
+ };
+ pb_msg_t msg = {
+ .type = PB_CMD_PROP,
+ .action = PB_ACTION_RES,
+ .sender = PB_MOD_ADDR,
+ .cmd = &cmd,
+ };
+ return pb_msg_write(&msg);
+}
+
+pb_buf_t pb_send_write_req(uint8_t propid, uint8_t * value, size_t size) {
+ pb_cmd_prop_t cmd = {
+ .propid = propid,
+ .value = value,
+ ._value_size = size,
+ };
+ pb_msg_t msg = {
+ .type = PB_CMD_PROP,
+ .action = PB_ACTION_REQ,
+ .sender = PB_MOD_ADDR,
+ .cmd = &cmd,
+ };
+ return pb_msg_write(&msg);
+}
+
+pb_buf_t pb_send_state_req() {
+ pb_cmd_state_t cmd = {
+ .state = pb_hook_mod_state_read(),
+ };
+ pb_msg_t msg = {
+ .type = PB_CMD_STATE,
+ .action = PB_ACTION_REQ,
+ .sender = PB_MOD_ADDR,
+ .cmd = &cmd,
+ };
+ return pb_msg_write(&msg);
+}
+
+pb_buf_t pb_send_state_res(pb_global_state_t state) {
+ pb_cmd_state_t cmd = {
+ .state = state,
+ };
+ pb_msg_t msg = {
+ .type = PB_CMD_STATE,
+ .action = PB_ACTION_RES,
+ .sender = PB_MOD_ADDR,
+ .cmd = &cmd,
+ };
+ return pb_msg_write(&msg);
+}
+
+pb_buf_t pb_send_state_set(pb_global_state_t state) {
+ pb_cmd_state_t cmd = {
+ .state = state,
+ };
+ pb_msg_t msg = {
+ .type = PB_CMD_STATE,
+ .action = PB_ACTION_SET,
+ .sender = PB_MOD_ADDR,
+ .cmd = &cmd,
+ };
+ return pb_msg_write(&msg);
+}
+
+pb_buf_t pb_send_magic_req() {
+ pb_cmd_magic_t cmd = {
+ .magic = (char *) &pb_cmd_magic_req[0],
+ ._magic_size = sizeof(pb_cmd_magic_req),
+ };
+ pb_msg_t msg = {
+ .type = PB_CMD_MAGIC,
+ .action = PB_ACTION_REQ,
+ .sender = PB_MOD_ADDR,
+ .cmd = &cmd,
+ };
+ return pb_msg_write(&msg);
+}
+
+pb_buf_t pb_send_magic_res() {
+ pb_cmd_magic_t cmd = {
+ .magic = (char *) &pb_cmd_magic_res[0],
+ ._magic_size = sizeof(pb_cmd_magic_res),
+ };
+ pb_msg_t msg = {
+ .type = PB_CMD_MAGIC,
+ .action = PB_ACTION_RES,
+ .sender = PB_MOD_ADDR,
+ .cmd = &cmd,
+ };
+ return pb_msg_write(&msg);
+}
+
diff --git a/lib/pbdrv/pb-send.h b/lib/pbdrv/pb-send.h
new file mode 100644
index 0000000..2f8be1e
--- /dev/null
+++ b/lib/pbdrv/pb-send.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "pb-types.h"
+#include "pb-buf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void pb_send_reply(pb_msg_t * msg, pb_buf_t * reply);
+
+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_set(pb_global_state_t state);
+pb_buf_t pb_send_magic_req();
+pb_buf_t pb_send_magic_res();
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/lib/pbdrv/pb-serial.c b/lib/pbdrv/pb-serial.c
new file mode 100644
index 0000000..b9ee4b1
--- /dev/null
+++ b/lib/pbdrv/pb-serial.c
@@ -0,0 +1,111 @@
+#include <mpack.h>
+
+#include "pb-mem.h"
+#include "pb-serial.h"
+#include "pb-types.h"
+
+void pb_ser_w(mpack_writer_t * writer, const pb_msg_t * cmd) {
+ if (cmd == NULL) return;
+
+ mpack_write_u8(writer, cmd->type);
+ mpack_write_u8(writer, cmd->action);
+ mpack_write_u16(writer, cmd->sender);
+ if (cmd->cmd == NULL) return;
+
+ switch (cmd->type) {
+ case PB_CMD_PROP: return pb_ser_w_cmd_prop(writer, cmd);
+ case PB_CMD_STATE: return pb_ser_w_cmd_state(writer, cmd);
+ case PB_CMD_MAGIC: return pb_ser_w_cmd_magic(writer, cmd);
+ default: break;
+ }
+}
+void pb_ser_r(mpack_reader_t * reader, pb_msg_t * cmd) {
+ cmd->type = mpack_expect_u8(reader);
+ cmd->action = mpack_expect_u8(reader);
+ cmd->sender = mpack_expect_u16(reader);
+
+ switch (cmd->type) {
+ case PB_CMD_PROP: return pb_ser_r_cmd_prop(reader, cmd);
+ case PB_CMD_STATE: return pb_ser_r_cmd_state(reader, cmd);
+ case PB_CMD_MAGIC: return pb_ser_r_cmd_magic(reader, cmd);
+ default: break;
+ }
+}
+void pb_ser_free(pb_msg_t * cmd) {
+ if (cmd == NULL) return;
+
+ switch (cmd->type) {
+ case PB_CMD_PROP: return pb_ser_free_cmd_prop(cmd);
+ case PB_CMD_STATE: return pb_ser_free_cmd_state(cmd);
+ case PB_CMD_MAGIC: return pb_ser_free_cmd_magic(cmd);
+ default: break;
+ }
+}
+
+void pb_ser_w_cmd_prop(mpack_writer_t * writer, const pb_msg_t * _msg) {
+ pb_cmd_prop_t * cmd = _msg->cmd;
+
+ mpack_write_u8(writer, cmd->propid);
+ mpack_write_bin(writer, (char *) cmd->value, cmd->_value_size);
+}
+void pb_ser_r_cmd_prop(mpack_reader_t * reader, pb_msg_t * _msg) {
+ pb_cmd_prop_t * cmd = _msg->cmd = pb_malloc(sizeof(pb_cmd_prop_t));
+
+ cmd->propid = mpack_expect_u8(reader);
+ cmd->_value_size = mpack_expect_bin(reader);
+ cmd->value = (uint8_t *) mpack_read_bytes_alloc(reader, cmd->_value_size);
+ mpack_done_bin(reader);
+}
+void pb_ser_free_cmd_prop(pb_msg_t * _msg) {
+ if (_msg->cmd != NULL) {
+ pb_cmd_prop_t * cmd = _msg->cmd;
+ if (cmd->value != NULL) {
+ MPACK_FREE(cmd->value);
+ cmd->value = NULL;
+ }
+ pb_free(_msg->cmd);
+ _msg->cmd = NULL;
+ }
+}
+
+void pb_ser_w_cmd_state(mpack_writer_t * writer, const pb_msg_t * _msg) {
+ pb_cmd_state_t * cmd = _msg->cmd;
+
+ mpack_write_u8(writer, cmd->state);
+}
+void pb_ser_r_cmd_state(mpack_reader_t * reader, pb_msg_t * _msg) {
+ pb_cmd_state_t * cmd = _msg->cmd = pb_malloc(sizeof(pb_cmd_state_t));
+
+ cmd->state = mpack_expect_u8(reader);
+}
+void pb_ser_free_cmd_state(pb_msg_t * _msg) {
+ if (_msg->cmd != NULL) {
+ pb_free(_msg->cmd);
+ _msg->cmd = NULL;
+ }
+}
+
+void pb_ser_w_cmd_magic(mpack_writer_t * writer, const pb_msg_t * _msg) {
+ pb_cmd_magic_t * cmd = _msg->cmd;
+
+ mpack_write_bin(writer, (char *) cmd->magic, cmd->_magic_size);
+}
+void pb_ser_r_cmd_magic(mpack_reader_t * reader, pb_msg_t * _msg) {
+ pb_cmd_magic_t * cmd = _msg->cmd = pb_malloc(sizeof(pb_cmd_magic_t));
+
+ cmd->_magic_size = mpack_expect_bin(reader);
+ cmd->magic = mpack_read_bytes_alloc(reader, cmd->_magic_size);
+ mpack_done_bin(reader);
+}
+void pb_ser_free_cmd_magic(pb_msg_t * _msg) {
+ if (_msg->cmd != NULL) {
+ pb_cmd_magic_t * cmd = _msg->cmd;
+ if (cmd->magic != NULL) {
+ MPACK_FREE(cmd->magic);
+ cmd->magic = NULL;
+ }
+ pb_free(_msg->cmd);
+ _msg->cmd = NULL;
+ }
+}
+
diff --git a/lib/pbdrv/pb-serial.h b/lib/pbdrv/pb-serial.h
new file mode 100644
index 0000000..d3d0007
--- /dev/null
+++ b/lib/pbdrv/pb-serial.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <mpack.h>
+
+#include "pb-types.h"
+
+#ifdef __cplusplus
+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;
+
+typedef void pb_ser_w_t(mpack_writer_t * writer, const pb_msg_t * msg);
+pb_ser_w_t pb_ser_w;
+
+typedef void pb_ser_r_t(mpack_reader_t * reader, pb_msg_t * msg);
+pb_ser_r_t pb_ser_r;
+
+typedef void pb_ser_free_t(pb_msg_t * msg);
+pb_ser_free_t pb_ser_free;
+
+__pb_cmd(cmd_prop)
+__pb_cmd(cmd_state)
+__pb_cmd(cmd_magic)
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/lib/pbdrv/pb-types.h b/lib/pbdrv/pb-types.h
index 96ffc37..4d085f9 100644
--- a/lib/pbdrv/pb-types.h
+++ b/lib/pbdrv/pb-types.h
@@ -1,4 +1,6 @@
#pragma once
+
+#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
@@ -14,24 +16,24 @@ extern "C" {
#define __weak
#endif
+//! I2C address (10 or 7 bit)
typedef uint16_t i2c_addr_t;
//! puzzle bus command types
enum pb_cmd_id {
- PB_CMD_REQ_READ, //!< request a puzzle module property
- PB_CMD_RES_READ, //!< respond to a puzzle module property request
- PB_CMD_REQ_WRITE, //!< request to write a puzzle module property
- PB_CMD_REQ_STATE, //!< request global state
- PB_CMD_RES_STATE, //!< respond to a global state request
- PB_CMD_REQ_SET_STATE, //!< request to overwrite module global state
- PB_CMD_MAGIC, //!< magic message (regular i2c command)
+ PB_CMD_PROP, //!< puzzle module property
+ PB_CMD_STATE, //!< global state
+ PB_CMD_MAGIC, //!< magic (handshake)
};
typedef enum pb_cmd_id pb_cmd_id_t;
-//! magic sent from main controller to puzzle module
-static const char pb_cmd_magic_msg[] = { 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 command action types
+enum pb_action {
+ PB_ACTION_REQ, //!< request
+ PB_ACTION_RES, //!< response
+ PB_ACTION_SET, //!< (over)write
+};
+typedef enum pb_action pb_action_t;
//! puzzle bus global states
enum pb_global_state {
@@ -42,54 +44,35 @@ enum pb_global_state {
};
typedef enum pb_global_state pb_global_state_t;
-//! puzzle bus message header (shared by all commands)
-typedef struct {
- const pb_cmd_id_t type; //!< command type
- const i2c_addr_t sender; //!< i2c address of sender
-} pb_msg_header_t;
-
-//! PB_CMD_REQ_READ data
-typedef struct {
- const pb_msg_header_t header;
- const uint8_t propid; //!< state property id to return
-} pb_cmd_req_read_t;
-
-//! PB_CMD_RES_READ data
-typedef struct {
- const pb_msg_header_t header;
- const uint8_t propid; //!< id of returned state property
- const uint8_t value[];
-} pb_cmd_res_read_t;
-
-//! PB_CMD_REQ_WRITE data
-typedef struct {
- const pb_msg_header_t header;
- const uint8_t propid; //!< state property id to write
- const uint8_t value[]; //!< new value of property
-} pb_cmd_req_write_t;
+//! magic sent from main controller to puzzle module
+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 };
-//! PB_CMD_REQ_STATE data
+//! puzzle bus message header (shared by all commands)
typedef struct {
- const pb_msg_header_t header;
- const pb_global_state_t state; //!< global state of sender
-} pb_cmd_req_state_t;
+ pb_cmd_id_t type; //!< command type
+ pb_action_t action; //!< command action
+ i2c_addr_t sender; //!< i2c address of sender
+ void * cmd; //!< command data (type dependant)
+} pb_msg_t;
-//! PB_CMD_RES_STATE data
+//! PB_CMD_PROP data
typedef struct {
- const pb_msg_header_t header;
- const pb_global_state_t state; //!< global state of sender
-} pb_cmd_res_state_t;
+ uint8_t propid; //!< id of state property
+ uint8_t * value; //!< new or current value
+ size_t _value_size; //!< [META] size of \p value
+} pb_cmd_prop_t;
-//! PB_CMD_REQ_SET_STATE data
+//! PB_CMD_STATE data
typedef struct {
- const pb_msg_header_t header;
- const pb_global_state_t state; //!< new global state
-} pb_cmd_req_set_state_t;
+ pb_global_state_t state; //!< global state
+} pb_cmd_state_t;
//! PB_CMD_MAGIC data
typedef struct {
- const pb_msg_header_t header;
- const char magic[]; //!< magic value
+ char * magic; //!< magic value
+ size_t _magic_size; //!< [META] size of \p magic
} pb_cmd_magic_t;
#ifdef __cplusplus
diff --git a/lib/pbdrv/pb-write.c b/lib/pbdrv/pb-write.c
deleted file mode 100644
index 752a4ac..0000000
--- a/lib/pbdrv/pb-write.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <mpack.h>
-
-#include "pb-write.h"
-
-typedef struct {
- mpack_writer_t writer;
- pbdrv_buf_t buf;
-} pbdrv_writer_t;
-
-static pbdrv_writer_t pbdrv_write_init() {
- pbdrv_writer_t writer;
- mpack_writer_init_growable(&writer.writer, &writer.buf.data, &writer.buf.size);
- return writer;
-}
-
-static pbdrv_buf_t pbdrv_write_finish(pbdrv_writer_t * writer) {
- if (mpack_writer_destroy(&writer->writer) != mpack_ok) {
- writer->buf.data = NULL;
- writer->buf.size = 0;
- }
- return writer->buf;
-}
-
-static void pbdrv_write_msg_header(pbdrv_writer_t * writer, pb_msg_header_t header) {
- mpack_write_u8(&writer->writer, header.type);
- mpack_write_u16(&writer->writer, header.sender);
-}
-
-pbdrv_buf_t pbdrv_write_cmd_req_set_state(pb_cmd_req_set_state_t data) {
- pbdrv_writer_t writer = pbdrv_write_init();
- pbdrv_write_msg_header(&writer, data.header);
- mpack_write_u8(&writer.writer, data.state);
- return pbdrv_write_finish(&writer);
-}
-
diff --git a/lib/pbdrv/pb-write.h b/lib/pbdrv/pb-write.h
deleted file mode 100644
index 3245898..0000000
--- a/lib/pbdrv/pb-write.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include "pb-types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//! binary buffer struct
-typedef struct {
- char * data; //! pointer to data
- size_t size; //! size of data
-} pbdrv_buf_t;
-
-pbdrv_buf_t pbdrv_write_cmd_req_read(pb_cmd_req_read_t data);
-pbdrv_buf_t pbdrv_write_cmd_res_read(pb_cmd_res_read_t data);
-pbdrv_buf_t pbdrv_write_cmd_req_write(pb_cmd_req_write_t data);
-pbdrv_buf_t pbdrv_write_cmd_req_state(pb_cmd_req_state_t data);
-pbdrv_buf_t pbdrv_write_cmd_res_state(pb_cmd_res_state_t data);
-pbdrv_buf_t pbdrv_write_cmd_req_set_state(pb_cmd_req_set_state_t data);
-pbdrv_buf_t pbdrv_write_cmd_magic(pb_cmd_magic_t data);
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/lib/pbdrv/pb.h b/lib/pbdrv/pb.h
index b6efed0..0f2e9d1 100644
--- a/lib/pbdrv/pb.h
+++ b/lib/pbdrv/pb.h
@@ -10,13 +10,14 @@
#define PB_ADDR_ADA_NEO_3 0x30
#define PB_ADDR_ADA_NEO_4 0x32
-// TODO: ???
-#define PB_ADDR_MOD_NEOTRELLIS 0
-#define PB_ADDR_MOD_SOFTWARE 0
-#define PB_ADDR_MOD_HARDWARE 0
-#define PB_ADDR_MOD_VAULT 0
-// #define BUSADDR_MOD_AUTOMATION 0
+// Main controller
+#define PB_ADDR_MOD_MAIN 0x08
-// main controller
-#define PB_ADDR_MOD_MAIN 0x00
+// Puzzle modules
+#define PB_ADDR_MOD_NEOTRELLIS 0x21
+#define PB_ADDR_MOD_SOFTWARE 0x22
+#define PB_ADDR_MOD_HARDWARE 0x23
+#define PB_ADDR_MOD_VAULT 0x24
+// #define BUSADDR_MOD_AUTOMATION 0x25
+#define PB_ADDR_MOD_DUMMY 0x69