forked from gary/BCU
2
0
Fork 0
BCU/library/drv_peripheral/drv_qfc41d.c

440 lines
11 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 drv_qfc41d.c
* @brief drv_qfc41d driver
* @version V1.0
* @author Gary
* @copyright
******************************************************************************/
#include "drv_qfc41d.h"
#include "eeprom_manager.h"
uint8_t rev_buff[QFC41D_MAX_RECV_SIZE] __attribute__((section(".ccmram")));
uint8_t send_buff[QFC41D_MAX_SEND_SIZE]__attribute__((section(".ccmram")));
#define MAX_PAYLOAD_LEN 128
char cmd[1000] = {0}; //降低栈空间使用
#define TX_DMA_BUFFER_SIZE 2000
volatile uint8_t dma_tx_busy = 0;
uint8_t dma_tx_buffer[2][TX_DMA_BUFFER_SIZE] __attribute__((section(".sram2")));
volatile uint8_t current_buffer = 0; // 0表示正常缓冲区1表示高优先级缓冲区
//定义
WifiBleItem qfc41dItem = {
.dev = QFC41D_UART_PORT,
.buf_pos = 0,
.buf_size = QFC41D_MAX_RECV_SIZE,
.buf = rev_buff,
.sendCall = NULL,
};
typedef struct {
uint16_t start_addr;
uint16_t reg_num;
} RegSegment;
RegSegment segments[] = {
{3000, 3}, //BMU个数电芯总数温感总数
{3010, 1}, //Can通讯协议
{3017, 1}, //设备地址
{3041, 1}, //SOC
{3068, 2}, //SOC满放校准电压满充校准电压
{3092, 1}, //充电末端降流电压
{4000, 72}, //放电欠压值
{4198, 72} //充电过压值
};
const uint8_t segment_count = sizeof(segments) / sizeof(segments[0]);
void parse_mqtt_message(char* message)
{
// +QMTRECV: 0,31,"bluesun/bms/control/123",11,"MQ3156+1MQ"
uint16_t first = 0;
uint16_t second = 0;
uint8_t buffer[5];
uint16_t length;
uint8_t data = 0;
char data_str[6] = {0};
char* quotes[4] = {0};
int quote_count = 0;
for(char* p = message; *p && quote_count < 4; p++)
{
if(*p == '\"')
{
quotes[quote_count++] = p;
}
}
if(quote_count < 4)
{
return;
}
char* payload_start = quotes[2] + 1;
char* payload_end = quotes[3];
size_t payload_len = payload_end - payload_start;
if(payload_len >= MAX_PAYLOAD_LEN)
{
return;
}
char payload[MAX_PAYLOAD_LEN];
strncpy(payload, payload_start, payload_len);
payload[payload_len] = '\0';
char* processed = payload;
size_t len = strlen(processed);
// 去除开头"MQ"
if(len >= 2 && strncmp(processed, "MQ", 2) == 0)
{
processed += 2;
len -= 2;
}
// 去除结尾"MQ"
if(len >= 2 && strcmp(processed + len - 2, "MQ") == 0)
{
processed[len - 2] = '\0';
len -= 2;
}
char* plus_pos = strchr(processed, '+');
if(!plus_pos)
{
return;
}
*plus_pos = '\0';
first = atoi(processed);
second = atoi(plus_pos + 1);
if(strstr(message, "control") != NULL)
{
buffer[0] = (second >> 8) & 0xFF;
buffer[1] = second & 0xFF;
if (first == 3156 && second == 1)
{
bms_soft_reset_save(kSoftReset_CmdCtrl, NULL, 0);
drv_misc_reset_mcu();
}
else
{
data = bcu_modbus_485_0x06_fun(first, 1, buffer, &length);
}
if (data == 0)
{
drv_mqtt_publish_control_no_respose("ok", 2);
}
}
else if (strstr(message, "read") != NULL)
{
char data_str[650] = {0};
uint8_t is_first_data = 1; // 标记是否为第一个数据
uint8_t read_success = 1;
for (uint8_t i = 0; i < segment_count; i++)
{
uint16_t start_addr = segments[i].start_addr;
uint16_t reg_num = segments[i].reg_num;
uint16_t length = 0;
uint8_t read_buffer[150] = {0};
uint8_t err = bcu_modbus_485_0x03_fun(start_addr, reg_num, read_buffer, &length);
if (err != 0 || length != (reg_num << 1))
{
read_success = 0;
break;
}
for (uint16_t j = 0; j < reg_num; j++)
{
uint16_t value = (read_buffer[j * 2] << 8) | read_buffer[j * 2 + 1];
if (!is_first_data)
{
strcat(data_str, "+");
}
else
{
is_first_data = 0;
}
char val_str[6];
snprintf(val_str, sizeof(val_str), "%u", value);
strcat(data_str, val_str);
}
}
if (read_success && strlen(data_str) > 0)
{
drv_mqtt_publish_read_no_respose(data_str, strlen(data_str));
}
}
}
static void drv_qfc41d_push_data(WifiBleItem* item, uint8_t *buf, uint16_t len)
{
uint16_t i = 0;
if((item != NULL) && (item->buf_pos + len < item->buf_size))
{
item->buf[item->buf_pos++] = buf[i];
// 处理换行符,表示一条完整的 AT 指令返回
if (buf[i] == '\n')
{
item->buf[item->buf_pos] = '\0'; // 添加结束符
if (item->buf_pos < 100)
{
parse_mqtt_message(item->buf); // 解析消息
}
item->buf_pos = 0; // 重置索引,准备下一条数据
}
}
}
static void drv_qf41d_uart_rx_it_call(kit_ret_e res, void *data)
{
OS_TRACE_ISR_ENTER();
drv_qfc41d_push_data(&qfc41dItem, data, 1);
OS_TRACE_ISR_EXIT();
}
// 发送单个字符
void drv_wireless_send_char(char c)
{
while (!(USART2->SR & USART_SR_TXE)); // 等待发送缓冲区空
USART2->DR = c;
}
// 发送字符串
void drv_wireless_send_string(const char *str)
{
while (*str)
{
drv_wireless_send_char(*str++);
}
drv_wireless_send_char('\r'); // 发送 CR
drv_wireless_send_char('\n'); // 发送 LF
}
void drv_wireless_send_string_dma_high_priority(const char *str)
{
uint32_t start_time = kit_time_get_tick();
while (dma_tx_busy && current_buffer == 0)
{
if (kit_time_get_tick() - start_time > 180)
{
__disable_irq();
if (DMA1_Stream6->CR & DMA_SxCR_EN)
{
DMA1_Stream6->CR &= ~DMA_SxCR_EN;
while (DMA1_Stream6->CR & DMA_SxCR_EN);
DMA1->HIFCR |= DMA_HIFCR_CTCIF6 | DMA_HIFCR_CTEIF6;
}
dma_tx_busy = 0;
current_buffer = 0;
USART2->CR3 &= ~USART_CR3_DMAT;
__enable_irq();
break;
}
}
uint16_t len = 0;
while (*str && len < TX_DMA_BUFFER_SIZE - 2)
{
dma_tx_buffer[1][len++] = *str++;
}
dma_tx_buffer[1][len++] = '\r';
dma_tx_buffer[1][len++] = '\n';
__disable_irq();
// 确保DMA已停止
DMA1_Stream6->CR &= ~DMA_SxCR_EN;
while (DMA1_Stream6->CR & DMA_SxCR_EN);
DMA1_Stream6->M0AR = (uint32_t)dma_tx_buffer[1];
DMA1_Stream6->NDTR = len;
dma_tx_busy = 1;
current_buffer = 1;
DMA1_Stream6->CR |= DMA_SxCR_EN;
USART2->CR3 |= USART_CR3_DMAT;
__enable_irq();
}
void drv_wireless_send_string_dma(const char *str)
{
__disable_irq();
if (dma_tx_busy || current_buffer == 1)
{
__enable_irq();
return;
}
__enable_irq();
bsp_task_delay_ms(250);
uint16_t len = 0;
while (*str && len < TX_DMA_BUFFER_SIZE - 2)
{
dma_tx_buffer[0][len++] = *str++;
}
dma_tx_buffer[0][len++] = '\r';
dma_tx_buffer[0][len++] = '\n';
__disable_irq();
if (dma_tx_busy || current_buffer == 1)
{
__enable_irq();
return;
}
DMA1_Stream6->CR &= ~DMA_SxCR_EN;
while (DMA1_Stream6->CR & DMA_SxCR_EN);
DMA1_Stream6->M0AR = (uint32_t)dma_tx_buffer[0];
DMA1_Stream6->NDTR = len;
dma_tx_busy = 1;
current_buffer = 0;
DMA1_Stream6->CR |= DMA_SxCR_EN;
USART2->CR3 |= USART_CR3_DMAT;
__enable_irq();
}
// 发送 AT 指令并等待返回值
int drv_at_send_cmd(const char *cmd, const char *response, uint32_t timeout)
{
memset(qfc41dItem.buf, 0, QFC41D_MAX_RECV_SIZE);
qfc41dItem.buf_pos = 0; // 清空接收缓冲区索引
drv_wireless_send_string(cmd);
uint32_t start_time = kit_time_get_tick(); // 获取当前时间
while (kit_time_get_tick() - start_time < timeout)
{
if (strstr((char *)qfc41dItem.buf, response))
{
return 1; // 成功匹配返回值
}
}
return 0; // 超时未收到期望数据
}
static uint8_t drv_wifi_init()
{
if (!drv_at_send_cmd("AT", "OK", WIFI_TIMEOUT))
{
return 1 ;
}
if (!drv_at_send_cmd("AT+QSTASTOP", "OK", WIFI_TIMEOUT))
{
return 1;
}
if (!drv_at_send_cmd("AT+QSOFTAPSTOP", "OK", WIFI_TIMEOUT))
{
return 1;
}
return 0;
}
uint8_t drv_ble_init()
{
if (!drv_at_send_cmd("AT+QBLEINIT=3", "OK", WIFI_TIMEOUT))
{
return 1;
}
//设置wifi名称必须以BSM开头后缀可以加sn码
if (!drv_at_send_cmd("AT+QBLENAME=BSM11223344", "OK", WIFI_TIMEOUT))
{
return 1;
}
return 0;
}
uint8_t drv_qfc41d_init(void)
{
//初始化串口
drv_uart_init((UartDev)qfc41dItem.dev, 115200, 0 | UART_CFG_STOP_BIT_1, kGpioType_WIRELESSUart_Tx, kGpioType_WIRELESSUart_Rx);
USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE | USART_CR1_UE;
//设置接收回调函数
drv_uart_set_interrupt(QFC41D_UART_PORT, kUartInterrupt_Rx, APP_CFG_INT_PRIO_UART2_RX, drv_qf41d_uart_rx_it_call);//#define SIM_UART_PORT kUartDev_2
//初始化蓝牙BLE
if (drv_ble_init() != 0)
{
return 1;
}
return 0;
}
#define MQTT_BROKER "47.120.14.45" // 你的 MQTT 服务器地址
#define MQTT_PORT 3011 // MQTT 端口
#define MQTT_CLIENT_ID "fc41d_client" // 客户端 ID
#define MQTT_USER "user" // MQTT 用户名
#define MQTT_PASSWORD "password" // MQTT 密码
#define MQTT_TOPIC "bluesun/bms/period/11223344"
#define MQTT_TOPIC_control "bluesun/bms/control/reply/11223344"
#define MQTT_TOPIC_read "bluesun/bms/read/reply/11223344"
static uint8_t drv_mqtt_subscribe()
{
snprintf(cmd, sizeof(cmd), "AT+MQTTSUB=0,1,\"%s\",2", MQTT_TOPIC);
drv_wireless_send_string(cmd);
return 0;
}
uint8_t drv_mqtt_publish(char* str,uint16_t length)
{
snprintf(cmd, sizeof(cmd), "AT+QMTPUB=1,1,2,0,%s,%d,%s",MQTT_TOPIC, length, str);
if (!drv_at_send_cmd(cmd, "OK\0", WIFI_TIMEOUT))
{
return 1;
}
return 0;
}
uint8_t drv_mqtt_publish_no_respose(char* str,uint16_t length)
{
// snprintf(cmd, sizeof(cmd), "AT+QMTPUB=0,1,2,0,%s,%d,%s",MQTT_TOPIC, length, str);
snprintf(cmd, sizeof(cmd), "AT+QMTPUB=1,1,2,0,\"%s\",%d,\"%s\"", MQTT_TOPIC, length, str);
// drv_wireless_send_string(cmd); // 未使用DMA
drv_wireless_send_string_dma(cmd); // 使用DMA
return 0;
}
uint8_t drv_mqtt_publish_control_no_respose(char* str,uint16_t length)
{
snprintf(cmd, sizeof(cmd), "AT+QMTPUB=1,1,2,0,\"%s\",%d,\"%s\"", MQTT_TOPIC_control, length, str);
drv_wireless_send_string_dma_high_priority(cmd);
return 0;
}
uint8_t drv_mqtt_publish_read_no_respose(char* str,uint16_t length)
{
snprintf(cmd, sizeof(cmd), "AT+QMTPUB=1,1,2,0,\"%s\",%d,\"%s\"", MQTT_TOPIC_read, length, str);
drv_wireless_send_string_dma_high_priority(cmd);
return 0;
}