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 @@
bf7d4a1f157303f4850d0b9b465c733ce38e8689ff40ac4743a44520524c41d5

View File

@@ -0,0 +1 @@
{"version": "1.0", "algorithm": "sha256", "created_at": "2025-06-09T03:56:58.876693+00:00", "files": [{"path": "CMakeLists.txt", "size": 634, "hash": "d1094c2ef5d880113acbd4ad0065a625a9b333c9016384a21bd99ff530466731"}, {"path": "README.md", "size": 2971, "hash": "63f416e55e394f953645d05cbc907a70f2c18f8f4612f8cf907f245e9dde88c6"}, {"path": "idf_component.yml", "size": 199, "hash": "d2ec16903ae51fef3de198ebf5be3519d09cc8dc18dc24c49d7997fe1e0989a1"}, {"path": "license.txt", "size": 11358, "hash": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"}, {"path": "include/sscma_client.h", "size": 106, "hash": "b24611302baeff2b6342f17a67596c72123f742833e1e8b760c5e21007773e95"}, {"path": "include/sscma_client_commands.h", "size": 1763, "hash": "43bb21048584ee77d15cfe00fddf7742994f4e16eeb84bb215d22ef3ad6f488d"}, {"path": "include/sscma_client_flasher.h", "size": 1886, "hash": "94497dd41e9c6d459f8d6116916edec4cc98ba3098fda8cdce10e31558469f9f"}, {"path": "include/sscma_client_io.h", "size": 5112, "hash": "6f32d32f8d528e87645c0febaf6927e38b5b65ab00300767d58993b655991580"}, {"path": "include/sscma_client_ops.h", "size": 13936, "hash": "13178c0480a5a91941af1cdc7280080bf84104e290737a480aed76b2a76a0703"}, {"path": "include/sscma_client_types.h", "size": 4713, "hash": "133ece18c05ca06292cff123355f6d2ec8c7e8fd296d0efe6f52536f82972b32"}, {"path": "interface/sscma_client_flasher_interface.h", "size": 2545, "hash": "f9469993aadde2e01f5a8c69ba696108a47e8c79657d3ff8426b8808427d0847"}, {"path": "interface/sscma_client_io_interface.h", "size": 2047, "hash": "732a0b3f1479dd2bc8f35b14a71053eae5d1009dd68d8e07b582be5ef4425d61"}, {"path": "src/sscma_client_flasher.c", "size": 1605, "hash": "caf9efef1368c5adf26877295bf927bf9d0941338db24380b2af95f80c0ca680"}, {"path": "src/sscma_client_flasher_we2_spi.c", "size": 21998, "hash": "54a16e124fd97f11943afbd5a251d9eb07065079d5a3b95f34c279695e870106"}, {"path": "src/sscma_client_flasher_we2_uart.c", "size": 28576, "hash": "ac302843861e5a1a055be49bf03ce5f30d9d472452158cc51b60893c9694c797"}, {"path": "src/sscma_client_io.c", "size": 1543, "hash": "81d66fdd77c2bfebb9364fe3e66ef5755e474293bd6ccc24a554770700fcc0c1"}, {"path": "src/sscma_client_io_i2c.c", "size": 10855, "hash": "7f5395a0540beb6af2b68fadb316160e65935a04fd51b0bec3c1aab59c9a7746"}, {"path": "src/sscma_client_io_spi.c", "size": 23090, "hash": "e852c916d719cd41638c4f50b08e0299e7283a97b13089c999ee132742c0b6f2"}, {"path": "src/sscma_client_io_uart.c", "size": 4648, "hash": "ed583c4172da357ab0f236aa9fb54bb187f2742c01cbcb8f7c69ecc406781220"}, {"path": "src/sscma_client_ops.c", "size": 67261, "hash": "8a98e651dd8c9e160a092e7261809708f1d9fa828614f5e78926a939052101f7"}]}

View File

@@ -0,0 +1,18 @@
set(srcs "src/sscma_client_ops.c"
"src/sscma_client_io.c"
"src/sscma_client_io_i2c.c"
"src/sscma_client_io_spi.c"
"src/sscma_client_io_uart.c"
"src/sscma_client_flasher.c"
"src/sscma_client_flasher_we2_uart.c"
"src/sscma_client_flasher_we2_spi.c"
)
set(includes "include" "interface")
set(require "json" "mbedtls" "esp_timer")
set(priv_requires "driver")
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes}
REQUIRES ${require}
PRIV_REQUIRES ${priv_requires}
)

View File

@@ -0,0 +1,93 @@
# SSCMA Client
[![Component Registry](https://components.espressif.com/components/wvirgil123/sscma_client/badge.svg)](https://components.espressif.com/components/wvirgil123/sscma_client)
## Quick Start
Below is a minimal example for initializing and using the SSCMA Client component via UART, with English comments and no project-specific dependencies.
```c
#include "sscma_client_io.h"
#include "sscma_client_ops.h"
#include "driver/uart.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
static sscma_client_io_handle_t io = NULL;
sscma_client_handle_t client = NULL;
// Callback for inference result
typedef void (*sscma_client_event_cb_t)(sscma_client_handle_t, const sscma_client_reply_t *, void *);
void on_event(sscma_client_handle_t client, const sscma_client_reply_t *reply, void *user_ctx)
{
printf("on_event: %s\n", reply->data);
}
void on_log(sscma_client_handle_t client, const sscma_client_reply_t *reply, void *user_ctx)
{
printf("log: %s\n", reply->data);
}
void on_connect(sscma_client_handle_t client, const sscma_client_reply_t *reply, void *user_ctx)
{
printf("on_connect\n");
}
void app_main(void)
{
// 1. Initialize UART for SSCMA communication
uart_config_t uart_config = {
.baud_rate = 921600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
int intr_alloc_flags = 0;
ESP_ERROR_CHECK(uart_driver_install(1, 8 * 1024, 0, 0, NULL, intr_alloc_flags));
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(1, 21, 20, -1, -1));
// 2. Create SSCMA client UART IO
sscma_client_io_uart_config_t io_uart_config = {
.user_ctx = NULL,
};
sscma_client_new_io_uart_bus((sscma_client_uart_bus_handle_t)1, &io_uart_config, &io);
// 3. Configure SSCMA client
sscma_client_config_t sscma_client_config = SSCMA_CLIENT_CONFIG_DEFAULT();
sscma_client_config.reset_gpio_num = GPIO_NUM_5; // Set your reset GPIO
sscma_client_new(io, &sscma_client_config, &client);
// 4. Register callbacks
const sscma_client_callback_t callback = {
.on_connect = on_connect,
.on_event = on_event,
.on_log = on_log,
};
sscma_client_register_callback(client, &callback, NULL);
// 5. Initialize SSCMA client
sscma_client_init(client);
// 6. Set model and get info
sscma_client_set_model(client, 1);
sscma_client_info_t *info;
if (sscma_client_get_info(client, &info, true) == ESP_OK) {
printf("ID: %s\n", info->id ? info->id : "NULL");
// ... print other info fields ...
}
// 7. Run inference
if (sscma_client_invoke(client, -1, false, false) != ESP_OK) {
printf("invoke failed\n");
}
// 8. Main loop
while (1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
```

View File

@@ -0,0 +1,7 @@
dependencies:
esp_io_expander:
version: ^1.0.1
idf: '>=4.4.2'
description: SSCMA client
url: https://github.com/Seeed-Studio/SenseCAP-Watcher/tree/main/components/sscma_client
version: 1.0.2

View File

@@ -0,0 +1,5 @@
#pragma once
#include "sscma_client_io.h"
#include "sscma_client_flasher.h"
#include "sscma_client_ops.h"

View File

@@ -0,0 +1,68 @@
#pragma once
#define RESPONSE_PREFIX "\r{"
#define RESPONSE_SUFFIX "}\n"
#define RESPONSE_PREFIX_LEN (sizeof(RESPONSE_PREFIX) - 1)
#define RESPONSE_SUFFIX_LEN (sizeof(RESPONSE_SUFFIX) - 1)
#define CMD_TYPE_RESPONSE 0
#define CMD_TYPE_EVENT 1
#define CMD_TYPE_LOG 2
#define CMD_PREFIX "AT+"
#define CMD_QUERY "?"
#define CMD_SET "="
#define CMD_SUFFIX "\r\n"
#define CMD_PREFIX_LEN (sizeof(CMD_PREFIX) - 1)
#define CMD_SUFFIX_LEN (sizeof(CMD_SUFFIX) - 1)
#define CMD_WAIT_DELAY 2000 // ms
#define CMD_AT_ID "ID"
#define CMD_AT_NAME "NAME"
#define CMD_AT_VERSION "VER"
#define CMD_AT_STATS "STAT"
#define CMD_AT_BREAK "BREAK"
#define CMD_AT_RESET "RST"
#define CMD_AT_WIFI "WIFI"
#define CMD_AT_MQTTSERVER "MQTTSERVER"
#define CMD_AT_MQTTPUBSUB "MQTTPUBSUB"
#define CMD_AT_INVOKE "INVOKE"
#define CMD_AT_SAMPLE "SAMPLE"
#define CMD_AT_INFO "INFO"
#define CMD_AT_TSCORE "TSCORE"
#define CMD_AT_TIOU "TIOU"
#define CMD_AT_ALGOS "ALGOS"
#define CMD_AT_MODELS "MODELS"
#define CMD_AT_MODEL "MODEL"
#define CMD_AT_SENSORS "SENSORS"
#define CMD_AT_SENSOR "SENSOR"
#define CMD_AT_ACTION "ACTION"
#define CMD_AT_LED "LED"
#define CMD_AT_OTA "OTA"
#define EVENT_INVOKE "INVOKE"
#define EVENT_SAMPLE "SAMPLE"
#define EVENT_WIFI "WIFI"
#define EVENT_MQTT "MQTT"
#define EVENT_SUPERVISOR "SUPERVISOR"
#define EVENT_INIT "INIT@STAT"
#define LOG_AT "AT"
#define LOG_LOG "LOG"
typedef enum {
CMD_OK = 0,
CMD_AGAIN = 1,
CMD_ELOG = 2,
CMD_ETIMEDOUT = 3,
CMD_EIO = 4,
CMD_EINVAL = 5,
CMD_ENOMEM = 6,
CMD_EBUSY = 7,
CMD_ENOTSUP = 8,
CMD_EPERM = 9,
CMD_EUNKNOWN = 10
} sscma_client_error_t;

View File

@@ -0,0 +1,60 @@
#pragma once
#include <stdbool.h>
#include "esp_err.h"
#include "esp_io_expander.h"
#include "soc/soc_caps.h"
#include "sscma_client_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *sscma_client_flasher_we2_handle_t; /*!< Type of SSCMA flasher WE2 handle */
/**
* @brief Flasher configuration structure, for WE2
*/
typedef struct
{
int reset_gpio_num; /* !< GPIO number of reset pin */
void *user_ctx; /*!< User private data */
esp_io_expander_handle_t io_expander; /*!< IO expander handle */
struct
{
unsigned int reset_high_active : 1; /*!< Reset line is high active */
unsigned int reset_use_expander : 1; /*!< Reset line use IO expander */
} flags;
} sscma_client_flasher_we2_config_t;
/**
* @brief Create SSCMA flasher, for WE2
*
* @param[in] io IO handle
* @param[in] flasher_config Flasher configuration, for WE2
* @param[out] ret_io Returned flasher handle
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t sscma_client_new_flasher_we2_uart(const sscma_client_io_handle_t io, const sscma_client_flasher_we2_config_t *flasher_config, sscma_client_flasher_handle_t *ret_flasher);
/**
* @brief Create SSCMA flasher, for WE2
*
* @param[in] io IO handle
* @param[in] flasher_config Flasher configuration, for WE2
* @param[out] ret_io Returned flasher handle
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
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);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,157 @@
#pragma once
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "esp_err.h"
#include "esp_io_expander.h"
#include "sscma_client_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *sscma_client_spi_bus_handle_t; /*!< Type of SSCMA SPI bus handle */
typedef void *sscma_client_i2c_bus_handle_t; /*!< Type of SSCMA I2C bus handle */
typedef void *sscma_client_uart_bus_handle_t; /*!< Type of SSCMA UART bus handle */
/**
* @brief Client IO configuration structure, for SPI interface
*/
typedef struct
{
int cs_gpio_num; /*!< GPIO used for CS line */
int sync_gpio_num; /*!< GPIO used for SYNC line */
int spi_mode;
int wait_delay; /*!< Traditional SPI mode (0~3) */
unsigned int pclk_hz; /*!< Frequency of pixel clock */
size_t trans_queue_depth; /*!< Size of internal transaction queue */
void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */
esp_io_expander_handle_t io_expander; /*!< IO expander handle */
struct
{
unsigned int octal_mode : 1; /*!< transmit with octal mode (8 data lines), this mode is used to simulate Intel 8080 timing */
unsigned int sio_mode : 1; /*!< Read and write through a single data line (MOSI) */
unsigned int lsb_first : 1; /*!< transmit LSB bit first */
unsigned int cs_high_active : 1; /*!< CS line is high active */
unsigned int sync_high_active : 1; /*!< SYNC line is high active */
unsigned int sync_use_expander : 1; /*!< SYNC line use IO expander */
} flags;
} sscma_client_io_spi_config_t;
/**
* @brief Create SSCMA client IO handle, for SPI interface
*
* @param[in] bus SPI bus handle
* @param[in] io_config IO configuration, for SPI interface
* @param[out] ret_io Returned IO handle
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
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);
/**
* @brief Client IO configuration structure, for I2C interface
*
*/
typedef struct
{
uint32_t dev_addr; /*!< I2C device address */
int wait_delay;
void *user_ctx; /*!< User private data, passed directly to user_ctx */
} sscma_client_io_i2c_config_t;
/**
* @brief Create SSCMA client IO handle, for I2C interface
*
* @param[in] bus I2C bus handle
* @param[in] io_config IO configuration, for I2C interface
* @param[out] ret_io Returned IO handle
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
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);
/**
* @brief Client IO configuration structure, for uart interface
*
*/
typedef struct
{
void *user_ctx; /*!< User private data, passed directly to user_ctx */
} sscma_client_io_uart_config_t;
/**
* @brief Create SSCMA client IO handle, for uart interface
*
* @param[in] bus UART bus handle
* @param[in] io_config IO configuration, for uart interface
* @param[out] ret_io Returned IO handle
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
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);
/**
* @brief Destory SSCMA client IO handle
*
* @param[in] io IO handle
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_del_io(sscma_client_io_handle_t io);
/**
* @brief Write data to SSCMA client IO
*
* @param[in] io IO handle
* @param[in] data Data to be written
* @param[in] size Size of data
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t sscma_client_io_write(sscma_client_io_handle_t io, const void *data, size_t size);
/**
* @brief Read data from SSCMA client IO
*
* @param[in] io IO handle
* @param[in] data Data to be read
* @param[in] size Size of data
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t sscma_client_io_read(sscma_client_io_handle_t io, void *data, size_t size);
/**
* @brief Get available size of data
*
* @param[in] io IO handle
* @param[out] len Available size
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK
*/
esp_err_t sscma_client_io_available(sscma_client_io_handle_t io, size_t *len);
/**
* @brief Flush data
*
* @param[in] io IO handle
* @return
* - ESP_OK
*/
esp_err_t sscma_client_io_flush(sscma_client_io_handle_t io);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,424 @@
#pragma once
#include "esp_err.h"
#include "esp_io_expander.h"
#include "sscma_client_types.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Configuration of SCCMA client
*/
typedef struct
{
int reset_gpio_num; /*!< GPIO number of reset pin */
int tx_buffer_size; /*!< Size of TX buffer */
int rx_buffer_size; /*!< Size of RX buffer */
int process_task_priority; /* SSCMA process task priority */
int process_task_stack; /* SSCMA process task stack size */
int process_task_affinity; /* SSCMA process task pinned to core (-1 is no
affinity) */
int monitor_task_priority; /* SSCMA monitor task priority */
int monitor_task_stack; /* SSCMA monitor task stack size */
int monitor_task_affinity; /* SSCMA monitor task pinned to core (-1 is no
affinity) */
int event_queue_size; /* Event queue size */
void *user_ctx; /* User context */
esp_io_expander_handle_t io_expander; /*!< IO expander handle */
struct
{
unsigned int reset_active_high : 1; /*!< Setting this if the panel reset is
high level active */
unsigned int reset_use_expander : 1; /*!< Reset line use IO expander */
} flags; /*!< SSCMA client config flags */
} sscma_client_config_t;
#define SSCMA_CLIENT_CONFIG_DEFAULT() \
{ \
.reset_gpio_num = -1, .tx_buffer_size = 4096, .rx_buffer_size = 65536, .process_task_priority = 5, .process_task_stack = 4096, .process_task_affinity = -1, .monitor_task_priority = 4, \
.monitor_task_stack = 10240, .monitor_task_affinity = -1, .event_queue_size = 2, .user_ctx = NULL, \
.flags = { \
.reset_active_high = false, \
}, \
}
/**
* @brief Create new SCCMA client
*
* @param[in] io IO handle
* @param[in] config SCCMA client config
* @param[out] ret_client SCCMA client handle
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NO_MEM if out of memory
*/
esp_err_t sscma_client_new(const sscma_client_io_handle_t io, const sscma_client_config_t *config, sscma_client_handle_t *ret_client);
/**
* @brief Destroy SCCMA client
*
* @param[in] client SCCMA client handle
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_del(sscma_client_handle_t client);
/**
* @brief Initialize SCCMA client
*
* @param[in] client SCCMA client handle
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_init(sscma_client_handle_t client);
/**
* @brief Reset SCCMA client
*
* @param[in] client SCCMA client handle
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_reset(sscma_client_handle_t client);
/**
* @brief Read data from SCCMA client
*
* @param[in] client SCCMA client handle
* @param[out] data Data to be read
* @param[in] size Size of data
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NOT_SUPPORTED if read is not supported by transport
* - ESP_OK on success
*/
esp_err_t sscma_client_read(sscma_client_handle_t client, void *data, size_t size);
/**
* @brief Write data to SCCMA client
*
* @param[in] client SCCMA client handle
* @param[in] data Data to be written
* @param[in] size Size of data
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NOT_SUPPORTED if read is not supported by transport
* - ESP_OK on success
*/
esp_err_t sscma_client_write(sscma_client_handle_t client, const void *data, size_t size);
/**
* @brief Get available data
*
* @param[in] client SCCMA client handle
* @param[out] ret_avail Available data
*
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_available(sscma_client_handle_t client, size_t *ret_avail);
/**
* @brief Register callback
*
* @param[in] client SCCMA client handle
* @param[in] callback SCCMA client callback
* @param[in] user_ctx User context
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_register_callback(sscma_client_handle_t client, const sscma_client_callback_t *callback, void *user_ctx);
/**
* @brief Clear reply
*
* @param[in] reply Reply
* @return void
*/
void sscma_client_reply_clear(sscma_client_reply_t *reply);
/**
* @brief Send request to SCCMA client
*
* @param[in] client SCCMA client handle
*
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_request(sscma_client_handle_t client, const char *cmd, sscma_client_reply_t *reply, bool wait, TickType_t timeout);
/**
* @brief Get SCCMA client info
*
* @param[in] client SCCMA client handle
* @param[in] info Copyer to sscma_client_info_t
* @param[in] cached true if info is cached
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_get_info(sscma_client_handle_t client, sscma_client_info_t **info, bool cached);
/**
* @brief Send request to SCCMA clien
*
* @param[in] client SCCMA client handle
* @param[in] model Copyer to sscma_client_model_t
* @param[in] cached true if model is cached
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_get_model(sscma_client_handle_t client, sscma_client_model_t **model, bool cached);
/**
* @brief Set model
*
* @param[in] client SCCMA client handle
* @param[in] model Copyer to sscma_client_model_t
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_set_model(sscma_client_handle_t client, int model);
/**
* @brief Set sensor
*
* @param[in] client SCCMA client handle
* @param[in] id sensor id
* @param[in] opt_id sensor config
* @param[in] bool true if enable
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_set_sensor(sscma_client_handle_t client, int id, int opt_id, bool enable);
/**
* @brief Get sensor
*
* @param[in] client SCCMA client handle
* @param[in] sensor Copyer to sscma_client_sensor_t
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_get_sensor(sscma_client_handle_t client, sscma_client_sensor_t *sensor);
/**
* @brief SSCMA client sample
* @param[in] client SCCMA client handle
* @param[in] times Number of times
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_sample(sscma_client_handle_t client, int times);
/**
* @brief SSCMA client invoke
* @param[in] client SCCMA client handle
* @param[in] times Number of times
* @param[in] fliter true if fliter
* @param[in] show true if show
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_invoke(sscma_client_handle_t client, int times, bool fliter, bool show);
/**
* @brief SSCMA client break
* @param[in] client SCCMA client handle
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_break(sscma_client_handle_t client);
/**
* @brief Set iou threshold
* @param[in] client SCCMA client handle
* @param[in] threshold iou threshold
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_set_iou_threshold(sscma_client_handle_t client, int threshold);
/**
* @brief Get iou threshold
* @param[in] client SCCMA client handle
* @param[out] threshold iou threshold
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_get_iou_threshold(sscma_client_handle_t client, int *threshold);
/**
* @brief Set confidence threshold
* @param[in] client SCCMA client handle
* @param[in] threshold confidence threshold
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_set_confidence_threshold(sscma_client_handle_t client, int threshold);
/**
* @brief Get confidence threshold
* @param[in] client SCCMA client handle
* @param[out] threshold confidence threshold
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_get_confidence_threshold(sscma_client_handle_t client, int *threshold);
/**
* @brief Set model info
* @param[in] client SCCMA client handle
* @param[in] model_info model info
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_set_model_info(sscma_client_handle_t client, const char *model_info);
/**
* Fetch boxes and classes from sscma client reply
* @param[in] reply sscma client reply
* @param[out] boxes sscma client boxes
* @param[out] num_boxes number of boxes
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_fetch_boxes_from_reply(const sscma_client_reply_t *reply, sscma_client_box_t **boxes, int *num_boxes);
/**
* Prase boxes from sscma client reply
* @param[in] reply sscma client reply
* @param[out] boxes sscma client boxes
* @param[in] max_boxes max number of boxes
* @param[out] num_boxes number of boxes
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_copy_boxes_from_reply(const sscma_client_reply_t *reply, sscma_client_box_t *boxes, int max_boxes, int *num_boxes);
/**
* Fetch classes from sscma client reply
* @param[in] reply sscma client reply
* @param[out] classes sscma client classes
* @param[out] num_classes number of classes
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_fetch_classes_from_reply(const sscma_client_reply_t *reply, sscma_client_class_t **classes, int *num_classes);
/**
* Prase classes from sscma client reply
* @param[in] reply sscma client reply
* @param[out] classes sscma client classes
* @param[in] max_classes max number of classes
* @param[out] num_classes number of classes
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_copy_classes_from_reply(const sscma_client_reply_t *reply, sscma_client_class_t *classes, int max_classes, int *num_classes);
/**
* Fetch points from sscma client reply
* @param[in] reply sscma client reply
* @param[out] points sscma client points
* @param[out] num_points number of points
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_fetch_points_from_reply(const sscma_client_reply_t *reply, sscma_client_point_t **points, int *num_points);
/**
* Prase points from sscma client reply
* @param[in] reply sscma client reply
* @param[out] points sscma client points
* @param[in] max_points max number of points
* @param[out] num_points number of points
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_copy_points_from_reply(const sscma_client_reply_t *reply, sscma_client_point_t *points, int max_points, int *num_points);
/**
* Fetch keypoints from sscma client reply
* @param[in] reply sscma client reply
* @param[out] keypoints sscma client keypoints
* @param[out] num_keypoints number of keypoints
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_fetch_keypoints_from_reply(const sscma_client_reply_t *reply, sscma_client_keypoint_t **keypoints, int *num_keypoints);
/**
* Prase keypoints from sscma client reply
* @param[in] reply sscma client reply
* @param[out] keypoints sscma client keypoints
* @param[in] max_keypoints max number of keypoints
* @param[out] num_keypoints number of keypoints
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_copy_keypoints_from_reply(const sscma_client_reply_t *reply, sscma_client_keypoint_t *keypoints, int max_keypoints, int *num_keypoints);
/**
* Fetch image from sscma client reply
* @param[in] reply sscma client reply
* @param[out] image sscma client image
* @param[out] image_size size of image
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_fetch_image_from_reply(const sscma_client_reply_t *reply, char **image, int *image_size);
/**
* Prase image from sscma client reply
* @param[in] reply sscma client reply
* @param[out] image sscma client image
* @param[in] max_image_size max size of image
* @param[out] image_size size of image
* @return
* - ESP_OK
*/
esp_err_t sscma_utils_copy_image_from_reply(const sscma_client_reply_t *reply, char *image, int max_image_size, int *image_size);
/**
* Start ota
* @param[in] client SCCMA client handle
* @param[in] flasher flasher handle
* @param[in] offset offset in file
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_ota_start(sscma_client_handle_t client, const sscma_client_flasher_handle_t flasher, size_t offset);
/**
* Write data to ota
* @param[in] client SCCMA client handle
* @param[in] data data to write
* @param[in] len length of data
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_ota_write(sscma_client_handle_t client, const void *data, size_t len);
/**
* Finish ota
* @param[in] client SCCMA client handle
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_ota_finish(sscma_client_handle_t client);
/**
* Abort ota
* @param[in] client SCCMA client handle
* @return
* - ESP_OK on success
*/
esp_err_t sscma_client_ota_abort(sscma_client_handle_t client);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,178 @@
#pragma once
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "cJSON.h"
#include "esp_assert.h"
#include "sscma_client_io_interface.h"
#include "sscma_client_flasher_interface.h"
#include "esp_io_expander.h"
#define SSCMA_CLIENT_MODEL_MAX_CLASSES 80
#define SSCMA_CLIENT_MODEL_KEYPOINTS_MAX 80
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sscma_client_t *sscma_client_handle_t; /*!< Type of SCCMA client handle */
typedef struct sscma_client_io_t *sscma_client_io_handle_t; /*!< Type of SSCMA client IO handle */
typedef struct sscma_client_flasher_t *sscma_client_flasher_handle_t; /*!< Type of SCCMA client flasher handle */
/**
* @brief Reply message
*/
typedef struct
{
cJSON *payload;
char *data;
size_t len;
} sscma_client_reply_t;
/**
* @brief Request message
*/
typedef struct
{
char cmd[32];
QueueHandle_t reply;
ListItem_t item;
} sscma_client_request_t;
/**
*
*/
typedef struct
{
char *id; /* !< ID */
char *name; /* !< Name */
char *hw_ver; /* !< Hardware version */
char *sw_ver; /* !< Software version */
char *fw_ver; /* !< Firmware version */
} sscma_client_info_t;
typedef struct
{
int id; /* !< ID */
char *uuid; /* !< UUID */
char *name; /*!< Name */
char *ver; /*!< Version */
char *url; /*!< URL */
char *checksum; /*!< Checksum */
char *classes[SSCMA_CLIENT_MODEL_MAX_CLASSES]; /*!< Classes */
} sscma_client_model_t;
typedef struct
{
int id;
int type;
int state;
int opt_id;
char *opt_detail;
} sscma_client_sensor_t;
typedef struct
{
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
uint8_t score;
uint8_t target;
} sscma_client_box_t;
typedef struct
{
uint8_t target;
uint8_t score;
} sscma_client_class_t;
typedef struct
{
uint16_t x;
uint16_t y;
uint16_t z;
uint8_t score;
uint8_t target;
} sscma_client_point_t;
typedef struct
{
sscma_client_box_t box;
uint8_t points_num;
sscma_client_point_t points[SSCMA_CLIENT_MODEL_KEYPOINTS_MAX];
} sscma_client_keypoint_t;
/**
* @brief Callback function of SCCMA client
* @param[in] client SCCMA client handle
* @param[in] reply Reply message
* @param[in] user_ctx User context
* @return None
*/
typedef void (*sscma_client_reply_cb_t)(sscma_client_handle_t client, const sscma_client_reply_t *reply, void *user_ctx);
/**
* @brief Type of SCCMA client callback
*/
typedef struct
{
sscma_client_reply_cb_t on_connect;
sscma_client_reply_cb_t on_disconnect; // TODO
sscma_client_reply_cb_t on_response;
sscma_client_reply_cb_t on_event;
sscma_client_reply_cb_t on_log;
} sscma_client_callback_t;
struct sscma_client_t
{
sscma_client_io_handle_t io; /* !< IO handle */
sscma_client_flasher_handle_t flasher; /* !< flasher */
int reset_gpio_num; /* !< GPIO number of reset pin */
bool reset_level; /* !< Level of reset pin */
bool inited; /* !< Whether inited */
sscma_client_info_t info; /* !< Info */
sscma_client_model_t model; /* !< Model */
sscma_client_reply_cb_t on_connect; /* !< Callback function */
sscma_client_reply_cb_t on_disconnect; /* !< Callback function */
sscma_client_reply_cb_t on_response; /* !< Callback function */
sscma_client_reply_cb_t on_event; /* !< Callback function */
sscma_client_reply_cb_t on_log; /* !< Callback function */
void *user_ctx; /* !< User context */
esp_io_expander_handle_t io_expander; /* !< IO expander handle */
struct
{
TaskHandle_t handle;
#ifdef CONFIG_SSCMA_PROCESS_TASK_STACK_ALLOC_EXTERNAL
StaticTask_t *task;
StackType_t *stack;
#endif
} monitor_task;
struct
{
TaskHandle_t handle;
#ifdef CONFIG_SSCMA_MONITOR_TASK_STACK_ALLOC_EXTERNAL
StaticTask_t *task;
StackType_t *stack;
#endif
} process_task;
struct
{
char *data; /* !< Data buffer */
size_t len; /* !< Data length */
size_t pos; /* !< Data position */
} rx_buffer, tx_buffer; /* !< RX and TX buffer */
QueueHandle_t reply_queue; /* !< Queue for reply message */
List_t *request_list; /* !< Request list */
};
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,112 @@
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sscma_client_flasher_t sscma_client_flasher_t; /*!< Type of SSCMA flasher handle */
struct sscma_client_flasher_t
{
/**
* @brief Start flasher transmitter
* @param[in] handle transmitter handle
* @param[in] offset offset
* @return
* - ESP_OK
*/
esp_err_t (*start)(sscma_client_flasher_t *handle, size_t offset);
/**
* @brief Write data to flasher transmitter
* @param[in] handle transmitter handle
* @param[in] data data
* @param[in] len length
* @return
* - ESP_OK
*/
esp_err_t (*write)(sscma_client_flasher_t *handle, const void *data, size_t len);
/**
* @brief Start flasher transmitter
* @param[in] handle transmitter handle
* @return
* - ESP_OK
*/
esp_err_t (*finish)(sscma_client_flasher_t *handle);
/**
* @brief Abort flasher transmitter
* @param[in] handle transmitter handle
* @return
* - ESP_OK
*/
esp_err_t (*abort)(sscma_client_flasher_t *handle);
/**
* @brief Delete flasher transmitter
* @param[in] handle transmitter handle
* @return
* - ESP_OK
*/
esp_err_t (*del)(sscma_client_flasher_t *handle);
};
/**
* Start flasher transmitter
* @param[in] handle transmitter handle
* @param[in] offset offset
* @return
* - ESP_OK
*/
esp_err_t sscma_client_flasher_start(sscma_client_flasher_t *handle, size_t offset);
/**
* Write data to flasher transmitter
* @param[in] handle transmitter handle
* @param[in] data data
* @param[in] len length
* @return
* - ESP_OK
*/
esp_err_t sscma_client_flasher_write(sscma_client_flasher_t *handle, const void *data, size_t len);
/**
* Finish flasher transmitter
* @param[in] handle transmitter handle
* @return
* - ESP_OK
*/
esp_err_t sscma_client_flasher_finish(sscma_client_flasher_t *handle);
/**
* Abort flasher transmitter
* @param[in] handle transmitter handle
* @return
* - ESP_OK
*/
esp_err_t sscma_client_flasher_abort(sscma_client_flasher_t *handle);
/**
* Delete flasher transmitter
* @param[in] handle transmitter handle
* @return
* - ESP_OK
*/
esp_err_t sscma_client_flasher_delete(sscma_client_flasher_t *handle);
/**
* Create xmodem flasher
* @param[in] io io
* @param[out] ret_handle handle
* @return
* - ESP_OK
*/
esp_err_t sscma_client_flasher_xmodem_create(sscma_client_io_t *io, sscma_client_flasher_t **ret_handle);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,82 @@
#pragma once
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct sscma_client_io_t sscma_client_io_t; /*!< Type of SSCMA client IO */
/**
* @brief SSCMA IO interface
*/
struct sscma_client_io_t
{
/**
* @brief Bus handle
*/
void *handle;
/**
* @brief Destory SCCMA client
*
* @param[in] io SCCMA client handle]
* @return
* - ESP_OK on success
*/
esp_err_t (*del)(sscma_client_io_t *io);
/**
* @brief Write data to SCCMA client
*
* @param[in] io SCCMA client handle
* @param[in] data Data to be written
* @param[in] size Size of data
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NOT_SUPPORTED if read is not supported by transport
* - ESP_OK on success
*/
esp_err_t (*write)(sscma_client_io_t *io, const void *data, size_t size);
/**
* @brief Read data from SCCMA client
*
* @param[in] io SCCMA client IO handle
* @param[in] data Data to be read
* @param[in] size Size of data
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NOT_SUPPORTED if read is not supported by transport
* - ESP_OK on success
*
*/
esp_err_t (*read)(sscma_client_io_t *io, void *data, size_t size);
/**
* @brief Get available size of data
*
* @param[in] io SCCMA client IO handle
* @param[out] ret_avail Available size
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NOT_SUPPORTED if read is not supported by transport
* - ESP_OK
*/
esp_err_t (*available)(sscma_client_io_t *io, size_t *ret_avail);
/**
* @brief Flush data
*
* @param[in] io IO handle
* @return
* - ESP_OK
*/
esp_err_t (*flush)(sscma_client_io_t *io);
};
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

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