add some code

This commit is contained in:
2025-09-05 13:25:11 +08:00
parent 9ff0a99e7a
commit 3cf1229a85
8911 changed files with 2535396 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
#include "esp_check.h"
#include "sscma_client_flasher.h"
#include "sscma_client_flasher_interface.h"
static const char *TAG = "sscma_client.flasher";
esp_err_t sscma_client_flasher_start(sscma_client_flasher_handle_t handle, size_t offset)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(handle->start, ESP_ERR_NOT_SUPPORTED, TAG, "not supported");
return handle->start(handle, offset);
}
esp_err_t sscma_client_flasher_write(sscma_client_flasher_handle_t handle, const void *data, size_t len)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(handle->write, ESP_ERR_NOT_SUPPORTED, TAG, "not supported");
return handle->write(handle, data, len);
}
esp_err_t sscma_client_flasher_finish(sscma_client_flasher_handle_t handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(handle->finish, ESP_ERR_NOT_SUPPORTED, TAG, "not supported");
return handle->finish(handle);
}
esp_err_t sscma_client_flasher_abort(sscma_client_flasher_handle_t handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(handle->abort, ESP_ERR_NOT_SUPPORTED, TAG, "not supported");
return handle->abort(handle);
}
esp_err_t sscma_client_flasher_delete(sscma_client_flasher_handle_t handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(handle->del, ESP_ERR_NOT_SUPPORTED, TAG, "not supported");
return handle->del(handle);
}

View File

@@ -0,0 +1,596 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/cdefs.h>
#include "sdkconfig.h"
#if CONFIG_SSCMA_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_timer.h"
#include "sscma_client_commands.h"
#include "sscma_client_io.h"
#include "sscma_client_io_interface.h"
#include "sscma_client_flasher.h"
#include "sscma_client_flasher_interface.h"
#include "driver/spi_master.h"
static const char *TAG = "sscma_client.flasher.we2.spi";
typedef enum {
REG_OFF = 0x00,
REG_BYPASS_CACHE = 0x00, // removeds
REG_ISP_WRITE_EN = 0x01,
REG_XIP_EN = 0x02,
REG_ISP_TEST_MODE = 0x04,
REG_D8_ISP_EN = 0x01,
REG_D8_TEST_MODE = 0x02,
REG_D8_SPI_DO_EN = 0x04,
} FlashSubMod_t;
#define OTA_MAX_OFFSET (0x1000000) // 16 MB
#define OTA_BASE_ADDR (0x38000000)
#define OTA_START_OFFSET (0x400000)
#define OTA_CONTROL_ADDR (0x51010000)
#define OTA_PPDONE_COUNT_ADDR (OTA_CONTROL_ADDR + 0x40)
#define OTA_CRC_WRITTEN_ADDR (OTA_CONTROL_ADDR + 0x04)
#define OTA_CRC_READ_ADDR (OTA_CONTROL_ADDR + 0x08)
#define OTA_CRC_CLEAR_ADDR (OTA_CONTROL_ADDR + 0x30)
#define OTA_CONTROL_REG_DEFAULT (0x028C208B)
#define OTA_CHUNKED_SIZE (256)
#define OTA_CMD_WRITE (0xF2)
#define OTA_CMD_READ (0xF3)
#define OTA_ENABLE_REG (0xD8)
#define OTA_STATUS_REG (0x0C)
#define OTA_BURST_MODE_REG (0x0D)
#define OTA_BURST_ENABLE_REG (0x13)
#define OTA_BURST_WRITE_REG (0x00)
#define OTA_PP_STATUS_REG (0x1D)
static esp_err_t sscma_client_flasher_we2_start(sscma_client_flasher_handle_t flasher, size_t offset);
static esp_err_t sscma_client_flasher_we2_write(sscma_client_flasher_handle_t flasher, const void *data, size_t len);
static esp_err_t sscma_client_flasher_we2_finish(sscma_client_flasher_handle_t flasher);
static esp_err_t sscma_client_flasher_we2_abort(sscma_client_flasher_handle_t flasher);
static esp_err_t sscma_client_flasher_we2_del(sscma_client_flasher_handle_t flasher);
typedef struct
{
sscma_client_flasher_t base; /*!< The base class. */
sscma_client_io_t *io; /*!< The IO interface. */
esp_io_expander_handle_t io_expander; /* !< IO expander handle */
int reset_gpio_num; /*!< The reset GPIO number. */
bool reset_level; /*!< The reset GPIO level. */
size_t offset; /*!< The offset. */
uint32_t count; /*!< The Page Program Count. */
void *user_ctx; /* !< User context */
uint8_t data[OTA_CHUNKED_SIZE + 6]; /* !< The data buffer. */
SemaphoreHandle_t lock; /*!< The lock. */
} sscma_client_flasher_we2_spi_t;
esp_err_t sscma_client_new_flasher_we2_spi(const sscma_client_io_handle_t io, const sscma_client_flasher_we2_config_t *config, sscma_client_flasher_handle_t *ret_flasher)
{
esp_err_t ret = ESP_OK;
sscma_client_flasher_we2_spi_t *flasher_we2 = NULL;
ESP_RETURN_ON_FALSE(io && config && ret_flasher, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
flasher_we2 = (sscma_client_flasher_we2_spi_t *)calloc(1, sizeof(sscma_client_flasher_we2_spi_t));
ESP_RETURN_ON_FALSE(flasher_we2, ESP_ERR_NO_MEM, TAG, "no mem for flasher");
flasher_we2->reset_gpio_num = config->reset_gpio_num;
flasher_we2->reset_level = config->flags.reset_high_active ? 1 : 0;
flasher_we2->io = io;
flasher_we2->base.start = sscma_client_flasher_we2_start;
flasher_we2->base.write = sscma_client_flasher_we2_write;
flasher_we2->base.finish = sscma_client_flasher_we2_finish;
flasher_we2->base.abort = sscma_client_flasher_we2_abort;
flasher_we2->base.del = sscma_client_flasher_we2_del;
if (config->flags.reset_use_expander)
{
flasher_we2->io_expander = config->io_expander;
ESP_GOTO_ON_FALSE(flasher_we2->io_expander, ESP_ERR_INVALID_ARG, err, TAG, "invalid io expander");
ESP_GOTO_ON_ERROR(esp_io_expander_set_dir(flasher_we2->io_expander, config->reset_gpio_num, IO_EXPANDER_OUTPUT), err, TAG, "set GPIO direction failed");
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_INPUT,
.pin_bit_mask = 1ULL << config->reset_gpio_num,
};
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
}
flasher_we2->lock = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(flasher_we2->lock, ESP_ERR_NO_MEM, err, TAG, "no mem for flasher lock");
*ret_flasher = &flasher_we2->base;
return ESP_OK;
err:
if (flasher_we2->lock != NULL)
{
vSemaphoreDelete(flasher_we2->lock);
}
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_dir(flasher_we2->io_expander, flasher_we2->reset_gpio_num, IO_EXPANDER_INPUT);
}
else
{
gpio_reset_pin(flasher_we2->reset_gpio_num);
}
}
if (flasher_we2 != NULL)
{
free(flasher_we2);
}
return ret;
}
esp_err_t sscma_client_flasher_we2_del(sscma_client_flasher_handle_t flasher)
{
sscma_client_flasher_we2_spi_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_spi_t, base);
if (flasher_we2->lock != NULL)
{
vSemaphoreDelete(flasher_we2->lock);
}
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_dir(flasher_we2->io_expander, flasher_we2->reset_gpio_num, IO_EXPANDER_INPUT);
}
else
{
gpio_reset_pin(flasher_we2->reset_gpio_num);
}
}
if (flasher != NULL)
{
free(flasher);
}
return ESP_OK;
}
static esp_err_t sscma_client_flasher_we2_start(sscma_client_flasher_handle_t flasher, size_t offset)
{
esp_err_t ret = ESP_OK;
int64_t start = 0;
uint32_t addr = 0;
size_t remain = 0;
uint32_t status = 0;
sscma_client_flasher_we2_spi_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_spi_t, base);
spi_transaction_t spi_trans = {};
// assert(offset >= OTA_START_OFFSET);
xSemaphoreTake(flasher_we2->lock, portMAX_DELAY);
flasher_we2->count = 0;
flasher_we2->offset = offset;
ESP_GOTO_ON_ERROR(spi_device_acquire_bus(flasher_we2->io->handle, portMAX_DELAY), err, TAG, "acquire spi bus failed");
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = OTA_ENABLE_REG;
flasher_we2->data[2] = REG_D8_ISP_EN + REG_D8_TEST_MODE + REG_D8_SPI_DO_EN;
spi_trans.length = 3 * 8;
spi_trans.tx_buffer = flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = OTA_BURST_ENABLE_REG;
flasher_we2->data[2] = 0x31;
spi_trans.length = 3 * 8;
spi_trans.tx_buffer = flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = OTA_BURST_MODE_REG;
flasher_we2->data[2] = 0x11;
spi_trans.length = 3 * 8;
spi_trans.tx_buffer = flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = 0x00;
flasher_we2->data[2] = (OTA_CONTROL_ADDR & 0xFF);
flasher_we2->data[3] = (OTA_CONTROL_ADDR >> 8) & 0xFF;
flasher_we2->data[4] = (OTA_CONTROL_ADDR >> 16) & 0xFF;
flasher_we2->data[5] = (OTA_CONTROL_ADDR >> 24) & 0xFF;
flasher_we2->data[6] = (OTA_CONTROL_REG_DEFAULT & 0xFF);
flasher_we2->data[7] = (OTA_CONTROL_REG_DEFAULT >> 8) & 0xFF;
flasher_we2->data[8] = (OTA_CONTROL_REG_DEFAULT >> 16) & 0xFF;
flasher_we2->data[9] = (OTA_CONTROL_REG_DEFAULT >> 24) & 0xFF;
spi_trans.length = 10 * 8;
spi_trans.tx_buffer = flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
// if offset == 0, clear boot slot magic first
if (offset == 0)
{
ESP_LOGW(TAG, "Writing firmware... clearing magic for boot from slot 0");
remain = 4096; // magic partition size 4K
addr = OTA_BASE_ADDR + OTA_MAX_OFFSET - remain;
// write chunk
do
{
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = 0x00;
flasher_we2->data[2] = (addr & 0xFF);
flasher_we2->data[3] = (addr >> 8) & 0xFF;
flasher_we2->data[4] = (addr >> 16) & 0xFF;
flasher_we2->data[5] = (addr >> 24) & 0xFF;
memset(flasher_we2->data + 6, 0xFF, OTA_CHUNKED_SIZE);
spi_trans.length = (6 + OTA_CHUNKED_SIZE) * 8;
spi_trans.tx_buffer = flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
remain -= OTA_CHUNKED_SIZE;
addr += OTA_CHUNKED_SIZE;
flasher_we2->count++;
// check status
start = esp_timer_get_time();
status = 0xFFFFFFFF;
do
{
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = 0x00;
flasher_we2->data[2] = (OTA_PPDONE_COUNT_ADDR & 0xFF);
flasher_we2->data[3] = (OTA_PPDONE_COUNT_ADDR >> 8) & 0xFF;
flasher_we2->data[4] = (OTA_PPDONE_COUNT_ADDR >> 16) & 0xFF;
flasher_we2->data[5] = (OTA_PPDONE_COUNT_ADDR >> 24) & 0xFF;
spi_trans.length = (6) * 8;
spi_trans.tx_buffer = &flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = OTA_STATUS_REG;
flasher_we2->data[2] = 0;
spi_trans.length = (3) * 8;
spi_trans.tx_buffer = &flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
status = 0;
memset(&flasher_we2->data[0], 0x00, 7);
memset(&flasher_we2->data[7], 0xFF, 7);
flasher_we2->data[0] = OTA_CMD_READ;
flasher_we2->data[1] = 0x08;
flasher_we2->data[2] = 0x00;
spi_trans.length = 7 * 8;
spi_trans.tx_buffer = &flasher_we2->data[0];
spi_trans.rx_buffer = &flasher_we2->data[7];
spi_trans.rxlength = 7 * 8;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
memcpy(&status, &flasher_we2->data[10], 4);
if ((esp_timer_get_time() - start) > 10000000)
{
spi_device_release_bus(flasher_we2->io->handle);
ESP_LOGE(TAG, "Timeout");
ret = ESP_ERR_TIMEOUT;
goto err;
}
taskYIELD();
}
while (!((status >> 28) == 1 || (status & 0xFFFFF) == flasher_we2->count));
// CRC Error
if (((status >> 28) == 1) || (status >> 28) == 3)
{
ESP_LOGE(TAG, "CRC Error");
ret = ESP_FAIL;
goto err;
}
}
while (remain > 0);
}
spi_device_release_bus(flasher_we2->io->handle);
err:
if (ret != ESP_OK)
{
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
vTaskDelay(50);
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << flasher_we2->reset_gpio_num,
};
gpio_config(&io_conf);
gpio_set_level(flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
gpio_reset_pin(flasher_we2->reset_gpio_num);
vTaskDelay(50);
}
}
}
xSemaphoreGive(flasher_we2->lock);
return ret;
}
static esp_err_t sscma_client_flasher_we2_write(sscma_client_flasher_handle_t flasher, const void *data, size_t len)
{
esp_err_t ret = ESP_OK;
int64_t start = 0;
size_t remain = len;
uint32_t addr = 0;
uint32_t status = 0;
spi_transaction_t spi_trans = {};
sscma_client_flasher_we2_spi_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_spi_t, base);
assert(len % OTA_CHUNKED_SIZE == 0);
assert(flasher_we2->offset + len <= OTA_MAX_OFFSET);
xSemaphoreTake(flasher_we2->lock, portMAX_DELAY);
ESP_GOTO_ON_ERROR(spi_device_acquire_bus(flasher_we2->io->handle, portMAX_DELAY), err, TAG, "acquire spi bus failed");
do
{
// write chunk
addr = OTA_BASE_ADDR + flasher_we2->offset;
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = 0x00;
flasher_we2->data[2] = (addr & 0xFF);
flasher_we2->data[3] = (addr >> 8) & 0xFF;
flasher_we2->data[4] = (addr >> 16) & 0xFF;
flasher_we2->data[5] = (addr >> 24) & 0xFF;
memcpy(&flasher_we2->data[6], (uint8_t *)data + (len - remain), OTA_CHUNKED_SIZE);
spi_trans.length = (6 + OTA_CHUNKED_SIZE) * 8;
spi_trans.tx_buffer = flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
remain -= OTA_CHUNKED_SIZE;
flasher_we2->offset += OTA_CHUNKED_SIZE;
flasher_we2->count++;
// check status
start = esp_timer_get_time();
status = 0xFFFFFFFF;
do
{
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = 0x00;
flasher_we2->data[2] = (OTA_PPDONE_COUNT_ADDR & 0xFF);
flasher_we2->data[3] = (OTA_PPDONE_COUNT_ADDR >> 8) & 0xFF;
flasher_we2->data[4] = (OTA_PPDONE_COUNT_ADDR >> 16) & 0xFF;
flasher_we2->data[5] = (OTA_PPDONE_COUNT_ADDR >> 24) & 0xFF;
spi_trans.length = (6) * 8;
spi_trans.tx_buffer = &flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = OTA_STATUS_REG;
flasher_we2->data[2] = 0;
spi_trans.length = (3) * 8;
spi_trans.tx_buffer = &flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
status = 0;
memset(&flasher_we2->data[0], 0x00, 7);
memset(&flasher_we2->data[7], 0xFF, 7);
flasher_we2->data[0] = OTA_CMD_READ;
flasher_we2->data[1] = 0x08;
flasher_we2->data[2] = 0x00;
spi_trans.length = 7 * 8;
spi_trans.tx_buffer = &flasher_we2->data[0];
spi_trans.rx_buffer = &flasher_we2->data[7];
spi_trans.rxlength = 7 * 8;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
if (ret != ESP_OK)
{
spi_device_release_bus(flasher_we2->io->handle);
goto err;
}
memcpy(&status, &flasher_we2->data[10], 4);
if ((esp_timer_get_time() - start) > 3000000)
{
spi_device_release_bus(flasher_we2->io->handle);
ESP_LOGE(TAG, "Timeout");
ret = ESP_ERR_TIMEOUT;
goto err;
}
taskYIELD();
}
while (!((status >> 28) == 1 || (status & 0xFFFFF) == flasher_we2->count));
// CRC Error
if (((status >> 28) == 1) || (status >> 28) == 3)
{
ESP_LOGE(TAG, "CRC Error");
ret = ESP_FAIL;
goto err;
}
}
while (remain > 0);
spi_device_release_bus(flasher_we2->io->handle);
err:
xSemaphoreGive(flasher_we2->lock);
return ret;
}
static esp_err_t sscma_client_flasher_we2_finish(sscma_client_flasher_handle_t flasher)
{
esp_err_t ret = ESP_OK;
spi_transaction_t spi_trans = {};
sscma_client_flasher_we2_spi_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_spi_t, base);
xSemaphoreTake(flasher_we2->lock, portMAX_DELAY);
ESP_GOTO_ON_ERROR(spi_device_acquire_bus(flasher_we2->io->handle, portMAX_DELAY), err, TAG, "acquire spi bus failed");
flasher_we2->data[0] = OTA_CMD_WRITE;
flasher_we2->data[1] = OTA_ENABLE_REG;
flasher_we2->data[2] = REG_OFF;
spi_trans.length = 3 * 8;
spi_trans.tx_buffer = &flasher_we2->data;
spi_trans.rx_buffer = NULL;
spi_trans.rxlength = 0;
ret = spi_device_transmit(flasher_we2->io->handle, &spi_trans);
spi_device_release_bus(flasher_we2->io->handle);
err:
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
vTaskDelay(200);
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << flasher_we2->reset_gpio_num,
};
gpio_config(&io_conf);
gpio_set_level(flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
gpio_reset_pin(flasher_we2->reset_gpio_num);
vTaskDelay(200);
}
}
xSemaphoreGive(flasher_we2->lock);
return ret;
}
static esp_err_t sscma_client_flasher_we2_abort(sscma_client_flasher_handle_t flasher)
{
esp_err_t ret = ESP_OK;
sscma_client_flasher_we2_spi_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_spi_t, base);
xSemaphoreTake(flasher_we2->lock, portMAX_DELAY);
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
vTaskDelay(200);
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << flasher_we2->reset_gpio_num,
};
gpio_config(&io_conf);
gpio_set_level(flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
gpio_reset_pin(flasher_we2->reset_gpio_num);
vTaskDelay(200);
}
}
xSemaphoreGive(flasher_we2->lock);
return ret;
}

View File

@@ -0,0 +1,890 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/cdefs.h>
#include "sdkconfig.h"
#if CONFIG_SSCMA_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_timer.h"
#include "sscma_client_commands.h"
#include "sscma_client_io.h"
#include "sscma_client_io_interface.h"
#include "sscma_client_flasher.h"
#include "sscma_client_flasher_interface.h"
static const char *TAG = "sscma_client.flasher.we2.uart";
#define OTA_ENTER_CMD "1"
#define OTA_ENTER_HINT "Send data using the xmodem protocol from your terminal"
#define OTA_ENTER_TIMEOUT 5000
#define OTA_DONE_HINT "Do you want to end file transmission and reboot system?"
#define OTA_DONE_TIMEOUT 60000
#define XSOH 0x01 // Start Of Header
#define XSTX 0x02
#define XETX 0x03
#define XEOT 0x04 // End Of Transfer
#define XENQ 0x05
#define XACK 0x06 // ACK
#define XNACK 0x15 // NACK
#define XETB 0x17 //
#define XCAN 0x18 // CANCEL
#define XC 0x43
#define XEOF 0x1A
#define XMODEM_BLOCK_SIZE 128
#define XMODEM_RX_BUFFER_SIZE 1024
#define WRITE_BLOCK_MAX_RETRIES 15
#define TRANSFER_ACK_TIMEOUT 30000 // 30 seconds
#define TRANSFER_EOT_TIMEOUT 30000 // 30 seconds
#define TRANSFER_ETB_TIMEOUT 30000 // 30 seconds
#define TRANSFER_WRITE_BLOCK_TIMEOUT 30000 // 30 seconds
static esp_err_t sscma_client_flasher_we2_start(sscma_client_flasher_handle_t flasher, size_t offset);
static esp_err_t sscma_client_flasher_we2_write(sscma_client_flasher_handle_t flasher, const void *data, size_t len);
static esp_err_t sscma_client_flasher_we2_finish(sscma_client_flasher_handle_t flasher);
static esp_err_t sscma_client_flasher_we2_abort(sscma_client_flasher_handle_t flasher);
static esp_err_t sscma_client_flasher_we2_del(sscma_client_flasher_handle_t flasher);
typedef enum {
INITIAL,
WAIT_FOR_C,
WAIT_FOR_C_TIMEOUT,
WAIT_FOR_C_ACK,
WRITE_BLOCK_FAILED,
ABORT_TRANSFER,
WRITE_BLOCK,
C_ACK_RECEIVED,
COMPLETE,
WRITE_EOT,
WAIT_FOR_EOT_ACK,
TIMEOUT_EOT,
WRITE_BLOCK_TIMEOUT,
WRITE_ETB,
WAIT_FOR_ETB_ACK,
TIMEOUT_ETB,
WAIT_WRITE_BLOCK,
FAILED,
FINAL,
} xmodem_state_t;
typedef struct xmodem_packet_t
{
uint8_t preamble;
uint8_t id;
uint8_t id_complement;
uint8_t data[XMODEM_BLOCK_SIZE];
union
{
uint8_t data[2];
uint16_t value;
} crc;
} __attribute__((packed, aligned(1))) xmodem_packet_t;
typedef struct
{
sscma_client_flasher_t base; /*!< The base class. */
sscma_client_io_t *io; /*!< The IO interface. */
esp_io_expander_handle_t io_expander; /* !< IO expander handle */
int reset_gpio_num; /*!< The reset GPIO number. */
bool reset_level; /*!< The reset GPIO level. */
void *user_ctx; /* !< User context */
SemaphoreHandle_t lock; /*!< The lock. */
xmodem_state_t state; /*!< The state of the flasher. */
xmodem_packet_t cur_packet; /*!< The current packet being transmitted. */
uint8_t cur_packet_id; /*!< The ID of the current packet. */
int64_t cur_time; /*!< The current time. */
struct
{
char *data; /* !< Data buffer */
size_t len; /* !< Data length */
size_t pos; /* !< Data position */
} rx_buffer, tx_buffer; /* !< RX and TX buffer */
uint32_t xfer_size;
uint8_t write_block_retries; /*!< The write block retries. */
} sscma_client_flasher_we2_uart_t;
static inline bool xmodem_calculate_crc(const uint8_t *data, const uint32_t size, uint16_t *result)
{
uint16_t crc = 0x0;
uint32_t count = size;
bool status = false;
uint8_t i = 0;
if (0 != data && 0 != result)
{
status = true;
while (0 < count--)
{
crc = crc ^ (uint16_t)*data << 8;
data++;
i = 8;
do
{
if (0x8000 & crc)
{
crc = crc << 1 ^ 0x1021;
}
else
{
crc = crc << 1;
}
}
while (0 < --i);
}
*result = ((crc & 0xFF) << 8) + ((crc >> 8) & 0xFF);
}
return status;
}
static inline bool xmodem_verify_packet(const xmodem_packet_t packet, uint8_t expected_packet_id)
{
bool status = false;
uint8_t crc_status = false;
uint16_t calculated_crc = 0;
crc_status = xmodem_calculate_crc(packet.data, XMODEM_BLOCK_SIZE, &calculated_crc);
if (packet.preamble == XSOH && packet.id == expected_packet_id && packet.id_complement == 0xFF - packet.id && crc_status && calculated_crc == packet.crc.value)
{
status = true;
}
return status;
}
static inline bool xmodem_timeout(sscma_client_flasher_we2_uart_t *flasher_we2, int64_t timeout)
{
if (esp_timer_get_time() - flasher_we2->cur_time >= (timeout * 1000))
{
return true;
}
vTaskDelay(1 / portTICK_PERIOD_MS);
return false;
}
static xmodem_state_t xmodem_process(sscma_client_flasher_we2_uart_t *flasher)
{
uint8_t response = 0;
uint8_t ctrl = 0;
size_t rlen = 0;
uint16_t crc = 0;
switch (flasher->state)
{
case INITIAL: {
flasher->state = WAIT_FOR_C;
flasher->cur_time = esp_timer_get_time();
break;
}
case WAIT_FOR_C: {
if (sscma_client_io_available(flasher->io, &rlen) == ESP_OK && rlen)
{
sscma_client_io_read(flasher->io, &response, 1);
if (response == XC)
{
flasher->state = WRITE_BLOCK;
flasher->cur_time = esp_timer_get_time();
}
}
else if (xmodem_timeout(flasher, TRANSFER_ACK_TIMEOUT))
{
flasher->state = WAIT_FOR_C_TIMEOUT;
}
break;
}
case WRITE_BLOCK: {
if (flasher->tx_buffer.data == NULL || flasher->tx_buffer.len == 0)
{
break;
}
/* setup current packet */
if (flasher->cur_packet.id != flasher->cur_packet_id || flasher->cur_packet_id == 1)
{
flasher->cur_packet.preamble = XSOH;
flasher->cur_packet.id = flasher->cur_packet_id;
flasher->cur_packet.id_complement = 0xFF - flasher->cur_packet_id;
memset(flasher->cur_packet.data, 0xFF, XMODEM_BLOCK_SIZE);
flasher->xfer_size = flasher->tx_buffer.len - flasher->tx_buffer.pos > XMODEM_BLOCK_SIZE ? XMODEM_BLOCK_SIZE : flasher->tx_buffer.len - flasher->tx_buffer.pos;
memcpy(flasher->cur_packet.data, flasher->tx_buffer.data + flasher->tx_buffer.pos, flasher->xfer_size);
xmodem_calculate_crc(flasher->cur_packet.data, XMODEM_BLOCK_SIZE, &crc);
flasher->cur_packet.crc.value = crc;
}
sscma_client_io_write(flasher->io, (uint8_t *)&flasher->cur_packet, sizeof(xmodem_packet_t));
flasher->cur_packet_id++;
flasher->tx_buffer.pos += flasher->xfer_size;
flasher->state = WAIT_FOR_C_ACK;
flasher->cur_time = esp_timer_get_time();
break;
}
case WAIT_WRITE_BLOCK: {
if (flasher->tx_buffer.data != NULL && flasher->tx_buffer.len != 0)
{
flasher->state = WRITE_BLOCK;
}
break;
}
case WAIT_FOR_C_ACK: {
if (sscma_client_io_available(flasher->io, &rlen) == ESP_OK && rlen)
{
sscma_client_io_read(flasher->io, &response, 1);
flasher->cur_time = esp_timer_get_time();
switch (response)
{
case XACK: {
flasher->state = C_ACK_RECEIVED;
break;
}
case XNACK: {
flasher->state = WRITE_BLOCK_FAILED;
break;
}
case XEOF: {
flasher->state = COMPLETE;
break;
}
default:
break;
}
}
else if (xmodem_timeout(flasher, TRANSFER_ACK_TIMEOUT))
{
flasher->state = WRITE_BLOCK_TIMEOUT;
}
break;
}
case WRITE_BLOCK_FAILED: {
if (flasher->write_block_retries > WRITE_BLOCK_MAX_RETRIES)
{
flasher->state = ABORT_TRANSFER;
}
else
{
flasher->state = WRITE_BLOCK;
flasher->cur_packet_id--;
flasher->tx_buffer.pos -= flasher->xfer_size;
flasher->write_block_retries++;
}
break;
}
case C_ACK_RECEIVED: {
if (flasher->tx_buffer.pos >= flasher->tx_buffer.len)
{
flasher->tx_buffer.len = 0;
flasher->tx_buffer.data = NULL;
flasher->state = WAIT_WRITE_BLOCK;
}
else
{
flasher->write_block_retries = 0;
flasher->state = WRITE_BLOCK;
}
break;
}
case WRITE_EOT: {
ctrl = XEOT;
sscma_client_io_write(flasher->io, (uint8_t *)&ctrl, sizeof(char));
flasher->state = WAIT_FOR_EOT_ACK;
break;
}
case WAIT_FOR_EOT_ACK: {
if (sscma_client_io_available(flasher->io, &rlen) == ESP_OK && rlen)
{
sscma_client_io_read(flasher->io, &response, 1);
switch (response)
{
case XACK:
flasher->state = COMPLETE;
break;
case XNACK:
flasher->state = ABORT_TRANSFER;
break;
default:
break;
}
}
else if (xmodem_timeout(flasher, TRANSFER_EOT_TIMEOUT))
{
flasher->state = TIMEOUT_EOT;
}
break;
}
case COMPLETE: {
ctrl = XEOT;
sscma_client_io_write(flasher->io, (uint8_t *)&ctrl, sizeof(char));
flasher->state = FINAL;
break;
}
case ABORT_TRANSFER: {
ctrl = XCAN;
sscma_client_io_write(flasher->io, (uint8_t *)&ctrl, sizeof(char));
flasher->state = FINAL;
break;
}
case TIMEOUT_EOT: {
flasher->state = ABORT_TRANSFER;
break;
}
case WRITE_BLOCK_TIMEOUT: {
flasher->state = WRITE_BLOCK_FAILED;
break;
}
default: {
flasher->state = ABORT_TRANSFER;
break;
}
}
return flasher->state;
}
esp_err_t xmodem_start(sscma_client_flasher_we2_uart_t *flasher)
{
esp_err_t ret = ESP_OK;
flasher->state = INITIAL;
flasher->cur_packet_id = 1;
flasher->tx_buffer.data = NULL;
flasher->tx_buffer.len = 0;
flasher->tx_buffer.pos = 0;
flasher->xfer_size = 0;
flasher->cur_time = esp_timer_get_time();
do
{
xmodem_process(flasher);
if (flasher->state == WRITE_BLOCK)
{
ret = ESP_OK;
break;
}
if (flasher->state == WAIT_FOR_C_TIMEOUT)
{
ret = ESP_ERR_TIMEOUT;
break;
}
}
while ((esp_timer_get_time() - flasher->cur_time) / 1000 < TRANSFER_ACK_TIMEOUT);
return ret;
}
esp_err_t xmodem_write(sscma_client_flasher_we2_uart_t *flasher, const void *data, size_t len)
{
esp_err_t ret = ESP_OK;
flasher->tx_buffer.data = (char *)data;
flasher->tx_buffer.pos = 0;
flasher->tx_buffer.len = len;
flasher->xfer_size = 0;
do
{
xmodem_process(flasher);
if (flasher->state == WAIT_WRITE_BLOCK)
{
ret = ESP_OK;
break;
}
if (flasher->state == WRITE_BLOCK_TIMEOUT)
{
ret = ESP_ERR_TIMEOUT;
break;
}
if (flasher->state == FAILED)
{
ret = ESP_FAIL;
break;
}
}
while (1);
return ret;
}
esp_err_t xmodem_finish(sscma_client_flasher_we2_uart_t *flasher)
{
esp_err_t ret = ESP_OK;
flasher->state = WRITE_EOT;
flasher->cur_packet_id = -1;
flasher->tx_buffer.data = NULL;
flasher->tx_buffer.len = 0;
flasher->tx_buffer.pos = 0;
flasher->xfer_size = 0;
do
{
xmodem_process(flasher);
if (flasher->state == COMPLETE)
{
ret = ESP_OK;
break;
}
if (flasher->state == WRITE_BLOCK_TIMEOUT)
{
ret = ESP_ERR_TIMEOUT;
break;
}
if (flasher->state == FAILED)
{
ret = ESP_FAIL;
break;
}
}
while (1);
return ret;
}
esp_err_t xmodem_abort(sscma_client_flasher_we2_uart_t *flasher)
{
esp_err_t ret = ESP_OK;
flasher->state = ABORT_TRANSFER;
flasher->tx_buffer.data = NULL;
flasher->tx_buffer.len = 0;
flasher->tx_buffer.pos = 0;
flasher->xfer_size = 0;
do
{
xmodem_process(flasher);
if (flasher->state == FINAL)
{
ret = ESP_OK;
break;
}
if (flasher->state == TIMEOUT_EOT)
{
ret = ESP_ERR_TIMEOUT;
break;
}
if (flasher->state == FAILED)
{
ret = ESP_FAIL;
break;
}
}
while (1);
return ret;
}
esp_err_t sscma_client_new_flasher_we2_uart(const sscma_client_io_handle_t io, const sscma_client_flasher_we2_config_t *config, sscma_client_flasher_handle_t *ret_flasher)
{
esp_err_t ret = ESP_OK;
sscma_client_flasher_we2_uart_t *flasher_we2 = NULL;
ESP_RETURN_ON_FALSE(io && config && ret_flasher, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
flasher_we2 = (sscma_client_flasher_we2_uart_t *)calloc(1, sizeof(sscma_client_flasher_we2_uart_t));
ESP_RETURN_ON_FALSE(flasher_we2, ESP_ERR_NO_MEM, TAG, "no mem for flasher");
flasher_we2->reset_gpio_num = config->reset_gpio_num;
flasher_we2->reset_level = config->flags.reset_high_active ? 1 : 0;
flasher_we2->io = io;
flasher_we2->tx_buffer.data = NULL;
flasher_we2->tx_buffer.len = 0;
flasher_we2->tx_buffer.pos = 0;
flasher_we2->xfer_size = 0;
flasher_we2->state = INITIAL;
flasher_we2->cur_packet_id = 0;
flasher_we2->cur_time = esp_timer_get_time();
flasher_we2->write_block_retries = 0;
flasher_we2->base.start = sscma_client_flasher_we2_start;
flasher_we2->base.write = sscma_client_flasher_we2_write;
flasher_we2->base.finish = sscma_client_flasher_we2_finish;
flasher_we2->base.abort = sscma_client_flasher_we2_abort;
flasher_we2->base.del = sscma_client_flasher_we2_del;
if (config->flags.reset_use_expander)
{
flasher_we2->io_expander = config->io_expander;
ESP_GOTO_ON_FALSE(flasher_we2->io_expander, ESP_ERR_INVALID_ARG, err, TAG, "invalid io expander");
ESP_GOTO_ON_ERROR(esp_io_expander_set_dir(flasher_we2->io_expander, config->reset_gpio_num, IO_EXPANDER_OUTPUT), err, TAG, "set GPIO direction failed");
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_INPUT,
.pin_bit_mask = 1ULL << config->reset_gpio_num,
};
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
}
flasher_we2->rx_buffer.data = (char *)malloc(XMODEM_RX_BUFFER_SIZE);
ESP_GOTO_ON_FALSE(flasher_we2->rx_buffer.data, ESP_ERR_NO_MEM, err, TAG, "no mem for rx buffer");
flasher_we2->rx_buffer.pos = 0;
flasher_we2->rx_buffer.len = XMODEM_RX_BUFFER_SIZE;
flasher_we2->lock = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(flasher_we2->lock, ESP_ERR_NO_MEM, err, TAG, "no mem for flasher lock");
*ret_flasher = &flasher_we2->base;
return ESP_OK;
err:
if (flasher_we2->rx_buffer.data)
{
free(flasher_we2->rx_buffer.data);
}
if (flasher_we2->lock != NULL)
{
vSemaphoreDelete(flasher_we2->lock);
}
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_dir(flasher_we2->io_expander, flasher_we2->reset_gpio_num, IO_EXPANDER_INPUT);
}
else
{
gpio_reset_pin(flasher_we2->reset_gpio_num);
}
}
if (flasher_we2 != NULL)
{
free(flasher_we2);
}
return ret;
}
esp_err_t sscma_client_flasher_we2_del(sscma_client_flasher_handle_t flasher)
{
sscma_client_flasher_we2_uart_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_uart_t, base);
if (flasher_we2->rx_buffer.data)
{
free(flasher_we2->rx_buffer.data);
}
if (flasher_we2->lock != NULL)
{
vSemaphoreDelete(flasher_we2->lock);
}
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_dir(flasher_we2->io_expander, flasher_we2->reset_gpio_num, IO_EXPANDER_INPUT);
}
else
{
gpio_reset_pin(flasher_we2->reset_gpio_num);
}
}
if (flasher != NULL)
{
free(flasher);
}
return ESP_OK;
}
static esp_err_t sscma_client_flasher_we2_start(sscma_client_flasher_handle_t flasher, size_t offset)
{
esp_err_t ret = ESP_OK;
int64_t start = 0;
size_t rlen = 0;
sscma_client_flasher_we2_uart_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_uart_t, base);
xSemaphoreTake(flasher_we2->lock, portMAX_DELAY);
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
vTaskDelay(50);
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << flasher_we2->reset_gpio_num,
};
gpio_config(&io_conf);
gpio_set_level(flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
gpio_reset_pin(flasher_we2->reset_gpio_num);
vTaskDelay(50);
}
}
else
{
ESP_GOTO_ON_ERROR(sscma_client_io_write(flasher_we2->io, CMD_PREFIX CMD_AT_RESET CMD_SUFFIX, sizeof(CMD_PREFIX CMD_AT_RESET CMD_SUFFIX) - 1), err, TAG, "reset sscma failed");
vTaskDelay(50 / portTICK_PERIOD_MS); // wait for sscma to be ready
}
// enter ota mode
flasher_we2->rx_buffer.pos = 0;
start = esp_timer_get_time();
ret = ESP_ERR_TIMEOUT;
sscma_client_io_flush(flasher_we2->io);
do
{
sscma_client_io_write(flasher_we2->io, OTA_ENTER_CMD, sizeof(OTA_ENTER_CMD) - 1);
if (sscma_client_io_available(flasher_we2->io, &rlen) == ESP_OK && rlen > 0)
{
if (rlen + flasher_we2->rx_buffer.pos > flasher_we2->rx_buffer.len)
{
ret = ESP_ERR_NO_MEM;
break;
}
for (int i = 0; i < rlen; i++)
{
char c = '\0';
sscma_client_io_read(flasher_we2->io, &c, 1);
if (isprint(c))
{
flasher_we2->rx_buffer.data[flasher_we2->rx_buffer.pos++] = c;
}
}
flasher_we2->rx_buffer.data[flasher_we2->rx_buffer.pos] = 0;
if (strnstr(flasher_we2->rx_buffer.data, OTA_ENTER_HINT, flasher_we2->rx_buffer.pos) != NULL)
{
vTaskDelay(100 / portTICK_PERIOD_MS);
ret = ESP_OK;
break;
}
}
vTaskDelay(5 / portTICK_PERIOD_MS);
}
while ((esp_timer_get_time() - start) / 1000 < OTA_ENTER_TIMEOUT);
ESP_GOTO_ON_ERROR(ret, err, TAG, "enter ota mode failed");
// write offset config
if (offset != 0)
{
char config[12] = { 0xC0, 0x5A, (offset >> 0) & 0xFF, (offset >> 8) & 0xFF, (offset >> 16) & 0xFF, (offset >> 24) & 0xFF, 0x00, 0x00, 0x00, 0x00, 0x5A, 0xC0 };
ESP_GOTO_ON_ERROR(xmodem_start(flasher_we2), err, TAG, "write config failed");
ESP_GOTO_ON_ERROR(xmodem_write(flasher_we2, config, sizeof(config)), err, TAG, "write config failed");
ESP_GOTO_ON_ERROR(xmodem_finish(flasher_we2), err, TAG, "write config failed");
flasher_we2->tx_buffer.pos = 0;
start = esp_timer_get_time();
ret = ESP_ERR_TIMEOUT;
do
{
if (sscma_client_io_available(flasher_we2->io, &rlen) == ESP_OK && rlen > 0)
{
if (rlen + flasher_we2->rx_buffer.pos > flasher_we2->rx_buffer.len)
{
ret = ESP_ERR_NO_MEM;
break;
}
for (int i = 0; i < rlen; i++)
{
char c = '\0';
sscma_client_io_read(flasher_we2->io, &c, 1);
if (isprint(c))
{
flasher_we2->rx_buffer.data[flasher_we2->rx_buffer.pos++] = c;
}
}
flasher_we2->rx_buffer.data[flasher_we2->rx_buffer.pos] = 0;
if (strnstr(flasher_we2->rx_buffer.data, OTA_DONE_HINT, flasher_we2->rx_buffer.pos) != NULL)
{
sscma_client_io_write(flasher_we2->io, "n", 1);
ret = ESP_OK;
break;
}
}
vTaskDelay(5 / portTICK_PERIOD_MS);
}
while ((esp_timer_get_time() - start) / 1000 < OTA_DONE_TIMEOUT);
ESP_GOTO_ON_ERROR(ret, err, TAG, "enter ota mode failed");
}
ESP_GOTO_ON_ERROR(xmodem_start(flasher_we2), err, TAG, "start xmodem failed");
err:
if (ret != ESP_OK)
{
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
vTaskDelay(50);
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << flasher_we2->reset_gpio_num,
};
gpio_config(&io_conf);
gpio_set_level(flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
gpio_reset_pin(flasher_we2->reset_gpio_num);
vTaskDelay(50);
}
}
}
xSemaphoreGive(flasher_we2->lock);
return ret;
}
static esp_err_t sscma_client_flasher_we2_write(sscma_client_flasher_handle_t flasher, const void *data, size_t len)
{
esp_err_t ret = ESP_OK;
sscma_client_flasher_we2_uart_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_uart_t, base);
assert(len % XMODEM_BLOCK_SIZE == 0);
xSemaphoreTake(flasher_we2->lock, portMAX_DELAY);
ret = xmodem_write(flasher_we2, data, len);
xSemaphoreGive(flasher_we2->lock);
return ret;
}
static esp_err_t sscma_client_flasher_we2_finish(sscma_client_flasher_handle_t flasher)
{
esp_err_t ret = ESP_OK;
int64_t start = 0;
size_t rlen = 0;
sscma_client_flasher_we2_uart_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_uart_t, base);
xSemaphoreTake(flasher_we2->lock, portMAX_DELAY);
ret = xmodem_finish(flasher_we2);
flasher_we2->tx_buffer.pos = 0;
start = esp_timer_get_time();
ret = ESP_ERR_TIMEOUT;
do
{
if (sscma_client_io_available(flasher_we2->io, &rlen) == ESP_OK && rlen > 0)
{
if (rlen + flasher_we2->rx_buffer.pos > flasher_we2->rx_buffer.len)
{
ret = ESP_ERR_NO_MEM;
break;
}
for (int i = 0; i < rlen; i++)
{
char c = '\0';
sscma_client_io_read(flasher_we2->io, &c, 1);
if (isprint(c))
{
flasher_we2->rx_buffer.data[flasher_we2->rx_buffer.pos++] = c;
}
}
flasher_we2->rx_buffer.data[flasher_we2->rx_buffer.pos] = 0;
if (strnstr(flasher_we2->rx_buffer.data, OTA_DONE_HINT, flasher_we2->rx_buffer.pos) != NULL)
{
sscma_client_io_write(flasher_we2->io, "y", 1);
ret = ESP_OK;
break;
}
}
vTaskDelay(5 / portTICK_PERIOD_MS);
}
while ((esp_timer_get_time() - start) / 1000 < OTA_DONE_TIMEOUT);
ESP_GOTO_ON_ERROR(ret, err, TAG, "finish ota failed");
vTaskDelay(100 / portTICK_PERIOD_MS);
err:
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
vTaskDelay(200);
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << flasher_we2->reset_gpio_num,
};
gpio_config(&io_conf);
gpio_set_level(flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
gpio_reset_pin(flasher_we2->reset_gpio_num);
vTaskDelay(200);
}
}
xSemaphoreGive(flasher_we2->lock);
return ret;
}
static esp_err_t sscma_client_flasher_we2_abort(sscma_client_flasher_handle_t flasher)
{
esp_err_t ret = ESP_OK;
sscma_client_flasher_we2_uart_t *flasher_we2 = __containerof(flasher, sscma_client_flasher_we2_uart_t, base);
xSemaphoreTake(flasher_we2->lock, portMAX_DELAY);
ret = xmodem_abort(flasher_we2);
if (flasher_we2->reset_gpio_num >= 0)
{
if (flasher_we2->io_expander)
{
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
esp_io_expander_set_level(flasher_we2->io_expander, flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
vTaskDelay(200);
}
else
{
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << flasher_we2->reset_gpio_num,
};
gpio_config(&io_conf);
gpio_set_level(flasher_we2->reset_gpio_num, flasher_we2->reset_level);
vTaskDelay(50 / portTICK_PERIOD_MS);
gpio_set_level(flasher_we2->reset_gpio_num, !flasher_we2->reset_level);
gpio_reset_pin(flasher_we2->reset_gpio_num);
vTaskDelay(200);
}
}
xSemaphoreGive(flasher_we2->lock);
return ret;
}

View File

@@ -0,0 +1,43 @@
#include "esp_check.h"
#include "sscma_client_io.h"
#include "sscma_client_io_interface.h"
static const char *TAG = "sscma_client.io";
esp_err_t sscma_client_io_del(sscma_client_io_t *io)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(io->del, ESP_ERR_NOT_SUPPORTED, TAG, "del not supported");
return io->del(io);
}
esp_err_t sscma_client_io_write(sscma_client_io_t *io, const void *data, size_t len)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(io->write, ESP_ERR_NOT_SUPPORTED, TAG, "write not supported");
assert(len > 0);
assert(data);
return io->write(io, data, len);
}
esp_err_t sscma_client_io_read(sscma_client_io_t *io, void *data, size_t len)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(io->read, ESP_ERR_NOT_SUPPORTED, TAG, "read not supported");
assert(data);
return io->read(io, data, len);
}
esp_err_t sscma_client_io_available(sscma_client_io_t *io, size_t *ret_avail)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(io->available, ESP_ERR_NOT_SUPPORTED, TAG, "available not supported");
return io->available(io, ret_avail);
}
esp_err_t sscma_client_io_flush(sscma_client_io_t *io)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(io->flush, ESP_ERR_NOT_SUPPORTED, TAG, "flush not supported");
return io->flush(io);
}

View File

@@ -0,0 +1,281 @@
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "sdkconfig.h"
#if CONFIG_SSCMA_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "sscma_client_io_interface.h"
#include "sscma_client_io.h"
#include "driver/i2c.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
static const char *TAG = "sscma_client.io.i2c";
#define I2C_ADDRESS (0x62)
#define HEADER_LEN (uint8_t)4
#define MAX_PL_LEN (uint8_t)250
#define CHECKSUM_LEN (uint8_t)2
#define PACKET_SIZE (uint16_t)(HEADER_LEN + MAX_PL_LEN + CHECKSUM_LEN)
#define FEATURE_TRANSPORT 0x10
#define FEATURE_TRANSPORT_CMD_READ 0x01
#define FEATURE_TRANSPORT_CMD_WRITE 0x02
#define FEATURE_TRANSPORT_CMD_AVAILABLE 0x03
#define FEATURE_TRANSPORT_CMD_START 0x04
#define FEATURE_TRANSPORT_CMD_STOP 0x05
#define FEATURE_TRANSPORT_CMD_RESET 0x06
static esp_err_t client_io_i2c_del(sscma_client_io_t *io);
static esp_err_t client_io_i2c_write(sscma_client_io_t *io, const void *data, size_t len);
static esp_err_t client_io_i2c_read(sscma_client_io_t *io, void *data, size_t len);
static esp_err_t client_io_i2c_available(sscma_client_io_t *io, size_t *len);
static esp_err_t client_io_i2c_flush(sscma_client_io_t *io);
typedef struct
{
sscma_client_io_t base;
uint32_t i2c_bus_id; // I2C bus id, indicating which I2C port
uint32_t dev_addr; // Device address
int wait_delay; // I2C wait delay
void *user_ctx; // User context
SemaphoreHandle_t lock; // Lock
uint8_t buffer[PACKET_SIZE]; // I2C packet buffer
} sscma_client_io_i2c_t;
esp_err_t sscma_client_new_io_i2c_bus(sscma_client_i2c_bus_handle_t bus, const sscma_client_io_i2c_config_t *io_config, sscma_client_io_handle_t *ret_io)
{
#if CONFIG_SSCMA_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
esp_err_t ret = ESP_OK;
sscma_client_io_i2c_t *i2c_client_io = NULL;
ESP_GOTO_ON_FALSE(io_config && ret_io, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
i2c_client_io = (sscma_client_io_i2c_t *)calloc(1, sizeof(sscma_client_io_i2c_t));
ESP_GOTO_ON_FALSE(i2c_client_io, ESP_ERR_NO_MEM, err, TAG, "no mem for i2c client io");
i2c_client_io->i2c_bus_id = (uint32_t)bus;
i2c_client_io->dev_addr = io_config->dev_addr;
i2c_client_io->wait_delay = io_config->wait_delay;
i2c_client_io->user_ctx = io_config->user_ctx;
i2c_client_io->base.del = client_io_i2c_del;
i2c_client_io->base.write = client_io_i2c_write;
i2c_client_io->base.read = client_io_i2c_read;
i2c_client_io->base.available = client_io_i2c_available;
i2c_client_io->base.flush = client_io_i2c_flush;
i2c_client_io->lock = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(i2c_client_io->lock, ESP_ERR_NO_MEM, err, TAG, "no mem for lock");
*ret_io = &i2c_client_io->base;
ESP_LOGD(TAG, "new i2c sscma client io @%p", i2c_client_io);
return ESP_OK;
err:
if (i2c_client_io)
{
if (i2c_client_io->lock)
{
vSemaphoreDelete(i2c_client_io->lock);
}
free(i2c_client_io);
}
return ret;
}
static esp_err_t client_io_i2c_del(sscma_client_io_t *io)
{
esp_err_t ret = ESP_OK;
sscma_client_io_i2c_t *i2c_client_io = __containerof(io, sscma_client_io_i2c_t, base);
vSemaphoreDelete(i2c_client_io->lock);
free(i2c_client_io);
ESP_LOGD(TAG, "del i2c sscma client io @%p", i2c_client_io);
return ret;
}
static esp_err_t client_io_i2c_write(sscma_client_io_t *io, const void *data, size_t len)
{
esp_err_t ret = ESP_OK;
sscma_client_io_i2c_t *i2c_client_io = __containerof(io, sscma_client_io_i2c_t, base);
uint16_t packets = len / MAX_PL_LEN;
uint16_t remain = len % MAX_PL_LEN;
xSemaphoreTake(i2c_client_io->lock, portMAX_DELAY);
if (data)
{
for (uint16_t i = 0; i < packets; i++)
{
i2c_client_io->buffer[0] = FEATURE_TRANSPORT;
i2c_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_WRITE;
i2c_client_io->buffer[2] = MAX_PL_LEN >> 8;
i2c_client_io->buffer[3] = MAX_PL_LEN & 0xFF;
memcpy(i2c_client_io->buffer + 4, data + i * MAX_PL_LEN, MAX_PL_LEN);
// TODO CRC
i2c_client_io->buffer[4 + MAX_PL_LEN] = 0xFF;
i2c_client_io->buffer[5 + MAX_PL_LEN] = 0xFF;
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_write_to_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, MAX_PL_LEN + 6, portMAX_DELAY), err, TAG,
"i2c master write failed");
}
if (remain)
{
i2c_client_io->buffer[0] = FEATURE_TRANSPORT;
i2c_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_WRITE;
i2c_client_io->buffer[2] = remain >> 8;
i2c_client_io->buffer[3] = remain & 0xFF;
memcpy(i2c_client_io->buffer + 4, data + packets * MAX_PL_LEN, remain);
// TODO CRC
i2c_client_io->buffer[4 + remain] = 0xFF;
i2c_client_io->buffer[5 + remain] = 0xFF;
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_write_to_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, remain + 6, portMAX_DELAY), err, TAG, "i2c master write failed");
}
}
err:
xSemaphoreGive(i2c_client_io->lock);
return ret;
}
static esp_err_t client_io_i2c_read(sscma_client_io_t *io, void *data, size_t len)
{
esp_err_t ret = ESP_OK;
sscma_client_io_i2c_t *i2c_client_io = __containerof(io, sscma_client_io_i2c_t, base);
uint16_t packets = len / MAX_PL_LEN;
uint16_t remain = len % MAX_PL_LEN;
xSemaphoreTake(i2c_client_io->lock, portMAX_DELAY);
if (data)
{
for (uint16_t i = 0; i < packets; i++)
{
i2c_client_io->buffer[0] = FEATURE_TRANSPORT;
i2c_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_READ;
i2c_client_io->buffer[2] = MAX_PL_LEN >> 8;
i2c_client_io->buffer[3] = MAX_PL_LEN & 0xFF;
i2c_client_io->buffer[4] = 0xFF;
i2c_client_io->buffer[5] = 0xFF;
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_write_to_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, 6, portMAX_DELAY), err, TAG, "i2c master write failed");
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_read_from_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, MAX_PL_LEN + 6, portMAX_DELAY), err, TAG,
"i2c master read failed");
memcpy(data + i * MAX_PL_LEN, i2c_client_io->buffer, MAX_PL_LEN);
}
if (remain)
{
i2c_client_io->buffer[0] = FEATURE_TRANSPORT;
i2c_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_READ;
i2c_client_io->buffer[2] = remain >> 8;
i2c_client_io->buffer[3] = remain & 0xFF;
i2c_client_io->buffer[4] = 0xFF;
i2c_client_io->buffer[5] = 0xFF;
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_write_to_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, 6, portMAX_DELAY), err, TAG, "i2c master write failed");
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_read_from_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, remain + 6, portMAX_DELAY), err, TAG, "i2c master read failed");
memcpy(data + packets * MAX_PL_LEN, i2c_client_io->buffer, remain);
}
}
err:
xSemaphoreGive(i2c_client_io->lock);
return ret;
}
static esp_err_t client_io_i2c_available(sscma_client_io_t *io, size_t *len)
{
esp_err_t ret = ESP_OK;
sscma_client_io_i2c_t *i2c_client_io = __containerof(io, sscma_client_io_i2c_t, base);
xSemaphoreTake(i2c_client_io->lock, portMAX_DELAY);
i2c_client_io->buffer[0] = FEATURE_TRANSPORT;
i2c_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_AVAILABLE;
i2c_client_io->buffer[2] = 0x00;
i2c_client_io->buffer[3] = 0x00;
i2c_client_io->buffer[4] = 0xFF;
i2c_client_io->buffer[5] = 0xFF;
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_write_to_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, HEADER_LEN + CHECKSUM_LEN, portMAX_DELAY), err, TAG,
"i2c master write failed");
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_read_from_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, 2, portMAX_DELAY), err, TAG, "i2c master read failed");
*len = (i2c_client_io->buffer[0] << 8) | i2c_client_io->buffer[1];
err:
xSemaphoreGive(i2c_client_io->lock);
return ret;
}
static esp_err_t client_io_i2c_flush(sscma_client_io_t *io)
{
esp_err_t ret = ESP_OK;
sscma_client_io_i2c_t *i2c_client_io = __containerof(io, sscma_client_io_i2c_t, base);
xSemaphoreTake(i2c_client_io->lock, portMAX_DELAY);
i2c_client_io->buffer[0] = FEATURE_TRANSPORT;
i2c_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_RESET;
i2c_client_io->buffer[2] = 0x00;
i2c_client_io->buffer[3] = 0x00;
i2c_client_io->buffer[4] = 0xFF;
i2c_client_io->buffer[5] = 0xFF;
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
ESP_GOTO_ON_ERROR(i2c_master_write_to_device(i2c_client_io->i2c_bus_id, i2c_client_io->dev_addr, i2c_client_io->buffer, HEADER_LEN + CHECKSUM_LEN, portMAX_DELAY), err, TAG,
"i2c master write failed");
if (i2c_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(i2c_client_io->wait_delay));
}
err:
xSemaphoreGive(i2c_client_io->lock);
return ret;
}

View File

@@ -0,0 +1,622 @@
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "sdkconfig.h"
#if CONFIG_SSCMA_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "cJSON.h"
#include "sscma_client_io_interface.h"
#include "sscma_client_io.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
static const char *TAG = "sscma_client.io.spi";
#define HEADER_LEN (uint8_t)4
#define MAX_PL_LEN (uint8_t)250
#define CHECKSUM_LEN (uint8_t)2
#define PACKET_SIZE (uint16_t)(HEADER_LEN + MAX_PL_LEN + CHECKSUM_LEN)
#define MAX_RECIEVE_SIZE (uint16_t)4095
#define FEATURE_TRANSPORT 0x10
#define FEATURE_TRANSPORT_CMD_READ 0x01
#define FEATURE_TRANSPORT_CMD_WRITE 0x02
#define FEATURE_TRANSPORT_CMD_AVAILABLE 0x03
#define FEATURE_TRANSPORT_CMD_START 0x04
#define FEATURE_TRANSPORT_CMD_STOP 0x05
#define FEATURE_TRANSPORT_CMD_RESET 0x06
static esp_err_t client_io_spi_del(sscma_client_io_t *io);
static esp_err_t client_io_spi_write(sscma_client_io_t *io, const void *data, size_t len);
static esp_err_t client_io_spi_read(sscma_client_io_t *io, void *data, size_t len);
static esp_err_t client_io_spi_available(sscma_client_io_t *io, size_t *len);
static esp_err_t client_io_spi_flush(sscma_client_io_t *io);
typedef struct
{
sscma_client_io_t base;
spi_device_handle_t spi_dev; // SPI bus id, indicating which SPI port
int sync_gpio_num; // D/C line GPIO number
size_t spi_trans_max_bytes; // SPI transaction max bytes
int wait_delay; // SPI wait delay
void *user_ctx; // User context
esp_io_expander_handle_t io_expander; // IO expander
SemaphoreHandle_t lock; // Lock
uint8_t buffer[PACKET_SIZE];
} sscma_client_io_spi_t;
esp_err_t sscma_client_new_io_spi_bus(sscma_client_spi_bus_handle_t bus, const sscma_client_io_spi_config_t *io_config, sscma_client_io_handle_t *ret_io)
{
#if CONFIG_SSCMA_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
esp_err_t ret = ESP_OK;
sscma_client_io_spi_t *spi_client_io = NULL;
ESP_GOTO_ON_FALSE(io_config && ret_io, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
spi_client_io = (sscma_client_io_spi_t *)calloc(1, sizeof(sscma_client_io_spi_t));
ESP_GOTO_ON_FALSE(spi_client_io, ESP_ERR_NO_MEM, err, TAG, "no mem for spi client io");
spi_device_interface_config_t dev_config = {
.flags = (io_config->flags.lsb_first ? SPI_DEVICE_TXBIT_LSBFIRST : 0) | (io_config->flags.sio_mode ? SPI_DEVICE_3WIRE : 0) | (io_config->flags.cs_high_active ? SPI_DEVICE_POSITIVE_CS : 0),
.clock_speed_hz = io_config->pclk_hz,
.mode = io_config->spi_mode,
.spics_io_num = io_config->cs_gpio_num,
.queue_size = 1,
};
ret = spi_bus_add_device((spi_host_device_t)bus, &dev_config, &spi_client_io->spi_dev);
ESP_GOTO_ON_ERROR(ret, err, TAG, "adding spi device to bus failed");
if (io_config->sync_gpio_num >= 0)
{
if (io_config->flags.sync_use_expander)
{
if (io_config->io_expander == NULL)
{
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "io expander not set");
}
spi_client_io->io_expander = io_config->io_expander;
ESP_GOTO_ON_ERROR(esp_io_expander_set_dir(io_config->io_expander, io_config->sync_gpio_num, IO_EXPANDER_INPUT), err, TAG, "setting sync GPIO for sync failed");
}
else
{
// zero-initialize the config structure.
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pin_bit_mask = (1 << io_config->sync_gpio_num);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_down_en = 1;
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configuring sync GPIO for sync failed");
}
}
spi_client_io->sync_gpio_num = io_config->sync_gpio_num;
spi_client_io->wait_delay = io_config->wait_delay;
spi_client_io->user_ctx = io_config->user_ctx;
spi_client_io->base.del = client_io_spi_del;
spi_client_io->base.write = client_io_spi_write;
spi_client_io->base.read = client_io_spi_read;
spi_client_io->base.available = client_io_spi_available;
spi_client_io->base.flush = client_io_spi_flush;
spi_client_io->base.handle = spi_client_io->spi_dev;
spi_client_io->lock = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(spi_client_io->lock, ESP_ERR_NO_MEM, err, TAG, "no mem for mutex");
size_t max_trans_bytes = 0;
ESP_GOTO_ON_ERROR(spi_bus_get_max_transaction_len((spi_host_device_t)bus, &max_trans_bytes), err, TAG, "get spi max transaction len failed");
spi_client_io->spi_trans_max_bytes = max_trans_bytes;
ESP_LOGI(TAG, "spi max trans bytes: %d", spi_client_io->spi_trans_max_bytes);
*ret_io = &spi_client_io->base;
ESP_LOGD(TAG, "new spi sscma client io @%p", spi_client_io);
return ESP_OK;
err:
if (spi_client_io)
{
if (spi_client_io->spi_dev)
{
spi_bus_remove_device(spi_client_io->spi_dev);
spi_bus_free((spi_host_device_t)bus);
}
if (spi_client_io->lock)
{
vSemaphoreDelete(spi_client_io->lock);
}
free(spi_client_io);
}
return ret;
}
static esp_err_t client_io_spi_del(sscma_client_io_t *io)
{
esp_err_t ret = ESP_OK;
sscma_client_io_spi_t *spi_client_io = __containerof(io, sscma_client_io_spi_t, base);
if (spi_client_io->lock)
{
vSemaphoreDelete(spi_client_io->lock);
}
spi_bus_remove_device(spi_client_io->spi_dev);
spi_bus_free((spi_host_device_t)spi_client_io->spi_dev);
if (spi_client_io->sync_gpio_num >= 0)
{
gpio_reset_pin(spi_client_io->sync_gpio_num);
}
ESP_LOGD(TAG, "del spi sscma client io @%p", spi_client_io);
free(spi_client_io);
return ret;
}
static esp_err_t client_io_spi_write(sscma_client_io_t *io, const void *data, size_t len)
{
esp_err_t ret = ESP_OK;
spi_transaction_t spi_trans = {};
sscma_client_io_spi_t *spi_client_io = __containerof(io, sscma_client_io_spi_t, base);
uint16_t packets = len / MAX_PL_LEN;
uint16_t remain = len % MAX_PL_LEN;
size_t trans_len = 0;
xSemaphoreTake(spi_client_io->lock, portMAX_DELAY);
if (spi_device_acquire_bus(spi_client_io->spi_dev, portMAX_DELAY) != ESP_OK)
{
xSemaphoreGive(spi_client_io->lock);
return ESP_FAIL;
}
if (data)
{
for (uint16_t i = 0; i < packets; i++)
{
trans_len = PACKET_SIZE;
memset(spi_client_io->buffer, 0, sizeof(spi_client_io->buffer));
spi_client_io->buffer[0] = FEATURE_TRANSPORT;
spi_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_WRITE;
spi_client_io->buffer[2] = MAX_PL_LEN >> 8;
spi_client_io->buffer[3] = MAX_PL_LEN & 0xFF;
spi_client_io->buffer[4 + MAX_PL_LEN] = 0xFF;
spi_client_io->buffer[5 + MAX_PL_LEN] = 0xFF;
memcpy(spi_client_io->buffer + 4, data + i * MAX_PL_LEN, MAX_PL_LEN);
spi_trans.tx_buffer = spi_client_io->buffer;
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
do
{
uint16_t chunk_size = trans_len;
if (chunk_size > spi_client_io->spi_trans_max_bytes)
{
chunk_size = spi_client_io->spi_trans_max_bytes;
spi_trans.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
}
else
{
chunk_size = trans_len;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
}
spi_trans.length = chunk_size * 8;
spi_trans.rxlength = 0;
spi_trans.rx_buffer = NULL;
spi_trans.user = spi_client_io;
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
spi_trans.tx_buffer = spi_trans.tx_buffer + chunk_size;
trans_len -= chunk_size;
}
while (trans_len > 0);
}
if (remain)
{
trans_len = PACKET_SIZE;
memset(spi_client_io->buffer, 0, sizeof(spi_client_io->buffer));
spi_client_io->buffer[0] = FEATURE_TRANSPORT;
spi_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_WRITE;
spi_client_io->buffer[2] = remain >> 8;
spi_client_io->buffer[3] = remain & 0xFF;
spi_client_io->buffer[4 + remain] = 0xFF;
spi_client_io->buffer[5 + remain] = 0xFF;
memcpy(spi_client_io->buffer + 4, data + packets * MAX_PL_LEN, remain);
spi_trans.tx_buffer = spi_client_io->buffer;
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
do
{
uint16_t chunk_size = trans_len;
if (chunk_size > spi_client_io->spi_trans_max_bytes)
{
chunk_size = spi_client_io->spi_trans_max_bytes;
spi_trans.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
}
else
{
chunk_size = trans_len;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
}
spi_trans.length = chunk_size * 8;
spi_trans.tx_buffer = spi_client_io->buffer;
spi_trans.rxlength = 0;
spi_trans.rx_buffer = NULL;
spi_trans.user = spi_client_io;
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
spi_trans.tx_buffer = spi_trans.tx_buffer + chunk_size;
trans_len -= chunk_size;
}
while (trans_len > 0);
}
}
err:
spi_device_release_bus(spi_client_io->spi_dev);
xSemaphoreGive(spi_client_io->lock);
return ret;
}
static esp_err_t client_io_spi_read(sscma_client_io_t *io, void *data, size_t len)
{
esp_err_t ret = ESP_OK;
spi_transaction_t spi_trans = {};
sscma_client_io_spi_t *spi_client_io = __containerof(io, sscma_client_io_spi_t, base);
uint16_t packets = len / MAX_RECIEVE_SIZE;
uint16_t remain = len % MAX_RECIEVE_SIZE;
size_t trans_len = 0;
xSemaphoreTake(spi_client_io->lock, portMAX_DELAY);
if (spi_device_acquire_bus(spi_client_io->spi_dev, portMAX_DELAY) != ESP_OK)
{
xSemaphoreGive(spi_client_io->lock);
return ESP_FAIL;
}
if (data)
{
for (uint16_t i = 0; i < packets; i++)
{
trans_len = PACKET_SIZE;
memset(spi_client_io->buffer, 0, sizeof(spi_client_io->buffer));
spi_client_io->buffer[0] = FEATURE_TRANSPORT;
spi_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_READ;
spi_client_io->buffer[2] = MAX_RECIEVE_SIZE >> 8;
spi_client_io->buffer[3] = MAX_RECIEVE_SIZE & 0xFF;
spi_client_io->buffer[4] = 0xFF;
spi_client_io->buffer[5] = 0xFF;
spi_trans.tx_buffer = spi_client_io->buffer;
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
do
{
uint16_t chunk_size = trans_len;
if (chunk_size > spi_client_io->spi_trans_max_bytes)
{
chunk_size = spi_client_io->spi_trans_max_bytes;
spi_trans.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
}
else
{
chunk_size = trans_len;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
}
spi_trans.length = chunk_size * 8;
spi_trans.rxlength = 0;
spi_trans.rx_buffer = NULL;
spi_trans.user = spi_client_io;
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
spi_trans.tx_buffer = spi_trans.tx_buffer + chunk_size;
trans_len -= chunk_size;
}
while (trans_len > 0);
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
trans_len = MAX_RECIEVE_SIZE;
spi_trans.rx_buffer = data + i * MAX_RECIEVE_SIZE;
do
{
uint16_t chunk_size = trans_len;
if (chunk_size > spi_client_io->spi_trans_max_bytes)
{
chunk_size = spi_client_io->spi_trans_max_bytes;
spi_trans.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
}
else
{
chunk_size = trans_len;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
}
spi_trans.length = chunk_size * 8;
spi_trans.tx_buffer = NULL;
spi_trans.rxlength = chunk_size * 8;
spi_trans.user = spi_client_io;
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
spi_trans.rx_buffer = spi_trans.rx_buffer + chunk_size;
trans_len -= chunk_size;
}
while (trans_len > 0);
}
if (remain)
{
trans_len = PACKET_SIZE;
memset(spi_client_io->buffer, 0, sizeof(spi_client_io->buffer));
spi_client_io->buffer[0] = FEATURE_TRANSPORT;
spi_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_READ;
spi_client_io->buffer[2] = remain >> 8;
spi_client_io->buffer[3] = remain & 0xFF;
spi_client_io->buffer[4] = 0xFF;
spi_client_io->buffer[5] = 0xFF;
spi_trans.tx_buffer = spi_client_io->buffer;
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
do
{
uint16_t chunk_size = trans_len;
if (chunk_size > spi_client_io->spi_trans_max_bytes)
{
chunk_size = spi_client_io->spi_trans_max_bytes;
spi_trans.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
}
else
{
chunk_size = trans_len;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
}
spi_trans.rxlength = 0;
spi_trans.rx_buffer = NULL;
spi_trans.length = chunk_size * 8;
spi_trans.user = spi_client_io;
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
spi_trans.tx_buffer = spi_trans.tx_buffer + chunk_size;
trans_len -= chunk_size;
}
while (trans_len > 0);
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
trans_len = remain;
spi_trans.rx_buffer = data + packets * MAX_RECIEVE_SIZE;
do
{
uint16_t chunk_size = trans_len;
if (chunk_size > spi_client_io->spi_trans_max_bytes)
{
chunk_size = spi_client_io->spi_trans_max_bytes;
spi_trans.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
}
else
{
chunk_size = trans_len;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
}
spi_trans.length = chunk_size * 8;
spi_trans.tx_buffer = NULL;
spi_trans.rxlength = chunk_size * 8;
spi_trans.user = spi_client_io;
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
spi_trans.rx_buffer = spi_trans.rx_buffer + chunk_size;
trans_len -= chunk_size;
}
while (trans_len > 0);
}
}
err:
spi_device_release_bus(spi_client_io->spi_dev);
xSemaphoreGive(spi_client_io->lock);
return ret;
}
static esp_err_t client_io_spi_available(sscma_client_io_t *io, size_t *len)
{
esp_err_t ret = ESP_OK;
spi_transaction_t spi_trans = {};
sscma_client_io_spi_t *spi_client_io = __containerof(io, sscma_client_io_spi_t, base);
size_t trans_len = 0;
uint32_t sync_level = 0;
*len = 0;
xSemaphoreTake(spi_client_io->lock, portMAX_DELAY);
if (spi_client_io->sync_gpio_num >= 0)
{
if (spi_client_io->io_expander)
{
if (esp_io_expander_get_level(spi_client_io->io_expander, spi_client_io->sync_gpio_num, &sync_level) != ESP_OK)
{
xSemaphoreGive(spi_client_io->lock);
return ESP_FAIL;
}
}
else
{
sync_level = gpio_get_level(spi_client_io->sync_gpio_num);
}
if (sync_level == 0)
{
xSemaphoreGive(spi_client_io->lock);
return ESP_OK;
}
}
else
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
if (spi_device_acquire_bus(spi_client_io->spi_dev, portMAX_DELAY) != ESP_OK)
{
xSemaphoreGive(spi_client_io->lock);
return ESP_FAIL;
}
trans_len = PACKET_SIZE;
memset(spi_client_io->buffer, 0, sizeof(spi_client_io->buffer));
spi_client_io->buffer[0] = FEATURE_TRANSPORT;
spi_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_AVAILABLE;
spi_client_io->buffer[2] = 0x00;
spi_client_io->buffer[3] = 0x00;
spi_client_io->buffer[4] = 0xFF;
spi_client_io->buffer[5] = 0xFF;
spi_trans.tx_buffer = spi_client_io->buffer;
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
do
{
uint16_t chunk_size = trans_len;
if (chunk_size > spi_client_io->spi_trans_max_bytes)
{
chunk_size = spi_client_io->spi_trans_max_bytes;
spi_trans.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
}
else
{
chunk_size = trans_len;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
}
spi_trans.length = chunk_size * 8;
spi_trans.rxlength = 0;
spi_trans.rx_buffer = NULL;
spi_trans.user = spi_client_io;
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
spi_trans.tx_buffer = spi_trans.tx_buffer + chunk_size;
trans_len -= chunk_size;
}
while (trans_len > 0);
spi_trans.length = 2 * 8;
spi_trans.tx_buffer = NULL;
spi_trans.rxlength = 2 * 8; // 8 bits per byte
spi_trans.rx_buffer = spi_client_io->buffer;
spi_trans.user = spi_client_io;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
memset(spi_client_io->buffer, 0, sizeof(spi_client_io->buffer));
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
*len = (spi_client_io->buffer[0] << 8) | spi_client_io->buffer[1];
if (*len == 0xFFFF)
{
*len = 0;
}
err:
spi_device_release_bus(spi_client_io->spi_dev);
xSemaphoreGive(spi_client_io->lock);
return ret;
}
static esp_err_t client_io_spi_flush(sscma_client_io_t *io)
{
esp_err_t ret = ESP_OK;
spi_transaction_t spi_trans = {};
sscma_client_io_spi_t *spi_client_io = __containerof(io, sscma_client_io_spi_t, base);
size_t trans_len = 0;
uint32_t sync_level = 0;
xSemaphoreTake(spi_client_io->lock, portMAX_DELAY);
if (spi_client_io->sync_gpio_num >= 0)
{
if (spi_client_io->io_expander)
{
if (esp_io_expander_get_level(spi_client_io->io_expander, spi_client_io->sync_gpio_num, &sync_level) != ESP_OK)
{
xSemaphoreGive(spi_client_io->lock);
return ESP_FAIL;
}
}
else
{
sync_level = gpio_get_level(spi_client_io->sync_gpio_num);
}
if (sync_level == 0)
{
xSemaphoreGive(spi_client_io->lock);
return ESP_OK;
}
}
else
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
if (spi_device_acquire_bus(spi_client_io->spi_dev, portMAX_DELAY) != ESP_OK)
{
xSemaphoreGive(spi_client_io->lock);
return ESP_FAIL;
}
trans_len = PACKET_SIZE;
memset(spi_client_io->buffer, 0, sizeof(spi_client_io->buffer));
spi_client_io->buffer[0] = FEATURE_TRANSPORT;
spi_client_io->buffer[1] = FEATURE_TRANSPORT_CMD_RESET;
spi_client_io->buffer[2] = 0x00;
spi_client_io->buffer[3] = 0x00;
spi_client_io->buffer[4] = 0xFF;
spi_client_io->buffer[5] = 0xFF;
spi_trans.tx_buffer = spi_client_io->buffer;
if (spi_client_io->wait_delay > 0)
{
vTaskDelay(pdMS_TO_TICKS(spi_client_io->wait_delay));
}
do
{
uint16_t chunk_size = trans_len;
if (chunk_size > spi_client_io->spi_trans_max_bytes)
{
chunk_size = spi_client_io->spi_trans_max_bytes;
spi_trans.flags |= SPI_TRANS_CS_KEEP_ACTIVE;
}
else
{
chunk_size = trans_len;
spi_trans.flags &= ~SPI_TRANS_CS_KEEP_ACTIVE;
}
spi_trans.length = chunk_size * 8;
spi_trans.rxlength = 0;
spi_trans.rx_buffer = NULL;
spi_trans.user = spi_client_io;
ret = spi_device_transmit(spi_client_io->spi_dev, &spi_trans);
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (queue) failed");
spi_trans.tx_buffer = spi_trans.tx_buffer + chunk_size;
trans_len -= chunk_size;
}
while (trans_len > 0);
err:
spi_device_release_bus(spi_client_io->spi_dev);
xSemaphoreGive(spi_client_io->lock);
return ret;
}

View File

@@ -0,0 +1,144 @@
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "sscma_client_io_interface.h"
#include "sscma_client_io.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
static const char *TAG = "sscma_client.io.uart";
static esp_err_t client_io_uart_del(sscma_client_io_t *io);
static esp_err_t client_io_uart_write(sscma_client_io_t *io, const void *data, size_t len);
static esp_err_t client_io_uart_read(sscma_client_io_t *io, void *data, size_t len);
static esp_err_t client_io_uart_available(sscma_client_io_t *io, size_t *len);
static esp_err_t client_io_uart_flush(sscma_client_io_t *io);
typedef struct
{
sscma_client_io_t base;
SemaphoreHandle_t lock; // Mutex lock
uint32_t uart_port; // UART port
void *user_ctx; // User context
} sscma_client_io_uart_t;
esp_err_t sscma_client_new_io_uart_bus(sscma_client_uart_bus_handle_t bus, const sscma_client_io_uart_config_t *io_config, sscma_client_io_handle_t *ret_io)
{
#if CONFIG_SSCMA_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
esp_err_t ret = ESP_OK;
sscma_client_io_uart_t *uart_client_io = NULL;
ESP_GOTO_ON_FALSE(io_config && ret_io, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
uart_client_io = (sscma_client_io_uart_t *)calloc(1, sizeof(sscma_client_io_uart_t));
ESP_GOTO_ON_FALSE(uart_client_io, ESP_ERR_NO_MEM, err, TAG, "no mem for uart client io");
uart_client_io->uart_port = (uint32_t)bus;
uart_client_io->user_ctx = io_config->user_ctx;
uart_client_io->base.del = client_io_uart_del;
uart_client_io->base.write = client_io_uart_write;
uart_client_io->base.read = client_io_uart_read;
uart_client_io->base.available = client_io_uart_available;
uart_client_io->base.flush = client_io_uart_flush;
uart_client_io->lock = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(uart_client_io->lock, ESP_ERR_NO_MEM, err, TAG, "no mem for mutex");
*ret_io = &uart_client_io->base;
ESP_LOGI(TAG, "new uart sscma client io @%p", uart_client_io);
return ESP_OK;
err:
if (uart_client_io)
{
if (uart_client_io->lock)
{
vSemaphoreDelete(uart_client_io->lock);
}
free(uart_client_io);
}
return ret;
}
esp_err_t client_io_uart_del(sscma_client_io_t *io)
{
esp_err_t ret = ESP_OK;
sscma_client_io_uart_t *uart_client_io = __containerof(io, sscma_client_io_uart_t, base);
if (uart_client_io->lock)
{
vSemaphoreDelete(uart_client_io->lock);
}
free(uart_client_io);
ESP_LOGD(TAG, "del uart sscma client io @%p", uart_client_io);
return ret;
}
static esp_err_t client_io_uart_write(sscma_client_io_t *io, const void *data, size_t len)
{
esp_err_t ret = ESP_OK;
sscma_client_io_uart_t *uart_client_io = __containerof(io, sscma_client_io_uart_t, base);
ESP_GOTO_ON_FALSE(uart_client_io, ESP_ERR_INVALID_STATE, err, TAG, "uart not initialized");
xSemaphoreTake(uart_client_io->lock, portMAX_DELAY);
ret = uart_write_bytes(uart_client_io->uart_port, data, len);
xSemaphoreGive(uart_client_io->lock);
err:
return ret == len ? ESP_OK : ESP_FAIL;
}
static esp_err_t client_io_uart_read(sscma_client_io_t *io, void *data, size_t len)
{
esp_err_t ret = ESP_OK;
sscma_client_io_uart_t *uart_client_io = __containerof(io, sscma_client_io_uart_t, base);
ESP_GOTO_ON_FALSE(uart_client_io, ESP_ERR_INVALID_STATE, err, TAG, "uart not initialized");
xSemaphoreTake(uart_client_io->lock, portMAX_DELAY);
ret = uart_read_bytes(uart_client_io->uart_port, data, len, portMAX_DELAY);
xSemaphoreGive(uart_client_io->lock);
err:
return ret == len ? ESP_OK : ESP_FAIL;
}
static esp_err_t client_io_uart_available(sscma_client_io_t *io, size_t *len)
{
esp_err_t ret = ESP_OK;
sscma_client_io_uart_t *uart_client_io = __containerof(io, sscma_client_io_uart_t, base);
ESP_GOTO_ON_FALSE(uart_client_io, ESP_ERR_INVALID_STATE, err, TAG, "uart not initialized");
xSemaphoreTake(uart_client_io->lock, portMAX_DELAY);
ret = uart_get_buffered_data_len(uart_client_io->uart_port, len);
if (ret != ESP_OK)
{
*len = 0;
}
xSemaphoreGive(uart_client_io->lock);
err:
return ret;
}
static esp_err_t client_io_uart_flush(sscma_client_io_t *io)
{
sscma_client_io_uart_t *uart_client_io = __containerof(io, sscma_client_io_uart_t, base);
ESP_RETURN_ON_ERROR(uart_flush(uart_client_io->uart_port), TAG, "uart flush failed");
return ESP_OK;
}

File diff suppressed because it is too large Load Diff