ESP32-PaxCounter/src/spislave.cpp
2018-11-03 20:29:02 +01:00

152 lines
4.9 KiB
C++

/*
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
Copyright 2018 Christian Ambach <christian.ambach@deutschebahn.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
NOTICE:
Parts of the source files in this repository are made available under different
licenses. Refer to LICENSE.txt file in repository for more details.
*/
#include "spislave.h"
#include <driver/spi_slave.h>
#include <sys/param.h>
#include <rom/crc.h>
static const char TAG[] = __FILE__;
#define HEADER_SIZE 4
// SPI transaction size needs to be at least 8 bytes and dividable by 4, see
// https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/spi_slave.html
#define BUFFER_SIZE \
(MAX(8, HEADER_SIZE + PAYLOAD_BUFFER_SIZE) + \
(4 - MAX(8, HEADER_SIZE + PAYLOAD_BUFFER_SIZE) % 4))
DMA_ATTR uint8_t txbuf[BUFFER_SIZE];
DMA_ATTR uint8_t rxbuf[BUFFER_SIZE];
QueueHandle_t SPISendQueue;
TaskHandle_t spiTask;
void spi_slave_task(void *param) {
while (1) {
MessageBuffer_t msg;
size_t transaction_size;
memset(txbuf, 0, sizeof(txbuf));
memset(rxbuf, 0, sizeof(rxbuf));
if (xQueueReceive(SPISendQueue, &msg, portMAX_DELAY) != pdTRUE) {
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
continue;
}
uint8_t *messageType = txbuf + 2;
*messageType = msg.MessagePort;
uint8_t *messageSize = txbuf + 3;
*messageSize = msg.MessageSize;
memcpy(txbuf + HEADER_SIZE, &msg.Message, msg.MessageSize);
transaction_size = HEADER_SIZE + msg.MessageSize;
transaction_size += (4 - transaction_size % 4);
uint16_t *crc = (uint16_t *)txbuf;
*crc = crc16_be(0, messageType, msg.MessageSize + HEADER_SIZE - 2);
spi_slave_transaction_t spi_transaction = {0};
spi_transaction.length = transaction_size * 8;
spi_transaction.tx_buffer = txbuf;
spi_transaction.rx_buffer = rxbuf;
ESP_LOGI(TAG, "Prepared SPI transaction for %zu bytes", transaction_size);
ESP_LOG_BUFFER_HEXDUMP(TAG, txbuf, transaction_size, ESP_LOG_DEBUG);
esp_err_t ret =
spi_slave_transmit(HSPI_HOST, &spi_transaction, portMAX_DELAY);
ESP_LOG_BUFFER_HEXDUMP(TAG, rxbuf, transaction_size, ESP_LOG_DEBUG);
ESP_LOGI(TAG, "Transaction finished with size %zu bits",
spi_transaction.trans_len);
}
}
esp_err_t spi_init() {
#ifndef HAS_SPI
return ESP_OK;
#else
SPISendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
if (SPISendQueue == 0) {
ESP_LOGE(TAG, "Could not create SPI send queue. Aborting.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "SPI send queue created, size %d Bytes",
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
spi_bus_config_t spi_bus_cfg = {.mosi_io_num = SPI_MOSI,
.miso_io_num = SPI_MISO,
.sclk_io_num = SPI_SCLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 0,
.flags = 0};
spi_slave_interface_config_t spi_slv_cfg = {.spics_io_num = SPI_CS,
.flags = 0,
.queue_size = 1,
.mode = 0,
.post_setup_cb = NULL,
.post_trans_cb = NULL};
gpio_set_pull_mode(SPI_MOSI, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(SPI_SCLK, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(SPI_CS, GPIO_PULLUP_ONLY);
ESP_LOGI(TAG, "Starting SPIloop...");
xTaskCreate(spi_slave_task, "spiloop", 4096, (void *)NULL, 2, &spiTask);
esp_err_t ret =
spi_slave_initialize(HSPI_HOST, &spi_bus_cfg, &spi_slv_cfg, 1);
return ret;
#endif
}
void spi_enqueuedata(uint8_t messageType, MessageBuffer_t *message) {
// enqueue message in SPI send queue
#ifdef HAS_SPI
BaseType_t ret =
xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0);
if (ret == pdTRUE) {
ESP_LOGI(TAG, "%d bytes enqueued for SPI interface",
message->MessageSize);
} else {
ESP_LOGW(TAG, "SPI sendqueue is full");
}
#endif
}
void spi_queuereset(void) {
#ifdef HAS_SPI
xQueueReset(SPISendQueue);
#endif
}
void spi_housekeeping(void) {
#ifdef HAS_SPI
ESP_LOGD(TAG, "spiloop %d bytes left", uxTaskGetStackHighWaterMark(spiTask));
#endif
}