diff --git a/i2c-hub/firmware/i2c-hub-firmware/.vscode/settings.json b/i2c-hub/firmware/i2c-hub-firmware/.vscode/settings.json index b448cd8..4ee63c0 100644 --- a/i2c-hub/firmware/i2c-hub-firmware/.vscode/settings.json +++ b/i2c-hub/firmware/i2c-hub-firmware/.vscode/settings.json @@ -38,6 +38,50 @@ "raspberry-pi-pico.ninjaPath": "${HOME}/.pico-sdk/ninja/v1.12.1/ninja", "files.associations": { "uart.h": "c", - "freertos.h": "c" + "freertos.h": "c", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "map": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "typeinfo": "cpp" } } diff --git a/i2c-hub/firmware/i2c-hub-firmware/.vscode/tasks.json b/i2c-hub/firmware/i2c-hub-firmware/.vscode/tasks.json index 862f6ac..8fb5999 100644 --- a/i2c-hub/firmware/i2c-hub-firmware/.vscode/tasks.json +++ b/i2c-hub/firmware/i2c-hub-firmware/.vscode/tasks.json @@ -68,6 +68,7 @@ "showReuseMessage": true, "clear": true }, + "dependsOn": ["Compile Project"], "problemMatcher": [], "windows": { "command": "${env:USERPROFILE}/.pico-sdk/openocd/0.12.0+dev/openocd.exe", diff --git a/i2c-hub/firmware/i2c-hub-firmware/CMakeLists.txt b/i2c-hub/firmware/i2c-hub-firmware/CMakeLists.txt index 01280fb..cb95956 100644 --- a/i2c-hub/firmware/i2c-hub-firmware/CMakeLists.txt +++ b/i2c-hub/firmware/i2c-hub-firmware/CMakeLists.txt @@ -31,7 +31,7 @@ include(pico_sdk_import.cmake) # Adding FreeRTOS set(FREERTOS_KERNEL_PATH ../lib/FreeRTOS-Kernel) include(cmake/FreeRTOS_Kernel_import.cmake) -#include(cmake/freeRTOS.cmake) +include(src/gobotrpc/cmake/CMakeLists.txt) project(i2c-hub-firmware C CXX ASM) @@ -55,7 +55,7 @@ pico_enable_stdio_usb(i2c-hub-firmware 0) # Add the standard library to the build target_link_libraries(i2c-hub-firmware FreeRTOS-Kernel-Heap4 - #FreeRTOS + GobotRPC pico_stdlib ) diff --git a/i2c-hub/firmware/i2c-hub-firmware/cmake/freeRTOS.cmake b/i2c-hub/firmware/i2c-hub-firmware/cmake/freeRTOS.cmake deleted file mode 100644 index e654935..0000000 --- a/i2c-hub/firmware/i2c-hub-firmware/cmake/freeRTOS.cmake +++ /dev/null @@ -1,14 +0,0 @@ -SET(FreeRTOS_DIR ${CMAKE_CURRENT_LIST_DIR}/../lib/FreeRTOS-Kernel) -FILE(GLOB FreeRTOS_src ${FreeRTOS_DIR}/*.c) - -add_library(FreeRTOS STATIC - ${FreeRTOS_src} - ${FreeRTOS_DIR}/portable/GCC/ARM_CM0/port.c - ${FreeRTOS_DIR}/portable/MemMang/heap_4.c -) - -target_include_directories(FreeRTOS PUBLIC - ${FreeRTOS_DIR}/portable/GCC/ARM_CM0/ - ${FreeRTOS_DIR}/include/ - ${CMAKE_CURRENT_LIST_DIR}/.. -) \ No newline at end of file diff --git a/i2c-hub/firmware/i2c-hub-firmware/docs/.$NetworkStack.drawio.dtmp b/i2c-hub/firmware/i2c-hub-firmware/docs/.$NetworkStack.drawio.dtmp new file mode 100644 index 0000000..3197b4c --- /dev/null +++ b/i2c-hub/firmware/i2c-hub-firmware/docs/.$NetworkStack.drawio.dtmp @@ -0,0 +1,700 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/cmake/CMakeLists.txt b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/cmake/CMakeLists.txt new file mode 100644 index 0000000..16ef9f0 --- /dev/null +++ b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/cmake/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(GobotRPC STATIC + ${CMAKE_CURRENT_LIST_DIR}/../rx.cpp + ${CMAKE_CURRENT_LIST_DIR}/../init.cpp + ${CMAKE_CURRENT_LIST_DIR}/../protocol.cpp + ${CMAKE_CURRENT_LIST_DIR}/../error_msg.cpp +) + +target_include_directories(GobotRPC PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/../include + ${CMAKE_CURRENT_LIST_DIR}/../../.. +) + +target_link_libraries(GobotRPC + FreeRTOS-Kernel-Heap4 +) \ No newline at end of file diff --git a/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/error_msg.cpp b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/error_msg.cpp new file mode 100644 index 0000000..7b52875 --- /dev/null +++ b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/error_msg.cpp @@ -0,0 +1,43 @@ +#include "gobotrpc.hpp" +#include + +const char * TEST_MSG_RPC_RESULT_GOOD = "Good"; +const char * TEST_MSG_RPC_RESULT_PACKAGE_READY = "Package Ready"; +const char * TEST_MSG_RPC_RESULT_ERROR_INVALID_FRAMESUBMITIONRESULT = "Invalid FrameSubmitionResult"; +const char * TEST_MSG_RPC_RESULT_ERROR_INVALID_RPC_TYPE = "Invalid RPC Type (0b10)"; +const char * TEST_MSG_RPC_RESULT_ERROR_INVALID_RPC_NUMBER = "Invalid RPC Number"; +const char * TEST_MSG_RPC_RESULT_ERROR_NO_EMPTY_OR_FITTING_SLOT = "No empty or fitting slot for submitted frame"; + +char * mapFrameSubmitionResult2String(FrameSubmitionResult res) { + + switch (res) { + case PENDING: return (char *)(TEST_MSG_RPC_RESULT_GOOD); + case COMPLEATE: return (char *) TEST_MSG_RPC_RESULT_PACKAGE_READY; + + case ERROR_INVALID_RPC_TYPE: return (char *) TEST_MSG_RPC_RESULT_ERROR_INVALID_RPC_TYPE; + case ERROR_INVALID_RPC_NUMBER: return (char *) TEST_MSG_RPC_RESULT_ERROR_INVALID_RPC_NUMBER; + case ERROR_NO_EMPTY_OR_FITTING_SLOT: return (char *) TEST_MSG_RPC_RESULT_ERROR_INVALID_FRAMESUBMITIONRESULT; + } + return (char *) TEST_MSG_RPC_RESULT_ERROR_INVALID_FRAMESUBMITIONRESULT; +} + +void GobotRPCParser::print_out_slots() { + for(int i = 0; i < NUM_SLOTS; i++) { + printf("[%d] %d%d (%x-%d) %d T%08x ", i, + buffer[i].is_complete, buffer[i].is_in_use, buffer[i].sender_address, + buffer[i].rpcNum, buffer[i].type, buffer[i].timestamp + ); + + for(int j = 0; j < MAX_PAGE_SIZES; j++) { + printf("%02x", buffer[i].buffer[j]); + } + + printf(" "); + + for(int j = 0; j < 32; j++) { + printf("%d", (buffer[i].used_bit_masked >> (31-j)) & 1); + } + + printf("\n"); + } +} diff --git a/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/include/gobotrpc.hpp b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/include/gobotrpc.hpp new file mode 100644 index 0000000..ca45337 --- /dev/null +++ b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/include/gobotrpc.hpp @@ -0,0 +1,64 @@ +#pragma once +#include +#include + +#include "protocol.hpp" + +#define MAX_PAGE_SIZES 4*7 + +enum FrameSubmitionResult { + PENDING, + COMPLEATE, + ERROR_INVALID_RPC_TYPE, + ERROR_INVALID_RPC_NUMBER, + ERROR_NO_EMPTY_OR_FITTING_SLOT, +}; + +struct RPC_RX_PackageSlot { + char buffer[MAX_PAGE_SIZES]; + + bool is_complete; + bool is_in_use; + + uint32_t sender_address; + enum RPCNumber rpcNum; + enum RPCType type; + uint32_t used_bit_masked; + uint32_t timestamp; +}; + +struct RPCPackage { + char buffer[MAX_PAGE_SIZES]; + size_t length; + uint32_t addr; + RPCNumber rpcNum; + RPCType type; +}; + +#define NUM_SLOTS 8 + +class GobotRPCParser { +private: + RPC_RX_PackageSlot buffer[NUM_SLOTS]; + uint32_t masked [NUM_SLOTS]; + uint32_t address_mask; + + size_t finishedScanIndex; + + void find_fitting_slot(RPCHeader header, uint32_t addr, int * fitting_slot, int * empty_slot); + static void insertFrameInPackageSlot(RPC_RX_PackageSlot * package, char * data, size_t segment, size_t length); + void freePackageSlot(size_t index); + +public: + GobotRPCParser(); + + void print_out_slots(); + enum FrameSubmitionResult submit_frame(char * data, size_t length, uint32_t addr, uint32_t timestamp); + + int getFinishedIndexPackages(); + void retrivePackage(RPCPackage * dest, int index); +}; + +char * mapFrameSubmitionResult2String(FrameSubmitionResult res); + +FrameSubmitionResult getPackageStatus(RPC_RX_PackageSlot * package); diff --git a/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/include/protocol.hpp b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/include/protocol.hpp new file mode 100644 index 0000000..27945d3 --- /dev/null +++ b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/include/protocol.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +enum RPCNumber { + Get_Info = 0x0, + Home = 0x01, + Move_Step = 0x2, + Move_XY = 0x3, + Set_Padding = 0x4, + Release_Motors = 0x5, + Drop_Stone = 0x6, + Get_Stone_Status = 0x7, + Move_Z_Axis = 0x8, + Set_Vacum = 0x9, + Invalid = 0xf +}; + +const uint32_t RPC_NUMBER_MAX = 0x9; + +enum RPCType { + REQUEST = 0b00, + RESPONSE_RPC = 0b01, + INVALID = 0b10, + ERROR = 0b11 +}; + +struct RPCHeader { + RPCNumber rpcNum : 4; + RPCType type : 2; + unsigned char segment: 2; +}; diff --git a/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/init.cpp b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/init.cpp new file mode 100644 index 0000000..de8e827 --- /dev/null +++ b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/init.cpp @@ -0,0 +1,19 @@ +#include "gobotrpc.hpp" +#include + +GobotRPCParser::GobotRPCParser() { + for(int i = 0; i < NUM_SLOTS; i++) { + buffer[i].timestamp = 0; + buffer[i].is_complete = false; + buffer[i].is_in_use = false; + buffer[i].used_bit_masked = 0; + buffer[i].sender_address = 0; + buffer[i].rpcNum = Invalid; + buffer[i].type = INVALID; + + memset(buffer[i].buffer, 0, MAX_PAGE_SIZES); + } + + finishedScanIndex = 0; + address_mask = 0xFFFFFFFF; +} diff --git a/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/protocol.cpp b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/protocol.cpp new file mode 100644 index 0000000..65510f6 --- /dev/null +++ b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/protocol.cpp @@ -0,0 +1,64 @@ +#include "protocol.hpp" +#include "gobotrpc.hpp" +#include + +uint32_t getRpcRequestCompleteMask(RPCNumber rpcNum) { + switch (rpcNum) { + case Get_Info: return 0b00000000000000000000000000000000; + case Home: return 0b00000000000000000000000000000011; + case Move_Step: return 0b00000000000000000000000000111111; + case Move_XY: return 0b00000000000000000000000000111111; + case Set_Padding: return 0b00000000000000001101111110111111; + case Release_Motors: return 0b00000000000000000000000001111111; + case Drop_Stone: return 0b00000000000000000000000000000000; + case Get_Stone_Status: return 0b00000000000000000000000000000000; + case Move_Z_Axis: return 0b00000000000000000000000000000001; + case Set_Vacum: return 0b00000000000000000000000000000001; + default: return 0b00000000000000000000000000000000; + } +} + +uint32_t getRpcResponseCompleteMask(RPCNumber rpcNum) { + switch (rpcNum) { + case Get_Info: return 0b00001111111111111111111111111111; + case Home: return 0b00000000000000000000000000111111; + case Move_Step: return 0b00000000000000000000000000000000; + case Move_XY: return 0b00000000000000000000000000000000; + case Set_Padding: return 0b00000000000000000000000000000000; + case Release_Motors: return 0b00000000000000000000000000000000; + case Drop_Stone: return 0b00000000000000000000000000000000; + case Get_Stone_Status: return 0b00000000000000000000000000000000; + case Move_Z_Axis: return 0b00000000000000000000000000000000; + case Set_Vacum: return 0b00000000000000000000000000000000; + default: return 0b00000000000000000000000000000000; + } +} + +uint32_t ERROR_MASK = 0b00000000000000000000000000000000; + +FrameSubmitionResult getPackageStatus(RPC_RX_PackageSlot * package) { + + uint32_t mask; + + switch (package->type) { + case REQUEST: + mask = getRpcRequestCompleteMask(package->rpcNum); + break; + case RESPONSE_RPC: + mask = getRpcResponseCompleteMask(package->rpcNum); + break; + case ERROR: + mask = ERROR_MASK; + break; + default: + return ERROR_INVALID_RPC_TYPE; + }; + + uint32_t masked_bits = package->used_bit_masked & mask; + + if(masked_bits == mask) { + return COMPLEATE; + } + + return PENDING; +} \ No newline at end of file diff --git a/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/rx.cpp b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/rx.cpp new file mode 100644 index 0000000..92aec4a --- /dev/null +++ b/i2c-hub/firmware/i2c-hub-firmware/src/gobotrpc/rx.cpp @@ -0,0 +1,127 @@ +#include "gobotrpc.hpp" +#include "protocol.hpp" +#include + +RPCHeader parseRPCHeader(char data) +{ + RPCHeader header; + header.rpcNum = (RPCNumber)(data & 0b00001111); + header.type = (RPCType)((data & 0b00110000) >> 4); + header.segment = (data & 0b11000000) >> 6; + + return header; +} + +FrameSubmitionResult GobotRPCParser::submit_frame(char *data, size_t length, uint32_t addr, uint32_t timestamp) +{ + RPCHeader header = parseRPCHeader(data[0]); + + if (header.type == INVALID) { + return ERROR_INVALID_RPC_TYPE; + } + + if (header.rpcNum > RPC_NUMBER_MAX) { + return ERROR_INVALID_RPC_NUMBER; + } + + int fitting_slot; + int empty_slot; + find_fitting_slot(header, addr, &fitting_slot, &empty_slot); + + int slotNum; + + // Check if packageSlot is complete + + if (fitting_slot != -1) { + slotNum = fitting_slot; + } + else if (empty_slot != -1) { + slotNum = empty_slot; + + this->buffer[slotNum].is_in_use = true; + this->buffer[slotNum].is_complete = false; + this->buffer[slotNum].sender_address = addr; + this->buffer[slotNum].rpcNum = header.rpcNum; + this->buffer[slotNum].type = header.type; + } + else { + return ERROR_NO_EMPTY_OR_FITTING_SLOT; + } + + insertFrameInPackageSlot(&this->buffer[slotNum], data, header.segment, length); + this->buffer[slotNum].timestamp = timestamp; + volatile FrameSubmitionResult res = getPackageStatus(&(this->buffer[slotNum])); + + if (res == COMPLEATE) { + this->buffer[slotNum].is_complete = true; + } + + return res; +} + +void GobotRPCParser::insertFrameInPackageSlot(RPC_RX_PackageSlot *packageSlot, char *data, size_t segment, size_t length) +{ + size_t offset = segment * 7; + + for (int i = 0; i < length - 1; i++) { + packageSlot->buffer[offset + i] = data[i + 1]; + packageSlot->used_bit_masked |= 1 << (offset + i); + } +} + +void GobotRPCParser::find_fitting_slot(RPCHeader header, uint32_t addr, int *fitting_slot, int *empty_slot) +{ + uint32_t masked_addr = addr & this->address_mask; + + *fitting_slot = -1; + *empty_slot = -1; + + for (int i = 0; i < NUM_SLOTS; i++) { + if (this->buffer[i].is_complete) { + continue; + } + + uint32_t masked_slot_addr = this->buffer[i].sender_address & this->address_mask; + + if (masked_slot_addr == masked_addr && header.rpcNum == this->buffer[i].rpcNum) { + *fitting_slot = i; + return; + } + + if (*empty_slot == -1 && !buffer[i].is_in_use) { + *empty_slot = i; + } + } +} + +int GobotRPCParser::getFinishedIndexPackages() { + + for (int i = 0; i < NUM_SLOTS; i++) { + size_t index = (i + this->finishedScanIndex) % NUM_SLOTS; + if (this->buffer[i].is_complete) { + this->finishedScanIndex = (index + 1) % NUM_SLOTS; + return index; + } + } + + return -1; +} + +void GobotRPCParser::retrivePackage(RPCPackage *dest, int index) { + memcpy(dest->buffer, buffer[index].buffer, MAX_PAGE_SIZES); + dest->addr = buffer[index].sender_address; + dest->rpcNum = buffer[index].rpcNum; + dest->type = buffer[index].type; + + freePackageSlot(index); +} + +void GobotRPCParser::freePackageSlot(size_t index) { + this->buffer[index].timestamp = 0; + this->buffer[index].is_complete = false; + this->buffer[index].is_in_use = false; + this->buffer[index].used_bit_masked = 0; + this->buffer[index].sender_address = 0; + this->buffer[index].rpcNum = Invalid; + this->buffer[index].type = INVALID; +} \ No newline at end of file diff --git a/i2c-hub/firmware/i2c-hub-firmware/src/main.cpp b/i2c-hub/firmware/i2c-hub-firmware/src/main.cpp index 18988f6..553cb8a 100644 --- a/i2c-hub/firmware/i2c-hub-firmware/src/main.cpp +++ b/i2c-hub/firmware/i2c-hub-firmware/src/main.cpp @@ -7,8 +7,53 @@ #define LED_PIN 25 +#include "gobotrpc/include/gobotrpc.hpp" void TaskFn(void * args) { + printf("\n\n\n\n"); + + + GobotRPCParser rpcRXParser; + + char data0[] = "\x04\x01\x02\x03\x04\x05\x06"; + char data1[] = "\x44\x11\x12\x13\x14\x15\x16"; + char data3[] = "\x11\xaa\xbb\xcc\xdd\xee\xff"; + char data2[] = "\x84\xaa\xbb"; + + + rpcRXParser.submit_frame(data0, 7, 0x42, xTaskGetTickCount()); + rpcRXParser.print_out_slots(); + printf("\n"); + + rpcRXParser.submit_frame(data3, 7, 0x43, xTaskGetTickCount()); + rpcRXParser.print_out_slots(); + printf("\n"); + + rpcRXParser.submit_frame(data1, 7, 0x42, xTaskGetTickCount()); + rpcRXParser.print_out_slots(); + printf("\n"); + + vTaskDelay(10 / portTICK_PERIOD_MS); + + rpcRXParser.submit_frame(data3, 7, 0x43, xTaskGetTickCount()); + rpcRXParser.print_out_slots(); + printf("\n"); + + rpcRXParser.submit_frame(data2, 3, 0x42, xTaskGetTickCount()); + rpcRXParser.print_out_slots(); + printf("\n"); + + size_t index = rpcRXParser.getFinishedIndexPackages(); + printf("Index: %d\n", index); + RPCPackage package; + rpcRXParser.retrivePackage(&package, index); + + for(int i=0; i