mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-18 18:18:54 +00:00
v1.2.1
This commit is contained in:
569
application/baremetal/bootloader/lib/aicupg/uart_proto_layer.c
Normal file
569
application/baremetal/bootloader/lib/aicupg/uart_proto_layer.c
Normal file
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2025, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <aic_common.h>
|
||||
#include <aic_utils.h>
|
||||
#include <aic_core.h>
|
||||
#include <uart.h>
|
||||
#include <uart_proto_layer.h>
|
||||
#include <aicupg.h>
|
||||
#include <crc16.h>
|
||||
|
||||
//#define AICUPG_UART_DEBUG
|
||||
#ifdef AICUPG_UART_DEBUG
|
||||
#undef pr_err
|
||||
#undef pr_warn
|
||||
#undef pr_info
|
||||
#undef pr_debug
|
||||
#define pr_err printf
|
||||
#define pr_warn printf
|
||||
#define pr_info printf
|
||||
#define pr_debug printf
|
||||
#endif
|
||||
|
||||
#define update_last_recv_time() \
|
||||
do { \
|
||||
uart_proto.last_recv_time = aic_get_time_ms(); \
|
||||
} while(0)
|
||||
|
||||
static LIST_HEAD(task);
|
||||
|
||||
struct uart_proto_device uart_proto;
|
||||
static u8 g_uart_send_recv_buf[LNG_FRM_MAX_LEN];
|
||||
static int uart_proto_id = 0;
|
||||
|
||||
static int uart_proto_add_task(u32 dir, u8 *data, u32 data_len)
|
||||
{
|
||||
struct proto_task *t = NULL;
|
||||
|
||||
t = aicos_malloc(0, sizeof(struct proto_task));
|
||||
if (!t)
|
||||
{
|
||||
pr_err("alloc task failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
t->direction = dir;
|
||||
t->status = UPG_UART_CMD_RECV;
|
||||
t->data = data;
|
||||
t->data_len = data_len;
|
||||
t->xfer_len = 0;
|
||||
t->single_frame_trans_siz = 0;
|
||||
t->single_frame_transed_siz = 0;
|
||||
|
||||
list_add_tail(&t->list, &task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct proto_task *uart_proto_get_task(void)
|
||||
{
|
||||
struct list_head *pos;
|
||||
|
||||
list_for_each(pos, &task) {
|
||||
return list_entry(pos, struct proto_task, list);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int uart_proto_del_task(void)
|
||||
{
|
||||
struct proto_task *t;
|
||||
|
||||
t = uart_proto_get_task();
|
||||
if (!t) {
|
||||
pr_info("list is NULL.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
list_del(&t->list);
|
||||
free(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uart_proto_putchar(int id, u8 ch)
|
||||
{
|
||||
pr_debug("---> Send 0x%x\n", ch);
|
||||
uart_putchar(id, ch);
|
||||
uart_proto.last_send_time = aic_get_time_ms();
|
||||
}
|
||||
|
||||
static int uart_proto_gets(int id, u8 *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = uart_gets(id, buf, len);
|
||||
if (ret) {
|
||||
uart_proto.last_recv_time = aic_get_time_ms();
|
||||
#ifdef AICUPG_UART_DEBUG
|
||||
if (ret <= 64)
|
||||
hexdump_msg("Recvs:", buf, ret, 1);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uart_proto_puts(int id, u8 *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = uart_puts(id, buf, len);
|
||||
if (ret) {
|
||||
uart_proto.last_send_time = aic_get_time_ms();
|
||||
#ifdef AICUPG_UART_DEBUG
|
||||
if (ret <= 64)
|
||||
hexdump_msg("Sends:", buf, ret, 1);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pack_frame(u8 blk, u8 *frame, u8 *data, int len)
|
||||
{
|
||||
u16 crc16;
|
||||
int flen;
|
||||
|
||||
if (len == LNG_FRM_DLEN) {
|
||||
pr_debug("pack long frame\n");
|
||||
frame[0] = STX;
|
||||
frame[1] = blk;
|
||||
frame[2] = 255 - blk;
|
||||
memcpy(&frame[3], data, len);
|
||||
crc16 = crc16_ccitt(0, data, len);
|
||||
frame[LNG_FRM_DLEN + 3] = (u8)(crc16 >> 8);
|
||||
frame[LNG_FRM_DLEN + 4] = (u8)(crc16 & 0xFF);
|
||||
flen = len + 5;
|
||||
} else if (len <= SHT_FRM_DLEN) {
|
||||
pr_debug("pack short frame\n");
|
||||
frame[0] = SOH;
|
||||
frame[1] = blk;
|
||||
frame[2] = 255 - blk;
|
||||
frame[3] = (u8)len;
|
||||
memcpy(&frame[4], data, len);
|
||||
crc16 = crc16_ccitt(0, data, len);
|
||||
frame[len + 4] = (u8)(crc16 >> 8);
|
||||
frame[len + 5] = (u8)(crc16 & 0xFF);
|
||||
flen = len + 6;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return flen;
|
||||
}
|
||||
|
||||
static int read_short_frame_data(u8 *buf, int len)
|
||||
{
|
||||
int flen;
|
||||
u16 crc16, crc16_i;
|
||||
u8 blk1, blk2, nextblk;
|
||||
|
||||
pr_debug("SHORT: %llu\n", aic_get_time_us());
|
||||
// hexdump(buf, len, 1);
|
||||
blk1 = buf[1];
|
||||
blk2 = buf[2];
|
||||
flen = buf[3];
|
||||
if (blk1 != (255 - blk2)) {
|
||||
pr_err("blk1 %d != blk2 %d\n", blk1, (255 - blk2));
|
||||
return UART_ERR_DATA;
|
||||
}
|
||||
pr_debug("blk no %d\n", blk1);
|
||||
|
||||
crc16_i = buf[4 + flen] << 8 | buf[4 + flen + 1];
|
||||
crc16 = crc16_ccitt(0, &buf[4], flen);
|
||||
if (crc16 != crc16_i) {
|
||||
pr_err("crc16 error: 0x%x != 0x%x\n", crc16, crc16_i);
|
||||
return UART_ERR_DATA;
|
||||
}
|
||||
|
||||
nextblk = uart_proto.recv_blk_no + 1;
|
||||
if (blk1 != 1 && nextblk != blk1 && !uart_proto.first_connect) {
|
||||
pr_err("blk no discontinue should be %d, got %d\n", nextblk, blk1);
|
||||
return UART_ERR_DATA;
|
||||
}
|
||||
|
||||
if (blk1 == uart_proto.recv_blk_no) {
|
||||
printf("Repeat frame.\n");
|
||||
return UART_SKIP_DATA;
|
||||
}
|
||||
uart_proto.recv_blk_no = blk1;
|
||||
uart_proto.first_connect = 0;
|
||||
pr_debug("%s done\n", __func__);
|
||||
return flen;
|
||||
}
|
||||
|
||||
/*
|
||||
* return > 0: ACK
|
||||
* return = 0: ACK
|
||||
* return < 0: NAK
|
||||
*/
|
||||
static int read_long_frame_data(u8 *buf, int len)
|
||||
{
|
||||
int flen;
|
||||
u16 crc16, crc16_i;
|
||||
u8 blk1, blk2, nextblk;
|
||||
|
||||
pr_debug("LONG: %llu\n", aic_get_time_us());
|
||||
blk1 = buf[1];
|
||||
blk2 = buf[2];
|
||||
flen = LNG_FRM_DLEN;
|
||||
if (blk1 != (255 - blk2)) {
|
||||
pr_err("blk1 %d != blk2 %d\n", blk1, (255 - blk2));
|
||||
return UART_ERR_DATA;
|
||||
}
|
||||
pr_debug("blk no %d\n", blk1);
|
||||
|
||||
crc16_i = buf[3 + flen] << 8 | buf[3 + flen + 1];
|
||||
crc16 = crc16_ccitt(0, &buf[3], flen);
|
||||
if (crc16 != crc16_i) {
|
||||
pr_err("crc16 error: 0x%x != 0x%x\n", crc16, crc16_i);
|
||||
hexdump(buf, LNG_FRM_MAX_LEN, 1);
|
||||
return UART_ERR_DATA;
|
||||
}
|
||||
|
||||
nextblk = uart_proto.recv_blk_no + 1;
|
||||
if (blk1 != 1 && nextblk != blk1 && !uart_proto.first_connect) {
|
||||
pr_err("blk no discontinue should be %d, got %d\n", nextblk, blk1);
|
||||
return UART_ERR_DATA;
|
||||
}
|
||||
|
||||
/* Recv repeat frame, just skip it */
|
||||
if (blk1 == uart_proto.recv_blk_no) {
|
||||
pr_warn("Repeat frame.\n");
|
||||
return UART_SKIP_DATA;
|
||||
}
|
||||
uart_proto.recv_blk_no = blk1;
|
||||
uart_proto.first_connect = 0;
|
||||
pr_debug("%s done\n", __func__);
|
||||
return flen;
|
||||
}
|
||||
|
||||
static int read_frame_data(u8 *buf, int len)
|
||||
{
|
||||
if (buf[0] == SOH) {
|
||||
return read_short_frame_data(buf, len);
|
||||
} else if (buf[0] == STX) {
|
||||
return read_long_frame_data(buf, len);
|
||||
} else {
|
||||
return UART_ERR_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
static int uart_proto_layer_host_send_proc(struct proto_task *t, u8 *pframe)
|
||||
{
|
||||
int ret, rest;
|
||||
u8 ch = 0, *p;
|
||||
u64 delta = 0;
|
||||
|
||||
switch (t->status) {
|
||||
case UPG_UART_DATA_RECV:
|
||||
if (t->single_frame_transed_siz == 0) {
|
||||
ret = uart_proto_gets(uart_proto_id, &pframe[0], 1);
|
||||
if (ret == 0) {
|
||||
//pr_debug("read head failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pframe[0] != SOH && pframe[0] != STX) {
|
||||
//pr_err("frame error. unknown frame data.\n");
|
||||
break;
|
||||
}
|
||||
t->single_frame_transed_siz++;
|
||||
}
|
||||
|
||||
if (t->single_frame_transed_siz == 1) {
|
||||
ret = uart_proto_gets(uart_proto_id, &pframe[1], 1);
|
||||
if (ret == 0) {
|
||||
pr_err("read blk1 failed.\n");
|
||||
return -1;
|
||||
}
|
||||
t->single_frame_transed_siz++;
|
||||
}
|
||||
|
||||
if (t->single_frame_transed_siz == 2) {
|
||||
ret = uart_proto_gets(uart_proto_id, &pframe[2], 1);
|
||||
if (ret == 0) {
|
||||
pr_err("read blk2 failed.\n");
|
||||
return -1;
|
||||
}
|
||||
t->single_frame_transed_siz++;
|
||||
}
|
||||
|
||||
if (t->single_frame_transed_siz == 3) {
|
||||
ret = uart_proto_gets(uart_proto_id, &pframe[3], 1);
|
||||
if (ret == 0) {
|
||||
pr_err("read frm_len failed.\n");
|
||||
return -1;
|
||||
}
|
||||
t->single_frame_transed_siz++;
|
||||
if (pframe[0] == SOH) {
|
||||
t->single_frame_trans_siz = pframe[3] + 6;
|
||||
} else if (pframe[0] == STX) {
|
||||
t->single_frame_trans_siz = LNG_FRM_DLEN + 5;
|
||||
}
|
||||
}
|
||||
|
||||
rest = t->single_frame_trans_siz - t->single_frame_transed_siz;
|
||||
ret = uart_proto_gets(uart_proto_id, &pframe[t->single_frame_transed_siz], rest);
|
||||
if (ret != rest) {
|
||||
t->single_frame_transed_siz += ret;
|
||||
delta = aic_get_time_ms() - uart_proto.last_recv_time;
|
||||
if (delta > 1000) {
|
||||
pr_warn("Long time no data, re-recv it ...\n");
|
||||
update_last_recv_time();
|
||||
t->single_frame_trans_siz = 0;
|
||||
t->single_frame_transed_siz = 0;
|
||||
uart_proto_putchar(uart_proto_id, NAK);
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
t->single_frame_transed_siz += ret;
|
||||
ret = read_frame_data(pframe, t->single_frame_transed_siz);
|
||||
if (ret > 0) {
|
||||
pr_debug("Recv %d\n", ret);
|
||||
p = t->data + t->xfer_len;
|
||||
if (pframe[0] == SOH)
|
||||
memcpy(p, &pframe[4], ret);
|
||||
else if (pframe[0] == STX)
|
||||
memcpy(p, &pframe[3], ret);
|
||||
t->xfer_len += ret;
|
||||
uart_proto_putchar(uart_proto_id, ACK);
|
||||
} else if (ret == 0) {
|
||||
uart_proto_putchar(uart_proto_id, ACK);
|
||||
} else {
|
||||
t->single_frame_trans_siz = 0;
|
||||
t->single_frame_transed_siz = 0;
|
||||
uart_proto_putchar(uart_proto_id, NAK);
|
||||
break;
|
||||
}
|
||||
t->single_frame_trans_siz = 0;
|
||||
t->single_frame_transed_siz = 0;
|
||||
memset(pframe, 0, LNG_FRM_MAX_LEN);
|
||||
pr_debug("Ack frame\n");
|
||||
}
|
||||
|
||||
if (t->xfer_len >= t->data_len) {
|
||||
pr_debug("Recv in data len %d\n", t->xfer_len);
|
||||
uart_proto_layer_set_status(UPG_UART_DATA_RECV_DONE);
|
||||
t->status = UPG_UART_CMD_RECV;
|
||||
uart_proto_del_task();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case UPG_UART_CMD_RECV:
|
||||
ret = uart_proto_gets(uart_proto_id, &ch, 1);
|
||||
if (ret == 0) {
|
||||
delta = aic_get_time_ms() - uart_proto.last_recv_time;
|
||||
if (delta > SIG_A_INTERVAL_MS) {
|
||||
update_last_recv_time();
|
||||
pr_debug("Wait host connect ...\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ch == SOH || ch == STX) {
|
||||
pframe[0] = ch;
|
||||
t->status = UPG_UART_DATA_RECV;
|
||||
t->single_frame_transed_siz++;
|
||||
} else if (ch == SIG_C) {
|
||||
uart_proto_putchar(uart_proto_id, ACK);
|
||||
pr_debug("Ack SIG_C\n");
|
||||
break;
|
||||
} else if (ch == DC1_SEND) {
|
||||
uart_proto_putchar(uart_proto_id, ACK);
|
||||
t->direction = DIR_HOST_SEND;
|
||||
t->status = UPG_UART_DATA_RECV;
|
||||
memset(pframe, 0, LNG_FRM_MAX_LEN);
|
||||
pr_debug("Host switch to send mode.\n");
|
||||
break;
|
||||
} else if (ch == DC2_RECV) {
|
||||
uart_proto_putchar(uart_proto_id, ACK);
|
||||
t->direction = DIR_HOST_RECV;
|
||||
t->status = UPG_UART_DATA_SEND;
|
||||
pr_debug("Host switch to recv mode.\n");
|
||||
//csi_coret_config(drv_get_sys_freq() / 200, CORET_IRQn);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uart_proto_layer_host_recv_proc(struct proto_task *t, u8 *pframe)
|
||||
{
|
||||
int ret, rest, slice, flen;
|
||||
u8 ch = 0, *p;
|
||||
u64 delta = 0;
|
||||
|
||||
switch (t->status) {
|
||||
case UPG_UART_DATA_SEND:
|
||||
p = t->data + t->xfer_len;
|
||||
rest = t->data_len - t->xfer_len;
|
||||
if (rest > 0) {
|
||||
if (rest > LNG_FRM_DLEN)
|
||||
slice = LNG_FRM_DLEN;
|
||||
else if (rest > SHT_FRM_DLEN)
|
||||
slice = SHT_FRM_DLEN;
|
||||
else
|
||||
slice = rest;
|
||||
t->single_frame_transed_siz = slice;
|
||||
flen = pack_frame(uart_proto.send_blk_no, pframe, p, slice);
|
||||
ret = uart_proto_puts(uart_proto_id, pframe, flen);
|
||||
if (ret != flen) {
|
||||
pr_err("write frame data error. ret:%d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
pr_debug("frame data is written.\n");
|
||||
}
|
||||
t->status = UPG_UART_CMD_RECV;
|
||||
break;
|
||||
case UPG_UART_CMD_RECV:
|
||||
ret = uart_proto_gets(uart_proto_id, &ch, 1);
|
||||
if (ret == 0) {
|
||||
delta = aic_get_time_ms() - uart_proto.last_recv_time;
|
||||
if (delta > 20) {
|
||||
update_last_recv_time();
|
||||
t->status = UPG_UART_DATA_SEND;
|
||||
pr_debug("Timeout retry ...\n");
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ch == SIG_C) {
|
||||
uart_proto_putchar(uart_proto_id, ACK);
|
||||
pr_debug("Ack SIG_C\n");
|
||||
break;
|
||||
} else if (ch == DC1_SEND) {
|
||||
uart_proto_putchar(uart_proto_id, ACK);
|
||||
t->direction = DIR_HOST_SEND;
|
||||
t->status = UPG_UART_DATA_RECV;
|
||||
memset(pframe, 0, LNG_FRM_MAX_LEN);
|
||||
pr_debug("Host switch to send mode.\n");
|
||||
break;
|
||||
} else if (ch == DC2_RECV) {
|
||||
uart_proto_putchar(uart_proto_id, ACK);
|
||||
t->direction = DIR_HOST_RECV;
|
||||
t->status = UPG_UART_DATA_SEND;
|
||||
pr_debug("Host switch to recv mode.\n");
|
||||
//csi_coret_config(drv_get_sys_freq() / 200, CORET_IRQn);
|
||||
break;
|
||||
} else if (ch == NAK) {
|
||||
t->status = UPG_UART_DATA_SEND;
|
||||
break;
|
||||
} else if (ch == ACK) {
|
||||
t->xfer_len += t->single_frame_transed_siz;
|
||||
uart_proto.send_blk_no++;
|
||||
t->status = UPG_UART_DATA_SEND;
|
||||
}
|
||||
|
||||
if (t->xfer_len >= t->data_len) {
|
||||
pr_debug("Send out data len %d\n", t->xfer_len);
|
||||
uart_proto_layer_set_status(UPG_UART_DATA_SEND_DONE);
|
||||
t->status = UPG_UART_CMD_RECV;
|
||||
uart_proto_del_task();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uart_proto_layer_proc(void)
|
||||
{
|
||||
struct proto_task *t = NULL;
|
||||
int ret;
|
||||
u8 *pframe;
|
||||
|
||||
t = uart_proto_get_task();
|
||||
if (!t)
|
||||
return 0;
|
||||
|
||||
pframe = g_uart_send_recv_buf;
|
||||
while (1) {
|
||||
switch (t->direction) {
|
||||
case DIR_HOST_SEND:
|
||||
ret = uart_proto_layer_host_send_proc(t, pframe);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DIR_HOST_RECV:
|
||||
ret = uart_proto_layer_host_recv_proc(t, pframe);
|
||||
if (ret) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uart_proto_start_read(u8 *data, u32 data_len)
|
||||
{
|
||||
return uart_proto_add_task(DIR_HOST_SEND, data, data_len);
|
||||
}
|
||||
|
||||
int uart_proto_start_write(u8 *data, u32 data_len)
|
||||
{
|
||||
return uart_proto_add_task(DIR_HOST_RECV, data, data_len);
|
||||
}
|
||||
|
||||
int uart_proto_layer_get_status(void)
|
||||
{
|
||||
u8 status = 0;
|
||||
|
||||
ringbuf_out(&(uart_proto.status_fifo.rb), &status, 1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void uart_proto_layer_set_status(int status)
|
||||
{
|
||||
ringbuf_in(&(uart_proto.status_fifo.rb), &status, 1);
|
||||
}
|
||||
|
||||
irqreturn_t uart_proto_layer_irqhandler(int irq, void *data)
|
||||
{
|
||||
csi_coret_config(drv_get_sys_freq() / 5000, CORET_IRQn);
|
||||
uart_proto_layer_proc();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uart_proto_layer_init(int id)
|
||||
{
|
||||
uart_proto_id = id;
|
||||
|
||||
INIT_LIST_HEAD(&task);
|
||||
|
||||
memset(&uart_proto, 0, sizeof(uart_proto));
|
||||
uart_proto.first_connect = 1;
|
||||
|
||||
ringbuf_init(&(uart_proto.status_fifo.rb), uart_proto.status_fifo.buffer, 4);
|
||||
|
||||
//10ms
|
||||
csi_coret_config(drv_get_sys_freq() / 1000, CORET_IRQn);
|
||||
aicos_request_irq(CORET_IRQn, uart_proto_layer_irqhandler, 0, NULL, NULL);
|
||||
aicos_irq_set_prio(CORET_IRQn, 8);
|
||||
aicos_irq_enable(CORET_IRQn);
|
||||
|
||||
/* Send CAN first */
|
||||
uart_proto_putchar(uart_proto_id, CAN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uart_proto_layer_deinit()
|
||||
{
|
||||
aicos_irq_disable(CORET_IRQn);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user