356 lines
8.7 KiB
C
356 lines
8.7 KiB
C
/******************************************************************************
|
||
* @file drv_qfc41d.c
|
||
* @brief drv_qfc41d driver
|
||
* @version V1.0
|
||
* @author Gary
|
||
* @copyright
|
||
******************************************************************************/
|
||
|
||
#include "drv_qfc41d.h"
|
||
|
||
uint8_t rev_buff[QFC41D_MAX_RECV_SIZE] = {0};
|
||
uint8_t send_buff[QFC41D_MAX_SEND_SIZE] = {0};
|
||
|
||
#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];
|
||
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,
|
||
};
|
||
|
||
void parse_mqtt_message(char* message)
|
||
{
|
||
// 示例消息: +QMTRECV: 0,31,"bluesun/bms/control/123",11,"MQ3156+1MQ"
|
||
uint16_t first = 0;
|
||
uint16_t second = 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)
|
||
{
|
||
if((first >= 3000) && (first <= 3168))
|
||
{
|
||
bcu_data_set_0x06_msg(first, second);
|
||
}
|
||
else if ((first >= 4000) && (first <= 4999))
|
||
{
|
||
hmi_write_modbus_cfg(first - 4000, second);
|
||
}
|
||
drv_mqtt_publish_control_no_respose("ok", 2);
|
||
}
|
||
else if (strstr(message, "read") != NULL)
|
||
{
|
||
//需要解决发送过程中与实时值DMA上传的冲突问题,可以尝试标志位或者队列的方式
|
||
drv_mqtt_publish_read_no_respose("1", 1);
|
||
}
|
||
|
||
}
|
||
|
||
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 timeout = 0;
|
||
|
||
uint32_t start_time = kit_time_get_tick();
|
||
while (dma_tx_busy && current_buffer == 0)
|
||
{
|
||
if (kit_time_get_tick() - start_time > 100)
|
||
{
|
||
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;
|
||
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';
|
||
|
||
// 设置 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; // 开启 DMA 发送
|
||
}
|
||
|
||
void drv_wireless_send_string_dma(const char *str)
|
||
{
|
||
if (dma_tx_busy || current_buffer == 1) return; // 正在发送或高优先级发送中,丢弃
|
||
bsp_task_delay_ms(250);
|
||
uint16_t len = 0;
|
||
|
||
// 拷贝数据到 DMA 缓冲区
|
||
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';
|
||
|
||
// 设置 DMA 参数并启动
|
||
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; // 开启 DMA 发送
|
||
}
|
||
|
||
|
||
// 发送 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;
|
||
}
|