add some code
This commit is contained in:
@@ -0,0 +1 @@
|
||||
bf7d4a1f157303f4850d0b9b465c733ce38e8689ff40ac4743a44520524c41d5
|
||||
@@ -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"}]}
|
||||
18
managed_components/wvirgil123__sscma_client/CMakeLists.txt
Normal file
18
managed_components/wvirgil123__sscma_client/CMakeLists.txt
Normal 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}
|
||||
)
|
||||
93
managed_components/wvirgil123__sscma_client/README.md
Normal file
93
managed_components/wvirgil123__sscma_client/README.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# SSCMA Client
|
||||
|
||||
[](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);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "sscma_client_io.h"
|
||||
#include "sscma_client_flasher.h"
|
||||
#include "sscma_client_ops.h"
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
202
managed_components/wvirgil123__sscma_client/license.txt
Normal file
202
managed_components/wvirgil123__sscma_client/license.txt
Normal 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.
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
1806
managed_components/wvirgil123__sscma_client/src/sscma_client_ops.c
Normal file
1806
managed_components/wvirgil123__sscma_client/src/sscma_client_ops.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user