Implemented RX on Node

This commit is contained in:
AlexanderHD27
2025-01-06 03:28:10 +01:00
parent caf7586b5b
commit 1e317adedd
29 changed files with 1646 additions and 2298 deletions

View File

@@ -63,6 +63,7 @@ target_link_libraries(i2c-hub-firmware
# Add the standard include files to the build
target_include_directories(i2c-hub-firmware PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/include
)
# Add any user requested libraries

File diff suppressed because it is too large Load Diff

View File

@@ -14,8 +14,10 @@ add_library(GobotRPC STATIC
target_include_directories(GobotRPC PUBLIC
${CMAKE_CURRENT_LIST_DIR}/../include
${CMAKE_CURRENT_LIST_DIR}/../include/util
${CMAKE_CURRENT_LIST_DIR}/../include/ti
${CMAKE_CURRENT_LIST_DIR}/../../..
${CMAKE_CURRENT_LIST_DIR}/../../../include
)
target_link_libraries(GobotRPC

View File

@@ -0,0 +1,19 @@
add_library(GobotRPC_Node_RP2040_I2C STATIC
${CMAKE_CURRENT_LIST_DIR}/../node_interface/rp2040/i2c/init.cpp
${CMAKE_CURRENT_LIST_DIR}/../node_interface/rp2040/i2c/rx_tx.cpp
${CMAKE_CURRENT_LIST_DIR}/../crc16.cpp
${CMAKE_CURRENT_LIST_DIR}/../protocol_base.cpp
${CMAKE_CURRENT_LIST_DIR}/../node_interface/init.cpp
)
target_include_directories(GobotRPC_Node_RP2040_I2C PUBLIC
${CMAKE_CURRENT_LIST_DIR}/../node_interface/include
${CMAKE_CURRENT_LIST_DIR}/../include/util
${CMAKE_CURRENT_LIST_DIR}/../../..
)
target_link_libraries(GobotRPC_Node_RP2040_I2C
FreeRTOS-Kernel-Heap4
pico_stdlib
hardware_i2c
hardware_irq
)

View File

@@ -1,3 +1,5 @@
#include "crc16.hpp"
#define POLY 0x8408
/*
// 16 12 5

View File

@@ -12,6 +12,10 @@ enum GobotRPCTypes {
ERROR = 0b10
};
struct GobotRPCPackage_Req_Vacum {
uint8_t enable : 8;
};
#define GobotRPC_Package_DATA_OFFSET 2
#define CALC_SIZE_GobotRPC_PACKAGE(data_len) (data_len + GobotRPC_Package_DATA_OFFSET + 2)
@@ -24,5 +28,6 @@ public:
void assembleGobotRPCHeader(char * buffer, GobotRPCNumber number, GobotRPCTypes data_size, size_t);
void assembleCRC(char * buffer, size_t data_len);
bool checkCRC(char * buffer, size_t data_len);
GobotRPCHeaderInfo extractGobotRPCHeader(char * buffer);

View File

@@ -0,0 +1,32 @@
#pragma once
#include "protocol.hpp"
#include "node_interface_hardware.hpp"
#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
typedef void (*onPackageRxCallback)(void * args, char *data, uint16_t len, GobotRPCTypes type, GobotRPCNumber number);
class GobotRPC_NI {
private:
onPackageRxCallback onPackageRx;
void *onPackageRxArgs;
QueueHandle_t txQueue;
QueueHandle_t rxQueue;
TaskHandle_t rxTaskHandle;
unsigned int core;
public:
GobotRPC_NI(unsigned int core, QueueHandle_t txQueue, QueueHandle_t rxQueue);
void registerOnPackageRxCallback(onPackageRxCallback callback, void *context);
void sendPackage(char *data, size_t len, GobotRPCTypes type, GobotRPCNumber number);
void rxTask();
};

View File

@@ -0,0 +1,78 @@
#pragma once
#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/irq.h"
struct GobotRPC_NI_Package_Transport {
char data[32];
uint length;
uint index;
};
enum I2C_WRITE_STATE {
I2C_WRITE_STATE_FIRST,
I2C_WRITE_STATE_LENGTH,
I2C_WRITE_STATE_DATA,
};
enum I2C_READ_STATE {
I2C_READ_STAGE_FIRST,
I2C_READ_STAGE_DONE,
I2C_READ_STAGE_WIP,
I2C_READ_STAGE_INVALID
};
enum I2C_SLAVE_EVENT {
I2C_SLAVE_RECEIVE,
I2C_SLAVE_REQUEST,
I2C_SLAVE_FINISH
};
class GobotRPC_NI_Hardware {
};
struct GobotRPC_NI_Hardware_RP2040_I2C_PreTxQueues {
QueueHandle_t isrPreTxQueue;
QueueHandle_t isrTXQueue;
};
class GobotRPC_NI_Hardware_RP2040_I2C : public GobotRPC_NI_Hardware {
uint core;
QueueHandle_t isrPreTxQueue;
QueueHandle_t isrTXQueue;
QueueHandle_t isrRXQueue;
TaskHandle_t preTxTaskHandle;
uint i2cSDA_PIN;
uint i2cSCL_PIN;
uint int_PIN;
uint8_t i2cAddress;
I2C_WRITE_STATE writeState = I2C_WRITE_STATE_FIRST;
I2C_READ_STATE readState = I2C_READ_STAGE_INVALID;
GobotRPC_NI_Package_Transport rxPackage;
GobotRPC_NI_Package_Transport txPackage;
public:
i2c_inst_t * i2c_inst;
GobotRPC_NI_Hardware_RP2040_I2C(
xQueueHandle TXQueue, xQueueHandle RXQueue, uint core,
i2c_inst_t * i2c_inst,
uint8_t i2cAddress,
uint i2cSDA_PIN, uint i2cSCL_PIN, uint int_PIN
);
void onI2CIRQ(I2C_SLAVE_EVENT event, BaseType_t * xHigherPriorityTaskWoken);
void preTxTask();
};
extern GobotRPC_NI_Hardware_RP2040_I2C * g_gobotrpc_ni_hardware_rp2040_i2c;

View File

@@ -0,0 +1,66 @@
#include "node_interface.hpp"
#include "FreeRTOS.h"
#include "task.h"
#include <string.h>
static void rxTaskFn(void *pvParameters) {
GobotRPC_NI *ni = (GobotRPC_NI *)pvParameters;
ni->rxTask();
}
GobotRPC_NI::GobotRPC_NI(unsigned int core, QueueHandle_t txQueue, QueueHandle_t rxQueue) {
this->core = core;
this->txQueue = txQueue;
this->rxQueue = rxQueue;
this->onPackageRx = NULL;
this->onPackageRxArgs = NULL;
xTaskCreateAffinitySet(
rxTaskFn,
"GobotRPC_NI RX Task",
2048,
this,
4,
this->core,
&this->rxTaskHandle
);
}
void GobotRPC_NI::registerOnPackageRxCallback(onPackageRxCallback callback, void *context) {
this->onPackageRx = callback;
this->onPackageRxArgs = context;
}
void GobotRPC_NI::rxTask() {
while (true) {
GobotRPC_NI_Package_Transport package;
if (xQueueReceive(this->rxQueue, &package, portMAX_DELAY) == pdTRUE) {
GobotRPCHeaderInfo header = extractGobotRPCHeader(package.data);
if(this->onPackageRx != NULL) {
if (!checkCRC(package.data, header.len)) {
volatile int a = 0;
continue;
}
this->onPackageRx(
onPackageRxArgs,
package.data + GobotRPC_Package_DATA_OFFSET,
header.len, header.type, header.number
);
}
}
}
}
void GobotRPC_NI::sendPackage(char *data, size_t len, GobotRPCTypes type, GobotRPCNumber number) {
GobotRPC_NI_Package_Transport package;
memcpy(package.data + GobotRPC_Package_DATA_OFFSET, data, len);
assembleGobotRPCHeader(package.data, number, type, len);
assembleCRC(package.data, len);
xQueueSend(this->txQueue, &package, portMAX_DELAY);
}

View File

@@ -0,0 +1,124 @@
#include "node_interface_hardware.hpp"
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include <string.h>
GobotRPC_NI_Hardware_RP2040_I2C * g_gobotrpc_ni_hardware_rp2040_i2c;
i2c_inst_t * g_i2c_inst;
bool g_transfer_in_progress = false;
static void finish_transfer(BaseType_t * xHigherPriorityTaskWoken) {
if(g_transfer_in_progress) {
GobotRPC_NI_Hardware_RP2040_I2C * gobotrpc_ni = g_gobotrpc_ni_hardware_rp2040_i2c;
g_transfer_in_progress = false;
gobotrpc_ni->onI2CIRQ(I2C_SLAVE_FINISH, xHigherPriorityTaskWoken);
}
}
static void i2c_isr() {
GobotRPC_NI_Hardware_RP2040_I2C * gobotrpc_ni = g_gobotrpc_ni_hardware_rp2040_i2c;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
i2c_hw_t * hw = i2c_get_hw(g_i2c_inst);
uint32_t intr_stat = hw->intr_stat;
if (intr_stat == 0) {
return;
}
if (intr_stat & I2C_IC_INTR_STAT_R_TX_ABRT_BITS) {
hw->clr_tx_abrt;
finish_transfer(&xHigherPriorityTaskWoken);
}
if (intr_stat & I2C_IC_INTR_STAT_R_START_DET_BITS) {
hw->clr_start_det;
finish_transfer(&xHigherPriorityTaskWoken);
}
if (intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) {
hw->clr_stop_det;
finish_transfer(&xHigherPriorityTaskWoken);
}
if (intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) {
g_transfer_in_progress = true;
gobotrpc_ni->onI2CIRQ(I2C_SLAVE_RECEIVE, &xHigherPriorityTaskWoken);
}
if (intr_stat & I2C_IC_INTR_STAT_R_RD_REQ_BITS) {
hw->clr_rd_req;
g_transfer_in_progress = true;
gobotrpc_ni->onI2CIRQ(I2C_SLAVE_REQUEST, &xHigherPriorityTaskWoken);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
static void preTxTaskFn(void *pvParameters) {
GobotRPC_NI_Hardware_RP2040_I2C * hw = (GobotRPC_NI_Hardware_RP2040_I2C *)(pvParameters);
hw->preTxTask();
};
GobotRPC_NI_Hardware_RP2040_I2C::GobotRPC_NI_Hardware_RP2040_I2C(
xQueueHandle TXQueue, xQueueHandle RXQueue, uint core,
i2c_inst_t * i2c_inst,
uint8_t i2cAddress,
uint i2cSDA_PIN, uint i2cSCL_PIN, uint int_PIN
) {
g_gobotrpc_ni_hardware_rp2040_i2c = this;
g_i2c_inst = i2c_inst;
this->core = core;
this->isrRXQueue = RXQueue;
this->isrPreTxQueue = TXQueue;
this->isrTXQueue = xQueueCreate(3, sizeof(GobotRPC_NI_Package_Transport));
xTaskCreateAffinitySet(
preTxTaskFn,
"GobotRPC_NI Hardware RP2040 I2C PreTx Task",
2048,
this,
4,
this->core,
&this->preTxTaskHandle
);
this->i2cSDA_PIN = i2cSDA_PIN;
this->i2cSCL_PIN = i2cSCL_PIN;
this->int_PIN = int_PIN;
this->i2cAddress = i2cAddress;
this->i2c_inst = i2c_inst;
memset(&rxPackage.data, 0, sizeof(GobotRPC_NI_Package_Transport::data));
memset(&txPackage.data, 0, sizeof(GobotRPC_NI_Package_Transport::data));
gpio_init(i2cSDA_PIN);
gpio_init(i2cSCL_PIN);
gpio_set_function(i2cSDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(i2cSCL_PIN, GPIO_FUNC_I2C);
gpio_init(int_PIN);
gpio_set_dir(int_PIN, GPIO_OUT);
gpio_put(int_PIN, 0);
// Note: The I2C slave does clock stretching implicitly after a RD_REQ, while the Tx FIFO is empty.
// There is also an option to enable clock stretching while the Rx FIFO is full, but we leave it
// disabled since the Rx FIFO should never fill up (unless slave->handler() is way too slow).
i2c_set_slave_mode(i2c_inst, true, i2cAddress);
i2c_hw_t *hw = i2c_get_hw(i2c_inst);
// unmask necessary interrupts
hw->intr_mask = I2C_IC_INTR_MASK_M_RX_FULL_BITS |\
I2C_IC_INTR_MASK_M_RD_REQ_BITS |\
I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS |\
I2C_IC_INTR_MASK_M_STOP_DET_BITS |\
I2C_IC_INTR_MASK_M_START_DET_BITS;
// enable interrupt for current core
unsigned int intNum = i2c_inst == i2c0 ? I2C0_IRQ : I2C1_IRQ;
irq_set_exclusive_handler(intNum, i2c_isr);
irq_set_enabled(intNum, true);
}

View File

@@ -0,0 +1,98 @@
#include "node_interface_hardware.hpp"
#include "hardware/irq.h"
void GobotRPC_NI_Hardware_RP2040_I2C::onI2CIRQ(I2C_SLAVE_EVENT event, BaseType_t * xHigherPriorityTaskWoken) {
switch (event) {
case I2C_SLAVE_RECEIVE: { // I2C Write from Master
char data = i2c_read_byte_raw(i2c_inst);
switch (writeState) {
case I2C_WRITE_STATE_FIRST:
writeState = I2C_WRITE_STATE_LENGTH;
rxPackage.index = 0;
rxPackage.length = 0;
rxPackage.data[rxPackage.index++] = data;
break;
case I2C_WRITE_STATE_LENGTH:
rxPackage.data[rxPackage.index++] = data;
rxPackage.length = data;
writeState = I2C_WRITE_STATE_DATA;
break;
case I2C_WRITE_STATE_DATA:
rxPackage.data[rxPackage.index++] = data;
if(rxPackage.index == rxPackage.length) {
xQueueSendFromISR(isrRXQueue, &rxPackage, xHigherPriorityTaskWoken);
writeState = I2C_WRITE_STATE_FIRST;
} else {
writeState = I2C_WRITE_STATE_DATA;
}
break;
default:
break;
}
break;
}
case I2C_SLAVE_REQUEST: { // I2C Read from Master
if(xQueueIsQueueEmptyFromISR(isrTXQueue) == pdFALSE) {
readState = I2C_READ_STAGE_INVALID;
}
switch (readState) {
case I2C_READ_STAGE_INVALID:
i2c_write_byte_raw(i2c_inst, 0x00);
break;
case I2C_READ_STAGE_FIRST:
xQueueReceiveFromISR(isrTXQueue, &txPackage, xHigherPriorityTaskWoken);
txPackage.index = 0;
i2c_write_byte_raw(i2c_inst, txPackage.data[txPackage.index++]);
readState = I2C_READ_STAGE_WIP;
break;
case I2C_READ_STAGE_WIP:
if(txPackage.index == txPackage.length - 1) {
readState = I2C_READ_STAGE_DONE;
} else {
i2c_write_byte_raw(i2c_inst, txPackage.data[txPackage.index++]);
}
break;
case I2C_READ_STAGE_DONE:
i2c_write_byte_raw(i2c_inst, 0x00);
break;
default:
break;
}
break;
}
case I2C_SLAVE_FINISH:
writeState = I2C_WRITE_STATE_FIRST;
readState = I2C_READ_STAGE_FIRST;
rxPackage.index = 0;
break;
default:
break;
}
}
void GobotRPC_NI_Hardware_RP2040_I2C::preTxTask() {
GobotRPC_NI_Package_Transport pkg;
while (1) {
xQueueReceive(isrPreTxQueue, &pkg, portMAX_DELAY);
xQueueSend(isrTXQueue, &pkg, portMAX_DELAY);
gpio_put(int_PIN, 1);
}
}

View File

@@ -22,4 +22,10 @@ void assembleCRC(char * buffer, size_t data_len) {
unsigned short crc = crc16(buffer, data_len + GobotRPC_Package_DATA_OFFSET);
buffer[GobotRPC_Package_DATA_OFFSET + data_len + 1] = crc & 0xff;
buffer[GobotRPC_Package_DATA_OFFSET + data_len + 0] = (crc >> 8) & 0xff;
}
bool checkCRC(char * buffer, size_t data_len) {
unsigned short crc = crc16(buffer, data_len - 2);
unsigned short crc_received = buffer[data_len - GobotRPC_Package_DATA_OFFSET + 1] | (buffer[data_len - GobotRPC_Package_DATA_OFFSET + 0] << 8);
return crc == crc_received;
}

View File

@@ -17,7 +17,7 @@ void GobotRPC_TI_Hardware_RP2040_I2C::i2cTxTask() {
pullPackageCB(&pkg, pullPackageCBArgs);
xSemaphoreTake(i2cMutex, portMAX_DELAY);
unsigned int res = i2c_write_burst_blocking(i2c, pkg.addr & 0x7f, (uint8_t *)(&pkg.data), pkg.len);
unsigned int res = i2c_write_blocking(i2c, pkg.addr & 0x7f, (uint8_t * )(pkg.data), pkg.len, false);
xSemaphoreGive(i2cMutex);
if(res == PICO_ERROR_GENERIC) {

Binary file not shown.