393 lines
13 KiB
C
393 lines
13 KiB
C
|
/**
|
|||
|
* @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;
|
|||
|
}
|