LPCXpresso55S69_ESP_Hosted/src/app_nh_impl.c

451 lines
12 KiB
C

/* Board */
#include "board.h"
#include "clock_config.h"
#include "pin_mux.h"
/* FreeRTOS */
/* clang-format off */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* clang-format on */
/* SDK drivers */
#include "fsl_gpio.h"
#include "fsl_pint.h"
#include "fsl_spi.h"
/* Debug Console */
#include "fsl_debug_console.h"
/* Private */
#include "app_nh_impl.h"
static int app_nh_impl_spi_init(void);
static int app_nh_impl_pin_init(void);
static inline bool app_nh_impl_is_isr(void);
static void app_nh_impl_drdy_callback(pint_pin_int_t pintr, uint32_t pmatch_status);
static void app_nh_impl_hs_callback(pint_pin_int_t pintr, uint32_t pmatch_status);
static nh_ret_t app_nh_impl_ops_xfer(void *handle, uint8_t *tx_data, uint8_t *rx_data, uint32_t len);
static nh_ret_t app_nh_impl_ops_drdy_read(void *handle, bool *rdy);
static nh_ret_t app_nh_impl_ops_hs_poll(void *handle, uint32_t timeout_ms);
static void app_nh_impl_cb_startup(void *handle, nh_event_init_t *init_data);
static void app_nh_impl_cb_init(void *handle);
static nh_ret_t app_nh_impl_buf_allocate(void *handle, uint8_t **buf, uint32_t size);
static nh_ret_t app_nh_impl_buf_free(void *handle, uint8_t *buf);
static nh_ret_t app_nh_impl_semaphore_create(void *handle, nh_osa_semaphore_t *sem);
static nh_ret_t app_nh_impl_semaphore_take(void *handle, nh_osa_semaphore_t sem, uint32_t timeout_msec);
static nh_ret_t app_nh_impl_semaphore_give(void *handle, nh_osa_semaphore_t sem);
static nh_ret_t app_nh_impl_semaphore_destroy(void *handle, nh_osa_semaphore_t sem);
static nh_ret_t app_nh_impl_queue_create(void *handle, nh_osa_queue_t *queue, uint32_t item_size, uint32_t max_length);
static nh_ret_t app_nh_impl_queue_enqueue(void *handle, nh_osa_queue_t queue, void *item, uint32_t timeout_msec);
static nh_ret_t app_nh_impl_queue_dequeue(void *handle, nh_osa_queue_t queue, void *item, uint32_t timeout_msec);
static nh_ret_t app_impl_queue_destroy(void *handle, nh_osa_queue_t queue);
static void app_nh_impl_shared_if_task(void *parameters);
static void app_nh_impl_ctrl_task(void *parameters);
static SemaphoreHandle_t s_esp_init_semphore;
static nh_osa_t s_nh_osa = {
.buf_allocate = app_nh_impl_buf_allocate,
.buf_free = app_nh_impl_buf_free,
.sem_create = app_nh_impl_semaphore_create,
.sem_give = app_nh_impl_semaphore_give,
.sem_take = app_nh_impl_semaphore_take,
.sem_destroy = app_nh_impl_semaphore_destroy,
.queue_create = app_nh_impl_queue_create,
.queue_enqueue = app_nh_impl_queue_enqueue,
.queue_dequeue = app_nh_impl_queue_dequeue,
.queue_destroy = app_impl_queue_destroy,
};
nh_shared_if_t g_nh_shared_if = {
.osa = &s_nh_osa,
.ops =
{
.xfer = app_nh_impl_ops_xfer,
.drdy_read = app_nh_impl_ops_drdy_read,
.hs_poll = app_nh_impl_ops_hs_poll,
},
.cb =
{
.init = app_nh_impl_cb_startup,
},
};
nh_ctrl_api_t g_nh_ctrl_api = {
.osa = &s_nh_osa,
.shared_if = &g_nh_shared_if,
.cb =
{
.init = app_nh_impl_cb_init,
},
};
int app_nh_impl_init(void) {
s_esp_init_semphore = xSemaphoreCreateBinary();
if (s_esp_init_semphore == NULL) {
return -1;
}
if (app_nh_impl_pin_init() != 0) {
return -1;
}
if (app_nh_impl_spi_init() != 0) {
return -2;
}
if (nh_shared_if_init(&g_nh_shared_if) != NH_RET_SUCCESS) {
return -3;
}
if (xTaskCreate(app_nh_impl_shared_if_task, "NH_IF", 512, &g_nh_shared_if, 2, NULL) != pdPASS) {
return -4;
}
if (nh_ctrl_api_init(&g_nh_ctrl_api) != NH_RET_SUCCESS) {
return -5;
}
if (xTaskCreate(app_nh_impl_ctrl_task, "NH_CTRL", 512, &g_nh_ctrl_api, 2, NULL) != pdPASS) {
return -6;
}
/* FIXME: De-init properly */
if (xSemaphoreTake(s_esp_init_semphore, pdMS_TO_TICKS(5000)) != pdPASS) {
PRINTF("Did not received ESPInit event in time, bailing out (assumed soft reset).\r\n");
}
return 0;
}
static int app_nh_impl_spi_init(void) {
spi_master_config_t cfg;
/* Main Clock to SPI */
CLOCK_AttachClk(kMAIN_CLK_to_HSLSPI);
SPI_MasterGetDefaultConfig(&cfg);
cfg.baudRate_Bps = 20000000UL;
cfg.sselNum = kSPI_Ssel1;
cfg.phase = kSPI_ClockPhaseSecondEdge; /* SPI Mode 1 */
if (SPI_MasterInit(SPI8, &cfg, CLOCK_GetHsLspiClkFreq()) != kStatus_Success) {
return -1;
}
return 0;
}
static int app_nh_impl_pin_init(void) {
/* Configure pin interrupt */
PINT_Init(PINT);
PINT_PinInterruptConfig(PINT, kPINT_PinInt0, kPINT_PinIntEnableRiseEdge, app_nh_impl_hs_callback);
PINT_EnableCallbackByIndex(PINT, kPINT_PinInt0);
PINT_PinInterruptConfig(PINT, kPINT_PinInt1, kPINT_PinIntEnableRiseEdge, app_nh_impl_drdy_callback);
PINT_EnableCallbackByIndex(PINT, kPINT_PinInt1);
EnableIRQ(PIN_INT0_IRQn);
NVIC_SetPriority(PIN_INT0_IRQn, 5);
EnableIRQ(PIN_INT1_IRQn);
NVIC_SetPriority(PIN_INT1_IRQn, 5);
return 0;
}
static inline bool app_nh_impl_is_isr(void) {
if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) {
/* We are in ISR... */
return true;
}
return false;
}
static void app_nh_impl_drdy_callback(pint_pin_int_t pintr, uint32_t pmatch_status) {
/* If there's a packet to be received by host, the DRDY is set high. */
if (GPIO_PinRead(GPIO, BOARD_INITMIKROEPINS_ESP_HS_PORT, BOARD_INITMIKROEPINS_ESP_HS_PIN)) {
nh_shared_if_inject_data_ready(&g_nh_shared_if);
}
}
static void app_nh_impl_hs_callback(pint_pin_int_t pintr, uint32_t pmatch_status) {
/* If the DRDY is high when HS rises, there's another packet waiting... */
if (GPIO_PinRead(GPIO, BOARD_INITMIKROEPINS_ESP_DRDY_PORT, BOARD_INITMIKROEPINS_ESP_DRDY_PIN)) {
nh_shared_if_inject_data_ready(&g_nh_shared_if);
}
}
static nh_ret_t app_nh_impl_ops_drdy_read(void *handle, bool *rdy) {
if (GPIO_PinRead(GPIO, BOARD_INITMIKROEPINS_ESP_DRDY_PORT, BOARD_INITMIKROEPINS_ESP_DRDY_PIN)) {
*rdy = true;
} else {
*rdy = false;
}
return NH_RET_SUCCESS;
}
static nh_ret_t app_nh_impl_ops_hs_poll(void *handle, uint32_t timeout_ms) {
TickType_t tick_start = xTaskGetTickCount();
while (GPIO_PinRead(GPIO, BOARD_INITMIKROEPINS_ESP_HS_PORT, BOARD_INITMIKROEPINS_ESP_HS_PIN) == 0) {
vTaskDelay(pdMS_TO_TICKS(20));
if (xTaskGetTickCount() - tick_start > pdMS_TO_TICKS(timeout_ms)) {
return NH_RET_TIMEOUT;
}
}
return NH_RET_SUCCESS;
}
static nh_ret_t app_nh_impl_ops_xfer(void *handle, uint8_t *tx_data, uint8_t *rx_data, uint32_t len) {
spi_transfer_t xfer = {
.txData = tx_data,
.rxData = rx_data,
.dataSize = len,
.configFlags = kSPI_FrameAssert,
};
if (SPI_MasterTransferBlocking(SPI8, &xfer) != kStatus_Success) {
return NH_RET_FAIL;
}
return NH_RET_SUCCESS;
}
static void app_nh_impl_cb_startup(void *handle, nh_event_init_t *init_data) {
PRINTF("Received init data and device capabilities from ESP:\r\n");
char *buf;
switch (init_data->chip_id) {
case NH_ESP_INIT_CHIP_ESP32:
buf = "ESP32";
break;
case NH_ESP_INIT_CHIP_ESP32S2:
buf = "ESP32S2";
break;
case NH_ESP_INIT_CHIP_ESP32S3:
buf = "ESP32S3";
break;
case NH_ESP_INIT_CHIP_ESP32C2:
buf = "ESP32C2";
break;
case NH_ESP_INIT_CHIP_ESP32C3:
buf = "ESP32C3";
break;
default:
buf = "UNKNOWN";
break;
}
PRINTF("Target SoC is: %s\r\n", buf);
PRINTF("Maximum SPI frequency: %dMHz\r\n", init_data->spi_freq);
PRINTF("Target capabilities: ");
if (init_data->capabilities & NH_EVENT_INIT_CAP_WLAN_SPI) {
PRINTF("WLAN_SPI | ");
}
if (init_data->capabilities & NH_EVENT_INIT_CAP_BT_SPI) {
PRINTF("BT_SPI | ");
}
if (init_data->capabilities & NH_EVENT_INIT_CAP_WLAN_SDIO) {
PRINTF("WLAN_SDIO | ");
}
if (init_data->capabilities & NH_EVENT_INIT_CAP_BT_SDIO) {
PRINTF("BT_SDIO | ");
}
if (init_data->capabilities & NH_EVENT_INIT_CAP_BT_UART) {
PRINTF("BT_UART | ");
}
if (init_data->capabilities & NH_EVENT_INIT_CAP_BLE_ONLY) {
PRINTF("BLE_ONLY | ");
}
if (init_data->capabilities & NH_EVENT_INIT_CAP_BR_EDR_ONLY) {
PRINTF("BR_EDR_ONLY | ");
}
if (init_data->capabilities & NH_EVENT_INIT_CAP_CHECKSUM) {
PRINTF("CHECKSUM | ");
}
PRINTF("\r\n");
}
static void app_nh_impl_cb_init(void *handle) {
PRINTF("ESPStart event received.\r\n");
xSemaphoreGive(s_esp_init_semphore);
}
static nh_ret_t app_nh_impl_buf_allocate(void *handle, uint8_t **buf, uint32_t size) {
*buf = pvPortMalloc(size);
if (*buf == NULL) {
return NH_RET_FAIL;
}
return NH_RET_SUCCESS;
}
static nh_ret_t app_nh_impl_buf_free(void *handle, uint8_t *buf) {
vPortFree(buf);
return NH_RET_SUCCESS;
}
static nh_ret_t app_nh_impl_semaphore_create(void *handle, nh_osa_semaphore_t *sem) {
*sem = xSemaphoreCreateBinary();
if (*sem == NULL) {
return NH_RET_FAIL;
}
return NH_RET_SUCCESS;
}
static nh_ret_t app_nh_impl_semaphore_take(void *handle, nh_osa_semaphore_t sem, uint32_t timeout_msec) {
nh_ret_t ret = NH_RET_SUCCESS;
if (app_nh_impl_is_isr()) {
if (timeout_msec != 0) {
/* Block in ISR is not permitted */
return NH_RET_FAIL;
}
BaseType_t higher_prio_task_woken = pdFALSE;
if (xSemaphoreTakeFromISR(sem, &higher_prio_task_woken) != pdPASS) {
ret = NH_RET_TIMEOUT;
}
portYIELD_FROM_ISR(higher_prio_task_woken);
} else {
if (xSemaphoreTake(sem, pdMS_TO_TICKS(timeout_msec)) != pdPASS) {
ret = NH_RET_TIMEOUT;
}
}
return ret;
}
static nh_ret_t app_nh_impl_semaphore_give(void *handle, nh_osa_semaphore_t sem) {
nh_ret_t ret = NH_RET_SUCCESS;
if (app_nh_impl_is_isr()) {
BaseType_t higher_prio_task_woken = pdFALSE;
if (xSemaphoreGiveFromISR(sem, &higher_prio_task_woken) != pdPASS) {
ret = NH_RET_FAIL;
}
portYIELD_FROM_ISR(higher_prio_task_woken);
} else {
if (xSemaphoreGive(sem) != pdPASS) {
ret = NH_RET_FAIL;
}
}
return ret;
}
static nh_ret_t app_nh_impl_semaphore_destroy(void *handle, nh_osa_semaphore_t sem) {
vSemaphoreDelete(sem);
return NH_RET_SUCCESS;
}
static nh_ret_t app_nh_impl_queue_create(void *handle, nh_osa_queue_t *queue, uint32_t item_size, uint32_t max_length) {
*queue = xQueueCreate(max_length, item_size);
if (*queue == NULL) {
return NH_RET_FAIL;
}
return NH_RET_SUCCESS;
}
static nh_ret_t app_nh_impl_queue_enqueue(void *handle, nh_osa_queue_t queue, void *item, uint32_t timeout_msec) {
nh_ret_t ret = NH_RET_SUCCESS;
if (app_nh_impl_is_isr()) {
if (timeout_msec != 0) {
return NH_RET_FAIL;
}
BaseType_t higher_prio_task_woken = pdFALSE;
if (xQueueSendFromISR(queue, item, &higher_prio_task_woken) != pdPASS) {
ret = NH_RET_TIMEOUT;
}
portYIELD_FROM_ISR(higher_prio_task_woken);
} else {
if (xQueueSend(queue, item, pdMS_TO_TICKS(timeout_msec)) != pdPASS) {
ret = NH_RET_TIMEOUT;
}
}
return ret;
}
static nh_ret_t app_nh_impl_queue_dequeue(void *handle, nh_osa_queue_t queue, void *item, uint32_t timeout_msec) {
nh_ret_t ret = NH_RET_SUCCESS;
if (app_nh_impl_is_isr()) {
if (timeout_msec != 0) {
return NH_RET_FAIL;
}
BaseType_t higher_prio_task_woken = pdFALSE;
if (xQueueReceiveFromISR(queue, item, &higher_prio_task_woken) != pdPASS) {
ret = NH_RET_TIMEOUT;
}
portYIELD_FROM_ISR(higher_prio_task_woken);
} else {
if (xQueueReceive(queue, item, pdMS_TO_TICKS(timeout_msec)) != pdPASS) {
ret = NH_RET_TIMEOUT;
}
}
return ret;
}
static nh_ret_t app_impl_queue_destroy(void *handle, nh_osa_queue_t queue) {
vQueueDelete(queue);
return NH_RET_SUCCESS;
}
static void app_nh_impl_shared_if_task(void *parameters) {
for (;;) {
nh_shared_if_task(&g_nh_shared_if);
}
vTaskDelete(NULL);
}
static void app_nh_impl_ctrl_task(void *parameters) {
for (;;) {
nh_ctrl_api_task(&g_nh_ctrl_api);
}
vTaskDelete(NULL);
}