WLE5CC_NODE_STS/STS/RC/rf_device.c

653 lines
18 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.

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file rf_device.c *
* @author Yunhorn (r) Technology Limited Application Team *
* @brief Yunhorn (r) SmarToilets (r) Product configuration file. *
******************************************************************************
* @attention
*
* Copyright (c) 2022 Yunhorn Technology Limited.
* Copyright (c) 2022 Shenzhen Yunhorn Technology Co., Ltd.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "rf_device.h"
/* 芯片头文件使能 如果使用了其他的芯片 把屏蔽掉*/
#define MCU_AI_WB2
#ifdef MCU_AI_WB2
/*
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "ir_uart.h"
#include "blog.h"
#include <bl_gpio.h>
#include "easy_flash.h"
#define DBG_TAG "IR-DEVICE"
TimerHandle_t hxd_busy_timer;
TimerHandle_t hxd_power_off_timer;
bool hxd_power_off_timer_start = 0;
*/
#endif
#define BUFFER_SIZE 2
#define POWER_OFF 1
#define POWER_ON 0
typedef struct
{
char buffer[BUFFER_SIZE];
int head;
int tail;
int count;
} CircularBuffer;
static CircularBuffer hxd_recv_buff;
unsigned char ac_codeGrud[2] = {0x03, 0xF8}; // 默认空调码组
static unsigned char hxd039b2_code_lren[] = {0x30, 0x70, 0xa0}; // 固定学习码
static void initBuffer(CircularBuffer *cb);
static bool isEmpty(CircularBuffer *cb);
static bool isFull(CircularBuffer *cb);
static bool enqueue(CircularBuffer *cb, unsigned char data);
static bool dequeue(CircularBuffer *cb, unsigned char *data);
static void printBuffer(CircularBuffer *cb);
static void hxd_039b2_delay_ms(uint32_t ms);
/**
* @brief hxd039b2 串口接收回调把这函数放到MCU的串口接收中断中运行
*
* @param uart_data 单字节接收数据
*/
void hxd_039b_uart_recv_cb(unsigned char uart_data)
{
enqueue(&hxd_recv_buff, uart_data);
if (isFull(&hxd_recv_buff))
{
// printBuffer(&hxd_recv_buff);
dequeue(&hxd_recv_buff, &ac_codeGrud[0]);
dequeue(&hxd_recv_buff, &ac_codeGrud[1]);
if (ac_codeGrud[0] != 0XFF)
{
/* 读取成功之后保存到flash*/
#ifdef MCU_AI_WB2
blog_info_hexdump("ir_acCode", ac_codeGrud, 2);
#endif
}
}
}
/**
* @brief 保存空调码组至可以保存至flash 或者其他地址,以实现掉电保存
*
* @param ac_codeGrud
* @param size_len
*/
void hxd_039b2_save_ac_codeGrud(unsigned char *ac_codeGrud, int size_len)
{
#ifdef MCU_AI_WB2
flash_save_new_ac_gcode(ac_codeGrud, size_len);
#endif
}
/**
* @brief 读取
*
* @param ac_codeGrud
*/
int hxd_039b2_get_ac_codeGrud(unsigned char *ac_codeGrud)
{
int g_code_len = 0;
#ifdef MCU_AI_WB2
memset(ac_codeGrud, 0, 2);
g_code_len = flash_get_ac_gcode(ac_codeGrud);
#endif
return g_code_len;
}
/**
* @brief 发送给hxb_039b 的代码,应该把串口发送函数再次运行
*
* @param data
* @param data_len
*/
static void hxd_039b_send_data(unsigned char *data, int data_len)
{
// Ai-WB2的串口发送函数
if (data == NULL)
{
printf("data is NULL \r\n");
return;
}
int __hxd039b_busy = 0;
// 如果芯片处于忙碌状态,则直接退出,不做任何操作
__hxd039b_busy = bl_gpio_input_get_value(HXD039B2_BUSY_GPIO);
if (!__hxd039b_busy)
{
#ifdef MCU_AI_WB2
blog_error("hxd is busy don't send data");
#endif
return;
}
#ifdef MCU_AI_WB2
// bl_uart_datas_send(IR_UART_NUM, data, data_len);
uint16_t cnt = 0;
while (cnt < data_len)
{
bl_uart_data_send(IR_UART_NUM, data[cnt]);
cnt++;
}
#endif
/* 其他主控的串口发送函数*/
}
/**
* @brief 延迟函数需要MCU的延时函数在此处调用
*
* @param ms
*/
static void hxd_039b2_delay_ms(uint32_t ms)
{
#ifdef MCU_AI_WB2
vTaskDelay(pdMS_TO_TICKS(ms));
#endif
}
/**
* @brief hxd_039b 开始匹配红外码,需要按匹配键,之后使用目标遥控器开关进行匹配
*
* @param code_groud 缓存红外码组,成功则缓存
* @return int
* 成功输出 红外码组,失败输出 -1。输出的码组为16位整数需要自行分离2个8位的数据
*/
static int hxd_039b_find_code_groud(void)
{
// hxd_039b_send_data(hxd039b2_code_lren, 3);
uint16_t cnt = 0;
while (cnt < 3)
{
bl_uart_data_send(IR_UART_NUM, hxd039b2_code_lren[cnt]);
cnt++;
}
return 0;
}
/**
* @brief 长时间无操作关闭HXD芯片电源
*
* @param xTimer
*/
static void hxd_power_timers_cb(TimerHandle_t xTimer)
{
uint32_t ulCount;
configASSERT(xTimer);
ulCount = (uint32_t)pvTimerGetTimerID(xTimer);
/* 识别是否已经超过2s 没有操作?*/
if (ulCount >= 20)
{
/* 关闭HXD 电源并停止此定时器 */
#ifdef MCU_AI_WB2
blog_info("hxd039 power off");
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_OFF);
#endif
xTimerStop(xTimer, 0);
vTimerSetTimerID(xTimer, 0);
hxd_power_off_timer_start = false;
return;
}
ulCount++;
vTimerSetTimerID(xTimer, (void *)ulCount);
}
/**
* @brief 红外设备初始化
*
*/
void ir_dvice_init(void)
{
// 串口初始化接口
#ifdef MCU_AI_WB2
ir_uart_dvice_init(hxd_039b_uart_recv_cb);
bl_gpio_enable_output(HXD039B2_POWER_CTRL_GPIO, true, false); // 使能HXD039B2 控制IO
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_OFF); // 关闭HXD039B2的电源
// 初始化判忙IO
bl_gpio_enable_input(HXD039B2_BUSY_GPIO, true, false);
/* 读取flash 内部的空调码组 */
if (hxd_039b2_get_ac_codeGrud(ac_codeGrud) == 0)
{
/* 如果读不到,则设置默认值 */
if (ac_codeGrud[0] == 0 && ac_codeGrud[1] == 0)
{
ac_codeGrud[0] = 0x03;
ac_codeGrud[1] = 0xf8;
}
}
/* 创建电源关闭定时器默认100ms 定时*/
hxd_power_off_timer = xTimerCreate("power off", pdMS_TO_TICKS(100), pdTRUE, (void *)0, hxd_power_timers_cb);
#endif
/*初始化缓冲器*/
initBuffer(&hxd_recv_buff);
}
#ifdef MCU_AI_WB2
/**
* @brief 软件定时器定时判忙
*
* @param xTimer
*/
static void vTimerCallback(TimerHandle_t xTimer)
{
// uint32_t ulCount;
configASSERT(xTimer);
int __hxd039b_busy = 0;
__hxd039b_busy = bl_gpio_input_get_value(HXD039B2_BUSY_GPIO);
// ulCount = (uint32_t)pvTimerGetTimerID(xTimer);
// blog_info("__hxd039b_busy=%d ulCont=%d", __hxd039b_busy, ulCount);
// 如果超时或者退出忙碌
if (__hxd039b_busy)
{
// 学习成功关闭HXD039B电源
blog_info("Learn success,ac code 0x%02X 0x%02X", ac_codeGrud[0], ac_codeGrud[1]);
if (ac_codeGrud[0] == 0xff && ac_codeGrud[1] == 0xff)
{
// 如果返回的是0xffff 则重新进入学习状态
hxd_039b_find_code_groud();
__hxd039b_busy = 0;
return;
}
if (ac_codeGrud[0] == 0x88 && ac_codeGrud[1] == 0x99)
{
blog_error("Learn timerout");
goto __exit;
}
hxd_039b2_save_ac_codeGrud(ac_codeGrud, 2);
ac_codeGrud[0] = ac_codeGrud[1] = 0xff;
__exit:
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_OFF);
__hxd039b_busy = 0;
xTimerStop(xTimer, 0);
xTimerDelete(xTimer, 0);
return;
}
}
#endif
/**
* @brief 启动学习,运行此函数之后,对着红外接收头,按遥控器的开关键即可匹配红外码
*
*/
void ir_codec_start_learn(void)
{
#ifdef MCU_AI_WB2
// 开启HXD039B电源
uint16_t time_out_cont = 0;
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_ON);
hxd_busy_timer = xTimerCreate("busy timer", pdMS_TO_TICKS(200), pdTRUE, (void *)time_out_cont, vTimerCallback);
#endif
/* 延时时间让HXD039B 进入工作状态*/
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS);
// 发送数据
hxd_039b_find_code_groud();
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS * 10);
// 启动定时器判断HXD是否忙碌
#ifdef MCU_AI_WB2
xTimerStart(hxd_busy_timer, 0);
#endif
}
/**
* @brief 发送电源控制指令
*
* @param power_state 1为打开0为关闭
*/
void ir_codec_set_power(int power_state)
{
#ifdef MCU_AI_WB2
// 开启HXD039B电源
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_ON);
flash_get_ac_gcode(ac_codeGrud);
#endif
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS);
// 组织数据 例如打开空调: 0x30 0x06 0x03 0x03e 81
uint8_t ir_code[5] = {IR_CODE_BYTE_HANDLE, IR_CODE_BYTE_AC_TYPE, ac_codeGrud[0], ac_codeGrud[1], power_state ? IR_CODE_BYTE_AC_ON : IR_CODE_BYTE_AC_OFF};
hxd_039b_send_data(ir_code, 5);
// 延时等待发送完成后关闭HXD039B的电源
// hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS*20);
#ifdef MCU_AI_WB2
// 关闭HXD039B的电源
blog_info_hexdump("uart_data", ir_code, 5);
/* 判断电源定时器是否正在运行 */
if (hxd_power_off_timer_start)
{
/* 如果正在运行则重新设置ID数让定时器重新进行2S的定时*/
vTimerSetTimerID(hxd_power_off_timer, 0);
}
else
{
/* 如果没在运行,则启动定时器 */
hxd_power_off_timer_start = true;
xTimerStart(hxd_power_off_timer, 0);
}
// bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_OFF);
#endif
}
/**
* @brief 设置模式发送0~4
*
* @param mode 0: 自动模式 1:制冷模式 2:除湿模式 3送风模式 4: 制热模式
*/
void ir_codec_set_mode(int mode)
{
uint32_t ulCount = 0;
#ifdef MCU_AI_WB2
// 开启HXD039B电源
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_ON);
flash_get_ac_gcode(ac_codeGrud);
#endif
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS);
// 组织数据 例如打开空调: 0x30 0x06 0x03 0x03e 81
uint8_t ir_code[5] = {IR_CODE_BYTE_HANDLE, IR_CODE_BYTE_AC_TYPE, ac_codeGrud[0], ac_codeGrud[1], IR_CODE_BYTE_AC_MODE_AUTO + mode};
hxd_039b_send_data(ir_code, 5);
// 延时等待发送完成后关闭HXD039B的电源
// hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS*20);
#ifdef MCU_AI_WB2
// 关闭HXD039B的电源
blog_info_hexdump("uart_data", ir_code, 5);
if (hxd_power_off_timer_start)
{
/* 如果正在运行则重新设置ID数让定时器重新进行2S的定时*/
vTimerSetTimerID(hxd_power_off_timer, 0);
}
else
{
/* 如果没在运行,则启动定时器 */
hxd_power_off_timer_start = true;
xTimerStart(hxd_power_off_timer, 0);
}
#endif
}
/**
* @brief 设置温度,
*
* @param temperature
*/
void ir_codec_set_temperature(unsigned char temperature)
{
uint32_t ulCount = 0;
#ifdef MCU_AI_WB2
// 开启HXD039B电源
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_ON);
flash_get_ac_gcode(ac_codeGrud);
#endif
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS);
// 组织数据 例如打开空调: 0x30 0x06 0x03 0x03e 81
uint8_t ir_code[5] = {IR_CODE_BYTE_HANDLE, IR_CODE_BYTE_AC_TYPE, ac_codeGrud[0], ac_codeGrud[1], (temperature - 16) + IR_CODE_BYTE_AC_TEMPERATURE_16};
hxd_039b_send_data(ir_code, 5);
// 延时等待发送完成后关闭HXD039B的电源
// hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS*20);
#ifdef MCU_AI_WB2
// 关闭HXD039B的电源
blog_info_hexdump("uart_data", ir_code, 5);
if (hxd_power_off_timer_start)
{
/* 如果正在运行则重新设置ID数让定时器重新进行2S的定时*/
vTimerSetTimerID(hxd_power_off_timer, 0);
}
else
{
/* 如果没在运行,则启动定时器 */
hxd_power_off_timer_start = true;
xTimerStart(hxd_power_off_timer, 0);
}
#endif
}
/**
* @brief 设置风力大小
*
* @param fan_mode 0:低速风 1:中等风力 2:强风
*/
void ir_codec_set_fan_mode(unsigned char fan_mode)
{
#ifdef MCU_AI_WB2
// 开启HXD039B电源
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_ON);
flash_get_ac_gcode(ac_codeGrud);
#endif
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS);
// 组织数据 例如打开空调: 0x30 0x06 0x03 0x03e 81
uint8_t ir_code[5] = {IR_CODE_BYTE_HANDLE, IR_CODE_BYTE_AC_TYPE, ac_codeGrud[0], ac_codeGrud[1], fan_mode + IR_CODE_BYTE_AC_FAN_MODE_AUTO};
hxd_039b_send_data(ir_code, 5);
// 延时等待发送完成后关闭HXD039B的电源
// hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS*20);
#ifdef MCU_AI_WB2
// 关闭HXD039B的电源
blog_info_hexdump("uart_data", ir_code, 5);
if (hxd_power_off_timer_start)
{
/* 如果正在运行则重新设置ID数让定时器重新进行2S的定时*/
vTimerSetTimerID(hxd_power_off_timer, 0);
}
else
{
/* 如果没在运行,则启动定时器 */
hxd_power_off_timer_start = true;
xTimerStart(hxd_power_off_timer, 0);
}
#endif
}
/**
* @brief 设置风向
*
* @param trend 0向上 1中间 2向下
*/
void ir_codec_set_trend(unsigned char trend)
{
#ifdef MCU_AI_WB2
// 开启HXD039B电源
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_ON);
flash_get_ac_gcode(ac_codeGrud);
#endif
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS);
// 组织数据 例如打开空调: 0x30 0x06 0x03 0x03e 81
uint8_t ir_code[5] = {IR_CODE_BYTE_HANDLE, IR_CODE_BYTE_AC_TYPE, ac_codeGrud[0], ac_codeGrud[1], trend + IR_CODE_BYTE_AC_TREND_UP};
hxd_039b_send_data(ir_code, 5);
// 延时等待发送完成后关闭HXD039B的电源
// hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS*20);
#ifdef MCU_AI_WB2
// 关闭HXD039B的电源
blog_info_hexdump("uart_data", ir_code, 5);
if (hxd_power_off_timer_start)
{
/* 如果正在运行则重新设置ID数让定时器重新进行2S的定时*/
vTimerSetTimerID(hxd_power_off_timer, 0);
}
else
{
/* 如果没在运行,则启动定时器 */
hxd_power_off_timer_start = true;
xTimerStart(hxd_power_off_timer, 0);
}
#endif
}
/**
* @brief 自动风向开关
*
* @param trend_auto 0:关闭 1开启
*/
void ir_codec_set_trend_auto(unsigned char trend_auto)
{
#ifdef MCU_AI_WB2
// 开启HXD039B电源
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_ON);
flash_get_ac_gcode(ac_codeGrud);
#endif
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS);
// 组织数据 例如打开空调: 0x30 0x06 0x03 0x03e 81
uint8_t ir_code[5] = {IR_CODE_BYTE_HANDLE, IR_CODE_BYTE_AC_TYPE, ac_codeGrud[0], ac_codeGrud[1], trend_auto ? IR_CODE_BYTE_AC_TREND_AUTO_ON : IR_CODE_BYTE_AC_TREND_AUTO_OFF};
hxd_039b_send_data(ir_code, 5);
// 延时等待发送完成后关闭HXD039B的电源
// hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS*20);
#ifdef MCU_AI_WB2
// 关闭HXD039B的电源
blog_info_hexdump("uart_data", ir_code, 5);
if (hxd_power_off_timer_start)
{
/* 如果正在运行则重新设置ID数让定时器重新进行2S的定时*/
vTimerSetTimerID(hxd_power_off_timer, 0);
}
else
{
/* 如果没在运行,则启动定时器 */
hxd_power_off_timer_start = true;
xTimerStart(hxd_power_off_timer, 0);
}
#endif
}
/**
* @brief 灯光开关
*
* @param light_power 0关闭灯光 1打开灯光
*/
void ir_codec_set_light_power(unsigned char light_power)
{
#ifdef MCU_AI_WB2
// 开启HXD039B电源
bl_gpio_output_set(HXD039B2_POWER_CTRL_GPIO, POWER_ON);
flash_get_ac_gcode(ac_codeGrud);
#endif
hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS);
// 组织数据 例如打开空调: 0x30 0x06 0x03 0x03e 81
uint8_t ir_code[5] = {IR_CODE_BYTE_HANDLE, IR_CODE_BYTE_AC_TYPE, ac_codeGrud[0], ac_codeGrud[1], light_power ? IR_CODE_BYTE_AC_LIGHT_ON : IR_CODE_BYTE_AC_LIGHT_OFF};
hxd_039b_send_data(ir_code, 5);
// 延时等待发送完成后关闭HXD039B的电源
// hxd_039b2_delay_ms(HXD_039B2_START_TIME_MS*20);
#ifdef MCU_AI_WB2
// 关闭HXD039B的电源
blog_info_hexdump("uart_data", ir_code, 5);
if (hxd_power_off_timer_start)
{
/* 如果正在运行则重新设置ID数让定时器重新进行2S的定时*/
vTimerSetTimerID(hxd_power_off_timer, 0);
}
else
{
/* 如果没在运行,则启动定时器 */
hxd_power_off_timer_start = true;
xTimerStart(hxd_power_off_timer, 0);
}
#endif
}
/**
* @brief 以下是缓冲器程序
*
*/
/**
* @brief 初始化回环缓冲
*
* @param cb
* @return * void
*/
static void initBuffer(CircularBuffer *cb)
{
cb->head = 0;
cb->tail = 0;
cb->count = 0;
memset(cb->buffer, 0, BUFFER_SIZE);
}
/**
* @brief 判断 检查缓冲区是否为空
*
* @param cb 缓冲器枚举
* @return true 为空
* @return false 不为空
*/
static bool isEmpty(CircularBuffer *cb)
{
return cb->count == 0;
}
/**
* @brief 判断缓冲器是否已满?
*
* @param cb 缓冲器枚举
* @return true 已满
* @return false 没满
*/
static bool isFull(CircularBuffer *cb)
{
return cb->count == BUFFER_SIZE;
}
/**
* @brief 向缓冲区添加数据
*
* @param cb 缓冲器枚举
* @param data 数据
* @return true 添加成功
* @return false 添加失败
*/
static bool enqueue(CircularBuffer *cb, unsigned char data)
{
if (isFull(cb))
{
return false; // 缓冲区已满,添加失败
}
cb->buffer[cb->head] = data;
cb->head = (cb->head + 1) % BUFFER_SIZE;
cb->count++;
return true;
}
/**
* @brief 从缓冲器取数据
*
* @param cb 缓冲器枚举
* @param data 数据
* @return true 取出成功
* @return false 取出失败
*/
static bool dequeue(CircularBuffer *cb, unsigned char *data)
{
if (isEmpty(cb))
{
return false; // 缓冲区为空,取出失败
}
*data = cb->buffer[cb->tail];
cb->tail = (cb->tail + 1) % BUFFER_SIZE;
cb->count--;
return true;
}
/**
* @brief 打印缓冲区内容(用于调试)
*
* @param cb
* @return * void
*/
static void printBuffer(CircularBuffer *cb)
{
printf("Buffer: ");
for (int i = 0; i < BUFFER_SIZE; i++)
{
int index = (cb->tail + i) % BUFFER_SIZE;
if (index == cb->head && i < cb->count)
{
printf("|"); // 指示缓冲区头和尾之间的分隔
}
printf("0x%02X ", cb->buffer[index]);
}
printf("\r\n");
}