This repository has been archived on 2023-07-17. You can view files and clone it, but cannot push or open issues or pull requests.
bl_mcu_sdk/examples/audio_cube/data_protocol.c

404 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file ips.c
* @brief
*
* Copyright (c) 2021 Bouffalolab team
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
#include "drv_mmheap.h"
#include "hal_uart.h"
#include "hal_dma.h"
#include "data_protocol.h"
struct device *uart;
static isp_obj_t *isp_obj_uart;
void ips_obj_init(isp_obj_t *isp_obj_p)
{
if (!isp_obj_p)
return;
isp_obj_p->cmd_id = 0;
isp_obj_p->check = 0;
isp_obj_p->length = 0;
isp_obj_p->file_type = 0;
isp_obj_p->auot_ack = 1;
isp_obj_p->status.isp_state_mode = 0;
isp_obj_p->status.already_steps = 0;
}
/**
* @brief uart tx dma irq, ch0
*
* @param dev
* @param args
* @param size
* @param state
*/
void dma_ch0_irq_callback(struct device *dev, void *args, uint32_t size, uint32_t state)
{
if (isp_obj_uart == NULL) {
return;
}
/* close dma and dma irq */
device_control(uart, DEVICE_CTRL_TX_DMA_SUSPEND, NULL);
device_control(UART_DEV(uart)->tx_dma, DEVICE_CTRL_CLR_INT, NULL);
if (isp_obj_uart->status.isp_state_mode == SEND_DATA) {
isp_obj_uart->status.isp_state_mode = SEND_WAIT_ACK;
isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_SEND_ACK_WAIT);
}
}
// void dma_ch1_irq_callback(struct device *dev, void *args, uint32_t size, uint32_t state)
// {
// if (isp_obj_uart == NULL) {
// return;
// }
// if (isp_obj_uart->status.isp_state_mode == RECEIVE_DATA) {
// isp_obj_uart->status.isp_state_mode = RECEIVE_WAIT_ACK;
// isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_RECEIVE_ACK_WAIT);
// }
// device_control(uart, DEVICE_CTRL_RX_DMA_SUSPEND, 0);
// isp_obj_uart->status.already_steps = 0;
// device_control(uart, DEVICE_CTRL_SET_INT, (void *)(UART_RX_FIFO_IT));
// MSG("tx dma init\r\n");
// }
uint8_t isp_check(isp_obj_t *isp_obj)
{
if (isp_obj == NULL) {
return 0;
}
uint8_t check = isp_obj->cmd_id + (isp_obj->length & 0x00FF) + ((isp_obj->length >> 8) & 0x00FF);
if (isp_obj->length && isp_obj->file_data) {
for (uint16_t i = 0; i < isp_obj->length; i++) {
check += isp_obj->file_data[i];
}
}
return check;
}
/**
* @brief
*
* @param isp_obj_uart
* @return int
*/
int isp_uart_send_data(isp_obj_t *isp_obj_uart)
{
if (isp_obj_uart == NULL || isp_obj_uart->cmd_id == 0) {
return -1;
}
if ((isp_obj_uart->cmd_id & 0xF0) != 0x50)
return -2;
if (isp_obj_uart->status.isp_state_mode != NO_TASK)
return -3;
isp_obj_uart->check = isp_check(isp_obj_uart);
/* use tx blocking */
device_write(uart, 0, (void *)isp_obj_uart, sizeof(isp_cmd_id_t) + sizeof(uint8_t) + sizeof(uint16_t) + sizeof(isp_file_type_t));
/* use DMA tx non-blocking */
device_control(uart, DEVICE_CTRL_TX_DMA_RESUME, NULL);
device_control(UART_DEV(uart)->tx_dma, DEVICE_CTRL_SET_INT, NULL);
device_write(uart, 0, isp_obj_uart->file_data, isp_obj_uart->length);
isp_obj_uart->status.already_steps = 0;
isp_obj_uart->status.isp_state_mode = SEND_DATA;
return 0;
}
/**
* @brief
*
* @param isp_obj_uart
* @return int
*/
int isp_uart_send_ack(isp_obj_t *isp_obj_uart, ips_reply_t ips_reply)
{
if (isp_obj_uart == NULL || isp_obj_uart->cmd_id == 0) {
return -1;
}
// if (isp_obj_uart->status.isp_state_mode != RECEIVE_WAIT_ACK) {
// return -2;
// }
/* use DMA tx blocking */
device_write(uart, 0, (uint8_t *)&ips_reply, 2);
return 0;
}
/**
* @brief
*
* @param isp_obj
* @param buff
* @param size
*/
void isp_task_handler(isp_obj_t *isp_obj, uint8_t *buff, uint32_t size)
{
static uint32_t time_last = 0;
uint32_t time_now = bflb_platform_get_time_ms();
/* debug information */
// MSG("hand:%d, len:%d, mode:%d\r\n", isp_obj_uart->status.already_steps, isp_obj_uart->status.receive_length, isp_obj_uart->status.isp_state_mode);
if (size == 0) {
if ((time_now - time_last > isp_obj->time_out) && isp_obj->time_out) {
/* time out */
}
}
for (uint32_t i = 0; i < size; i++) {
/* receive 状态机 */
switch (isp_obj_uart->status.already_steps) {
case 0:
if (isp_obj_uart->status.isp_state_mode == NO_TASK) {
isp_obj_uart->status.isp_state_mode = OTHER_STATE;
} else if (isp_obj_uart->status.isp_state_mode != SEND_WAIT_ACK) {
return;
}
isp_obj_uart->cmd_id = *buff;
isp_obj_uart->status.already_steps++;
break;
case 1:
isp_obj_uart->check = *buff;
isp_obj_uart->status.already_steps++;
if (isp_obj_uart->status.isp_state_mode == SEND_WAIT_ACK) {
isp_obj_uart->status.isp_state_mode = NO_TASK;
if (isp_obj_uart->cmd_id == 0X4F && isp_obj_uart->check == 0X4B) {
isp_obj_uart->status.ips_reply = REPLY_SUCCES;
isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_SEND_SUCCES_ACK);
isp_obj_uart->status.isp_state_mode = NO_TASK;
isp_obj_uart->status.already_steps = 0;
} else if (isp_obj_uart->cmd_id == 0X52 && isp_obj_uart->check == 0X45) {
isp_obj_uart->status.ips_reply = REPLY_ERROR;
isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_SEND_ERROR_ACK);
isp_obj_uart->status.isp_state_mode = NO_TASK;
isp_obj_uart->status.already_steps = 0;
}
}
break;
case 2:
isp_obj_uart->length = *buff;
isp_obj_uart->status.already_steps++;
break;
case 3:
isp_obj_uart->length += *buff << 8;
isp_obj_uart->status.already_steps++;
break;
case 4: /* 接收的如果是命令,无法判断命令是简短命令(只需回复2个字节信息),还是复杂命令(需要回复一段数据包),需要自己在用户回调函数里处理,但这似乎不太合理 */
isp_obj_uart->file_type = *buff;
isp_obj_uart->status.already_steps++;
if ((isp_obj_uart->cmd_id & 0xF0) == 0x50) {
isp_obj_uart->status.isp_state_mode = RECEIVE_DATA;
isp_obj_uart->status.receive_length = 0;
} else {
isp_obj_uart->status.already_steps = 0;
/* 等待ACK的时候收到命令同时代表 命令 与 成功ACK */
if (isp_obj_uart->status.isp_state_mode == SEND_WAIT_ACK) {
/* 响应 CMD 含义 */
isp_obj_uart->status.isp_state_mode = RECEIVE_WAIT_ACK;
isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_CMD_);
/* 响应 ACK 含义 */
isp_obj_uart->status.ips_reply = REPLY_SUCCES;
isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_SEND_SUCCES_ACK);
isp_obj_uart->status.isp_state_mode = NO_TASK;
} else {
/* 正常空闲收到命令 */
isp_obj_uart->status.isp_state_mode = RECEIVE_WAIT_ACK;
isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_CMD_);
}
//isp_obj_uart->status.isp_state_mode = NO_TASK;
}
break;
case 5:
if (isp_obj_uart->status.receive_length < isp_obj_uart->length) {
isp_obj_uart->file_data[isp_obj_uart->status.receive_length] = *buff;
isp_obj_uart->status.receive_length++;
}
if (isp_obj_uart->status.receive_length >= isp_obj_uart->length) {
isp_obj_uart->status.isp_state_mode = RECEIVE_WAIT_ACK;
uint8_t check_data = isp_check(isp_obj_uart);
//MSG("check:%X\r\n", check);
if (isp_obj_uart->check == check_data) {
isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_RECEIVE_ACK_WAIT);
/* auot send ack */
if (isp_obj_uart->auot_ack == 0) {
isp_uart_send_ack(isp_obj_uart, REPLY_SUCCES);
isp_obj_uart->status.isp_state_mode = NO_TASK;
}
} else {
isp_obj_uart->isp_callback(isp_obj_uart, ISP_CALLBACK_RECEIVE_NACK_WAIT);
/* auot send Nack */
if (isp_obj_uart->auot_ack == 0) {
isp_uart_send_ack(isp_obj_uart, REPLY_ERROR);
isp_obj_uart->status.isp_state_mode = NO_TASK;
}
}
isp_obj_uart->status.receive_length = 0;
isp_obj_uart->status.already_steps = 0;
}
break;
default:
break;
}
buff++;
}
time_last = time_now;
}
/**
* @brief uart_irq_callback
*
* @param dev
* @param args
* @param size
* @param state
*/
void uart_irq_callback(struct device *dev, void *args, uint32_t size, uint32_t state)
{
static uint8_t fer_err_flag = 0;
if (state == UART_EVENT_RX_FIFO || state == UART_EVENT_RTO) {
if (isp_obj_uart == NULL) {
return;
}
/* Tx fifo overflow, send nack*/
if(fer_err_flag){
if(state == UART_EVENT_RX_FIFO){
}else if(state == UART_EVENT_RTO){
isp_obj_uart->status.isp_state_mode = NO_TASK;
isp_uart_send_ack(isp_obj_uart, REPLY_ERROR);
fer_err_flag = 0;
}
return;
}
isp_task_handler(isp_obj_uart, args, size);
}
else if(state == UART_EVENT_RX_FER){
/* Tx fifo overflow, baud rate should be reduced */
fer_err_flag = 1;
device_control(dev,DEVICE_CTRL_UART_CLEAR_RX_FIFO,NULL);
}
}
/**
* @brief
*
*/
uint8_t isp_uart_init(isp_obj_t *isp_obj)
{
if (isp_obj == NULL)
return 1;
uart = device_find("debug_log");
if(uart){
device_close(uart);
}else{
uart_register(UART0_INDEX, "debug_log");
uart = device_find("debug_log");
}
if (uart) {
device_close(uart);
UART_DEV(uart)->id = 0;
UART_DEV(uart)->baudrate = 3000000;
UART_DEV(uart)->databits = UART_DATA_LEN_8;
UART_DEV(uart)->stopbits = UART_STOP_ONE;
UART_DEV(uart)->parity = UART_PAR_NONE;
UART_DEV(uart)->fifo_threshold = 4;
device_close(uart);
device_open(uart, DEVICE_OFLAG_DMA_TX | DEVICE_OFLAG_INT_RX);
bflb_platform_delay_ms(5);
device_set_callback(uart, uart_irq_callback);
device_control(uart, DEVICE_CTRL_SET_INT, (void *)(UART_RX_FIFO_IT | UART_RTO_IT));
}
dma_register(DMA0_CH0_INDEX, "ch0");
struct device *dma_ch0 = device_find("ch0");
if (dma_ch0) {
DMA_DEV(dma_ch0)->direction = DMA_MEMORY_TO_PERIPH;
DMA_DEV(dma_ch0)->transfer_mode = DMA_LLI_ONCE_MODE;
DMA_DEV(dma_ch0)->src_req = DMA_REQUEST_NONE;
DMA_DEV(dma_ch0)->dst_req = DMA_REQUEST_UART0_TX;
DMA_DEV(dma_ch0)->src_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
DMA_DEV(dma_ch0)->dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
DMA_DEV(dma_ch0)->src_burst_size = DMA_BURST_INCR1;
DMA_DEV(dma_ch0)->dst_burst_size = DMA_BURST_INCR1;
DMA_DEV(dma_ch0)->src_width = DMA_TRANSFER_WIDTH_8BIT;
DMA_DEV(dma_ch0)->dst_width = DMA_TRANSFER_WIDTH_8BIT;
device_open(dma_ch0, 0);
device_control(uart, DEVICE_CTRL_ATTACH_TX_DMA, dma_ch0);
device_set_callback(dma_ch0, dma_ch0_irq_callback);
/* close dma irq */
//device_control(UART_DEV(uart)->tx_dma, DEVICE_CTRL_CLR_INT, NULL);
}
// dma_register(DMA0_CH1_INDEX, "ch1");
// struct device *dma_ch1 = device_find("ch1");
// if (dma_ch1) {
// DMA_DEV(dma_ch1)->direction = DMA_PERIPH_TO_MEMORY;
// DMA_DEV(dma_ch1)->transfer_mode = DMA_LLI_ONCE_MODE;
// DMA_DEV(dma_ch1)->src_req = DMA_REQUEST_UART0_RX;
// DMA_DEV(dma_ch1)->dst_req = DMA_REQUEST_NONE;
// DMA_DEV(dma_ch1)->src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
// DMA_DEV(dma_ch1)->dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
// DMA_DEV(dma_ch1)->src_burst_size = DMA_BURST_INCR1;
// DMA_DEV(dma_ch1)->dst_burst_size = DMA_BURST_INCR1;
// DMA_DEV(dma_ch1)->src_width = DMA_TRANSFER_WIDTH_8BIT;
// DMA_DEV(dma_ch1)->dst_width = DMA_TRANSFER_WIDTH_8BIT;
// device_open(dma_ch1, 0);
// device_control(uart, DEVICE_CTRL_ATTACH_RX_DMA, dma_ch1);
// device_set_callback(dma_ch1, dma_ch1_irq_callback);
// device_control(dma_ch1, DEVICE_CTRL_SET_INT, NULL);
// }
device_control(uart, DEVICE_CTRL_TX_DMA_SUSPEND, NULL);
isp_obj_uart = isp_obj;
return 0;
}