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/audiocube_sph0645/data_protocol.c

393 lines
13 KiB
C
Raw Normal View History

/**
* @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:
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) {
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 = 16;
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_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_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;
}