first
This commit is contained in:
418
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.c
Normal file
418
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.c
Normal file
@ -0,0 +1,418 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_enc.h"
|
||||
|
||||
#if TCFG_GX8002_ENC_ENABLE
|
||||
|
||||
#define GX8002_DEBUG_ENABLE 1
|
||||
|
||||
#define gx8002_info printf
|
||||
#if GX8002_DEBUG_ENABLE
|
||||
#define gx8002_debug printf
|
||||
#define gx8002_put_buf put_buf
|
||||
#else
|
||||
#define gx8002_debug(...)
|
||||
#define gx8002_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
|
||||
//====================================================================//
|
||||
// AC897N GX8002 ENC模型 //
|
||||
/*
|
||||
________ ________
|
||||
| | PCM 2CH | |
|
||||
| TX|----------------->|RX |
|
||||
| UART | | UART |
|
||||
| | PCM 1CH | |
|
||||
| RX|<-----------------|TX |
|
||||
|________| |________|
|
||||
BT_CHIP GX8002
|
||||
|
||||
NOTE:
|
||||
*/
|
||||
|
||||
//====================================================================//
|
||||
#define UART_RX_BUF_POINTS (256 * 4) // buf_len = UART_RX_BUF_POINTS x sizeof(16)
|
||||
#define UART_RX_BUF_FRAME_LEN (256 * sizeof(s16) * 2) // buf_len = UART_RX_BUF_FRAME_LEN
|
||||
#define UART_TX_BUF_POINTS (256 * 2) //buf_len = UART_TX_BUF_POINTS x sizeof(16)
|
||||
#define UART_TRANSPORT_BUAD 1000000 //发送波特率
|
||||
|
||||
#define THIS_TASK_NAME "gx8002_enc"
|
||||
|
||||
struct gx8002_enc_t {
|
||||
u8 task_init;
|
||||
u8 state;
|
||||
const uart_bus_t *uart_bus;
|
||||
OS_SEM rx_sem;
|
||||
int uart_rxbuf[(UART_RX_BUF_POINTS * sizeof(s16)) / sizeof(int)]; //uart硬件RX dma缓存, 要求buf长度为2的n次幂, 4字节对齐
|
||||
int uart_txbuf[(UART_TX_BUF_POINTS * sizeof(s16)) / sizeof(int)]; //uart硬件TX dma缓存, 要求buf4字节对齐
|
||||
int uart_rx_frame_buf[UART_RX_BUF_FRAME_LEN / sizeof(int)]; //用于读取Rx缓存中的数据, 临时buf
|
||||
};
|
||||
|
||||
enum {
|
||||
GX8002_ENC_STATE_CLOSE = 0,
|
||||
GX8002_ENC_STATE_OPEN,
|
||||
GX8002_ENC_STATE_RUN,
|
||||
};
|
||||
|
||||
|
||||
static struct gx8002_enc_t *gx8002_enc = NULL;
|
||||
|
||||
//============== extern function =================//
|
||||
/* extern void gx8002_vddio_power_ctrl(u8 on); */
|
||||
/* extern void gx8002_core_vdd_power_ctrl(u8 on); */
|
||||
|
||||
//for make
|
||||
__attribute__((weak))
|
||||
void gx8002_board_port_suspend(void)
|
||||
{
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void gx8002_vddio_power_ctrl(u8 on)
|
||||
{
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void gx8002_core_vdd_power_ctrl(u8 on)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_device_power_on(void)
|
||||
{
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2); //vddio先上电 --> wait 20ms --> core_vdd上电
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
}
|
||||
|
||||
static void gx8002_device_power_off(void)
|
||||
{
|
||||
gx8002_vddio_power_ctrl(0);
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
static void gx8002_enc_data_output(void)
|
||||
{
|
||||
int ret = 0;
|
||||
s16 *rxbuf = NULL;
|
||||
s16 magic_code = 0;
|
||||
static u8 cnt = 0;
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_RUN)) {
|
||||
if (gx8002_enc->uart_bus && gx8002_enc->uart_bus->read) {
|
||||
rxbuf = (s16 *)(gx8002_enc->uart_rx_frame_buf);
|
||||
putchar('r');
|
||||
ret = gx8002_enc->uart_bus->read((u8 *)rxbuf, UART_RX_BUF_FRAME_LEN, 0);
|
||||
#if 1
|
||||
//数据校验
|
||||
magic_code = rxbuf[0];
|
||||
for (int i = 1; i < ret / sizeof(s16); i++) {
|
||||
if (rxbuf[i] != magic_code) {
|
||||
if (rxbuf[i] != (magic_code + 1)) {
|
||||
gx8002_debug("data err: magic_code = 0x%x, rxbuf[%d] = 0x%x", magic_code, i, rxbuf[i]);
|
||||
printf("buf_in = %d", gx8002_enc->uart_bus->kfifo.buf_in);
|
||||
printf("buf_out = %d", gx8002_enc->uart_bus->kfifo.buf_out);
|
||||
put_buf(gx8002_enc->uart_bus->kfifo.buffer, gx8002_enc->uart_bus->kfifo.buf_size);
|
||||
ASSERT(0);
|
||||
break;
|
||||
wdt_clear();
|
||||
} else {
|
||||
magic_code++;
|
||||
gx8002_debug("increase: 0x%x", magic_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_enc_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
//RX pending
|
||||
os_sem_post(&(gx8002_enc->rx_sem));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_enc_uart_porting_config(u32 baud)
|
||||
{
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
u_arg.tx_pin = TCFG_GX8002_ENC_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_ENC_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = gx8002_enc->uart_rxbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(gx8002_enc->uart_rxbuf);
|
||||
u_arg.frame_length = UART_RX_BUF_FRAME_LEN;
|
||||
u_arg.rx_timeout = 100;
|
||||
u_arg.isr_cbfun = gx8002_enc_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
gx8002_enc->uart_bus = uart_dev_open(&u_arg);
|
||||
|
||||
if (gx8002_enc->uart_bus) {
|
||||
gx8002_info("gx8002 uart init succ");
|
||||
} else {
|
||||
gx8002_info("gx8002 uart init fail");
|
||||
ASSERT(gx8002_enc->uart_bus);
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_enc_uart_porting_close(void)
|
||||
{
|
||||
if (gx8002_enc && gx8002_enc->uart_bus) {
|
||||
uart_dev_close((uart_bus_t *)(gx8002_enc->uart_bus));
|
||||
gx8002_board_port_suspend();
|
||||
gx8002_enc->uart_bus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void __gx8002_enc_run(void)
|
||||
{
|
||||
//TODO: add gx8002 post start msg
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
while (1) {
|
||||
os_sem_pend(&(gx8002_enc->rx_sem), 0);
|
||||
|
||||
if (gx8002_enc->state != GX8002_ENC_STATE_RUN) {
|
||||
break;
|
||||
}
|
||||
|
||||
gx8002_enc_data_output();
|
||||
}
|
||||
}
|
||||
|
||||
static void __gx8002_enc_close(int priv)
|
||||
{
|
||||
if (gx8002_enc) {
|
||||
if (gx8002_enc->state == GX8002_ENC_STATE_CLOSE) {
|
||||
gx8002_device_power_off();
|
||||
gx8002_enc_uart_porting_close();
|
||||
if (priv) {
|
||||
os_sem_post((OS_SEM *)priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_enc_task(void *priv)
|
||||
{
|
||||
int msg[16];
|
||||
int res;
|
||||
|
||||
os_sem_create(&(gx8002_enc->rx_sem), 0);
|
||||
|
||||
gx8002_enc_uart_porting_config(UART_TRANSPORT_BUAD);
|
||||
gx8002_device_power_on();
|
||||
|
||||
gx8002_enc->state = GX8002_ENC_STATE_OPEN;
|
||||
|
||||
if (priv) {
|
||||
os_sem_post((OS_SEM *)priv);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
|
||||
if (res == OS_TASKQ) {
|
||||
switch (msg[1]) {
|
||||
case GX8002_ENC_MSG_RUN:
|
||||
__gx8002_enc_run();
|
||||
break;
|
||||
case GX8002_ENC_MSG_CLOSE:
|
||||
__gx8002_enc_close(msg[2]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//====================================================================//
|
||||
// GX8002 ENC API //
|
||||
//====================================================================//
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 打开gx8002_enc流程, 创建gx8002线程
|
||||
@param void
|
||||
@return void
|
||||
@note 不能在中断中调用, 需要在线程中调用;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_open(void)
|
||||
{
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
if (gx8002_enc == NULL) {
|
||||
gx8002_enc = zalloc(sizeof(struct gx8002_enc_t));
|
||||
if (gx8002_enc == NULL) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
OS_SEM sem_wait;
|
||||
os_sem_create(&sem_wait, 0);
|
||||
gx8002_enc->task_init = 1;
|
||||
task_create(gx8002_enc_task, (void *)&sem_wait, THIS_TASK_NAME);
|
||||
|
||||
os_sem_pend(&sem_wait, 0);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 启动gx8002_enc流程
|
||||
@param void
|
||||
@return void
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_start(void)
|
||||
{
|
||||
gx8002_debug("%s", __func__);
|
||||
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_OPEN)) {
|
||||
gx8002_enc->state = GX8002_ENC_STATE_RUN;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_ENC_MSG_RUN);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 关闭gx8002_enc流程, 释放资源
|
||||
@param void
|
||||
@return void
|
||||
@note 不能在中断中调用, 需要在线程中调用;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void gx8002_enc_close(void)
|
||||
{
|
||||
OS_SEM sem_wait;
|
||||
|
||||
gx8002_debug("%s", __func__);
|
||||
if (gx8002_enc) {
|
||||
if (gx8002_enc->task_init) {
|
||||
os_sem_create(&sem_wait, 0);
|
||||
gx8002_enc->state = GX8002_ENC_STATE_CLOSE;
|
||||
os_sem_post(&(gx8002_enc->rx_sem));
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_ENC_MSG_CLOSE, (u32)&sem_wait);
|
||||
os_sem_pend(&sem_wait, 0);
|
||||
gx8002_enc->task_init = 0;
|
||||
task_kill(THIS_TASK_NAME);
|
||||
}
|
||||
|
||||
free(gx8002_enc);
|
||||
gx8002_enc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief gx8002_enc数据输入, 支持1~2通道数据输入
|
||||
@param ch0_buf: 通道0数据buf
|
||||
@param ch1_buf: 通道1数据buf
|
||||
@param points: ch0和ch1 buf中点数
|
||||
@return
|
||||
@note 1)不能在中断中调用, 需要在线程中调用;
|
||||
@note 2)如果只有1通道数据, 把ch0_buf/ch1_buf传参为NULL即可;
|
||||
@note 3)ch0_buf和ch1_buf数据宽度为16bit;
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
u32 gx8002_enc_data_input(s16 *ch0_buf, s16 *ch1_buf, u32 points)
|
||||
{
|
||||
u32 send_points = 0;
|
||||
s16 *txbuf = NULL;
|
||||
u32 remain_points = points;
|
||||
u32 txbuf_points = 0;
|
||||
u8 ch_num = 0;
|
||||
|
||||
if (gx8002_enc && (gx8002_enc->state == GX8002_ENC_STATE_RUN)) {
|
||||
if (gx8002_enc->uart_bus && gx8002_enc->uart_bus->write) {
|
||||
if (ch0_buf && ch1_buf) {
|
||||
//2ch
|
||||
ch_num = 2;
|
||||
txbuf_points = (sizeof(gx8002_enc->uart_txbuf) / sizeof(s16) / 2);
|
||||
} else {
|
||||
ch_num = 1;
|
||||
if (ch0_buf == NULL) {
|
||||
ch0_buf = ch1_buf;
|
||||
}
|
||||
txbuf_points = (sizeof(gx8002_enc->uart_txbuf) / sizeof(s16));
|
||||
}
|
||||
|
||||
txbuf = (s16 *)(gx8002_enc->uart_txbuf);
|
||||
while (remain_points) {
|
||||
send_points = remain_points <= txbuf_points ? remain_points : txbuf_points;
|
||||
//gx8002_debug("send_points: %d", send_points);
|
||||
if (ch_num == 2) {
|
||||
for (int i = 0; i < send_points; i++) {
|
||||
txbuf[2 * i] = ch0_buf[i];
|
||||
txbuf[2 * i + 1] = ch1_buf[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < send_points; i++) {
|
||||
txbuf[i] = ch0_buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
gx8002_enc->uart_bus->write((const u8 *)txbuf, send_points * sizeof(s16) * ch_num);
|
||||
remain_points -= send_points;
|
||||
}
|
||||
|
||||
return points * sizeof(s16) * ch_num;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//====================================================================//
|
||||
// GX8002 ENC TEST //
|
||||
//====================================================================//
|
||||
|
||||
static void gx8002_enc_input_test(void *priv)
|
||||
{
|
||||
|
||||
if (gx8002_enc == NULL) {
|
||||
putchar('i');
|
||||
return;
|
||||
}
|
||||
#define BUF_TEST_POINTS 300
|
||||
static s16 cnt = 0x0;
|
||||
s16 tmp_buf[BUF_TEST_POINTS];
|
||||
putchar('w');
|
||||
cnt++;
|
||||
for (int i = 0; i < ARRAY_SIZE(tmp_buf); i++) {
|
||||
tmp_buf[i] = cnt;
|
||||
}
|
||||
//gx8002_enc_data_input(tmp_buf, NULL, BUF_TEST_POINTS); //1ch data
|
||||
gx8002_enc_data_input(tmp_buf, tmp_buf, BUF_TEST_POINTS); //two ch data
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
static void gx8002_enc_close_test(void *priv)
|
||||
{
|
||||
gx8002_enc_close();
|
||||
}
|
||||
|
||||
static int gx8002_enc_test(void)
|
||||
{
|
||||
gx8002_enc_open();
|
||||
gx8002_enc_start();
|
||||
|
||||
sys_timer_add(NULL, gx8002_enc_input_test, 50);
|
||||
sys_timer_add(NULL, gx8002_enc_close_test, 1000 * 60 * 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
//late_initcall(gx8002_enc_test);
|
||||
|
||||
|
||||
#endif /* #if TCFG_GX8002_ENC_ENABLE */
|
||||
10
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.h
Normal file
10
apps/common/device/gx8002_npu/gx8002_enc/gx8002_enc.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef __GX8002_NPU_H__
|
||||
#define __GX8002_NPU_H__
|
||||
|
||||
enum GX8002_MSG {
|
||||
GX8002_ENC_MSG_RUN = ('G' << 24) | ('E' << 16) | ('N' << 8) | ('C' << 0),
|
||||
GX8002_ENC_MSG_CLOSE,
|
||||
};
|
||||
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_H__ */
|
||||
921
apps/common/device/gx8002_npu/gx8002_npu.c
Normal file
921
apps/common/device/gx8002_npu/gx8002_npu.c
Normal file
@ -0,0 +1,921 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_npu.h"
|
||||
#include "gx8002_npu_api.h"
|
||||
#include "asm/pwm_led.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define GX8002_DEBUG_ENABLE 0
|
||||
|
||||
#define gx8002_info g_printf
|
||||
#if GX8002_DEBUG_ENABLE
|
||||
#define gx8002_debug g_printf
|
||||
#define gx8002_put_buf put_buf
|
||||
#else
|
||||
#define gx8002_debug(...)
|
||||
#define gx8002_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
|
||||
|
||||
//===========================================================//
|
||||
// GX8002 NPU LOGIC LAYER //
|
||||
//===========================================================//
|
||||
///// 分配内存 /////
|
||||
#define OS_MALLOC malloc
|
||||
|
||||
///// 释放内存 /////
|
||||
#define OS_FREE free
|
||||
|
||||
static const char msg_rcv_magic[MSG_MAGIC_LEN] = {
|
||||
MSG_RCV_MAGIC0, MSG_RCV_MAGIC1,
|
||||
MSG_RCV_MAGIC2, MSG_RCV_MAGIC3
|
||||
};
|
||||
|
||||
static unsigned char msg_seq = 0;
|
||||
static unsigned char initialized = 0;
|
||||
static struct message prev_snd_msg;
|
||||
static struct message prev_rcv_msg;
|
||||
static STREAM_READ stream_read = NULL;
|
||||
static STREAM_WRITE stream_write = NULL;
|
||||
static STREAM_EMPTY stream_is_empty = NULL;
|
||||
|
||||
struct msg_header {
|
||||
unsigned int magic;
|
||||
unsigned short cmd;
|
||||
unsigned char seq;
|
||||
unsigned char flags;
|
||||
unsigned short length;
|
||||
unsigned int crc32;
|
||||
} __attribute__((packed));
|
||||
|
||||
static const unsigned int crc32tab[] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
|
||||
0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
|
||||
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
|
||||
0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
|
||||
0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
|
||||
0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
|
||||
0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
|
||||
0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
|
||||
0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
|
||||
0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
|
||||
0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
|
||||
0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
|
||||
0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
|
||||
0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
|
||||
0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
|
||||
0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
|
||||
0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
|
||||
0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
|
||||
0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
|
||||
0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
|
||||
0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
|
||||
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
|
||||
0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
|
||||
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
|
||||
0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
|
||||
0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
|
||||
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
|
||||
0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
|
||||
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
|
||||
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
|
||||
0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
|
||||
0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
|
||||
0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
|
||||
0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
|
||||
0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
|
||||
0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
|
||||
0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
|
||||
0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
|
||||
0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
|
||||
0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
|
||||
0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
|
||||
0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
|
||||
0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
|
||||
0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
|
||||
0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
|
||||
0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
|
||||
0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
|
||||
0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
|
||||
0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
|
||||
0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
|
||||
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
|
||||
0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
|
||||
};
|
||||
|
||||
static unsigned int crc32(const unsigned char *buf, unsigned int size)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int crc = 0xFFFFFFFF;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
crc = crc32tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static inline int stream_getc(char *ch)
|
||||
{
|
||||
int ret = stream_read((unsigned char *)ch, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int msg_byte_match(char c)
|
||||
{
|
||||
char ch = 0;
|
||||
|
||||
return (stream_getc(&ch) && (ch == c));
|
||||
}
|
||||
|
||||
static int msg_find_magic(void)
|
||||
{
|
||||
int i;
|
||||
int offset = 0;
|
||||
|
||||
while (offset < MSG_LEN_MAX) {
|
||||
for (i = 0; i < MSG_MAGIC_LEN; i++) {
|
||||
offset++;
|
||||
if (!msg_byte_match(msg_rcv_magic[i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((i + 1) == MSG_MAGIC_LEN) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned char msg_get_new_seq(unsigned char seq)
|
||||
{
|
||||
unsigned char next_seq;
|
||||
|
||||
next_seq = (seq + 1) % MSG_SEQ_MAX;
|
||||
|
||||
return next_seq == 0 ? next_seq + 1 : next_seq;
|
||||
}
|
||||
|
||||
static int nc_message_receive(struct message *msg)
|
||||
{
|
||||
struct msg_header msg_header;
|
||||
unsigned int newcrc32 = 0;
|
||||
unsigned int oldcrc32 = 0;
|
||||
unsigned short bodylen;
|
||||
unsigned char *pheader = (unsigned char *)&msg_header;
|
||||
|
||||
if (!msg || !initialized) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream_is_empty()) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read stream until find mseeage magic */
|
||||
if (msg_find_magic() != 0) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&msg_header, 0, sizeof(struct msg_header));
|
||||
msg_header.magic = MSG_MAGIC;
|
||||
|
||||
/* Read the rest of message header */
|
||||
stream_read(pheader + MSG_MAGIC_LEN,
|
||||
sizeof(struct msg_header) - MSG_MAGIC_LEN);
|
||||
|
||||
/* Check message header integrity */
|
||||
newcrc32 = crc32((unsigned char *)&msg_header,
|
||||
sizeof(struct msg_header) - MSG_HEAD_CHECK_LEN);
|
||||
if (newcrc32 != msg_header.crc32) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read message body */
|
||||
if (msg_header.length > 0) {
|
||||
|
||||
msg->body = OS_MALLOC(msg_header.length);
|
||||
if (msg->body == NULL) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream_read(msg->body, msg_header.length);
|
||||
if (MSG_NEED_BCHECK(msg_header.flags)) {
|
||||
bodylen = msg_header.length - MSG_BODY_CHECK_LEN;
|
||||
newcrc32 = crc32(msg->body, bodylen);
|
||||
memcpy(&oldcrc32, msg->body + bodylen, MSG_BODY_CHECK_LEN);
|
||||
|
||||
if (oldcrc32 != newcrc32) {
|
||||
line_inf;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
bodylen = msg_header.length;
|
||||
}
|
||||
} else {
|
||||
bodylen = 0;
|
||||
}
|
||||
|
||||
msg->cmd = msg_header.cmd;
|
||||
msg->seq = msg_header.seq;
|
||||
msg->flags = msg_header.flags;
|
||||
msg->bodylen = bodylen;
|
||||
|
||||
prev_rcv_msg.cmd = msg->cmd;
|
||||
prev_rcv_msg.seq = msg->seq;
|
||||
|
||||
return bodylen;
|
||||
}
|
||||
|
||||
static int nc_message_send(struct message *msg)
|
||||
{
|
||||
struct msg_header msg_header;
|
||||
unsigned int body_crc32 = 0;
|
||||
|
||||
if (!msg || !initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&msg_header, 0, sizeof(struct msg_header));
|
||||
|
||||
msg_header.magic = MSG_MAGIC;
|
||||
msg_header.cmd = msg->cmd;
|
||||
msg_header.flags = msg->flags;
|
||||
|
||||
if ((msg->cmd == prev_snd_msg.cmd) &&
|
||||
(msg->seq == prev_snd_msg.seq) &&
|
||||
(MSG_TYPE(msg->cmd)) == MSG_TYPE_REQ) {
|
||||
msg_seq = prev_snd_msg.seq;
|
||||
} else {
|
||||
msg_seq = msg_get_new_seq(msg_seq);
|
||||
}
|
||||
|
||||
msg_header.seq = msg_seq;
|
||||
|
||||
if (!msg->body) {
|
||||
msg_header.length = 0;
|
||||
} else {
|
||||
if (MSG_NEED_BCHECK(msg->flags)) {
|
||||
body_crc32 = crc32((unsigned char *)msg->body, msg->bodylen);
|
||||
msg_header.length = msg->bodylen + MSG_BODY_CHECK_LEN;
|
||||
} else {
|
||||
msg_header.length = msg->bodylen;
|
||||
}
|
||||
}
|
||||
|
||||
msg_header.crc32 = crc32((unsigned char *)&msg_header,
|
||||
sizeof(struct msg_header) - MSG_BODY_CHECK_LEN);
|
||||
|
||||
stream_write((unsigned char *)&msg_header, sizeof(struct msg_header));
|
||||
|
||||
if (msg->body) {
|
||||
stream_write(msg->body, msg->bodylen);
|
||||
if (MSG_NEED_BCHECK(msg->flags)) {
|
||||
stream_write((unsigned char *)&body_crc32, MSG_BODY_CHECK_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
prev_snd_msg.cmd = msg->cmd;
|
||||
prev_snd_msg.seq = msg_seq;
|
||||
msg->seq = msg_seq;
|
||||
|
||||
return msg->bodylen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int nc_message_init(STREAM_READ read, STREAM_WRITE write, STREAM_EMPTY is_empty)
|
||||
{
|
||||
if (!read || !write || !is_empty) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream_read = read;
|
||||
stream_write = write;
|
||||
stream_is_empty = is_empty;
|
||||
|
||||
msg_seq = 0;
|
||||
memset(&prev_rcv_msg, 0xFF, sizeof(prev_rcv_msg));
|
||||
memset(&prev_snd_msg, 0xFF, sizeof(prev_snd_msg));
|
||||
initialized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_uart_agent_query_event(unsigned short cmd)
|
||||
{
|
||||
struct message snd_msg = {0};
|
||||
gx8002_info("gx8002 task query msg");
|
||||
|
||||
//snd_msg.cmd = MSG_REQ_VOICE_EVENT;
|
||||
snd_msg.cmd = cmd;
|
||||
snd_msg.flags = 0;
|
||||
snd_msg.body = NULL;
|
||||
snd_msg.bodylen = 0;
|
||||
|
||||
return nc_message_send(&snd_msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========================================================//
|
||||
// GX8002 NPU PORT LAYER //
|
||||
//===========================================================//
|
||||
|
||||
#define THIS_TASK_NAME "gx8002"
|
||||
|
||||
enum GX8002_STATE {
|
||||
GX8002_STATE_WORKING = 1,
|
||||
GX8002_STATE_SUSPEND,
|
||||
GX8002_STATE_UPGRADING,
|
||||
};
|
||||
|
||||
|
||||
struct gx8002_handle {
|
||||
u8 state;
|
||||
u8 idle; //0: busy, 1: idle
|
||||
OS_SEM rx_sem;
|
||||
const uart_bus_t *uart_bus;
|
||||
};
|
||||
|
||||
static struct gx8002_handle hdl;
|
||||
|
||||
#define __this (&hdl)
|
||||
static u8 uart_cbuf[32] __attribute__((aligned(4)));
|
||||
u8 gx_self_info[6] = {0, 0, 0, 0, //version
|
||||
0, //mic status
|
||||
0
|
||||
}; //gsensor status
|
||||
|
||||
//============== extern function =================//
|
||||
extern void gx8002_board_port_resumed(void);
|
||||
extern void gx8002_board_port_suspend(void);
|
||||
extern void gx8002_vddio_power_ctrl(u8 on);
|
||||
extern void gx8002_core_vdd_power_ctrl(u8 on);
|
||||
|
||||
static void gx8002_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
gx8002_info("gx8002 uart RX pnding");
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_uart_porting_config(u32 baud)
|
||||
{
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
if (__this->uart_bus) {
|
||||
gx8002_info("gx8002 uart have init");
|
||||
return;
|
||||
}
|
||||
u_arg.tx_pin = TCFG_GX8002_NPU_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_NPU_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = uart_cbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(uart_cbuf);
|
||||
u_arg.frame_length = 0xFFFF;
|
||||
u_arg.rx_timeout = 100;
|
||||
u_arg.isr_cbfun = gx8002_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
__this->uart_bus = uart_dev_open(&u_arg);
|
||||
if (__this->uart_bus) {
|
||||
gx8002_info("gx8002 uart init succ");
|
||||
} else {
|
||||
gx8002_info("gx8002 uart init fail");
|
||||
ASSERT(__this->uart_bus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_uart_porting_close(void)
|
||||
{
|
||||
if (__this->uart_bus) {
|
||||
uart_dev_close(__this->uart_bus);
|
||||
gpio_disable_fun_output_port(TCFG_GX8002_NPU_UART_TX_PORT);
|
||||
gx8002_board_port_suspend();
|
||||
__this->uart_bus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int gx8002_uart_stream_read(unsigned char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ASSERT(__this->uart_bus && __this->uart_bus->read);
|
||||
if (__this->uart_bus && __this->uart_bus->read) {
|
||||
ret = __this->uart_bus->read(buf, len, 1000);
|
||||
gx8002_debug("stream read len %d", len);
|
||||
gx8002_put_buf(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gx8002_uart_stream_write(const unsigned char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ASSERT(__this->uart_bus && __this->uart_bus->write);
|
||||
if (__this->uart_bus && __this->uart_bus->write) {
|
||||
__this->uart_bus->write(buf, len);
|
||||
ret = len;
|
||||
gx8002_debug("stream write len %d", len);
|
||||
gx8002_put_buf(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gx8002_uart_stream_is_empty(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_uart_porting_poll(u32 timeout)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_power_off(void)
|
||||
{
|
||||
//由板级提供
|
||||
gx8002_board_port_suspend();
|
||||
gx8002_vddio_power_ctrl(0);
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
static void gx8002_power_off_keep_vddio(void)
|
||||
{
|
||||
//由板级提供
|
||||
gx8002_board_port_suspend();
|
||||
//gx8002_vddio_power_ctrl(0); //通话是会影响mic配置, 不关MIC_LDO
|
||||
gx8002_core_vdd_power_ctrl(0);
|
||||
}
|
||||
|
||||
//======================================//
|
||||
// GX8002上电注意事项:
|
||||
// 1) 正常上电需要先将uart IO初始化为确认电平, 否则gx8002会进入升级模式;
|
||||
// 2) vddio先上电, core_vdd需要等vddio上电后之后3ms后上电;
|
||||
//======================================//
|
||||
static void gx8002_normal_power_on(void)
|
||||
{
|
||||
gx8002_board_port_resumed();
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
}
|
||||
|
||||
//进升级模式
|
||||
static void gx8002_upgrade_power_on(void)
|
||||
{
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(2);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
gx8002_board_port_resumed();
|
||||
}
|
||||
|
||||
static void gx8002_first_power_on(void)
|
||||
{
|
||||
//由板级提供
|
||||
//gx8002_core_vdd_power_ctrl(0);
|
||||
gx8002_vddio_power_ctrl(1);
|
||||
os_time_dly(10);
|
||||
gx8002_core_vdd_power_ctrl(1);
|
||||
|
||||
//gx8002_board_port_resumed();
|
||||
}
|
||||
|
||||
|
||||
static void __gx8002_module_suspend(u8 keep_vddio)
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
if (keep_vddio) {
|
||||
gx8002_power_off_keep_vddio();
|
||||
} else {
|
||||
gx8002_power_off();
|
||||
}
|
||||
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return;
|
||||
}
|
||||
__this->state = GX8002_STATE_SUSPEND;
|
||||
}
|
||||
|
||||
static void __gx8002_module_resumed()
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
gx8002_normal_power_on();
|
||||
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return;
|
||||
}
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
}
|
||||
|
||||
void gx8002_module_suspend(u8 keep_vddio)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_SUSPEND, keep_vddio);
|
||||
}
|
||||
|
||||
void gx8002_module_resumed()
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_RESUMED);
|
||||
}
|
||||
|
||||
void gx8002_normal_cold_reset(void)
|
||||
{
|
||||
gx8002_power_off();
|
||||
os_time_dly(50);
|
||||
gx8002_normal_power_on();
|
||||
}
|
||||
|
||||
void gx8002_upgrade_cold_reset(void)
|
||||
{
|
||||
gx8002_power_off();
|
||||
os_time_dly(50);
|
||||
gx8002_upgrade_power_on();
|
||||
}
|
||||
|
||||
int gx8002_uart_spp_ota_init(void);
|
||||
static void gx8002_app_event_handler(struct sys_event *event)
|
||||
{
|
||||
gx8002_info("%s", __func__);
|
||||
struct bt_event *bt = &(event->u.bt);
|
||||
switch (event->type) {
|
||||
case SYS_BT_EVENT:
|
||||
if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
|
||||
switch (bt->event) {
|
||||
case BT_STATUS_FIRST_CONNECTED:
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
gx8002_uart_spp_ota_init();
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
break;
|
||||
#if 0
|
||||
case BT_STATUS_SCO_STATUS_CHANGE:
|
||||
if (bt->value != 0xff) {
|
||||
gx8002_module_suspend();
|
||||
} else {
|
||||
gx8002_module_resumed();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_wakeup_handle(unsigned short cmd)
|
||||
{
|
||||
int err;
|
||||
struct message recv_msg = {0};
|
||||
unsigned short event;
|
||||
int ret = 0;
|
||||
|
||||
if (__this->state != GX8002_STATE_WORKING) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (gx8002_uart_porting_poll(1000) > 0) {
|
||||
os_sem_set(&(__this->rx_sem), 0);
|
||||
gx8002_uart_agent_query_event(cmd);
|
||||
|
||||
err = os_sem_pend(&(__this->rx_sem), 100);
|
||||
if (err != OS_NO_ERR) {
|
||||
gx8002_info("rx sem err: %d", err);
|
||||
__this->idle = 1;
|
||||
return -1;
|
||||
}
|
||||
gx8002_info("gx8002 task receive >>>>");
|
||||
// 有串口数据
|
||||
memset(&recv_msg, 0, sizeof(recv_msg));
|
||||
if (nc_message_receive(&recv_msg) < 0) {
|
||||
if (recv_msg.body) {
|
||||
OS_FREE(recv_msg.body);
|
||||
}
|
||||
gx8002_info("recv_msg NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (recv_msg.cmd) {
|
||||
case MSG_RSP_VOICE_EVENT:
|
||||
//语音事件
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
//处理语音事件
|
||||
ret = event;
|
||||
gx8002_event_state_update(event);
|
||||
break;
|
||||
|
||||
case MSG_RSP_MIC_EVENT:
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
ret = event;
|
||||
break;
|
||||
case MSG_RSP_GSENSOR_EVENT:
|
||||
event = recv_msg.body[1] << 8 | recv_msg.body[0];
|
||||
ret = event;
|
||||
break;
|
||||
|
||||
case MSG_RSP_VERSION_EVENT:
|
||||
gx8002_info(">> gx version");
|
||||
memcpy(gx_self_info, recv_msg.body, recv_msg.bodylen);
|
||||
put_buf(gx_self_info, sizeof(gx_self_info));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (recv_msg.body) {
|
||||
OS_FREE(recv_msg.body);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gx8002_self_test_handle()
|
||||
{
|
||||
int ret = 0;
|
||||
int mic_test_cnt = 0;
|
||||
int gsensor_test_cnt = 0;
|
||||
|
||||
//int self_test_result = 0;
|
||||
|
||||
gx8002_info("gx8002 self test start >>>>");
|
||||
__gsensor_test_retry:
|
||||
__this->idle = 0;
|
||||
gx8002_info("gsensor_test_cnt = %d", gsensor_test_cnt);
|
||||
ret = gx8002_wakeup_handle(MSG_REQ_GSENSOR_EVENT);
|
||||
if (ret == 0) {
|
||||
gx8002_info("gx8002 gsensor test OK");
|
||||
//self_test_result |= (0xA << 4);
|
||||
gx_self_info[5] = 0xA;
|
||||
} else {
|
||||
gsensor_test_cnt++;
|
||||
if (gsensor_test_cnt < 10) {
|
||||
gx8002_info("gx8002 gsensor no OK try again");
|
||||
os_time_dly(500 / 10);
|
||||
goto __gsensor_test_retry;
|
||||
}
|
||||
gx_self_info[5] = 1;
|
||||
}
|
||||
|
||||
//MIC状态查询
|
||||
__mic_test_retry:
|
||||
__this->idle = 0;
|
||||
gx8002_info("mic_test_cnt = %d", mic_test_cnt);
|
||||
ret = gx8002_wakeup_handle(MSG_REQ_MIC_EVENT);
|
||||
if (ret == 0) {
|
||||
gx8002_info("gx8002 mic test OK");
|
||||
//self_test_result |= 0xA;
|
||||
gx_self_info[4] = 0xA;
|
||||
} else {
|
||||
mic_test_cnt++;
|
||||
if (mic_test_cnt < 10) {
|
||||
gx8002_info("gx8002 mic no OK try again");
|
||||
os_time_dly(500 / 10);
|
||||
goto __mic_test_retry;
|
||||
}
|
||||
gx_self_info[4] = 1;
|
||||
}
|
||||
|
||||
__this->idle = 1;
|
||||
|
||||
//put_buf(gx_self_info,sizeof(gx_self_info));
|
||||
gx8002_info("gx_self_info[mic]:%x,gx_self_info[g]:%x", gx_self_info[4], gx_self_info[5]);
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_sdfile_update_timer(void *priv)
|
||||
{
|
||||
gx8002_info("gx8002 post update msg >>>>");
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_SDFILE);
|
||||
}
|
||||
|
||||
void gx8002_update_end_post_msg(u8 flag)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_UPDATE_END, flag);
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_upgrade_start(int update_type)
|
||||
{
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
gx8002_uart_porting_close();
|
||||
__this->state = GX8002_STATE_UPGRADING;
|
||||
|
||||
switch (update_type) {
|
||||
case GX8002_UPDATE_TYPE_SDFILE:
|
||||
gx8002_uart_sdfile_ota_init();
|
||||
break;
|
||||
case GX8002_UPDATE_TYPE_SPP:
|
||||
gx8002_uart_spp_ota_init();
|
||||
break;
|
||||
case GX8002_UPDATE_TYPE_APP:
|
||||
gx8002_uart_app_ota_init();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
}
|
||||
|
||||
static void gx8002_upgrade_end(u8 flag)
|
||||
{
|
||||
gx8002_uart_porting_config(115200);
|
||||
gx8002_normal_power_on();
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
}
|
||||
|
||||
void gx8002_voice_event_post_msg(u8 msg)
|
||||
{
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 2, GX8002_MSG_VOICE_EVENT, msg);
|
||||
}
|
||||
|
||||
void gx8002_npu_version_check(void *priv)
|
||||
{
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_GET_VERSION);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gx8002_uart_recv_task(void *param)
|
||||
{
|
||||
int msg[16];
|
||||
int res;
|
||||
|
||||
gx8002_info("gx8002 task init");
|
||||
#if 1
|
||||
//串口初始化
|
||||
gx8002_uart_porting_config(115200);
|
||||
|
||||
gx8002_first_power_on();
|
||||
|
||||
// 设置回调
|
||||
nc_message_init(gx8002_uart_stream_read, gx8002_uart_stream_write, gx8002_uart_stream_is_empty);
|
||||
#endif
|
||||
|
||||
os_sem_create(&(__this->rx_sem), 0);
|
||||
|
||||
__this->state = GX8002_STATE_WORKING;
|
||||
__this->idle = 1;
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
register_sys_event_handler(SYS_BT_EVENT, 0, 0, gx8002_app_event_handler);
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
|
||||
/* if (GX8002_UPGRADE_SDFILE_TOGGLE) { */
|
||||
/* sys_timeout_add(NULL, gx8002_sdfile_update_timer, 10000); */
|
||||
/* } */
|
||||
|
||||
#if GX8002_UPGRADE_APP_TOGGLE
|
||||
gx8002_uart_app_ota_update_register_handle();
|
||||
#endif /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
//gx版本查询
|
||||
sys_timeout_add(NULL, gx8002_npu_version_check, 1000);
|
||||
|
||||
while (1) {
|
||||
res = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
|
||||
if (res == OS_TASKQ) {
|
||||
switch (msg[1]) {
|
||||
case GX8002_MSG_WAKEUP:
|
||||
gx8002_wakeup_handle(MSG_REQ_VOICE_EVENT);
|
||||
break;
|
||||
case GX8002_MSG_VOICE_EVENT:
|
||||
gx8002_voice_event_handle(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_UPDATE:
|
||||
gx8002_upgrade_start(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_UPDATE_END:
|
||||
gx8002_upgrade_end(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_SUSPEND:
|
||||
__gx8002_module_suspend(msg[2]);
|
||||
break;
|
||||
case GX8002_MSG_RESUMED:
|
||||
__gx8002_module_resumed();
|
||||
break;
|
||||
case GX8002_MSG_SELF_TEST:
|
||||
gx8002_self_test_handle();
|
||||
break;
|
||||
case GX8002_MSG_GET_VERSION:
|
||||
gx8002_wakeup_handle(MSG_REQ_VERSION_EVENT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int gx8002_npu_init(void)
|
||||
{
|
||||
#if 0 //升级GX8002固件
|
||||
gpio_set_pull_down(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_pull_up(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_die(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_dieh(TCFG_GX8002_NPU_UART_TX_PORT, 0);
|
||||
gpio_set_direction(TCFG_GX8002_NPU_UART_TX_PORT, 1);
|
||||
|
||||
gpio_set_pull_down(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_pull_up(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_die(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_dieh(TCFG_GX8002_NPU_UART_RX_PORT, 0);
|
||||
gpio_set_direction(TCFG_GX8002_NPU_UART_RX_PORT, 1);
|
||||
return 0;
|
||||
#endif
|
||||
//创建recv任务
|
||||
task_create(gx8002_uart_recv_task, 0, THIS_TASK_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gx8002_npu_int_edge_wakeup_handle(u8 index, u8 gpio)
|
||||
{
|
||||
gx8002_info("gx8002 wakeup, cut_state: %d", __this->state);
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_WAKEUP);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_npu_mic_gsensor_self_test(void)
|
||||
{
|
||||
gx8002_info("gx8002 self test %d", __this->state);
|
||||
if (__this->state == GX8002_STATE_WORKING) {
|
||||
__this->idle = 0;
|
||||
os_taskq_post_msg(THIS_TASK_NAME, 1, GX8002_MSG_SELF_TEST);
|
||||
} else {
|
||||
__this->idle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 gx8002_npu_idle_query(void)
|
||||
{
|
||||
//gx8002_debug("__this->idle = %d", __this->idle);
|
||||
//return 1;
|
||||
if (__this->state == GX8002_STATE_UPGRADING) {
|
||||
return 0;
|
||||
}
|
||||
return __this->idle;
|
||||
}
|
||||
|
||||
static enum LOW_POWER_LEVEL gx8002_npu_level_query(void)
|
||||
{
|
||||
if (__this->state != GX8002_STATE_SUSPEND) {
|
||||
return LOW_POWER_MODE_LIGHT_SLEEP;
|
||||
} else {
|
||||
return LOW_POWER_MODE_DEEP_SLEEP;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(gx8002_lp_target) = {
|
||||
.name = "gx8002",
|
||||
.level = gx8002_npu_level_query,
|
||||
.is_idle = gx8002_npu_idle_query,
|
||||
};
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
95
apps/common/device/gx8002_npu/gx8002_npu.h
Normal file
95
apps/common/device/gx8002_npu/gx8002_npu.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef __GX8002_NPU_H__
|
||||
#define __GX8002_NPU_H__
|
||||
|
||||
/*
|
||||
* Message command
|
||||
*/
|
||||
#define MSG_TYPEBITS 8
|
||||
#define MSG_NRBITS 8
|
||||
|
||||
#define MSG_NRMASK ((1 << MSG_NRBITS) - 1)
|
||||
#define MSG_TYPEMASK ((1 << MSG_TYPEBITS) - 1)
|
||||
|
||||
#define MSG_NRSHIFT 0
|
||||
#define MSG_TYPESHIFT (MSG_NRSHIFT + MSG_NRBITS)
|
||||
|
||||
/* Create new message */
|
||||
#define NEW_MSG(type, nr) \
|
||||
(((type) << MSG_TYPESHIFT) | \
|
||||
((nr) << MSG_NRSHIFT))
|
||||
|
||||
/* Get message type */
|
||||
#define MSG_TYPE(cmd) (((cmd) >> MSG_TYPESHIFT) & MSG_TYPEMASK)
|
||||
|
||||
/* Get message nr */
|
||||
#define MSG_NR(cmd) (((cmd) >> MSG_NRSHIFT) & MSG_NRMASK)
|
||||
|
||||
/*
|
||||
* Message flags
|
||||
*/
|
||||
#define MSG_FLAG_BCHECK (1 << 0)
|
||||
#define MSG_FLAG_BCHECK_BITS 1
|
||||
#define MSG_FLAG_BCHECK_MASK ((1 << MSG_FLAG_BCHECK_BITS) - 1)
|
||||
#define MSG_FLAG_BCHECK_SHIFT 0
|
||||
|
||||
/* Check if need message body crc32 */
|
||||
#define MSG_NEED_BCHECK(flags) (((flags) >> MSG_FLAG_BCHECK_SHIFT) & MSG_FLAG_BCHECK_MASK)
|
||||
|
||||
|
||||
#define MSG_HEAD_LEN 14 /* Message header length */
|
||||
#define MSG_HEAD_CHECK_LEN 4 /* Message header crc32 length */
|
||||
#define MSG_MAGIC_LEN 4 /* Message magic length */
|
||||
#define MSG_BODY_LEN_MAX 3072 /* Message body maximun length */
|
||||
#define MSG_BODY_CHECK_LEN 4 /* Message body crc32 length */
|
||||
|
||||
#define MSG_SEQ_MAX 255 /* Message sequence maximum count */
|
||||
#define MSG_LEN_MAX (MSG_HEAD_LEN + MSG_BODY_LEN_MAX) /* Message maximun length */
|
||||
|
||||
#define MSG_MAGIC 0x58585542
|
||||
|
||||
#define MSG_RCV_MAGIC0 (((MSG_MAGIC) & 0x000000FF) >> 0 )
|
||||
#define MSG_RCV_MAGIC1 (((MSG_MAGIC) & 0x0000FF00) >> 8 )
|
||||
#define MSG_RCV_MAGIC2 (((MSG_MAGIC) & 0x00FF0000) >> 16)
|
||||
#define MSG_RCV_MAGIC3 (((MSG_MAGIC) & 0xFF000000) >> 24)
|
||||
|
||||
typedef enum {
|
||||
MSG_TYPE_REQ = 0x1,
|
||||
MSG_TYPE_RSP = 0x2,
|
||||
MSG_TYPE_NTF = 0x3,
|
||||
} MSG_TYPE;
|
||||
|
||||
struct message {
|
||||
unsigned short cmd;
|
||||
unsigned char seq;
|
||||
unsigned char flags;
|
||||
unsigned char *body;
|
||||
unsigned short bodylen;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef enum {
|
||||
MSG_REQ_VOICE_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x0C),
|
||||
MSG_RSP_VOICE_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x0C),
|
||||
|
||||
//查询gx固件版本
|
||||
MSG_REQ_VERSION_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x02),
|
||||
MSG_RSP_VERSION_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x02),
|
||||
|
||||
//查询MIC状态
|
||||
MSG_REQ_MIC_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x70),
|
||||
MSG_RSP_MIC_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x70),
|
||||
|
||||
//查询Gsensor状态
|
||||
MSG_REQ_GSENSOR_EVENT = NEW_MSG(MSG_TYPE_REQ, 0x71),
|
||||
MSG_RSP_GSENSOR_EVENT = NEW_MSG(MSG_TYPE_RSP, 0x71),
|
||||
} UART_MSG_ID;
|
||||
/* Stream read callback */
|
||||
typedef int (*STREAM_READ)(unsigned char *buf, int len);
|
||||
|
||||
/* Stream write callback */
|
||||
typedef int (*STREAM_WRITE)(const unsigned char *buf, int len);
|
||||
|
||||
/* Stream is empty callback */
|
||||
typedef int (*STREAM_EMPTY)(void);
|
||||
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_H__ */
|
||||
71
apps/common/device/gx8002_npu/gx8002_npu_api.h
Normal file
71
apps/common/device/gx8002_npu/gx8002_npu_api.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef __GX8002_NPU_API_H__
|
||||
#define __GX8002_NPU_API_H__
|
||||
|
||||
#include "app_config.h"
|
||||
#include "update_loader_download.h"
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define GX8002_UPGRADE_TOGGLE 1
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
#define GX8002_UPGRADE_SDFILE_TOGGLE 0 //for test, 升级文件存内置flash升级gx8002
|
||||
#define GX8002_UPGRADE_SPP_TOGGLE 0 //使用spp协议升级gx8002
|
||||
|
||||
#define GX8002_UPGRADE_APP_TOGGLE 1 //使用测试盒/手机APP传输数据, 通过ota流程升级gx8002
|
||||
#if CONFIG_DOUBLE_BANK_ENABLE
|
||||
#define GX8002_UPGRADE_APP_TWS_TOGGLE 1 //TWS同步升级使能
|
||||
#endif /* #if CONFIG_DOUBLE_BANK_ENABLE */
|
||||
#endif
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
|
||||
//语音事件列表
|
||||
enum gx8002_voice_event {
|
||||
MAIN_WAKEUP_VOICE_EVENT = 100, //"小度小度", "天猫精灵", "小爱同学"
|
||||
MUSIC_PAUSE_VOICE_EVENT = 102, //"暂停播放"
|
||||
MUSIC_STOP_VOICE_EVENT = 103, //"停止播放"
|
||||
MUSIC_PLAY_VOICE_EVENT = 104, //"播放音乐"
|
||||
VOLUME_UP_VOICE_EVENT = 105, //"增大音量"
|
||||
VOLUME_DOWN_VOICE_EVENT = 106, //"减小音量"
|
||||
MUSIC_PREV_VOICE_EVENT = 112, //"播放上一首"
|
||||
MUSIC_NEXT_VOICE_EVENT = 113, //"播放下一首"
|
||||
CALL_ANSWER_VOICE_EVENT = 114, //"接听电话"
|
||||
CALL_HANG_UP_VOICE_EVENT = 115, //"挂掉电话"
|
||||
};
|
||||
|
||||
enum GX8002_MSG {
|
||||
GX8002_MSG_BEGIN = ('8' << 24) | ('0' << 16) | ('0' << 8) | ('2' << 0),
|
||||
GX8002_MSG_WAKEUP,
|
||||
GX8002_MSG_VOICE_EVENT,
|
||||
GX8002_MSG_UPDATE,
|
||||
GX8002_MSG_UPDATE_END,
|
||||
GX8002_MSG_SUSPEND,
|
||||
GX8002_MSG_RESUMED,
|
||||
GX8002_MSG_SELF_TEST,
|
||||
GX8002_MSG_GET_VERSION,
|
||||
};
|
||||
|
||||
enum GX8002_UPDATE_TYPE {
|
||||
GX8002_UPDATE_TYPE_SDFILE = 0x5A,
|
||||
GX8002_UPDATE_TYPE_SPP,
|
||||
GX8002_UPDATE_TYPE_APP,
|
||||
};
|
||||
|
||||
void gx8002_npu_int_edge_wakeup_handle(u8 index, u8 gpio);
|
||||
int gx8002_npu_init(void);
|
||||
void gx8002_event_state_update(u8 voice_event);
|
||||
//int gx8002_uart_ota_init(void);
|
||||
int gx8002_uart_sdfile_ota_init(void);
|
||||
int gx8002_uart_spp_ota_init(void);
|
||||
int gx8002_uart_app_ota_init(void);
|
||||
void gx8002_voice_event_handle(u8 voice_event);
|
||||
void gx8002_uart_app_ota_update_register_handle(void);
|
||||
|
||||
void gx8002_cold_reset(void);
|
||||
void gx8002_normal_cold_reset(void);
|
||||
void gx8002_upgrade_cold_reset(void);
|
||||
void gx8002_update_end_post_msg(u8 flag);
|
||||
void gx8002_voice_event_post_msg(u8 msg);
|
||||
|
||||
#endif /* #ifndef __GX8002_NPU_API_H__ */
|
||||
193
apps/common/device/gx8002_npu/gx8002_npu_event_deal.c
Normal file
193
apps/common/device/gx8002_npu/gx8002_npu_event_deal.c
Normal file
@ -0,0 +1,193 @@
|
||||
#include "includes.h"
|
||||
#include "app_config.h"
|
||||
#include "gx8002_npu.h"
|
||||
#include "gx8002_npu_api.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
#include "tone_player.h"
|
||||
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
#include "bt_tws.h"
|
||||
#endif /* #if TCFG_USER_TWS_ENABLE */
|
||||
|
||||
#if TCFG_GX8002_NPU_ENABLE
|
||||
|
||||
#define gx8002_event_info printf
|
||||
|
||||
bool get_tws_sibling_connect_state(void);
|
||||
|
||||
#define TWS_FUNC_ID_VOICE_EVENT_SYNC TWS_FUNC_ID('V', 'O', 'I', 'C')
|
||||
|
||||
struct gx8002_event_hdl {
|
||||
u8 last_event;
|
||||
u32 last_event_jiffies;
|
||||
};
|
||||
|
||||
static struct gx8002_event_hdl hdl = {0};
|
||||
|
||||
#define __this (&hdl)
|
||||
|
||||
__attribute__((weak))
|
||||
void volume_down(u8 dec)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
void volume_up(u8 inc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
__attribute__((weak))
|
||||
int app_case_voice_event_handle(u8 voice_event)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gx8002_recognize_tone_play(void)
|
||||
{
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
if (tws_api_get_role() == TWS_ROLE_MASTER) {
|
||||
bt_tws_play_tone_at_same_time(SYNC_TONE_VOICE_RECOGNIZE, 200);
|
||||
}
|
||||
} else {
|
||||
tone_play(TONE_NORMAL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_event_handle(u8 voice_event)
|
||||
{
|
||||
u32 cur_jiffies = jiffies;
|
||||
u8 a2dp_state;
|
||||
u8 call_state;
|
||||
|
||||
if (voice_event == __this->last_event) {
|
||||
if (jiffies_to_msecs(cur_jiffies - __this->last_event_jiffies) < 1000) {
|
||||
gx8002_event_info("voice event %d same, ignore", voice_event);
|
||||
__this->last_event_jiffies = cur_jiffies;
|
||||
return;
|
||||
}
|
||||
}
|
||||
__this->last_event_jiffies = cur_jiffies;
|
||||
__this->last_event = voice_event;
|
||||
|
||||
gx8002_event_info("%s: %d", __func__, voice_event);
|
||||
|
||||
if (app_case_voice_event_handle(voice_event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//播放提示音
|
||||
if ((voice_event != VOLUME_UP_VOICE_EVENT) && (voice_event != VOLUME_DOWN_VOICE_EVENT)) {
|
||||
//gx8002_recognize_tone_play();
|
||||
}
|
||||
|
||||
switch (voice_event) {
|
||||
case MAIN_WAKEUP_VOICE_EVENT:
|
||||
gx8002_event_info("send SIRI cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL);
|
||||
break;
|
||||
case MUSIC_PAUSE_VOICE_EVENT:
|
||||
case MUSIC_STOP_VOICE_EVENT:
|
||||
case MUSIC_PLAY_VOICE_EVENT:
|
||||
call_state = get_call_status();
|
||||
if ((call_state == BT_CALL_OUTGOING) ||
|
||||
(call_state == BT_CALL_ALERT)) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
} else if (call_state == BT_CALL_INCOMING) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
|
||||
} else if (call_state == BT_CALL_ACTIVE) {
|
||||
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
} else {
|
||||
a2dp_state = a2dp_get_status();
|
||||
if (a2dp_state == BT_MUSIC_STATUS_STARTING) {
|
||||
if (voice_event == MUSIC_PAUSE_VOICE_EVENT) {
|
||||
gx8002_event_info("send PAUSE cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
|
||||
} else if (voice_event == MUSIC_STOP_VOICE_EVENT) {
|
||||
gx8002_event_info("send STOP cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_STOP, 0, NULL);
|
||||
}
|
||||
} else {
|
||||
if (voice_event == MUSIC_PLAY_VOICE_EVENT) {
|
||||
gx8002_event_info("send PLAY cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VOLUME_UP_VOICE_EVENT:
|
||||
gx8002_event_info("volume up");
|
||||
volume_up(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
|
||||
//gx8002_recognize_tone_play();
|
||||
break;
|
||||
case VOLUME_DOWN_VOICE_EVENT:
|
||||
gx8002_event_info("volume down");
|
||||
volume_down(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
|
||||
//gx8002_recognize_tone_play();
|
||||
break;
|
||||
case MUSIC_PREV_VOICE_EVENT:
|
||||
gx8002_event_info("volume PREV cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PREV, 0, NULL);
|
||||
break;
|
||||
case MUSIC_NEXT_VOICE_EVENT:
|
||||
gx8002_event_info("volume NEXT cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_NEXT, 0, NULL);
|
||||
break;
|
||||
case CALL_ANSWER_VOICE_EVENT:
|
||||
if (get_call_status() == BT_CALL_INCOMING) {
|
||||
gx8002_event_info("volume ANSWER cmd");
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
|
||||
}
|
||||
break;
|
||||
case CALL_HANG_UP_VOICE_EVENT:
|
||||
gx8002_event_info("volume HANG UP cmd");
|
||||
if ((get_call_status() >= BT_CALL_INCOMING) && (get_call_status() <= BT_CALL_ALERT)) {
|
||||
user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_event_sync_tws_state_deal(void *_data, u16 len, bool rx)
|
||||
{
|
||||
u8 *data = (u8 *)_data;
|
||||
u8 voice_event = data[0];
|
||||
//if (rx) {
|
||||
gx8002_event_info("tws event rx sync: %d", voice_event);
|
||||
//gx8002_event_handle(voice_event);
|
||||
gx8002_voice_event_post_msg(voice_event);
|
||||
//}
|
||||
}
|
||||
|
||||
static void gx8002_sync_tws_event(u8 voice_event)
|
||||
{
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
tws_api_send_data_to_sibling(&voice_event, 1, TWS_FUNC_ID_VOICE_EVENT_SYNC);
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_event_state_update(u8 voice_event)
|
||||
{
|
||||
//tone_play(TONE_NORMAL, 1);
|
||||
if (get_tws_sibling_connect_state() == TRUE) {
|
||||
gx8002_sync_tws_event(voice_event);
|
||||
} else {
|
||||
gx8002_event_handle(voice_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gx8002_voice_event_handle(u8 voice_event)
|
||||
{
|
||||
gx8002_event_handle(voice_event);
|
||||
}
|
||||
|
||||
REGISTER_TWS_FUNC_STUB(gx8002_voice_event_sync) = {
|
||||
.func_id = TWS_FUNC_ID_VOICE_EVENT_SYNC,
|
||||
.func = gx8002_event_sync_tws_state_deal,
|
||||
};
|
||||
|
||||
#endif /* #if TCFG_GX8002_NPU_ENABLE */
|
||||
@ -0,0 +1,736 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
//#include "../utils/gx_fifo.h"
|
||||
|
||||
#if GX8002_UPGRADE_APP_TOGGLE
|
||||
|
||||
typedef struct _gx8002_file_head_t {
|
||||
u16 head_crc;
|
||||
u16 data_crc;
|
||||
u32 addr;
|
||||
u32 len;
|
||||
u8 attr;
|
||||
u8 res;
|
||||
u16 index;
|
||||
char name[16];
|
||||
} gx8002_file_head_t;
|
||||
|
||||
struct app_ota_info {
|
||||
int update_result;
|
||||
u32 ufw_addr;
|
||||
u8 cur_seek_file;
|
||||
u8 update_role;
|
||||
OS_SEM ota_sem;
|
||||
OS_SEM rx_sem;
|
||||
cbuffer_t *cbuf_handle;
|
||||
update_op_api_t *file_ops;
|
||||
gx8002_file_head_t file_boot_head;
|
||||
gx8002_file_head_t file_bin_head;
|
||||
int packet_buf[UPGRADE_PACKET_SIZE / sizeof(int)];
|
||||
};
|
||||
|
||||
|
||||
enum GX_APP_UPDATE_ERR {
|
||||
GX_APP_UPDATE_ERR_NONE = 0,
|
||||
GX_APP_UPDATE_ERR_NOMEM = -100,
|
||||
GX_APP_UPDATE_ERR_FILE_READ,
|
||||
GX_APP_UPDATE_ERR_FILE_DIR_VERIFY,
|
||||
GX_APP_UPDATE_ERR_FILE_HEAD_VERIFY,
|
||||
GX_APP_UPDATE_ERR_FILE_DATA_VERIFY,
|
||||
|
||||
GX_APP_UPDATE_ERR_UPDATE_LOOP,
|
||||
GX_APP_UPDATE_ERR_UPDATE_STATE,
|
||||
};
|
||||
|
||||
enum GX8002_UPDATE_ROLE {
|
||||
GX8002_UPDATE_ROLE_NORMAL = 0,
|
||||
GX8002_UPDATE_ROLE_TWS_MASTER,
|
||||
GX8002_UPDATE_ROLE_TWS_SLAVE,
|
||||
};
|
||||
|
||||
static struct app_ota_info *ota_upgrade = NULL;
|
||||
#define __this ota_upgrade
|
||||
|
||||
#define GX8002_UFW_VERIFY_BUF_LEN 512
|
||||
#define GX8002_UFW_FILE_DATA_VERIFY_ENABLE 0
|
||||
|
||||
#define GX8002_OTA_UPGRADE_DEBUG_ENABLE 1
|
||||
|
||||
#define ota_upgrade_info printf
|
||||
|
||||
#if GX8002_OTA_UPGRADE_DEBUG_ENABLE
|
||||
#define ota_upgrade_debug printf
|
||||
#define ota_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define ota_upgrade_debug(...)
|
||||
#define ota_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
//=================================================================//
|
||||
// tws同步升级接口 //
|
||||
//=================================================================//
|
||||
extern void gx8002_uart_app_ota_tws_update_register_handle(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_init(void *priv);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_pend(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_post(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_respond(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_close(void);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_result(int result);
|
||||
extern int gx8002_uart_app_ota_tws_update_sync_result_get(void);
|
||||
|
||||
//=================================================================//
|
||||
// 使用fifo作数据缓存 //
|
||||
//=================================================================//
|
||||
////////////// FW Stream Porting //////////////////
|
||||
static u32 fw_stream_get_file_addr(u32 addr)
|
||||
{
|
||||
return __this->ufw_addr + addr;
|
||||
}
|
||||
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 16
|
||||
#define STREAM_FIFO_TIMEOUT_MS (5000)
|
||||
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//gx8002线程同步数据
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
static u32 read_cnt = 0;
|
||||
|
||||
if (__this->cbuf_handle) {
|
||||
if (cbuf_get_data_len(__this->cbuf_handle) < len) {
|
||||
os_sem_set(&(__this->rx_sem), 0);
|
||||
os_sem_pend(&(__this->rx_sem), msecs_to_jiffies(STREAM_FIFO_TIMEOUT_MS));
|
||||
}
|
||||
ret = cbuf_read(__this->cbuf_handle, buf, len);
|
||||
if (ret < len) {
|
||||
ota_upgrade_info("read errm ret = 0x%x, len = 0x%x", ret, len);
|
||||
return -1;
|
||||
}
|
||||
if (__this->update_role == GX8002_UPDATE_ROLE_TWS_MASTER) {
|
||||
//TODO: tws sync data
|
||||
gx8002_uart_app_ota_tws_update_sync_data(buf, (u16)len);
|
||||
if (gx8002_uart_app_ota_tws_update_sync_pend()) {
|
||||
ota_upgrade_info("read timeout");
|
||||
ret = -1;
|
||||
}
|
||||
} else if (__this->update_role == GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
//TODO: tws respond
|
||||
gx8002_uart_app_ota_tws_update_sync_respond();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
info->img_size = __this->file_bin_head.len;
|
||||
|
||||
ota_upgrade_debug("%s, img_size = 0x%x", __func__, info->img_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gx8002_ota_data_receive(u8 *data, u32 size)
|
||||
{
|
||||
gx8002_file_head_t *file_receive_table[] = {
|
||||
&(__this->file_boot_head),
|
||||
&(__this->file_bin_head)
|
||||
};
|
||||
|
||||
u32 file_addr = 0;
|
||||
u32 remain_len = 0;
|
||||
u32 rlen = 0;
|
||||
u16 ret = 0;
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(file_receive_table); i++) {
|
||||
file_addr = fw_stream_get_file_addr((file_receive_table[i])->addr);
|
||||
__this->file_ops->f_seek(NULL, SEEK_SET, file_addr);
|
||||
remain_len = (file_receive_table[i])->len;
|
||||
ota_upgrade_debug("receive %s data, len = 0x%x", (file_receive_table[i])->name, remain_len);
|
||||
while (remain_len) {
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
return __this->update_result;
|
||||
}
|
||||
rlen = (remain_len > size) ? size : remain_len;
|
||||
ret = __this->file_ops->f_read(NULL, data, rlen);
|
||||
|
||||
if ((u16) - 1 == ret) {
|
||||
ota_upgrade_debug("f_read %s err", (file_receive_table[i])->name);
|
||||
return GX_APP_UPDATE_ERR_FILE_READ;
|
||||
}
|
||||
//TODO: TWS send data sync
|
||||
while (cbuf_is_write_able(__this->cbuf_handle, rlen) < rlen) {
|
||||
/* ota_upgrade_debug("aaa"); */
|
||||
os_time_dly(2);
|
||||
/* ota_upgrade_debug("bbb"); */
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
return __this->update_result;
|
||||
}
|
||||
}
|
||||
if (cbuf_write(__this->cbuf_handle, data, rlen) != rlen) {
|
||||
ota_upgrade_debug("cbuf full !!!");
|
||||
}
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
|
||||
remain_len -= rlen;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_ota_data_passive_receive(u8 *data, u32 size)
|
||||
{
|
||||
int ret = 0;
|
||||
if ((__this == NULL) || (__this->cbuf_handle == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__this->update_role != GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cbuf_is_write_able(__this->cbuf_handle, size) < size) {
|
||||
ota_upgrade_info("passive receive cbuf full !!!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = cbuf_write(__this->cbuf_handle, data, size);
|
||||
os_sem_post(&(__this->rx_sem));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int __gx8002_ufw_file_data_verify(u32 file_addr, u32 file_len, u16 target_crc, u16(*func_read)(void *fp, u8 *buff, u16 len))
|
||||
{
|
||||
u8 *rbuf = malloc(GX8002_UFW_VERIFY_BUF_LEN);
|
||||
u16 crc_interval = 0;
|
||||
u16 r_len = 0;
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
if (rbuf == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
while (file_len) {
|
||||
r_len = (file_len > GX8002_UFW_VERIFY_BUF_LEN) ? GX8002_UFW_VERIFY_BUF_LEN : file_len;
|
||||
if (func_read) {
|
||||
func_read(NULL, rbuf, r_len);
|
||||
}
|
||||
|
||||
crc_interval = CRC16_with_initval(rbuf, r_len, crc_interval);
|
||||
|
||||
file_addr += r_len;
|
||||
file_len -= r_len;
|
||||
}
|
||||
|
||||
if (crc_interval != target_crc) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
}
|
||||
|
||||
_file_data_verify_end:
|
||||
if (rbuf) {
|
||||
free(rbuf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __gx8002_ufw_file_head_verify(gx8002_file_head_t *file_head)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
u16 calc_crc = CRC16(&(file_head->data_crc), sizeof(gx8002_file_head_t) - 2);
|
||||
|
||||
if (calc_crc != file_head->head_crc) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int gx8002_ufw_file_verify(u32 ufw_addr, update_op_api_t *file_ops)
|
||||
{
|
||||
int ret = 0;
|
||||
u16 r_len = 0;
|
||||
u8 file_cnt = 0;
|
||||
gx8002_file_head_t *file_head;
|
||||
u8 *rbuf = (u8 *)malloc(GX8002_UFW_VERIFY_BUF_LEN);
|
||||
if (rbuf == NULL) {
|
||||
ret = GX_APP_UPDATE_ERR_NOMEM;
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
file_ops->f_seek(NULL, SEEK_SET, ufw_addr);
|
||||
r_len = file_ops->f_read(NULL, rbuf, GX8002_UFW_VERIFY_BUF_LEN);
|
||||
|
||||
if ((u16) - 1 == r_len) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_READ;
|
||||
ota_upgrade_debug("f_read err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
file_head = (gx8002_file_head_t *)rbuf;
|
||||
ret = __gx8002_ufw_file_head_verify(file_head);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
ota_upgrade_debug("gx8002 ufw file head verify err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
if (strcmp(file_head->name, "gx8002")) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_HEAD_VERIFY;
|
||||
ota_upgrade_debug("gx8002 ufw file head name err");
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
do {
|
||||
file_head++;
|
||||
ret = __gx8002_ufw_file_head_verify(file_head);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(file_head->name, "gx8002.boot") == 0) {
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
memcpy(&(__this->file_boot_head), file_head, sizeof(gx8002_file_head_t));
|
||||
#if GX8002_UFW_FILE_DATA_VERIFY_ENABLE
|
||||
file_ops->f_seek(NULL, SEEK_SET, __this->ufw_addr + file_head->addr);
|
||||
ret = __gx8002_ufw_file_data_verify(__this->ufw_addr + file_head->addr, file_head->len, file_head->data_crc, file_ops->f_read);
|
||||
if (ret == GX_APP_UPDATE_ERR_NONE) {
|
||||
file_cnt++;
|
||||
} else {
|
||||
ota_upgrade_debug("gx8002.boot file head verify err");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
file_cnt++;
|
||||
#endif /* #if GX8002_UFW_FILE_DATA_VERIFY_ENABLE */
|
||||
}
|
||||
if (strcmp(file_head->name, "mcu_nor.bin") == 0) {
|
||||
ota_upgrade_info("find: %s", file_head->name);
|
||||
memcpy(&(__this->file_bin_head), file_head, sizeof(gx8002_file_head_t));
|
||||
#if GX8002_UFW_FILE_DATA_VERIFY_ENABLE
|
||||
file_ops->f_seek(NULL, SEEK_SET, __this->ufw_addr + file_head->addr);
|
||||
ret = __gx8002_ufw_file_data_verify(__this->ufw_addr + file_head->addr, file_head->len, file_head->data_crc, file_ops->f_read);
|
||||
if (ret == GX_APP_UPDATE_ERR_NONE) {
|
||||
file_cnt++;
|
||||
} else {
|
||||
ota_upgrade_debug("mcu_nor.bin file head verify err");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
file_cnt++;
|
||||
#endif /* #if GX8002_UFW_FILE_DATA_VERIFY_ENABLE */
|
||||
}
|
||||
} while (file_head->index == 0);
|
||||
|
||||
if ((ret != GX_APP_UPDATE_ERR_NONE) && (file_cnt != 2)) {
|
||||
ret = GX_APP_UPDATE_ERR_FILE_DATA_VERIFY;
|
||||
ota_upgrade_debug("file_cnt: %d err", file_cnt);
|
||||
goto _verify_end;
|
||||
}
|
||||
|
||||
ota_upgrade_info("find file_cnt: %d, verify ok", file_cnt);
|
||||
|
||||
_verify_end:
|
||||
if (rbuf) {
|
||||
free(rbuf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
ota_upgrade_info("status info: %s\n", reply_str);
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ota_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
ota_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 初始化函数, 公共流程
|
||||
@parma: addr: 访问外置芯片固件地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_app_ota_start(int (*complete_callback)(void))
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
__this->cbuf_handle = (cbuffer_t *)malloc(sizeof(cbuffer_t) + (UPGRADE_PACKET_SIZE * STREAM_FIFO_BLOCK_TOTAL));
|
||||
if (__this->cbuf_handle == NULL) {
|
||||
ret = GX_APP_UPDATE_ERR_NOMEM;
|
||||
return ret;
|
||||
}
|
||||
cbuf_init(__this->cbuf_handle, __this->cbuf_handle + 1, (UPGRADE_PACKET_SIZE * STREAM_FIFO_BLOCK_TOTAL));
|
||||
}
|
||||
|
||||
os_sem_create(&(__this->rx_sem), 0);
|
||||
|
||||
os_taskq_post_msg("gx8002", 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_APP);
|
||||
|
||||
if (complete_callback) {
|
||||
if (complete_callback()) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_LOOP;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 释放资源
|
||||
@parma: void
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_app_ota_close(void)
|
||||
{
|
||||
if (__this->update_role == GX8002_UPDATE_ROLE_TWS_SLAVE) {
|
||||
//从机出口
|
||||
gx8002_uart_app_ota_tws_update_sync_result(__this->update_result);
|
||||
|
||||
if (__this->cbuf_handle) {
|
||||
free(__this->cbuf_handle);
|
||||
__this->cbuf_handle = NULL;
|
||||
}
|
||||
|
||||
if (__this) {
|
||||
free(__this);
|
||||
__this = NULL;
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
} else {
|
||||
os_sem_post(&(__this->ota_sem));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 从机升级开始
|
||||
@parma: void
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_app_ota_passive_start(int (*complete_callback)(void), u8 *ota_data, u16 len)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (__this) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_STATE;
|
||||
}
|
||||
|
||||
__this = zalloc(sizeof(struct app_ota_info));
|
||||
if (__this == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
ASSERT(len == sizeof(gx8002_file_head_t));
|
||||
|
||||
memcpy((u8 *) & (__this->file_bin_head), ota_data, sizeof(gx8002_file_head_t));
|
||||
|
||||
__this->update_role = GX8002_UPDATE_ROLE_TWS_SLAVE;
|
||||
|
||||
ret = gx8002_app_ota_start(complete_callback);
|
||||
|
||||
if (ret) {
|
||||
gx8002_app_ota_close();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 初始化函数, 主机流程
|
||||
@parma: priv: 访问外置芯片固件地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
@return: 1) GX_APP_UPDATE_ERR_NONE = 0: 初始化成功
|
||||
2) < 0: 初始化失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_init(void *priv, update_op_api_t *file_ops)
|
||||
{
|
||||
int ret = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
if (__this) {
|
||||
return GX_APP_UPDATE_ERR_UPDATE_STATE;
|
||||
}
|
||||
|
||||
user_chip_update_info_t *update_info = (user_chip_update_info_t *)priv;
|
||||
|
||||
__this = zalloc(sizeof(struct app_ota_info));
|
||||
if (__this == NULL) {
|
||||
return GX_APP_UPDATE_ERR_NOMEM;
|
||||
}
|
||||
|
||||
__this->ufw_addr = update_info->addr;
|
||||
__this->file_ops = file_ops;
|
||||
__this->update_role = GX8002_UPDATE_ROLE_NORMAL;
|
||||
__this->update_result = GX_APP_UPDATE_ERR_NONE;
|
||||
|
||||
__this->cur_seek_file = FW_FLASH_MAX;
|
||||
|
||||
ota_upgrade_info("%s: ufw_addr = 0x%x", __func__, __this->ufw_addr);
|
||||
|
||||
ret = gx8002_ufw_file_verify(__this->ufw_addr, file_ops);
|
||||
|
||||
ota_upgrade_info("%s, ret = %d", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 获取升级问文件长度, 用于计算升级进度, 主机调用
|
||||
@parma: void
|
||||
@return: 1) 升级长度(int)
|
||||
2) = 0: 升级状态出错
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_get_len(void)
|
||||
{
|
||||
int update_len = 0;
|
||||
|
||||
if (__this == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
update_len = __this->file_boot_head.len + __this->file_bin_head.len;
|
||||
ota_upgrade_info("%s: boot_len = 0x%x, bin_len = 0x%x, update_len = 0x%x", __func__, __this->file_boot_head.len, __this->file_bin_head.len, update_len);
|
||||
|
||||
return update_len;
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: ota流程回调: 升级主流程, 主机调用
|
||||
@parma: void *priv 用于tws同步升级接口(update_op_tws_api_t), 非tws同步升级设置未NULL即可
|
||||
@return: 1) = 0: 升级成功
|
||||
2) < 0: 升级失败
|
||||
*/
|
||||
//===================================================================//
|
||||
static int gx8002_chip_update_loop(void *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (__this == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
|
||||
int (*start_callback)(void) = NULL;
|
||||
|
||||
if (priv) {
|
||||
__this->update_role = GX8002_UPDATE_ROLE_TWS_MASTER;
|
||||
|
||||
ret = gx8002_uart_app_ota_tws_update_init(priv);
|
||||
if (ret) {
|
||||
goto __update_end;
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_sync_start((u8 *) & (__this->file_bin_head), sizeof(gx8002_file_head_t));
|
||||
|
||||
start_callback = gx8002_uart_app_ota_tws_update_sync_pend;
|
||||
}
|
||||
|
||||
os_sem_create(&(__this->ota_sem), 0);
|
||||
|
||||
ret = gx8002_app_ota_start(start_callback);
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
goto __update_end;
|
||||
}
|
||||
|
||||
//update 线程接收数据
|
||||
ret = gx8002_ota_data_receive((u8 *)(__this->packet_buf), sizeof(__this->packet_buf));
|
||||
if (ret != GX_APP_UPDATE_ERR_NONE) {
|
||||
goto __update_end;
|
||||
}
|
||||
|
||||
//等待升级完成
|
||||
os_sem_pend(&(__this->ota_sem), 0);
|
||||
|
||||
if (__this->update_result != GX_APP_UPDATE_ERR_NONE) {
|
||||
ota_upgrade_info("gx8002 update failed.");
|
||||
} else {
|
||||
ota_upgrade_info("gx8002 update succ.");
|
||||
}
|
||||
|
||||
ret = __this->update_result;
|
||||
|
||||
__update_end:
|
||||
if (priv) {
|
||||
ret |= gx8002_uart_app_ota_tws_update_sync_result_get();
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
}
|
||||
if (__this->cbuf_handle) {
|
||||
free(__this->cbuf_handle);
|
||||
__this->cbuf_handle = NULL;
|
||||
}
|
||||
if (__this) {
|
||||
free(__this);
|
||||
__this = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 需要升级流程提供注册接口
|
||||
@parma: user_chip_update_file_name: 外置芯片升级文件名, 包含在update.ufw文件中
|
||||
@parma: user_update_handle: 当update.ufw存在升级文件时回调该函数升级外置芯片固件
|
||||
@parma: addr: 外置芯片固件在update.ufw升级文件中地址
|
||||
@parma: file_ops: 访问外置芯片固件文件操作接口
|
||||
*/
|
||||
//===================================================================//
|
||||
static const user_chip_update_t gx8002_user_chip_update_instance = {
|
||||
.file_name = "gx8002.bin",
|
||||
.update_init = gx8002_chip_update_init,
|
||||
.update_get_len = gx8002_chip_update_get_len,
|
||||
.update_loop = gx8002_chip_update_loop,
|
||||
};
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 注册ota流程回调, 提供给gx8002线程调用
|
||||
@parma: void
|
||||
@return: void
|
||||
*/
|
||||
//===================================================================//
|
||||
void gx8002_uart_app_ota_update_register_handle(void)
|
||||
{
|
||||
register_user_chip_update_handle(&gx8002_user_chip_update_instance);
|
||||
|
||||
#if GX8002_UPGRADE_APP_TWS_TOGGLE
|
||||
gx8002_uart_app_ota_tws_update_register_handle();
|
||||
#endif /* #if GX8002_UPGRADE_APP_TWS_TOGGLE */
|
||||
}
|
||||
|
||||
//===================================================================//
|
||||
/*
|
||||
@breif: 外置芯片启动升级流程, 提供给gx8002线程调用
|
||||
@parma: void
|
||||
@return: 1) 0: 升级成功
|
||||
2) -1: 升级失败
|
||||
*/
|
||||
//===================================================================//
|
||||
int gx8002_uart_app_ota_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
upgrade_uart_t uart_ops;
|
||||
|
||||
ota_upgrade_info("gx8002_uart_app_ota start >>>>");
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
fw_stream_t fw_stream_ops;
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
ret = gx8002_upgrade_task(NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
__this->update_result = GX_APP_UPDATE_ERR_UPDATE_LOOP;
|
||||
} else {
|
||||
__this->update_result = GX_APP_UPDATE_ERR_NONE;
|
||||
}
|
||||
|
||||
gx8002_app_ota_close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
int gx8002_uart_app_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_APP_TOGGLE */
|
||||
|
||||
@ -0,0 +1,265 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
//#include "../utils/gx_fifo.h"
|
||||
|
||||
#if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE)
|
||||
|
||||
struct gx8002_tws_update {
|
||||
update_op_tws_api_t *tws_handle;
|
||||
OS_SEM tws_sync_sem;
|
||||
u8 slave_result;
|
||||
};
|
||||
|
||||
enum GX8002_TWS_UPDATE_CMD {
|
||||
GX8002_TWS_UPDATE_CMD_START = 'G',
|
||||
GX8002_TWS_UPDATE_CMD_UFW_DATA,
|
||||
GX8002_TWS_UPDATE_CMD_RESPOND,
|
||||
GX8002_TWS_UPDATE_CMD_RESULT,
|
||||
};
|
||||
|
||||
static struct gx8002_tws_update *tws_update = NULL;
|
||||
|
||||
#define GX8002_OTA_UPGRADE_DEBUG_ENABLE 0
|
||||
|
||||
#define ota_upgrade_info printf
|
||||
|
||||
#if GX8002_OTA_UPGRADE_DEBUG_ENABLE
|
||||
#define ota_upgrade_debug printf
|
||||
#define ota_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define ota_upgrade_debug(...)
|
||||
#define ota_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
#define GX8002_TWS_SYNC_TIMEOUT 300
|
||||
|
||||
|
||||
extern int gx8002_ota_data_passive_receive(u8 *data, u32 size);
|
||||
extern int gx8002_app_ota_passive_start(int (*complete_callback)(void), u8 *ota_data, u16 len);
|
||||
extern update_op_tws_api_t *get_tws_update_api(void);
|
||||
extern void tws_update_register_user_chip_update_handle(void (*update_handle)(void *data, u32 len));
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_pend(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
if (os_sem_pend(&(tws_update->tws_sync_sem), GX8002_TWS_SYNC_TIMEOUT) == OS_TIMEOUT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_post(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
os_sem_post(&(tws_update->tws_sync_sem));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result(int result)
|
||||
{
|
||||
ota_upgrade_info("%s: result: 0x%x", __func__, result);
|
||||
if (tws_update) {
|
||||
if (result) {
|
||||
tws_update->slave_result = 'N';
|
||||
} else {
|
||||
tws_update->slave_result = 'O';
|
||||
}
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_RESULT, &(tws_update->slave_result), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result_get(void)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (gx8002_uart_app_ota_tws_update_sync_pend()) {
|
||||
ota_upgrade_info("%s timeout", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (tws_update->slave_result == 'O') {
|
||||
ota_upgrade_info("%s, get: O", __func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ota_upgrade_info("%s state err", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_respond(void)
|
||||
{
|
||||
ota_upgrade_debug("%s", __func__);
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_RESPOND, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_START, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len)
|
||||
{
|
||||
if (tws_update) {
|
||||
if (tws_update->tws_handle) {
|
||||
tws_update->tws_handle->tws_ota_user_chip_update_send(GX8002_TWS_UPDATE_CMD_UFW_DATA, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_init(void *priv)
|
||||
{
|
||||
ota_upgrade_info("%s", __func__);
|
||||
|
||||
if (tws_update) {
|
||||
free(tws_update);
|
||||
}
|
||||
|
||||
if (priv == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tws_update = zalloc(sizeof(struct gx8002_tws_update));
|
||||
if (tws_update == NULL) {
|
||||
return -1;
|
||||
}
|
||||
tws_update->tws_handle = priv;
|
||||
|
||||
os_sem_create(&(tws_update->tws_sync_sem), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_close(void)
|
||||
{
|
||||
if (tws_update) {
|
||||
free(tws_update);
|
||||
|
||||
tws_update = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gx8002_uart_app_ota_tws_update_handle(void *data, u32 len)
|
||||
{
|
||||
u8 *rx_packet = (u8 *)data;
|
||||
int ret = 0;
|
||||
|
||||
ota_upgrade_debug("receive cmd 0x%x, data len = 0x%x", rx_packet[0], len - 1);
|
||||
|
||||
switch (rx_packet[0]) {
|
||||
case GX8002_TWS_UPDATE_CMD_START:
|
||||
gx8002_uart_app_ota_tws_update_init(get_tws_update_api());
|
||||
ret = gx8002_app_ota_passive_start(gx8002_uart_app_ota_tws_update_sync_respond, rx_packet + 1, len - 1);
|
||||
if (ret) {
|
||||
gx8002_uart_app_ota_tws_update_close();
|
||||
}
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_UFW_DATA:
|
||||
gx8002_ota_data_passive_receive(rx_packet + 1, len - 1);
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_RESPOND:
|
||||
gx8002_uart_app_ota_tws_update_sync_post();
|
||||
break;
|
||||
|
||||
case GX8002_TWS_UPDATE_CMD_RESULT:
|
||||
ota_upgrade_info("result: 0x%x", rx_packet[1]);
|
||||
if (tws_update) {
|
||||
tws_update->slave_result = rx_packet[1];
|
||||
}
|
||||
gx8002_uart_app_ota_tws_update_sync_post();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void gx8002_uart_app_ota_tws_update_register_handle(void)
|
||||
{
|
||||
tws_update_register_user_chip_update_handle(gx8002_uart_app_ota_tws_update_handle);
|
||||
}
|
||||
|
||||
#else /* #if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE) */
|
||||
|
||||
void gx8002_uart_app_ota_tws_update_register_handle(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_init(void *priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_pend(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_post(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_data(u8 *buf, u16 len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_respond(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_close(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_start(u8 *buf, u16 len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result(int result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_app_ota_tws_update_sync_result_get(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* #if (GX8002_UPGRADE_APP_TWS_TOGGLE && OTA_TWS_SAME_TIME_ENABLE) */
|
||||
|
||||
482
apps/common/device/gx8002_npu/gx8002_upgrade/gx_uart_upgrade.c
Normal file
482
apps/common/device/gx8002_npu/gx8002_upgrade/gx_uart_upgrade.c
Normal file
@ -0,0 +1,482 @@
|
||||
#include "includes.h"
|
||||
#include "gx_uart_upgrade.h"
|
||||
#include "../gx8002_npu_api.h"
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
|
||||
#define GX_UPGRADE_DEBUG 0
|
||||
#if GX_UPGRADE_DEBUG
|
||||
//#define upgrade_debug(fmt, ...) y_printf("[gx_uart_upgrade]: " fmt, ##__VA_ARGS__)
|
||||
#define upgrade_debug printf
|
||||
#else
|
||||
#define upgrade_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define HANDSHAKE_BAUDRATE 576000
|
||||
#define UART_REPLY_TIMEOUT_MS 5000
|
||||
|
||||
static upgrade_uart_t uart_ops;
|
||||
static fw_stream_t fw_stream_ops;
|
||||
static upgrade_status_cb status_callback;
|
||||
|
||||
typedef struct {
|
||||
unsigned short chip_id;
|
||||
unsigned char chip_type;
|
||||
unsigned char chip_version;
|
||||
|
||||
unsigned short boot_delay;
|
||||
unsigned char baud_rate;
|
||||
unsigned char reserved_1;
|
||||
|
||||
unsigned int stage1_size;
|
||||
unsigned int stage2_baud_rate;
|
||||
unsigned int stage2_size;
|
||||
unsigned int stage2_checksum;
|
||||
unsigned char reserved[8];
|
||||
} __attribute__((packed)) boot_header_t;
|
||||
|
||||
static boot_header_t boot_header;
|
||||
static unsigned char data_buf[UPGRADE_PACKET_SIZE];
|
||||
static upgrade_stage_e current_stage;
|
||||
static int upgrade_initialized = 0;
|
||||
|
||||
static inline void set_upgrade_stage(upgrade_stage_e stage)
|
||||
{
|
||||
current_stage = stage;
|
||||
}
|
||||
|
||||
static inline upgrade_stage_e get_upgrade_stage(void)
|
||||
{
|
||||
return current_stage;
|
||||
}
|
||||
|
||||
static void status_report(upgrade_status_e status)
|
||||
{
|
||||
if (status_callback) {
|
||||
status_callback(get_upgrade_stage(), status);
|
||||
}
|
||||
}
|
||||
|
||||
static int upgrade_handshake(unsigned int timeout_ms, unsigned int retry_times)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
upgrade_debug("start upgrade_handshake, timeout_ms: %d, retry_times: %d\n", timeout_ms, retry_times);
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_HANDSHAKE);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
upgrade_debug("waiting 'M' ...\n");
|
||||
while (retry_times--) {
|
||||
upgrade_debug("handshake retry_times: %d", retry_times);
|
||||
unsigned char c = 0xef;
|
||||
uart_ops.send(&c, 1);
|
||||
if (!uart_ops.wait_reply((const unsigned char *)"M", 1, timeout_ms)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
upgrade_debug("get 'M' !\n");
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
} else {
|
||||
upgrade_debug("wait 'M' err !\n");
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
}
|
||||
|
||||
upgrade_debug("upgrade_handshake over, ret: %d\n ", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int is_little_endian(void)
|
||||
{
|
||||
int a = 0x11223344;
|
||||
unsigned char *p = (unsigned char *)&a;
|
||||
|
||||
return (*p == 0x44) ? 1 : 0;
|
||||
}
|
||||
|
||||
static unsigned int switch_endian(unsigned int v)
|
||||
{
|
||||
return (((v >> 0) & 0xff) << 24) | (((v >> 8) & 0xff) << 16) | (((v >> 16) & 0xff) << 8) | (((v >> 24) & 0xff) << 0);
|
||||
}
|
||||
|
||||
static unsigned int be32_to_cpu(unsigned int v)
|
||||
{
|
||||
if (is_little_endian()) {
|
||||
return switch_endian(v);
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
static int boot_info_baudrate[] = {300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
|
||||
static void print_bootheader(const boot_header_t *header)
|
||||
{
|
||||
upgrade_debug("chip_id %x\n", header->chip_id);
|
||||
upgrade_debug("chip_type %x\n", header->chip_type);
|
||||
upgrade_debug("chip_version %x\n", header->chip_version);
|
||||
upgrade_debug("boot_delay %x\n", header->boot_delay);
|
||||
upgrade_debug("baud_rate %d\n", boot_info_baudrate[header->baud_rate]);
|
||||
upgrade_debug("stage1_size %d\n", header->stage1_size);
|
||||
upgrade_debug("stage2_baud_rate %d\n", header->stage2_baud_rate);
|
||||
upgrade_debug("stage2_size %d\n", header->stage2_size);
|
||||
upgrade_debug("stage2_checksum %d\n", header->stage2_checksum);
|
||||
}
|
||||
|
||||
int parse_bootimg_header(void)
|
||||
{
|
||||
upgrade_debug("reading boot header ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_HEADER);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
int ret = fw_stream_ops.read(FW_BOOT_IMAGE, (unsigned char *)&boot_header, sizeof(boot_header));
|
||||
if (ret < sizeof(boot_header)) {
|
||||
upgrade_debug("read boot header err !\n");
|
||||
goto header_err;
|
||||
}
|
||||
|
||||
boot_header.stage1_size = be32_to_cpu(boot_header.stage1_size);
|
||||
boot_header.stage2_baud_rate = be32_to_cpu(boot_header.stage2_baud_rate);
|
||||
boot_header.stage2_size = be32_to_cpu(boot_header.stage2_size);
|
||||
boot_header.stage2_checksum = be32_to_cpu(boot_header.stage2_checksum);
|
||||
|
||||
print_bootheader(&boot_header);
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
return 0;
|
||||
|
||||
header_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int download_bootimg_stage1(void)
|
||||
{
|
||||
int wsize = 0;
|
||||
int len = 0;
|
||||
int size = 0;
|
||||
|
||||
upgrade_debug("start boot stage1 ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_S1);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
size = boot_header.stage1_size;
|
||||
size = size / 4;
|
||||
data_buf[0] = 'Y';
|
||||
data_buf[1] = (size >> 0) & 0xFF;
|
||||
data_buf[2] = (size >> 8) & 0xFF;
|
||||
data_buf[3] = (size >> 16) & 0xFF;
|
||||
data_buf[4] = (size >> 24) & 0xFF;
|
||||
uart_ops.send(data_buf, 5);
|
||||
|
||||
if (boot_header.chip_type == 0x01) {
|
||||
size = size * 4;
|
||||
}
|
||||
|
||||
upgrade_debug("download boot stage1 ...\n");
|
||||
while (wsize < size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
len = (boot_header.stage1_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (boot_header.stage1_size - wsize);
|
||||
len = fw_stream_ops.read(FW_BOOT_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
|
||||
wsize += len;
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting 'F' ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"F", 1, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'F' err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
upgrade_debug("get 'F' !\n");
|
||||
|
||||
///// stage1 running, change baudrate /////
|
||||
upgrade_debug("change baudrate: %d\n", boot_header.stage2_baud_rate);
|
||||
|
||||
uart_ops.close();
|
||||
uart_ops.open(boot_header.stage2_baud_rate, 8, 1, 0);
|
||||
|
||||
upgrade_debug("wait \"GET\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"GET", 3, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'GET' err !\n");
|
||||
goto stage1_err;
|
||||
}
|
||||
upgrade_debug("get \"GET\" !\n");
|
||||
|
||||
data_buf[0] = 'O';
|
||||
data_buf[1] = 'K';
|
||||
uart_ops.send(data_buf, 2);
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("boot stage1 ok !\n");
|
||||
|
||||
return 0;
|
||||
|
||||
stage1_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("boot stage1 err !\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int download_bootimg_stage2(void)
|
||||
{
|
||||
unsigned int checksum = 0;
|
||||
unsigned int stage2_size = 0;
|
||||
int len = 0;
|
||||
int wsize = 0;
|
||||
|
||||
upgrade_debug("start boot stage2 ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_BOOT_S2);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
|
||||
stage2_size = boot_header.stage2_size;
|
||||
checksum = boot_header.stage2_checksum;
|
||||
upgrade_debug("stage2_size = %u, checksum = %u\n", stage2_size, checksum);
|
||||
|
||||
if (checksum == 0 || stage2_size == 0) {
|
||||
upgrade_debug("stage2_size or checksum err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
data_buf[0] = 'S';
|
||||
uart_ops.send(data_buf, 1);
|
||||
uart_ops.send((const unsigned char *)&checksum, 4);
|
||||
uart_ops.send((const unsigned char *)&stage2_size, 4);
|
||||
|
||||
upgrade_debug("waiting \"ready\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"ready", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait ready error !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get \"ready\"\n");
|
||||
|
||||
upgrade_debug("download boot stage2 ...\n");
|
||||
while (wsize < stage2_size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
len = (stage2_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (stage2_size - wsize);
|
||||
len = fw_stream_ops.read(FW_BOOT_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
|
||||
wsize += len;
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting 'O' ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"O", 1, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait 'O' err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get 'O' !\n");
|
||||
|
||||
upgrade_debug("waiting \"boot>\" ...\n");
|
||||
|
||||
if (uart_ops.wait_reply((const unsigned char *)"boot>", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"boot>\" err !\n");
|
||||
goto stage2_err;
|
||||
}
|
||||
upgrade_debug("get \"boot>\" !\n");
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("boot stage2 ok !\n");
|
||||
|
||||
return 0;
|
||||
|
||||
stage2_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("boot stage2 err !\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int download_bootimg(void)
|
||||
{
|
||||
if (parse_bootimg_header() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (download_bootimg_stage1() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (download_bootimg_stage2() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int download_flashimg(void)
|
||||
{
|
||||
int wsize = 0;
|
||||
int len = 0;
|
||||
flash_img_info_t info = {0};
|
||||
|
||||
upgrade_debug("start flash image ...\n");
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_FLASH_IMG);
|
||||
status_report(UPGRADE_STATUS_START);
|
||||
fw_stream_ops.get_flash_img_info(&info);
|
||||
upgrade_debug("flash image size = %d\n", info.img_size);
|
||||
|
||||
if (info.img_size == 0) {
|
||||
upgrade_debug("flash image size err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
|
||||
memset(data_buf, 0, UPGRADE_PACKET_SIZE);
|
||||
len = sprintf((char *)data_buf, "serialdown %d %d %d\n", 0, info.img_size, UPGRADE_FLASH_BLOCK_SIZE);
|
||||
uart_ops.send(data_buf, len);
|
||||
|
||||
upgrade_debug("waiting \"~sta~\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~sta~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait ~sta~ err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~sta~\" !\n");
|
||||
|
||||
upgrade_debug("download flash image ...\n");
|
||||
|
||||
while (wsize < info.img_size) {
|
||||
if (wsize % UPGRADE_BLOCK_SIZE == 0) {
|
||||
status_report(UPGRADE_STATUS_DOWNLOADING);
|
||||
}
|
||||
|
||||
len = (info.img_size - wsize >= UPGRADE_PACKET_SIZE) ? UPGRADE_PACKET_SIZE : (info.img_size - wsize);
|
||||
len = fw_stream_ops.read(FW_FLASH_IMAGE, data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("read data err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
|
||||
len = uart_ops.send(data_buf, len);
|
||||
if (len <= 0) {
|
||||
upgrade_debug("send data err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
wsize += len;
|
||||
|
||||
if ((wsize % UPGRADE_FLASH_BLOCK_SIZE) == 0) {
|
||||
upgrade_debug("waiting \"~sta~\" ...\n");
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~sta~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"~sta~\" err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~sta~\" !\n");
|
||||
}
|
||||
}
|
||||
|
||||
upgrade_debug("download size: %d, waiting \"~fin~\" ...\n", wsize);
|
||||
if (uart_ops.wait_reply((const unsigned char *)"~fin~", 5, UART_REPLY_TIMEOUT_MS)) {
|
||||
upgrade_debug("wait \"~fin~\" err !\n");
|
||||
goto flash_err;
|
||||
}
|
||||
upgrade_debug("get \"~fin~\" !\n");
|
||||
|
||||
status_report(UPGRADE_STATUS_OK);
|
||||
upgrade_debug("flash image ok !\n");
|
||||
return 0;
|
||||
|
||||
flash_err:
|
||||
status_report(UPGRADE_STATUS_ERR);
|
||||
upgrade_debug("flash image err !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_proc(void)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (!upgrade_initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_upgrade_stage(UPGRADE_STAGE_NONE);
|
||||
|
||||
if (uart_ops.open(HANDSHAKE_BAUDRATE, 8, 1, 0) < 0) {
|
||||
upgrade_debug("open uart err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (fw_stream_ops.open(FW_BOOT_IMAGE) < 0) {
|
||||
upgrade_debug("open boot img stream err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (fw_stream_ops.open(FW_FLASH_IMAGE) < 0) {
|
||||
upgrade_debug("open flash img stream err !\n");
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
/* JL_PORTA->DIR &= ~BIT(4); */
|
||||
/* JL_PORTA->OUT |= BIT(4); */
|
||||
if (upgrade_handshake(10, 100) < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (download_bootimg() < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
if (download_flashimg() < 0) {
|
||||
goto upgrade_done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
upgrade_done:
|
||||
uart_ops.close();
|
||||
fw_stream_ops.close(FW_BOOT_IMAGE);
|
||||
fw_stream_ops.close(FW_FLASH_IMAGE);
|
||||
set_upgrade_stage(UPGRADE_STAGE_NONE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_init(upgrade_uart_t *uart, fw_stream_t *fw_stream, upgrade_status_cb status_cb)
|
||||
{
|
||||
if ((uart == NULL) || (fw_stream == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&uart_ops, uart, sizeof(upgrade_uart_t));
|
||||
memcpy(&fw_stream_ops, fw_stream, sizeof(fw_stream_t));
|
||||
|
||||
status_callback = status_cb;
|
||||
|
||||
upgrade_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_deinit(void)
|
||||
{
|
||||
upgrade_initialized = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
@ -0,0 +1,17 @@
|
||||
#ifndef __GX_URAT_UPGRADE_H__
|
||||
#define __GX_URAT_UPGRADE_H__
|
||||
|
||||
#include "gx_upgrade_def.h"
|
||||
|
||||
typedef struct {
|
||||
int (*open)(int baud, int databits, int stopbits, int parity);
|
||||
int (*close)(void);
|
||||
int (*wait_reply)(const unsigned char *buf, unsigned int len, unsigned int timeout);
|
||||
int (*send)(const unsigned char *buf, unsigned int len);
|
||||
} upgrade_uart_t;
|
||||
|
||||
int gx_uart_upgrade_init(upgrade_uart_t *uart, fw_stream_t *fw_stream, upgrade_status_cb status_cb);
|
||||
int gx_uart_upgrade_deinit(void);
|
||||
int gx_uart_upgrade_proc(void);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,136 @@
|
||||
#include "includes.h"
|
||||
#include "asm/uart_dev.h"
|
||||
#include "gx_uart_upgrade_porting.h"
|
||||
#include "../gx8002_npu_api.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if GX8002_UPGRADE_TOGGLE
|
||||
|
||||
#define GX_UART_UPGRADE_PORT_DEBUG 1
|
||||
|
||||
#ifdef GX_UART_UPGRADE_PORT_DEBUG
|
||||
//#define upgrade_debug(fmt, ...) y_printf("[gx_uart_upgrade]: " fmt, ##__VA_ARGS__)
|
||||
#define gx_uart_upgrade_port_debug y_printf
|
||||
#else
|
||||
#define gx_uart_upgrade_port_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
struct gx_upgrade_uart_port {
|
||||
const uart_bus_t *uart_bus;
|
||||
u32 cur_baud;
|
||||
};
|
||||
|
||||
static u8 uart_upgrade_cbuf[512] __attribute__((aligned(4)));
|
||||
|
||||
static struct gx_upgrade_uart_port uart_port = {0};
|
||||
|
||||
#define __this (&uart_port)
|
||||
|
||||
static void gx8002_upgrade_uart_isr_hook(void *arg, u32 status)
|
||||
{
|
||||
if (status != UT_TX) {
|
||||
//gx_uart_upgrade_port_debug("UT_RX_OT pending");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_open(int baud, int databits, int stopbits, int parity)
|
||||
{
|
||||
int ret = -1;
|
||||
struct uart_platform_data_t u_arg = {0};
|
||||
|
||||
if (__this->uart_bus) {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade have open");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_arg.tx_pin = TCFG_GX8002_NPU_UART_TX_PORT;
|
||||
u_arg.rx_pin = TCFG_GX8002_NPU_UART_RX_PORT;
|
||||
u_arg.rx_cbuf = uart_upgrade_cbuf;
|
||||
u_arg.rx_cbuf_size = sizeof(uart_upgrade_cbuf);
|
||||
u_arg.frame_length = 0xFFFF;
|
||||
u_arg.rx_timeout = 5;
|
||||
u_arg.isr_cbfun = gx8002_upgrade_uart_isr_hook;
|
||||
u_arg.baud = baud;
|
||||
u_arg.is_9bit = 0;
|
||||
|
||||
__this->uart_bus = uart_dev_open(&u_arg);
|
||||
if (__this->uart_bus != NULL) {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade open: baud: %d", baud);
|
||||
ret = 0;
|
||||
} else {
|
||||
gx_uart_upgrade_port_debug("gx8002 uart upgrade open fail");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_close(void)
|
||||
{
|
||||
if (__this->uart_bus) {
|
||||
uart_dev_close(__this->uart_bus);
|
||||
gpio_disable_fun_output_port(TCFG_GX8002_NPU_UART_TX_PORT);
|
||||
__this->uart_bus = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_upgrade_uart_porting_read(unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (__this->uart_bus && __this->uart_bus->read) {
|
||||
ret = __this->uart_bus->read(buf, len, timeout_ms);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = len;
|
||||
|
||||
if (__this->uart_bus && __this->uart_bus->write) {
|
||||
__this->uart_bus->write(buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gx_uart_upgrade_porting_wait_reply(const unsigned char *buf, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
int index = 0;
|
||||
unsigned char ch;
|
||||
|
||||
while (gx_upgrade_uart_porting_read(&ch, 1, timeout_ms) > 0) {
|
||||
//gx_uart_upgrade_port_debug("`0x%02x`\n", ch);
|
||||
if (ch == (unsigned char)buf[index]) {
|
||||
index++;
|
||||
}
|
||||
if (index == len) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uart_clock_critical_enter(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void uart_clock_critical_exit(void)
|
||||
{
|
||||
if (__this->uart_bus && __this->uart_bus->set_baud) {
|
||||
gx_uart_upgrade_port_debug("clock critical uart set_baud: %d", __this->cur_baud);
|
||||
__this->uart_bus->set_baud(__this->cur_baud);
|
||||
}
|
||||
}
|
||||
CLOCK_CRITICAL_HANDLE_REG(gx8002, uart_clock_critical_enter, uart_clock_critical_exit)
|
||||
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_TOGGLE */
|
||||
@ -0,0 +1,16 @@
|
||||
#ifndef _GX_UART_UPGRADE_UPGRADE_PORT_
|
||||
#define _GX_UART_UPGRADE_UPGRADE_PORT_
|
||||
|
||||
|
||||
int gx_upgrade_uart_porting_open(int baud, int databits, int stopbits, int parity);
|
||||
|
||||
int gx_upgrade_uart_porting_close(void);
|
||||
|
||||
int gx_upgrade_uart_porting_read(unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
|
||||
//int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
int gx_upgrade_uart_porting_write(const unsigned char *buf, unsigned int len);
|
||||
|
||||
int gx_uart_upgrade_porting_wait_reply(const unsigned char *buf, unsigned int len, unsigned int timeout_ms);
|
||||
|
||||
#endif /* #ifndef _GX_UART_UPGRADE_UPGRADE_PORT_ */
|
||||
@ -0,0 +1,47 @@
|
||||
#ifndef __GX_UPGRADE_DEF_H__
|
||||
#define __GX_UPGRADE_DEF_H__
|
||||
|
||||
#define UPGRADE_DATA_BLOCK_SIZE 256
|
||||
|
||||
#define UPGRADE_PACKET_SIZE 256
|
||||
#define UPGRADE_BLOCK_SIZE (1024 * 4)
|
||||
#define UPGRADE_FLASH_BLOCK_SIZE (1024 * 56) //56K
|
||||
|
||||
typedef enum {
|
||||
UPGRADE_STAGE_HANDSHAKE = 0,
|
||||
UPGRADE_STAGE_BOOT_HEADER,
|
||||
UPGRADE_STAGE_BOOT_S1,
|
||||
UPGRADE_STAGE_BOOT_S2,
|
||||
UPGRADE_STAGE_FLASH_IMG,
|
||||
UPGRADE_STAGE_NONE
|
||||
} upgrade_stage_e;
|
||||
|
||||
typedef enum {
|
||||
UPGRADE_STATUS_START = 0,
|
||||
UPGRADE_STATUS_DOWNLOADING,
|
||||
UPGRADE_STATUS_OK,
|
||||
UPGRADE_STATUS_ERR,
|
||||
UPGRADE_STATUS_NONE
|
||||
} upgrade_status_e;
|
||||
|
||||
typedef void (*upgrade_status_cb)(upgrade_stage_e stage, upgrade_status_e status);
|
||||
|
||||
typedef enum {
|
||||
FW_BOOT_IMAGE = 0, //"gx8002.boot"
|
||||
FW_FLASH_IMAGE, //"mcu_nor.bin"
|
||||
|
||||
FW_FLASH_MAX,
|
||||
} FW_IMAGE_TYPE;
|
||||
|
||||
typedef struct {
|
||||
unsigned int img_size;
|
||||
} flash_img_info_t;
|
||||
|
||||
typedef struct {
|
||||
int (*open)(FW_IMAGE_TYPE img_type);
|
||||
int (*close)(FW_IMAGE_TYPE img_type);
|
||||
int (*read)(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len);
|
||||
int (*get_flash_img_info)(flash_img_info_t *info);
|
||||
} fw_stream_t;
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,189 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
|
||||
#if GX8002_UPGRADE_SDFILE_TOGGLE
|
||||
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 20
|
||||
#define STREAM_FIFO_TIMEOUT_MS 7000
|
||||
|
||||
typedef int (*reply)(unsigned char *data, int size);
|
||||
static int ota_start = 0;
|
||||
|
||||
struct sdfile_fifo {
|
||||
FILE *boot_fp;
|
||||
FILE *bin_fp;
|
||||
};
|
||||
|
||||
static struct sdfile_fifo sdfile_upgrade = {0};
|
||||
#define __this (&sdfile_upgrade)
|
||||
|
||||
#define GX8002_SDFILE_UPGRADE_DEBUG_ENABLE 1
|
||||
|
||||
#define sdfile_upgrade_info g_printf
|
||||
|
||||
#if GX8002_SDFILE_UPGRADE_DEBUG_ENABLE
|
||||
#define sdfile_upgrade_debug r_printf
|
||||
#define sdfile_upgrade_put_buf put_buf
|
||||
#else
|
||||
#define sdfile_upgrade_debug(...)
|
||||
#define sdfile_upgrade_put_buf(...)
|
||||
#endif /* #if GX8002_DEBUG_ENABLE */
|
||||
|
||||
////////////// FW Stream Porting //////////////////
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
#define BOOT_IMAGE_PATH SDFILE_RES_ROOT_PATH"gx8002.boot"
|
||||
#define BIN_IMAGE_PATH SDFILE_RES_ROOT_PATH"mcu_nor.bin"
|
||||
FILE *fp = NULL;
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
fp = fopen(BOOT_IMAGE_PATH, "r");
|
||||
if (fp) {
|
||||
sdfile_upgrade_info("open %s succ", BOOT_IMAGE_PATH);
|
||||
__this->boot_fp = fp;
|
||||
} else {
|
||||
sdfile_upgrade_info("open %s failed!", BOOT_IMAGE_PATH);
|
||||
return -1;
|
||||
}
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
fp = fopen(BIN_IMAGE_PATH, "r");
|
||||
if (fp) {
|
||||
sdfile_upgrade_info("open %s succ", BIN_IMAGE_PATH);
|
||||
__this->bin_fp = fp;
|
||||
} else {
|
||||
sdfile_upgrade_info("open %s failed!", BIN_IMAGE_PATH);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
if (__this->boot_fp) {
|
||||
fclose(__this->boot_fp);
|
||||
__this->boot_fp = NULL;
|
||||
}
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
if (__this->bin_fp) {
|
||||
fclose(__this->bin_fp);
|
||||
__this->bin_fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *fp = NULL;
|
||||
|
||||
if (img_type == FW_BOOT_IMAGE) {
|
||||
fp = __this->boot_fp;
|
||||
} else if (img_type == FW_FLASH_IMAGE) {
|
||||
fp = __this->bin_fp;
|
||||
}
|
||||
|
||||
if (fp) {
|
||||
ret = fread(fp, buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__this->bin_fp) {
|
||||
info->img_size = flen(__this->bin_fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
sdfile_upgrade_info("status info: %s\n", reply_str);
|
||||
}
|
||||
}
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sdfile_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
sdfile_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_sdfile_ota_init(void)
|
||||
{
|
||||
upgrade_uart_t uart_ops;
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
fw_stream_t fw_stream_ops;
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
gx8002_upgrade_task(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_SDFILE_TOGGLE */
|
||||
|
||||
int gx8002_uart_sdfile_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_SDFILE_TOGGLE */
|
||||
|
||||
@ -0,0 +1,239 @@
|
||||
#include "includes.h"
|
||||
#include "gx_fifo.h"
|
||||
|
||||
#define os_mutex_t OS_MUTEX *
|
||||
#define gx_os_mutex_lock os_mutex_pend
|
||||
#define gx_os_mutex_unlock os_mutex_post
|
||||
|
||||
#define os_sem_t OS_SEM *
|
||||
#define gx_os_sem_post os_sem_post
|
||||
#define gx_os_sem_wait os_sem_pend
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
unsigned int length;
|
||||
} fifoBlock;
|
||||
|
||||
typedef struct {
|
||||
int fifo_head;
|
||||
int fifo_tail;
|
||||
int block_num;
|
||||
int block_total;
|
||||
int block_size;
|
||||
fifoBlock *fifo_block;
|
||||
os_mutex_t fifo_mutex;
|
||||
os_sem_t fifo_sem;
|
||||
} GxFIFO;
|
||||
|
||||
|
||||
//======================== OS porting ======================================//
|
||||
static void *gx_os_calloc(u32 nmemb, u32 size)
|
||||
{
|
||||
return zalloc(nmemb * size);
|
||||
}
|
||||
|
||||
static void gx_os_free(void *p)
|
||||
{
|
||||
if (p) {
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
static os_mutex_t gx_os_mutex_create()
|
||||
{
|
||||
os_mutex_t mutex;
|
||||
mutex = (os_mutex_t)gx_os_calloc((sizeof(*mutex)), 1);
|
||||
|
||||
ASSERT(mutex, "mutex alloc err");
|
||||
|
||||
os_mutex_create(mutex);
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
static void gx_os_mutex_destroy(os_mutex_t mutex)
|
||||
{
|
||||
if (mutex) {
|
||||
os_mutex_del(mutex, 0);
|
||||
gx_os_free(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static os_sem_t gx_os_sem_create(u32 cnt)
|
||||
{
|
||||
os_sem_t sem;
|
||||
sem = (os_mutex_t)gx_os_calloc((sizeof(*sem)), 1);
|
||||
|
||||
ASSERT(sem, "sem alloc err");
|
||||
|
||||
os_sem_create(sem, cnt);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
static void gx_os_sem_destroy(os_sem_t sem)
|
||||
{
|
||||
if (sem) {
|
||||
os_sem_del(sem, 0);
|
||||
gx_os_free(sem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============================================================//
|
||||
|
||||
int gx_fifo_destroy(fifo_handle_t fifo)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int i = 0;
|
||||
|
||||
if (temp_fifo == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
if (temp_fifo->fifo_block != NULL) {
|
||||
for (i = 0; i < temp_fifo->block_total; i++) {
|
||||
if (temp_fifo->fifo_block[i].data != NULL) {
|
||||
gx_os_free(temp_fifo->fifo_block[i].data);
|
||||
temp_fifo->fifo_block[i].data = NULL;
|
||||
}
|
||||
}
|
||||
gx_os_free(temp_fifo->fifo_block);
|
||||
temp_fifo->fifo_block = NULL;
|
||||
}
|
||||
|
||||
gx_os_sem_destroy(temp_fifo->fifo_sem);
|
||||
gx_os_mutex_destroy(temp_fifo->fifo_mutex);
|
||||
|
||||
gx_os_free(temp_fifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fifo_handle_t gx_fifo_create(int block_size, int block_num)
|
||||
{
|
||||
GxFIFO *temp_fifo = NULL;
|
||||
int i = 0;
|
||||
|
||||
if ((block_size == 0) || (block_num == 0)) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
if ((temp_fifo = (GxFIFO *)gx_os_calloc(sizeof(GxFIFO), 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
if ((temp_fifo->fifo_block = (fifoBlock *)gx_os_calloc(block_num * sizeof(fifoBlock), 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
|
||||
temp_fifo->fifo_mutex = gx_os_mutex_create();
|
||||
temp_fifo->fifo_sem = gx_os_sem_create(0);
|
||||
|
||||
for (i = 0; i < block_num; i++) {
|
||||
if ((temp_fifo->fifo_block[i].data = (char *)gx_os_calloc(block_size, 1)) == NULL) {
|
||||
goto fifo_failed;
|
||||
}
|
||||
}
|
||||
|
||||
temp_fifo->block_total = block_num;
|
||||
temp_fifo->block_size = block_size;
|
||||
temp_fifo->fifo_head = 0;
|
||||
temp_fifo->fifo_tail = -1;
|
||||
|
||||
return (fifo_handle_t)temp_fifo;
|
||||
|
||||
fifo_failed:
|
||||
gx_fifo_destroy((fifo_handle_t)temp_fifo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx_fifo_write(fifo_handle_t fifo, const char *write_data, int write_size)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int cp_size = 0;
|
||||
|
||||
if ((temp_fifo == NULL) || (write_data == NULL) || (write_size == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
if (temp_fifo->block_num >= temp_fifo->block_total) {
|
||||
printf("[%s]%d: fifo full!!!\n", __func__, __LINE__);
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
temp_fifo->fifo_tail++;
|
||||
if (temp_fifo->fifo_tail >= temp_fifo->block_total) {
|
||||
temp_fifo->fifo_tail = 0;
|
||||
}
|
||||
|
||||
(write_size >= temp_fifo->block_size)
|
||||
? (cp_size = temp_fifo->block_size) : (cp_size = write_size);
|
||||
memcpy(temp_fifo->fifo_block[temp_fifo->fifo_tail].data, write_data, cp_size);
|
||||
temp_fifo->fifo_block[temp_fifo->fifo_tail].length = cp_size;
|
||||
#if 1
|
||||
if (temp_fifo->block_num == 0) {
|
||||
//printf("[%s]%d new data: %d!!!\n", __func__, __LINE__, os_sem_query(temp_fifo->fifo_sem));
|
||||
gx_os_sem_post(temp_fifo->fifo_sem);
|
||||
}
|
||||
#endif
|
||||
temp_fifo->block_num++;
|
||||
|
||||
// gx_os_sem_post(temp_fifo->fifo_sem);
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
return cp_size;
|
||||
}
|
||||
|
||||
int gx_fifo_read(fifo_handle_t fifo, char *read_data, int read_size, int timeout)
|
||||
{
|
||||
GxFIFO *temp_fifo = (GxFIFO *)fifo;
|
||||
int cp_size = 0;
|
||||
|
||||
if ((temp_fifo == NULL) || (read_data == NULL) || (read_size == 0)) {
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
int ret = gx_os_sem_wait(temp_fifo->fifo_sem, timeout);
|
||||
if (ret != 0) {
|
||||
printf("[%s]%d: wait data timeout: %d !!!!!!!\n", __func__, __LINE__, ret);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
|
||||
while (temp_fifo->block_num == 0) {
|
||||
//printf("[%s]%d: fifo empty: %d!!!\n", __func__, __LINE__, gx_os_sem_query(temp_fifo->fifo_sem));
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
if (gx_os_sem_wait(temp_fifo->fifo_sem, timeout) != 0) {
|
||||
printf("[%s]%d: wait data timeout !!!!!!!\n", __func__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
//os_sem_pend(&temp_fifo->fifo_sem, 0);
|
||||
//os_mutex_pend(&temp_fifo->fifo_mutex, 0);
|
||||
gx_os_mutex_lock(temp_fifo->fifo_mutex, 0);
|
||||
//printf("[%s]%d, fifo has data: %d!!!\n", __func__, __LINE__, os_sem_query(&temp_fifo->fifo_sem));
|
||||
//return 0;
|
||||
}
|
||||
|
||||
(read_size >= temp_fifo->fifo_block[temp_fifo->fifo_head].length)
|
||||
? (cp_size = temp_fifo->fifo_block[temp_fifo->fifo_head].length) : (cp_size = read_size);
|
||||
memcpy(read_data, temp_fifo->fifo_block[temp_fifo->fifo_head].data, cp_size);
|
||||
read_size = temp_fifo->fifo_block[temp_fifo->fifo_head].length;
|
||||
|
||||
temp_fifo->fifo_head++;
|
||||
if (temp_fifo->fifo_head >= temp_fifo->block_total) {
|
||||
temp_fifo->fifo_head = 0;
|
||||
}
|
||||
|
||||
temp_fifo->block_num--;
|
||||
|
||||
gx_os_mutex_unlock(temp_fifo->fifo_mutex);
|
||||
|
||||
return cp_size;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
#ifndef __GX_FIFO_H__
|
||||
#define __GX_FIFO_H__
|
||||
|
||||
typedef int fifo_handle_t;
|
||||
fifo_handle_t gx_fifo_create(int block_size, int block_num);
|
||||
int gx_fifo_destroy(fifo_handle_t fifo);
|
||||
int gx_fifo_write(fifo_handle_t fifo, const char *write_data, int write_size);
|
||||
int gx_fifo_read(fifo_handle_t fifo, char *read_data, int read_size, int timeout);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,249 @@
|
||||
#include "includes.h"
|
||||
#include "../gx_uart_upgrade.h"
|
||||
#include "../../gx8002_npu_api.h"
|
||||
#include "../gx_uart_upgrade_porting.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
#include "classic/hci_lmp.h"
|
||||
#include "gx_fifo.h"
|
||||
|
||||
#if GX8002_UPGRADE_SPP_TOGGLE
|
||||
|
||||
#define spp_upgrade_info g_printf
|
||||
|
||||
//=============== SPP Porting ================//
|
||||
int gx8002_ota_recv(unsigned char *data, int size);
|
||||
static void gx8002_spp_data_handler(u8 packet_type, u16 ch, u8 *packet, u16 size)
|
||||
{
|
||||
switch (packet_type) {
|
||||
case 1:
|
||||
/* cbuf_init(&spp_buf_hdl, spp_buf, sizeof(spp_buf)); */
|
||||
/* spp_timer = sys_timer_add(NULL, spp_send_data_timer, 50); */
|
||||
/* spp_printf("spp connect\n"); */
|
||||
spp_upgrade_info("gx8002 spp connect\n");
|
||||
break;
|
||||
case 2:
|
||||
spp_upgrade_info("gx8002 spp disconnect\n");
|
||||
/* if (spp_timer) { */
|
||||
/* sys_timer_del(spp_timer); */
|
||||
/* spp_timer = 0; */
|
||||
/* } */
|
||||
break;
|
||||
case 7:
|
||||
//spp_upgrade_info("gx8002 spp_rx: %d", size);
|
||||
//put_buf(packet,size);
|
||||
gx8002_ota_recv(packet, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gx8002_spp_send_data(u8 *data, u32 size)
|
||||
{
|
||||
user_send_cmd_prepare(USER_CTRL_SPP_SEND_DATA, size, data);
|
||||
}
|
||||
|
||||
|
||||
void gx8002_spp_ota_init(void)
|
||||
{
|
||||
spp_data_deal_handle_register(gx8002_spp_data_handler);
|
||||
}
|
||||
|
||||
////////////// FW Stream Porting //////////////////
|
||||
#define STREAM_FIFO_BLOCK_TOTAL 16
|
||||
#define STREAM_FIFO_TIMEOUT_MS (5000 / 10)
|
||||
|
||||
/* typedef int (*reply)(unsigned char *data, int size); */
|
||||
static int ota_start = 0;
|
||||
//static os_sem_t ota_sem;
|
||||
static fifo_handle_t fw_fifo;
|
||||
|
||||
static int gx8002_ota_start(void)
|
||||
{
|
||||
if (!ota_start) {
|
||||
os_taskq_post_msg("gx8002", 2, GX8002_MSG_UPDATE, GX8002_UPDATE_TYPE_SPP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_gx8002_ota_start(void)
|
||||
{
|
||||
return ota_start;
|
||||
}
|
||||
|
||||
int gx8002_ota_recv(unsigned char *data, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((data == NULL) || (size == 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp((char *)data, "startupgrade", strlen("startupgrade")) == 0) {
|
||||
gx8002_ota_start();
|
||||
} else {
|
||||
if (ota_start) {
|
||||
if (fw_fifo > 0) {
|
||||
int cnt = size / UPGRADE_PACKET_SIZE;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
gx_fifo_write(fw_fifo, (const char *)&data[UPGRADE_PACKET_SIZE * i], UPGRADE_PACKET_SIZE);
|
||||
}
|
||||
|
||||
if (size % UPGRADE_PACKET_SIZE) {
|
||||
gx_fifo_write(fw_fifo, (const char *)&data[UPGRADE_PACKET_SIZE * i], size % UPGRADE_PACKET_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int fw_stream_open(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
if (fw_fifo == 0) {
|
||||
if ((fw_fifo = gx_fifo_create(UPGRADE_PACKET_SIZE, STREAM_FIFO_BLOCK_TOTAL)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_stream_close(FW_IMAGE_TYPE img_type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fw_fifo > 0) {
|
||||
ret = gx_fifo_destroy(fw_fifo);
|
||||
fw_fifo = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_read(FW_IMAGE_TYPE img_type, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fw_fifo > 0) {
|
||||
ret = gx_fifo_read(fw_fifo, (char *)buf, len, STREAM_FIFO_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_stream_get_flash_img_info(flash_img_info_t *info)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fw_fifo == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = gx_fifo_read(fw_fifo, (char *)info, sizeof(flash_img_info_t), STREAM_FIFO_TIMEOUT_MS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////// status info /////////////
|
||||
static const char *status_info_str[UPGRADE_STAGE_NONE][UPGRADE_STATUS_NONE] = {
|
||||
// UPGRADE_STAGE_HANDSHAKE
|
||||
{"handshake start\n", NULL, "handshake ok\n", "handshake err\n"},
|
||||
// UPGRADE_STAGE_BOOT_HEADER
|
||||
{"boot header start\n", NULL, "boot header ok\n", "boot header err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S1
|
||||
{"boot stage1 start\n", "boot stage1 downloading\n", "boot stage1 ok\n", "boot stage1 err\n"},
|
||||
// UPGRADE_STAGE_BOOT_S2
|
||||
{"boot stage2 start\n", "boot stage2 downloading\n", "boot stage2 ok\n", "boot stage2 err\n"},
|
||||
// UPGRADE_STAGE_FLASH_IMG
|
||||
{"flash img start\n", "flash img downloading\n", "flash img ok\n", "flash img err\n"},
|
||||
};
|
||||
|
||||
static void gx8002_upgrade_status_cb(upgrade_stage_e stage, upgrade_status_e status)
|
||||
{
|
||||
//printf("---- [%s]: stage: %d, status: %d ----\n", __func__, stage, status);
|
||||
const char *reply_str = status_info_str[stage][status];
|
||||
if (reply_str != NULL) {
|
||||
spp_upgrade_info("status info: %s\n", reply_str);
|
||||
//user_spp_send_data((unsigned char *)reply_str, strlen(reply_str));
|
||||
gx8002_spp_send_data((u8 *)reply_str, strlen(reply_str));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int gx8002_upgrade_task(void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
spp_upgrade_info("---- gx8002 ota start ----");
|
||||
gx8002_upgrade_cold_reset();
|
||||
|
||||
ret = gx_uart_upgrade_proc();
|
||||
|
||||
gx8002_normal_cold_reset();
|
||||
spp_upgrade_info("---- gx8002 ota over ----");
|
||||
|
||||
ota_start = 0;
|
||||
|
||||
if (ret < 0) {
|
||||
gx8002_update_end_post_msg(0);
|
||||
} else {
|
||||
gx8002_update_end_post_msg(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int gx8002_uart_spp_ota_init(void)
|
||||
{
|
||||
upgrade_uart_t uart_ops;
|
||||
fw_stream_t fw_stream_ops;
|
||||
|
||||
uart_ops.open = gx_upgrade_uart_porting_open;
|
||||
uart_ops.close = gx_upgrade_uart_porting_close;
|
||||
uart_ops.send = gx_upgrade_uart_porting_write;
|
||||
uart_ops.wait_reply = gx_uart_upgrade_porting_wait_reply;
|
||||
|
||||
|
||||
fw_stream_ops.open = fw_stream_open;
|
||||
fw_stream_ops.close = fw_stream_close;
|
||||
fw_stream_ops.read = fw_stream_read;
|
||||
fw_stream_ops.get_flash_img_info = fw_stream_get_flash_img_info;
|
||||
|
||||
gx_uart_upgrade_init(&uart_ops, &fw_stream_ops, gx8002_upgrade_status_cb);
|
||||
|
||||
ota_start = 1;
|
||||
|
||||
gx8002_upgrade_task(NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
|
||||
int gx8002_uart_spp_ota_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int get_gx8002_ota_start(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gx8002_ota_recv(unsigned char *data, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if GX8002_UPGRADE_SPP_TOGGLE */
|
||||
Reference in New Issue
Block a user