#include #include #include #include #include #include #include #include #include #include #include #include #include "eos.h" #include "msgq.h" #include "power.h" #include "app.h" #include "net.h" #include "net_priv.h" #define SPI_GPIO_RTS 35 #define SPI_GPIO_CTS 3 #define SPI_GPIO_MOSI 40 #define SPI_GPIO_MISO 39 #define SPI_GPIO_SCLK 38 #define SPI_GPIO_CS 8 #define SPI_HOST SPI3_HOST #define NET_SIZE_BUFQ 8 #define NET_SIZE_SNDQ 8 #define NET_SIZE_HDR 3 #define NET_SIZE_BUF (EOS_NET_MTU + 4) // #define EOS_DEBUG 1 static EOSBufQ net_buf_q; static unsigned char *net_bufq_array[NET_SIZE_BUFQ]; static EOSMsgQ net_send_q; static EOSMsgItem net_sndq_array[NET_SIZE_SNDQ]; static NETConfig net_config; static eos_net_handler_t net_handler[EOS_NET_MAX_MTYPE]; static spi_bus_config_t net_spi_bus_cfg; static spi_slave_interface_config_t net_spi_iface_cfg; static const char *TAG = "EOS NET"; static void bad_handler(unsigned char mtype, EOSMessage *msg, uint16_t len) { ESP_LOGE(TAG, "BAD HANDLER: 0x%.2X LEN: %d", mtype, len); } static void IRAM_ATTR net_bridge(unsigned char mtype, EOSMessage *msg, uint16_t len) { EOSMessage _msg; int rv; eos_app_alloc(&_msg); if (len > _msg.size) { eos_app_free(&_msg); return; } memcpy(_msg.buffer, msg->buffer, len); rv = eos_app_send(mtype & EOS_NET_MTYPE_MASK, &_msg, len); if (rv) ESP_LOGE(TAG, "BRIDGE ERR: %d", rv); } static void IRAM_ATTR net_msg_handler(unsigned char mtype, EOSMessage *msg, uint16_t len) { uint8_t idx; idx = mtype & EOS_NET_MTYPE_FLAG_BRIDGE ? EOS_NET_MTYPE_BRIDGE : mtype & EOS_NET_MTYPE_MASK; if ((idx < EOS_NET_MAX_MTYPE) && (len <= msg->size)) { net_handler[idx](mtype, msg, len); } else { bad_handler(mtype, msg, len); } } /* Called after a transaction is queued and ready for pickup by master */ static void IRAM_ATTR _post_setup_cb(spi_slave_transaction_t *trans) { NETConfig *config = trans->user; gpio_set_level(config->gpio_cts, 0); } /* Called after transaction is sent/received */ static void IRAM_ATTR _post_trans_cb(spi_slave_transaction_t *trans) { NETConfig *config = trans->user; gpio_set_level(config->gpio_cts, 1); } static void net_sleep(NETConfig *config) { esp_err_t ret; uint8_t msgq_len; xSemaphoreTake(config->mutex, portMAX_DELAY); msgq_len = eos_msgq_len(config->send_q); if (msgq_len) { gpio_set_level(config->gpio_rts, 0); } else { gpio_set_level(config->gpio_rts, 1); } xSemaphoreGive(config->mutex); ret = spi_slave_free(config->spi_host); assert(ret == ESP_OK); eos_power_sleep_rdy(config->dev); } static void net_wake(NETConfig *config) { esp_err_t ret; uint8_t msgq_len; ret = spi_slave_initialize(config->spi_host, config->spi_bus_cfg, config->spi_iface_cfg, SPI_DMA_CH_AUTO); assert(ret == ESP_OK); xSemaphoreTake(config->mutex, portMAX_DELAY); config->sleep = 0; msgq_len = eos_msgq_len(config->send_q); if (msgq_len) { gpio_set_level(config->gpio_rts, 0); } else { gpio_set_level(config->gpio_rts, 1); } xSemaphoreGive(config->mutex); } void IRAM_ATTR eos_net_xchg_task(void *param) { NETConfig *config = param; int skip_msg = 0, sleep_msg = 0; unsigned char mtype = 0; unsigned char mtype_flags = 0; unsigned char *snd_buf; unsigned char *rcv_buf; EOSMessage msg; uint16_t snd_buf_len, rcv_buf_len; size_t trans_len; spi_bus_config_t *spi_bus_cfg = config->spi_bus_cfg; spi_slave_interface_config_t *spi_iface_cfg = config->spi_iface_cfg; spi_slave_transaction_t _spi_tr_cfg, *spi_tr_cfg; esp_err_t ret; if (!config->present) { vTaskDelete(NULL); return; } snd_buf = spi_bus_dma_memory_alloc(config->spi_host, NET_SIZE_BUF, MALLOC_CAP_DMA); assert(snd_buf != NULL); rcv_buf = spi_bus_dma_memory_alloc(config->spi_host, NET_SIZE_BUF, MALLOC_CAP_DMA); assert(rcv_buf != NULL); memset(&_spi_tr_cfg, 0, sizeof(_spi_tr_cfg)); spi_tr_cfg = &_spi_tr_cfg; spi_iface_cfg->post_setup_cb = _post_setup_cb; spi_iface_cfg->post_trans_cb = _post_trans_cb; spi_tr_cfg->tx_buffer = snd_buf; spi_tr_cfg->rx_buffer = rcv_buf; spi_tr_cfg->length = NET_SIZE_BUF * 8; spi_tr_cfg->user = config; if (esp_reset_reason() == ESP_RST_DEEPSLEEP) { _eos_net_deep_wake(config); vTaskSuspend(NULL); net_wake(config); } else { ret = spi_slave_initialize(config->spi_host, spi_bus_cfg, spi_iface_cfg, SPI_DMA_CH_AUTO); assert(ret == ESP_OK); } while (1) { if (!skip_msg) { int msg_free; xSemaphoreTake(config->mutex, portMAX_DELAY); msg_free = 0; snd_buf_len = 0; eos_msgq_pop(config->send_q, &mtype, &msg, &snd_buf_len); if (mtype) { #ifdef EOS_DEBUG ESP_LOGI(TAG, "SEND:0x%.2X DEV:0x%.8lX LEN:%d", mtype, config->dev, snd_buf_len); #endif snd_buf[0] = mtype; snd_buf[1] = snd_buf_len >> 8; snd_buf[2] = snd_buf_len & 0xFF; if (msg.buffer) { memcpy(snd_buf + NET_SIZE_HDR, msg.buffer, snd_buf_len); msg_free = 1; } } else if (!sleep_msg && config->sleep_req) { snd_buf[0] = EOS_NET_MTYPE_SLEEP; snd_buf[1] = 0; snd_buf[2] = 0; sleep_msg = 1; config->sleep_req = 0; config->sleep = 1; } else { gpio_set_level(config->gpio_rts, 1); snd_buf[0] = 0; snd_buf[1] = 0; snd_buf[2] = 0; } xSemaphoreGive(config->mutex); if (msg_free) _eos_net_free(config, &msg); } skip_msg = 0; rcv_buf[0] = 0; rcv_buf[1] = 0; rcv_buf[2] = 0; ret = spi_slave_transmit(config->spi_host, spi_tr_cfg, portMAX_DELAY); assert(ret == ESP_OK); trans_len = spi_tr_cfg->trans_len / 8; #ifdef EOS_DEBUG ESP_LOGI(TAG, "RECV:0x%.2X DEV:0x%.8lX LEN:%d", rcv_buf[0], config->dev, trans_len); #endif if (sleep_msg) { net_sleep(config); vTaskSuspend(NULL); net_wake(config); sleep_msg = 0; continue; } /* SPI reset */ if (trans_len < NET_SIZE_HDR) { if (snd_buf[0]) skip_msg = 1; continue; } mtype = rcv_buf[0] & EOS_NET_MTYPE_MASK; mtype_flags = rcv_buf[0] & ~EOS_NET_MTYPE_MASK; if (snd_buf[0] && (mtype_flags & EOS_NET_MTYPE_FLAG_ONEW)) { skip_msg = 1; } rcv_buf_len = (uint16_t)rcv_buf[1] << 8; rcv_buf_len |= (uint16_t)rcv_buf[2] & 0xFF; if (snd_buf[0] && (trans_len < snd_buf_len + NET_SIZE_HDR) && !skip_msg) { spi_tr_cfg->tx_buffer = snd_buf + trans_len; spi_tr_cfg->rx_buffer = rcv_buf + trans_len; spi_tr_cfg->length = (NET_SIZE_BUF - trans_len) * 8; ret = spi_slave_transmit(config->spi_host, spi_tr_cfg, portMAX_DELAY); assert(ret == ESP_OK); trans_len += spi_tr_cfg->trans_len / 8; spi_tr_cfg->tx_buffer = snd_buf; spi_tr_cfg->rx_buffer = rcv_buf; spi_tr_cfg->length = NET_SIZE_BUF * 8; } if (rcv_buf[0] == EOS_NET_MTYPE_SLEEP) { eos_power_sleep_req(config->dev); continue; } if (mtype == 0) continue; eos_msg_init(&msg, rcv_buf + NET_SIZE_HDR, EOS_NET_MTU); if (mtype_flags & EOS_NET_MTYPE_FLAG_REPL) eos_msg_set_flags(&msg, EOS_MSG_FLAG_RPLY_REQ); config->handler(rcv_buf[0], &msg, rcv_buf_len); if (eos_msg_flags(&msg) & EOS_MSG_FLAG_RPLY_REQ) { if (!(eos_msg_flags(&msg) & EOS_MSG_FLAG_RPLY_REP)) { // eos_net_reply(EOS_MTYPE_ERR, msg, 0); } spi_tr_cfg->tx_buffer = rcv_buf; spi_tr_cfg->rx_buffer = NULL; ret = spi_slave_transmit(config->spi_host, spi_tr_cfg, portMAX_DELAY); assert(ret == ESP_OK); spi_tr_cfg->tx_buffer = snd_buf; spi_tr_cfg->rx_buffer = rcv_buf; } } vTaskDelete(NULL); } void _eos_net_init_gpio(NETConfig *config) { /* Configuration for the handshake lines */ gpio_config_t io_conf = {}; gpio_set_level(config->gpio_rts, 1); gpio_set_level(config->gpio_cts, 1); io_conf.intr_type = GPIO_INTR_DISABLE; io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pull_up_en = GPIO_PULLUP_DISABLE; io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; io_conf.pin_bit_mask = BIT64(config->gpio_rts) | BIT64(config->gpio_cts); gpio_config(&io_conf); } void eos_net_init(void) { SemaphoreHandle_t mutex; SemaphoreHandle_t bufq_mutex; SemaphoreHandle_t bufq_semaph; int i; eos_msgq_init(&net_send_q, net_sndq_array, NET_SIZE_SNDQ); eos_bufq_init(&net_buf_q, net_bufq_array, NET_SIZE_BUFQ); for (i=0; ibufq_semaph, portMAX_DELAY); xSemaphoreTake(config->bufq_mutex, portMAX_DELAY); msg->buffer = eos_bufq_pop(config->buf_q); msg->size = EOS_NET_MTU; xSemaphoreGive(config->bufq_mutex); } void _eos_net_free(NETConfig *config, EOSMessage *msg) { xSemaphoreTake(config->bufq_mutex, portMAX_DELAY); eos_bufq_push(config->buf_q, msg->buffer); xSemaphoreGive(config->bufq_semaph); xSemaphoreGive(config->bufq_mutex); } void eos_net_alloc(EOSMessage *msg) { _eos_net_alloc(&net_config, msg); } void eos_net_free(EOSMessage *msg) { _eos_net_free(&net_config, msg); } int _eos_net_send(NETConfig *config, unsigned char mtype, EOSMessage *msg, uint16_t len) { int wake, rv; wake = eos_msg_flags(msg) & EOS_MSG_FLAG_WAKE; rv = EOS_OK; xSemaphoreTake(config->mutex, portMAX_DELAY); if (!config->present) rv = EOS_ERR_NOTFOUND; if (rv) goto net_send_fin; if (!wake && (config->sleep || config->sleep_req)) rv = EOS_ERR_BUSY; if (rv) goto net_send_fin; rv = eos_msgq_push(config->send_q, mtype, msg, len); if (rv) goto net_send_fin; /* we can't wake app module by pulling rts low */ gpio_set_level(config->gpio_rts, 0); net_send_fin: xSemaphoreGive(config->mutex); if (rv) _eos_net_free(config, msg); return rv; } int eos_net_send(unsigned char mtype, EOSMessage *msg, uint16_t len) { return _eos_net_send(&net_config, mtype, msg, len); } void eos_net_reply(unsigned char mtype, EOSMessage *msg, uint16_t len) { unsigned char *buffer = msg->buffer - NET_SIZE_HDR; if (!(eos_msg_flags(msg) & EOS_MSG_FLAG_RPLY_REQ)) return; if (eos_msg_flags(msg) & EOS_MSG_FLAG_RPLY_REP) return; buffer[0] = mtype; buffer[1] = len >> 8; buffer[2] = len & 0xFF; eos_msg_set_flags(msg, EOS_MSG_FLAG_RPLY_REP); } void _eos_net_sleep_req(NETConfig *config) { int sleep, present; xSemaphoreTake(config->mutex, portMAX_DELAY); sleep = config->sleep; present = config->present; if (!sleep && present) { config->sleep_req = 1; gpio_set_level(config->gpio_rts, 0); } xSemaphoreGive(config->mutex); if (!present) eos_power_sleep_rdy(config->dev); } void _eos_net_wake(NETConfig *config) { int sleep, present; xSemaphoreTake(config->mutex, portMAX_DELAY); present = config->present; xSemaphoreGive(config->mutex); if (!present) return; do { vTaskResume(config->xchg_task_handle); vTaskDelay(10 / portTICK_PERIOD_MS); xSemaphoreTake(config->mutex, portMAX_DELAY); sleep = config->sleep; xSemaphoreGive(config->mutex); } while (sleep); } void _eos_net_deep_sleep(NETConfig *config) { gpio_hold_en(config->gpio_cts); } void _eos_net_deep_wake(NETConfig *config) { gpio_hold_dis(config->gpio_cts); } void eos_net_sleep_req(void) { _eos_net_sleep_req(&net_config); } void eos_net_wake(void) { _eos_net_wake(&net_config); } void eos_net_deep_sleep(void) { _eos_net_deep_sleep(&net_config); } void eos_net_deep_wake(void) { _eos_net_deep_wake(&net_config); } void eos_net_set_handler(unsigned char mtype, eos_net_handler_t handler) { if (handler == NULL) handler = bad_handler; if (mtype < EOS_NET_MAX_MTYPE) net_handler[mtype] = handler; }