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

499 lines
14 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.

/*
* @Author: mbw
* @Date: 2024-11-14 10:21:04
* @LastEditors: mbw && 1600520629@qq.com
* @LastEditTime: 2025-02-06 09:16:14
* @FilePath: \JT-DT-YD4N02A_RTT_MRS-NT26K\bsp\src\bsp_h308.c
* @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"
#include "bsp_led.h"
#include "at_device_nt26k.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 struct rt_timer uart4_rx_timer;
uint8_t sensor_rx_flag = 0; // 接收缓冲区中已经收到的数据包数量static rt_uint8_t alarm_flag = 0, fault_flag = 0;
rt_uint8_t alarm_flag = 0, fault_flag = 0;
TsH308 H308 = {0};
static rt_uint8_t alarm_status_buffer[H308_SAMPLING_TIMS] = {0};
static rt_uint8_t fault_buf[H308_SAMPLING_TIMS] = {0};
void _UART4_RxTimeout(void *parameter)
{
sensor_rx_flag = 0;
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:使用8字节对齐就好着4字节对齐就出现问题问题解决在cpuport.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 = rt_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 threshold)
{
if (count >= threshold && alarm_flag == 0)
{
if (H308.Data.lel > H308.alarm_value)
{
alarm_flag = 1;
H308.detection_flag = kH308Alarm;
Send_Laser_Alarm_Event(kAlarmEvent);
}
}
else if (alarm_flag == 1 && count == 0)
{
alarm_flag = 0;
H308.detection_flag = kH308Normal;
Send_Laser_Alarm_Event(kAlarmRcyEvent);
}
else if ((H308.Data.lel == 0) && (count == 0))
{
alarm_flag = 0;
H308.detection_flag = kH308Alarm;
}
}
static void H308_HandleFault(uint8_t count, uint8_t threshold)
{
if (count >= threshold && fault_flag != 1)
{
fault_flag = 1;
H308.detection_flag = kH308Fault;
rt_thread_mdelay(1);
Send_Laser_Alarm_Event(kFaultEvent);
}
else if (fault_flag == 1 && count == 0)
{
fault_flag = 0;
H308.detection_flag = kH308Normal;
rt_thread_mdelay(1);
Send_Laser_Alarm_Event(kFaultRcyEvent);
}
else if (rt_pin_read(LED_Y_PIN) == PIN_HIGH && (count == 0))
{
fault_flag = 0;
H308.detection_flag = kH308Normal;
}
}
static uint8_t H308_CheckData(void)
{
static rt_uint8_t alarm_count = 0, fault_count = 0;
static rt_uint8_t index = 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);
rt_thread_mdelay(1);
fault_count = H308_Count(fault_buf, kH308Fault, H308_SAMPLING_TIMS);
rt_thread_mdelay(1);
H308_HandleAlarm(alarm_count, H308_SAMPLING_TIMS);
rt_thread_mdelay(1);
H308_HandleFault(fault_count, H308_SAMPLING_TIMS);
return RT_EOK;
}
// TODO: 寿命检测
uint8_t IS_H308_EndOfLife(void)
{
if (ntp_flag) // 是否同步网络时间
{
ntp_flag = 0;
RTC_GetTime();
if ((RtcDateTime.year >= 2035) && (work_duration >= 6 * 365)) // 至少大于2035年且实际使用时长超过6年
{
if (RTC_GetCounter() >= H308.expiration_seconds)
{
H308.end_of_life = 1;
}
else
{
H308.end_of_life = 0;
return 0;
}
}
else
{
H308.end_of_life = 0;
return 0;
}
}
else
{
H308.end_of_life = 0;
return 0;
}
return H308.end_of_life;
}
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");
}
static void h308_thread_entry(void *param)
{
rt_err_t ret;
static uint8_t str[UART4_RX_RB_LENGTH] = {0};
static uint8_t h308_rx_timout_cnt = 0;
static uint8_t h308_err_cnt = 0;
rt_thread_mdelay(1000);
rt_uint8_t alarm_value = Flash_Get_SysCfg(kAlarmLValueId); // 获取系统报警阈值;
if (alarm_value > 25)
{
alarm_value = 10;
}
H308.alarm_value = alarm_value;
LOG_D("报警阈值:%d%LEL", H308.alarm_value);
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)
{
ret = H308_GetFrameData((const char *)str, len, &H308.Data);
LOG_I("str:%s", str);
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;
}
}
rt_memset(str, 0, len);
if (h308_rx_timout_cnt)
{
h308_rx_timout_cnt = 0;
}
}
else if (ret == -RT_ETIMEOUT) // 这个主要是考虑传感器未焊接好或者脱落的情况国标要求30s内反应 3*5 = 15s符合国标
{
h308_rx_timout_cnt++;
if (h308_rx_timout_cnt >= 6)
{
H308_RST_ON;
rt_thread_mdelay(100);
H308_RST_OFF; // 复位一下
h308_rx_timout_cnt = 0;
if (H308.detection_flag != kH308Fault)
{
H308.detection_flag = kH308Fault;
fault_flag = 1;
Send_Laser_Alarm_Event(kFaultEvent);
}
// 重置接收缓冲区和相关标志
lwrb_reset(&uart4_rx_rb);
sensor_rx_flag = 0;
}
}
}
}
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;
H308_PWR_ON;
uart4_rx_ok_sem = rt_sem_create("uart4_rx", 0, RT_IPC_FLAG_PRIO);
if (uart4_rx_ok_sem == RT_NULL)
{
LOG_E("uart4_rx_ok_sem create failed");
}
// TODO:这里改的静态
rt_timer_init(&uart4_rx_timer, "_UART4_RxTimeout", _UART4_RxTimeout, RT_NULL, 200, RT_TIMER_FLAG_PERIODIC);
UART4_Init();
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;
}
INIT_DEVICE_EXPORT(BSP_H308_Init);
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);
if (sensor_rx_flag == 0)
{
sensor_rx_flag = 1;
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