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

440 lines
11 KiB
C
Raw Normal View History

/******************************************************************************
* @file drv_qfc41d.c
* @brief drv_qfc41d driver
* @version V1.0
* @author Gary
* @copyright
******************************************************************************/
#include "drv_qfc41d.h"
#include "eeprom_manager.h"
2025-06-09 17:59:28 +08:00
uint8_t rev_buff[QFC41D_MAX_RECV_SIZE] __attribute__((section(".ccmram")));
uint8_t send_buff[QFC41D_MAX_SEND_SIZE]__attribute__((section(".ccmram")));
2025-05-29 18:13:04 +08:00
#define MAX_PAYLOAD_LEN 128
char cmd[1000] = {0}; //<2F><><EFBFBD><EFBFBD>ջ<EFBFBD>ռ<EFBFBD>ʹ<EFBFBD><CAB9>
#define TX_DMA_BUFFER_SIZE 2000
volatile uint8_t dma_tx_busy = 0;
2025-06-09 17:59:28 +08:00
uint8_t dma_tx_buffer[2][TX_DMA_BUFFER_SIZE] __attribute__((section(".sram2")));
volatile uint8_t current_buffer = 0; // 0<><30>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD><31>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD>ȼ<EFBFBD><C8BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//<2F><><EFBFBD><EFBFBD>
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<4D><55><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>о<EFBFBD><D0BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¸<EFBFBD><C2B8><EFBFBD><EFBFBD><EFBFBD>
{3010, 1}, //CanͨѶЭ<D1B6><D0AD>
{3017, 1}, //<2F><EFBFBD><E8B1B8>ַ
{3041, 1}, //SOC
{3068, 2}, //SOC<4F><43><EFBFBD><EFBFBD>У׼<D0A3><D7BC>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У׼<D0A3><D7BC>ѹ
{3092, 1}, //<2F><><EFBFBD><EFBFBD>ĩ<EFBFBD>˽<EFBFBD><CBBD><EFBFBD><EFBFBD><EFBFBD>ѹ
{4000, 72}, //<2F>ŵ<EFBFBD>Ƿѹֵ
{4198, 72} //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹֵ
};
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);
// ȥ<><C8A5><EFBFBD><EFBFBD>ͷ"MQ"
if(len >= 2 && strncmp(processed, "MQ", 2) == 0)
{
processed += 2;
len -= 2;
}
// ȥ<><C8A5><EFBFBD><EFBFBD>β"MQ"
if(len >= 2 && strcmp(processed + len - 2, "MQ") == 0)
{
processed[len - 2] = '\0';
len -= 2;
}
2025-05-29 18:13:04 +08:00
char* plus_pos = strchr(processed, '+');
if(!plus_pos)
{
return;
}
2025-05-29 18:13:04 +08:00
*plus_pos = '\0';
first = atoi(processed);
second = atoi(plus_pos + 1);
2025-05-29 18:13:04 +08:00
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)
2025-05-29 18:13:04 +08:00
{
drv_mqtt_publish_control_no_respose("ok", 2);
2025-05-29 18:13:04 +08:00
}
}
else if (strstr(message, "read") != NULL)
{
char data_str[650] = {0};
uint8_t is_first_data = 1; // <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>Ϊ<EFBFBD><CEAA>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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];
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><D0B7><EFBFBD><EFBFBD><EFBFBD>ʾһ<CABE><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> AT ָ<><EFBFBD><EEB7B5>
if (buf[i] == '\n')
{
item->buf[item->buf_pos] = '\0'; // <20><><EFBFBD>ӽ<EFBFBD><D3BD><EFBFBD><EFBFBD><EFBFBD>
if (item->buf_pos < 100)
{
parse_mqtt_message(item->buf); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
}
item->buf_pos = 0; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>׼<EFBFBD><D7BC><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
}
}
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();
}
// <20><><EFBFBD>͵<EFBFBD><CDB5><EFBFBD><EFBFBD>ַ<EFBFBD>
void drv_wireless_send_char(char c)
{
while (!(USART2->SR & USART_SR_TXE)); // <20>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
USART2->DR = c;
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
void drv_wireless_send_string(const char *str)
{
while (*str)
{
drv_wireless_send_char(*str++);
}
drv_wireless_send_char('\r'); // <20><><EFBFBD><EFBFBD> CR
drv_wireless_send_char('\n'); // <20><><EFBFBD><EFBFBD> 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();
// ȷ<><C8B7>DMA<4D><41>ֹͣ
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();
}
// <20><><EFBFBD><EFBFBD> AT ָ<><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD><EFBFBD>ֵ
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; // <20><><EFBFBD>ս<EFBFBD><D5BD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
drv_wireless_send_string(cmd);
uint32_t start_time = kit_time_get_tick(); // <20><>ȡ<EFBFBD><C8A1>ǰʱ<C7B0><CAB1>
while (kit_time_get_tick() - start_time < timeout)
{
if (strstr((char *)qfc41dItem.buf, response))
{
return 1; // <20>ɹ<EFBFBD>ƥ<EFBFBD><EFBFBD><E4B7B5>ֵ
}
}
return 0; // <20><>ʱδ<CAB1>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
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;
}
//<2F><><EFBFBD><EFBFBD>wifi<66><69><EFBFBD>ƣ<EFBFBD><C6A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>BSM<53><4D>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>׺<EFBFBD><D7BA><EFBFBD>Լ<EFBFBD>sn<73><6E>
if (!drv_at_send_cmd("AT+QBLENAME=BSM11223344", "OK", WIFI_TIMEOUT))
{
return 1;
}
return 0;
}
uint8_t drv_qfc41d_init(void)
{
//<2F><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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;
//<2F><><EFBFBD>ý<EFBFBD><C3BD>ջص<D5BB><D8B5><EFBFBD><EFBFBD><EFBFBD>
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
//<2F><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>BLE<4C><45>
if (drv_ble_init() != 0)
{
return 1;
}
return 0;
}
#define MQTT_BROKER "47.120.14.45" // <20><><EFBFBD><EFBFBD> MQTT <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
#define MQTT_PORT 3011 // MQTT <20>˿<EFBFBD>
#define MQTT_CLIENT_ID "fc41d_client" // <20>ͻ<EFBFBD><CDBB><EFBFBD> ID
#define MQTT_USER "user" // MQTT <20>û<EFBFBD><C3BB><EFBFBD>
#define MQTT_PASSWORD "password" // MQTT <20><><EFBFBD><EFBFBD>
2025-05-29 18:13:04 +08:00
#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); // δʹ<CEB4><CAB9>DMA
drv_wireless_send_string_dma(cmd); // ʹ<><CAB9>DMA
return 0;
}
2025-05-29 18:13:04 +08:00
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);
2025-05-29 18:13:04 +08:00
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);
2025-05-29 18:13:04 +08:00
return 0;
}