JT-DT-YD4N02B_4G_RTT_MRS/bsp/src/bsp_h308.c

452 lines
13 KiB
C
Raw Normal View History

2024-12-30 11:50:48 +08:00
/*
* @Author: mbw
* @Date: 2024-11-14 10:21:04
* @LastEditors: mbw && 1600520629@qq.com
* @LastEditTime: 2025-01-17 10:46:51
2025-01-09 15:29:36 +08:00
* @FilePath: \JT-DT-YD4N02A_RTT_MRS-NT26K\bsp\src\bsp_h308.c
2024-12-30 11:50:48 +08:00
* @Description:
*
* Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
*/
#include "bsp_h308.h"
// #include "drv_usart.h"
#include "lwrb.h"
// 用到了atoi
#include <stdlib.h>
#include "bsp_flash.h"
#include "bsp_rtc.h"
#include "user_sys.h"
#define LOG_TAG "bsp_h308"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
// 用了浮点打印
ALIGN(8)
static char h308_thread_stack[H308_THREAD_STACK_SIZE];
static struct rt_thread h308_thread;
#define UART4_RX_RB_LENGTH (128U)
static lwrb_t uart4_rx_rb;
static rt_uint8_t uart4_rx_rb_data[UART4_RX_RB_LENGTH];
static rt_sem_t uart4_rx_ok_sem;
static rt_timer_t uart4_rx_timer;
uint8_t sensor_rx_count = 0; // 接收缓冲区中,已经收到的数据包数量
TsH308 H308 = {0};
void _UART4_RxTimeout(void *parameter)
{
rt_sem_release(uart4_rx_ok_sem);
rt_timer_stop(uart4_rx_timer);
}
static uint8_t H308_XorChecksum(char *str, int len)
{
uint8_t xorvalue = 0;
if (str == RT_NULL || len < 2)
{
// 处理错误或返回
return 0; // 或者选择抛出异常
}
for (int i = 0; i < len - 4; i++) // 校验值前面的空格要,
{
xorvalue ^= str[i];
}
return xorvalue;
}
// float打印问题
// https://www.wch.cn/bbs/thread-108241-1.html
// https://www.wch.cn/bbs/thread-91909-1.html
// https://club.rt-thread.org/ask/article/1d040664a33a7b46.html
// https://club.rt-thread.org/ask/article/1d040664a33a7b46.html
/**
* @brief
* @param data:使84cpuport.c中将RT_ALIGN_DOWN((rt_ubase_t)stk, REGBYTES)RT_ALIGN_DOWN((rt_ubase_t)stk, 8);
* @retval None
*/
void H308_ShowData(TsH308Data data)
{
// A+000.00 +31.1 0657.80 +18.1 B+008.0 00 12
LOG_D("H308Data: %6.2f, %5.1f, %7.2f, %5.1f, %5.1f, %02X, %02X", data.lel, data.temp, data.laser_temp, data.signal_strength, data.gain, data.fault_code, data.checksum);
}
#ifdef TEST_ENABLE
void Sensor_ShowData(void)
{
H308_ShowData(H308.Data);
}
MSH_CMD_EXPORT(Sensor_ShowData, Sensor_ShowData);
#endif
uint8_t H308_GetFrameData(const char *p_src, const rt_uint8_t src_len, TsH308Data *pData)
{
// A+000.00 +31.1 0657.80 +18.1 B+008.0 00 12
rt_uint8_t xor = 0;
uint8_t ret = 0;
char *p_str = strstr(p_src, "A+"); // 查找子字符串的位置
uint32_t offset = p_str - p_src; // 计算偏移量
TsH308StrData _H308StrData = {0};
if ((p_str != NULL) && (offset <= src_len - 44))
{
if (sscanf(p_str, "A+%6s %6s %8s %6s B+%6s %2s %2s",
_H308StrData.vol, _H308StrData.temp, _H308StrData.laser_temp, _H308StrData.signal_strength,
_H308StrData.gain, _H308StrData.fault_code, _H308StrData.checksum) == 7)
{
pData->checksum = (rt_uint8_t)strtol(_H308StrData.checksum, NULL, 16);
xor = H308_XorChecksum(p_str, 44); // 对数据进行异或校验
if (xor == pData->checksum)
{
pData->lel = (float)(atof(_H308StrData.vol) * 20);
pData->temp = (float)atof(_H308StrData.temp);
pData->laser_temp = (float)atof(_H308StrData.laser_temp);
pData->signal_strength = (float)atof(_H308StrData.signal_strength);
pData->gain = (float)atof(_H308StrData.gain);
pData->fault_code = (rt_uint8_t)strtol(_H308StrData.fault_code, NULL, 16);
pData->checksum = (rt_uint8_t)strtol(_H308StrData.checksum, NULL, 16);
ret = 0;
}
else
{
LOG_E("xor failed");
ret = RT_ERROR;
}
}
else
{
ret = RT_ERROR;
LOG_E("H308_ExtractData failed");
}
}
return ret;
}
static uint8_t H308_Count(const rt_uint8_t *buffer, uint8_t value, uint8_t size)
{
uint8_t count = 0;
for (uint8_t i = 0; i < size; i++)
{
if (buffer[i] == value)
{
count++;
}
}
return count;
}
// static void H308_HandleAbnormal(uint8_t count, uint8_t *flag, uint8_t threshold)
//{
// if (count > threshold && *flag == 0)
// {
// H308.detection_flag = kH308Abnormal;
// Send_Laser_Alarm_Event(kAlarmExceptionEvent);
// *flag = 1;
// }
// else if (*flag == 1 && count < threshold)
// {
// *flag = 0;
// H308.detection_flag = kH308Normal;
// Send_Laser_Alarm_Event(kNormalDetectionEvents);
// }
// }
static void H308_HandleAlarm(uint8_t count, uint8_t *flag, uint8_t threshold)
{
if (count >= threshold && *flag == 0)
2024-12-30 11:50:48 +08:00
{
H308.detection_flag = kH308Alarm;
Send_Laser_Alarm_Event(kAlarmEvent);
*flag = 1;
}
else if (*flag == 1 && count == 0)
{
*flag = 0;
H308.detection_flag = kH308Normal;
Send_Laser_Alarm_Event(kAlarmRcyEvent);
}
}
static void H308_HandleFault(uint8_t count, uint8_t *flag, uint8_t threshold)
{
if (count >= threshold && *flag != 1)
2024-12-30 11:50:48 +08:00
{
*flag = 1;
H308.detection_flag = kH308Fault;
Send_Laser_Alarm_Event(kFaultEvent);
}
else if (*flag == 1 && count == 0)
{
*flag = 0;
H308.detection_flag = kH308Normal;
Send_Laser_Alarm_Event(kFaultRcyEvent);
}
}
static uint8_t H308_CheckData(void)
{
static rt_uint8_t alarm_flag = 0, fault_flag = 0;
static rt_uint8_t alarm_count = 0, fault_count = 0;
static rt_uint8_t index = 0;
static rt_uint8_t alarm_status_buffer[H308_SAMPLING_TIMS] = {0};
static rt_uint8_t fault_buf[H308_SAMPLING_TIMS] = {0};
alarm_status_buffer[index] = (H308.Data.lel < (float)H308.alarm_value) ? kH308Normal : kH308Alarm;
fault_buf[index] = (H308.Data.fault_code == 0) ? kH308Normal : kH308Fault;
index++;
if (index >= H308_SAMPLING_TIMS)
{
index = 0;
}
alarm_count = H308_Count(alarm_status_buffer, kH308Alarm, H308_SAMPLING_TIMS);
fault_count = H308_Count(fault_buf, kH308Fault, H308_SAMPLING_TIMS);
H308_HandleAlarm(alarm_count, &alarm_flag, H308_SAMPLING_TIMS);
H308_HandleFault(fault_count, &fault_flag, H308_SAMPLING_TIMS);
2024-12-30 11:50:48 +08:00
return RT_EOK;
}
// TODO: 寿命检测
uint8_t IS_H308_EndOfLife(void)
{
RTC_GetTime();
if (RtcDateTime.year > 2035)//至少大于2035年再检测
2024-12-30 11:50:48 +08:00
{
if (RTC_GetCounter() >= H308.expiration_seconds)
{
H308.end_of_life = 1;
}
2024-12-30 11:50:48 +08:00
}
return H308.end_of_life;
}
2025-01-15 09:56:50 +08:00
void UART4_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
USART_InitTypeDef USART_InitStructure = {0};
NVIC_InitTypeDef NVIC_InitStructure = {0};
lwrb_init(&uart4_rx_rb, uart4_rx_rb_data, sizeof(uart4_rx_rb_data));
USART_DeInit(UART4); // 寄存器恢复默认值
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(UART4, &USART_InitStructure);
USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(UART4, ENABLE);
LOG_I("UART4 Init");
}
2024-12-30 11:50:48 +08:00
static void h308_thread_entry(void *param)
{
2025-01-15 09:56:50 +08:00
rt_err_t ret;
2024-12-30 11:50:48 +08:00
static uint8_t str[UART4_RX_RB_LENGTH] = {0};
static uint8_t h308_rx_timout_cnt = 0;
static uint8_t h308_err_cnt = 0;
2025-01-09 15:29:36 +08:00
2025-01-15 09:56:50 +08:00
H308.alarm_value = Flash_Get_SysCfg(kAlarmLValueId); // 获取系统报警阈值
LOG_D("报警阈值:%d%LEL", H308.alarm_value);
2024-12-30 11:50:48 +08:00
while (1)
{
ret = rt_sem_take(uart4_rx_ok_sem, 3000);
if (ret == RT_EOK)
{
uint8_t len = lwrb_get_full(&uart4_rx_rb);
lwrb_read(&uart4_rx_rb, str, len);
rt_memset(&str[len - 2], 0, 2);
if (len >= 44)
{
2025-01-15 09:56:50 +08:00
ret = H308_GetFrameData((const char *)str, len, &H308.Data);
2025-01-09 15:29:36 +08:00
LOG_I("str:[%s]", str);
2024-12-30 11:50:48 +08:00
if (ret == 0)
{
H308_CheckData();
}
else
{
h308_err_cnt++;
}
}
else
{
h308_err_cnt++;
LOG_E("(len = %d) < 44, error data:[%s]", len, str);
if (h308_err_cnt >= 5)
{
H308_RST_ON;
rt_thread_mdelay(100);
H308_RST_OFF;
rt_thread_mdelay(10000);
h308_err_cnt = 0;
}
}
2025-01-09 15:29:36 +08:00
rt_memset(str, 0, len);
2024-12-30 11:50:48 +08:00
if (h308_rx_timout_cnt)
{
h308_rx_timout_cnt = 0;
}
}
else if (ret == -RT_ETIMEOUT)//这个主要是考虑传感器未焊接好或者脱落的情况国标要求30s内反应 3*5 = 15s符合国标
2024-12-30 11:50:48 +08:00
{
h308_rx_timout_cnt++;
if (h308_rx_timout_cnt >= 5)
{
H308_RST_ON;
rt_thread_mdelay(100);
H308_RST_OFF;//复位一下
2024-12-30 11:50:48 +08:00
h308_rx_timout_cnt = 0;
if (H308.detection_flag != kH308Fault)
{
H308.detection_flag = kH308Fault;
Send_Laser_Alarm_Event(kFaultEvent);
}
}
}
}
}
int BSP_H308_Init(void)
{
rt_pin_mode(H308_PWR_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(H308_RST_PIN, PIN_MODE_OUTPUT);
H308_RST_OFF;
2025-01-15 09:56:50 +08:00
H308_PWR_ON;
2025-01-09 15:29:36 +08:00
2024-12-30 11:50:48 +08:00
uart4_rx_ok_sem = rt_sem_create("uart4_rx", 0, RT_IPC_FLAG_FIFO);
if (uart4_rx_ok_sem == RT_NULL)
{
LOG_E("uart4_rx_ok_sem create failed");
}
uart4_rx_timer = rt_timer_create("_UART4_RxTimeout", _UART4_RxTimeout, RT_NULL, 200, RT_TIMER_FLAG_PERIODIC);
if (uart4_rx_timer == RT_NULL)
{
LOG_E("uart4_rx_timer create failed");
}
2025-01-15 09:56:50 +08:00
UART4_Init();
2024-12-30 11:50:48 +08:00
rt_err_t ret = rt_thread_init(&h308_thread,
"h308_thread",
h308_thread_entry,
RT_NULL,
&h308_thread_stack[0],
sizeof(h308_thread_stack),
H308_THREAD_PRIORITY, H308_THREAD_TIMESLICE);
if (ret == RT_EOK)
{
rt_thread_startup(&h308_thread);
}
else
{
LOG_E("rt_thread_init h308_thread Failed");
return ret;
}
return ret;
}
2025-01-15 09:56:50 +08:00
INIT_PREV_EXPORT(BSP_H308_Init);
2024-12-30 11:50:48 +08:00
void UART4_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void UART4_IRQHandler(void)
{
GET_INT_SP();
rt_interrupt_enter();
if (USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)
{
uint8_t temp = USART_ReceiveData(UART4);
lwrb_write(&uart4_rx_rb, &temp, 1);
// sensor_rx_count++;
rt_timer_start(uart4_rx_timer);
}
rt_interrupt_leave();
FREE_INT_SP();
}
#ifdef TEST_ENABLE
static void TEST_H308(int argc, char **argv)
{
if (argc == 2)
{
int cmd = atoi(argv[1]);
switch (cmd)
{
case 0:
H308_PWR_OFF;
LOG_D("H308_PWR_OFF");
break;
case 1:
H308_PWR_ON;
LOG_D("H308_PWR_ON");
break;
case 2:
H308_RST_OFF;
LOG_D("H308_RST_OFF");
break;
case 3:
H308_RST_ON;
LOG_D("H308_RST_ON");
break;
default:
break;
}
}
else
{
LOG_E("TEST_H308 --use _cmd_ [mode] 0:PWR_OFF 1:PWR_ON 2:RST_OFF 3:RST_ON");
}
}
MSH_CMD_EXPORT(TEST_H308, "TEST_H308");
static void TEST_H308_EndOfLife(void)
{
H308.end_of_life = 1;
}
MSH_CMD_EXPORT(TEST_H308_EndOfLife, TEST_H308_EndOfLife);
#endif