diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-06-15 13:30:45 +0200 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-06-15 13:30:45 +0200 |
commit | 20f442e5f5aa6a4fcf07f65e2f446a3c0ff8e4f2 (patch) | |
tree | 99f2422681eaa34a6f21b54d86e67115c291d5ce | |
parent | dbe08a8cd3d29cee7ba1adae4841c0a831784f31 (diff) |
WIP freertos + Arduino workaround
-rw-r--r-- | docs/handover.adoc | 18 | ||||
-rw-r--r-- | lib/pbdrv/CMakeLists.txt | 12 | ||||
-rw-r--r-- | lib/pbdrv/drv/arduino/mod.cpp | 41 | ||||
-rw-r--r-- | lib/pbdrv/drv/arduino/mod.h | 11 | ||||
-rw-r--r-- | lib/pbdrv/pb-mod.c | 4 | ||||
-rw-r--r-- | lib/pbdrv/pb-mod.h | 10 | ||||
-rw-r--r-- | lib/pbdrv/pb-route.c | 19 | ||||
-rw-r--r-- | lib/pbdrv/pb-send.c | 4 | ||||
-rw-r--r-- | lib/pbdrv/pb-send.h | 2 | ||||
-rw-r--r-- | main/i2c.c | 4 | ||||
-rw-r--r-- | main/pbdrv.c | 8 | ||||
-rw-r--r-- | puzzle/dummy/CMakeLists.txt | 7 | ||||
-rw-r--r-- | puzzle/dummy/FreeRTOSConfig.h | 51 | ||||
-rw-r--r-- | puzzle/dummy/main.cpp | 40 |
14 files changed, 182 insertions, 49 deletions
diff --git a/docs/handover.adoc b/docs/handover.adoc index 86ae3ad..378ec3a 100644 --- a/docs/handover.adoc +++ b/docs/handover.adoc @@ -8,10 +8,24 @@ went. We found the previous handover documents to be unhelpful when determining the 'actual' state of the project in the first few weeks, and felt they did not address the pitfalls of this project. -== Incidents - == Project History +=== Garbage workarounds + +This section details unelegant workarounds that should be removed from the +code. All workarounds are marked with ``FIXME:`` comments referring to one of +the workarounds mentioned in this section. + +RP2040 I^2^C limitations:: +- All puzzle module drivers have a hard-coded 2 second delay between receiving + the MAGIC handshake request and the MAGIC handshake response handler. This + was done to ensure responses are not ignored by the RP2040 (main controller) + while it is still in I^2^C master mode. + +=== Incidents + +== Group History + === 19-20 .19-20 group composition diff --git a/lib/pbdrv/CMakeLists.txt b/lib/pbdrv/CMakeLists.txt index b048ec7..59a1f25 100644 --- a/lib/pbdrv/CMakeLists.txt +++ b/lib/pbdrv/CMakeLists.txt @@ -21,13 +21,21 @@ add_library(pbdrv STATIC target_link_libraries(pbdrv mpack) target_include_directories(pbdrv SYSTEM INTERFACE .) -# puzzle bus module specific code (superset of pbdrv) +# puzzle bus *module* specific code add_library(pbdrv-mod STATIC pb-mod.c pb-send.c pb-route.c ) -target_link_libraries(pbdrv-mod pbdrv) +target_link_libraries(pbdrv-mod + # freertos is used to defer the handling of i2c messages outside the receive + # interrupt service routine + freertos_kernel + freertos_kernel_include + freertos_config + # pbdrv-mod is a superset of pbdrv + pbdrv + ) target_include_directories(pbdrv-mod SYSTEM INTERFACE .) # supported puzzle bus drivers diff --git a/lib/pbdrv/drv/arduino/mod.cpp b/lib/pbdrv/drv/arduino/mod.cpp index ac051db..d281495 100644 --- a/lib/pbdrv/drv/arduino/mod.cpp +++ b/lib/pbdrv/drv/arduino/mod.cpp @@ -4,24 +4,43 @@ #include <Arduino.h> #include <Wire.h> +#include <avr/delay.h> + +#include <FreeRTOS.h> +#include <timers.h> +#include <task.h> #include <stdlib.h> #include <stdint.h> #include "../../pb.h" #include "../../pb-mod.h" +#include "../../pb-buf.h" #include "mod.h" +//! Arduino setup function +extern void setup(void); +void loop(void) {} + +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); + 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 *) malloc(sizeof(pb_buf_t)); + msg->data = (char *) malloc(bytes); + msg->size = 0; while (Wire.available()) - data[size++] = Wire.read(); + msg->data[msg->size++] = Wire.read(); - pb_i2c_recv(data, size); + // defer pb_i2c_recv call + xTimerPendFunctionCallFromISR(async_pb_i2c_recv, msg, 0, NULL); } -void pb_setup() { +static void pb_setup() { Wire.begin((int) PB_MOD_ADDR); Wire.setWireTimeout(PB_TIMEOUT_US, true); Wire.setClock(PB_CLOCK_SPEED_HZ); @@ -29,6 +48,18 @@ void pb_setup() { Wire.onReceive(recv_event); } +void initVariant(void) { + // call regular arduino setup + setup(); + Serial.print("regular setup done and in initVariant\r\n"); // DEBUG + + // call pbdrv-mod setup + pb_setup(); + + // start freertos scheduler + vTaskStartScheduler(); +} + __weak void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { Wire.beginTransmission((int) addr); Wire.write(buf, sz); diff --git a/lib/pbdrv/drv/arduino/mod.h b/lib/pbdrv/drv/arduino/mod.h index c4cb9ce..87b5724 100644 --- a/lib/pbdrv/drv/arduino/mod.h +++ b/lib/pbdrv/drv/arduino/mod.h @@ -4,12 +4,17 @@ extern "C" { #endif +//! Arduino init variant (called before user setup) +void initVariant(void); + /** - * \brief puzzle bus driver setup + * \brief Arduino loop function * - * This function should be called from the Arduino \c setup() function. + * Loop won't run because everything is handled by the freertos scheduler. It + * is defined in this driver to cause compiler warnings if the user has defined + * the loop() function anyways. */ -void pb_setup(); +extern void loop(void); #ifdef __cplusplus } diff --git a/lib/pbdrv/pb-mod.c b/lib/pbdrv/pb-mod.c index faa321e..c27194e 100644 --- a/lib/pbdrv/pb-mod.c +++ b/lib/pbdrv/pb-mod.c @@ -32,7 +32,3 @@ __weak void pb_i2c_recv(const uint8_t * data, size_t sz) { pb_msg_free(msg); } -void pb_reply(pb_msg_t * msg, pb_buf_t * reply) { - return pb_i2c_send(msg->sender, (uint8_t *) reply->data, reply->size); -} - diff --git a/lib/pbdrv/pb-mod.h b/lib/pbdrv/pb-mod.h index 4fb3456..a2da421 100644 --- a/lib/pbdrv/pb-mod.h +++ b/lib/pbdrv/pb-mod.h @@ -14,7 +14,6 @@ #include <stddef.h> #include <stdbool.h> -#include "pb-buf.h" #include "pb-types.h" #ifdef __cplusplus @@ -29,11 +28,16 @@ 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); -void pb_reply(pb_msg_t * msg, pb_buf_t * reply); - pb_global_state_t pb_hook_mod_state_read(); void pb_hook_mod_state_write(pb_global_state_t state); +/** + * \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 } #endif diff --git a/lib/pbdrv/pb-route.c b/lib/pbdrv/pb-route.c index f26d45c..279b430 100644 --- a/lib/pbdrv/pb-route.c +++ b/lib/pbdrv/pb-route.c @@ -1,6 +1,13 @@ #include "pb-route.h" #include "pb-mod.h" #include "pb-send.h" +#include "pb-types.h" + +#include <string.h> + +// FIXME: this should be removed (see handover: RP2040 I2C limitations) +#include <FreeRTOS.h> +#include <task.h> __weak bool pb_hook_route_msg(pb_msg_t * msg) { return false; } __weak void pb_route_msg(pb_msg_t * msg) { @@ -59,7 +66,7 @@ __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_reply(msg, &buf); + pb_send_reply(msg, &buf); pb_buf_free(&buf); // notify of new global state variable @@ -77,8 +84,16 @@ __weak void pb_route_cmd_state_set(pb_msg_t * msg) { } __weak void pb_route_cmd_magic_req(pb_msg_t * msg) { + pb_cmd_magic_t * cmd = msg->cmd; + // return early if magic is invalid + if (cmd->_magic_size != sizeof(pb_cmd_magic_req)) return; + if (memcmp(cmd->magic, pb_cmd_magic_req, cmd->_magic_size) != 0) return; + + // FIXME: this should be removed (see handover: RP2040 I2C limitations) + vTaskDelay(2000 / portTICK_PERIOD_MS); + pb_buf_t buf = pb_send_magic_res(); - pb_reply(msg, &buf); + pb_send_reply(msg, &buf); pb_buf_free(&buf); } diff --git a/lib/pbdrv/pb-send.c b/lib/pbdrv/pb-send.c index f0d5004..b70af3a 100644 --- a/lib/pbdrv/pb-send.c +++ b/lib/pbdrv/pb-send.c @@ -2,6 +2,10 @@ #include "pb-mod.h" #include "pb-msg.h" +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, diff --git a/lib/pbdrv/pb-send.h b/lib/pbdrv/pb-send.h index 83051e2..2f8be1e 100644 --- a/lib/pbdrv/pb-send.h +++ b/lib/pbdrv/pb-send.h @@ -7,6 +7,8 @@ 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); @@ -17,3 +17,7 @@ void bus_task() { vTaskDelete(NULL); } +void pb_route_cmd_magic_res(pb_msg_t * msg) { + printf("got a magic response from 0x%02x!\n", msg->sender); +} + diff --git a/main/pbdrv.c b/main/pbdrv.c index d809b86..0624897 100644 --- a/main/pbdrv.c +++ b/main/pbdrv.c @@ -3,7 +3,7 @@ #include "pb.h" #include "pb-types.h" #include "pb-mod.h" -#include "pb-msg.h" +#include "pb-send.h" #include <hardware/i2c.h> #include <hardware/gpio.h> @@ -76,7 +76,7 @@ __weak void pb_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { void bus_scan() { i2c_set_slave_mode(PB_I2C, false, PB_MOD_ADDR); - pb_buf_t buf = pb_msg_write_req_magic(); + pb_buf_t buf = pb_send_magic_req(); // check for all 7-bit addresses uint16_t addr_max = 1 << 7; @@ -89,3 +89,7 @@ void bus_scan() { i2c_set_slave_mode(PB_I2C, true, PB_MOD_ADDR); } +void pb_mod_blocking_delay_ms(unsigned long ms) { + vTaskDelay(ms / portTICK_PERIOD_MS); +} + diff --git a/puzzle/dummy/CMakeLists.txt b/puzzle/dummy/CMakeLists.txt index c485e74..f80d18c 100644 --- a/puzzle/dummy/CMakeLists.txt +++ b/puzzle/dummy/CMakeLists.txt @@ -12,6 +12,12 @@ add_compile_definitions(DEBUG) set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/lib/Arduino-CMake-Toolchain/Arduino-toolchain.cmake) set(ARDUINO_BOARD "Arduino Uno [avr.uno]") +# freertos +add_library(freertos_config INTERFACE) +target_include_directories(freertos_config SYSTEM INTERFACE .) +set(FREERTOS_PORT GCC_ATMEGA) +set(FREERTOS_HEAP 4) + # used for testing # set(ARDUINO_BOARD "Raspberry Pi Pico W [rp2040.rpipicow]") # add_compile_definitions(USE_TINYUSB) @@ -20,6 +26,7 @@ set(ARDUINO_BOARD "Arduino Uno [avr.uno]") project(pb_mod_dummy C CXX) add_subdirectory(lib/pbdrv) +add_subdirectory(lib/FreeRTOS-Kernel) add_executable(main main.cpp diff --git a/puzzle/dummy/FreeRTOSConfig.h b/puzzle/dummy/FreeRTOSConfig.h new file mode 100644 index 0000000..ab6bd7f --- /dev/null +++ b/puzzle/dummy/FreeRTOSConfig.h @@ -0,0 +1,51 @@ +#pragma once + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configMAX_PRIORITIES 32 +#define configMINIMAL_STACK_SIZE ((configSTACK_DEPTH_TYPE) 192) +#define configUSE_16_BIT_TICKS 1 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 1 +#define configSTACK_DEPTH_TYPE uint16_t +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configTOTAL_HEAP_SIZE (1024) +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 0 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH 92 + +#include <assert.h> +#define configASSERT(x) assert(x) + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xQueueGetMutexHolder 1 + diff --git a/puzzle/dummy/main.cpp b/puzzle/dummy/main.cpp index e5f5e24..ddf3bf0 100644 --- a/puzzle/dummy/main.cpp +++ b/puzzle/dummy/main.cpp @@ -1,38 +1,26 @@ #include <Arduino.h> #include <Wire.h> +#include <FreeRTOS.h> +#include <task.h> + #include "drv/arduino/mod.h" #include "pb-mod.h" -#define TEST_A - -#ifdef TEST_A -#define ADDR_RX 0x69 -#define ADDR_TX 0x20 -#define MSG "aa" -#define MSG_SIZE 3 -#define MSG_DELAY 10 -#endif - -#ifdef TEST_B -#define ADDR_TX 0x69 -#define ADDR_RX 0x20 -#define MSG "bbbbbbbb" -#define MSG_SIZE 9 -#define MSG_DELAY 10 -#endif - const char * PB_MOD_NAME = "dummy"; -const i2c_addr_t PB_MOD_ADDR = ADDR_RX; +const i2c_addr_t PB_MOD_ADDR = 0x69; -void setup() { - pb_setup(); +void testTask() { + while(1) { + vTaskDelay(1000 / portTICK_PERIOD_MS); + Serial.write("Hello world!\r\n"); + } } -void loop() { - // pb_i2c_send(ADDR_TX, (uint8_t *) MSG, MSG_SIZE); - // delay(MSG_DELAY); +void setup() { + Serial.begin(115200); + Serial.write("setup called\r\n"); + xTaskCreate((TaskFunction_t) testTask, "test", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL); + Serial.write("setup done\r\n"); } -void pb_i2c_recv(const uint8_t * data, size_t size) { } - |