This commit is contained in:
lmx
2025-10-29 13:10:02 +08:00
commit 49a07fa419
2284 changed files with 642060 additions and 0 deletions

View 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 */

View 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__ */

View 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 */

View 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__ */

View 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__ */

View 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 */

View File

@ -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 */

View File

@ -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) */

View 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 */

View File

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

View File

@ -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 */

View File

@ -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_ */

View File

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

View File

@ -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 */

View File

@ -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;
}

View File

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

View File

@ -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 */