451 lines
12 KiB
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,
|
|
};
|
|
|
|
static nh_shared_if_t s_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 = &s_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(&s_nh_shared_if) != NH_RET_SUCCESS) {
|
|
return -3;
|
|
}
|
|
|
|
if (xTaskCreate(app_nh_impl_shared_if_task, "NH_SHARED_IF", 512, &s_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_PinInt1);
|
|
|
|
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(&s_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(&s_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] event 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(&s_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);
|
|
} |