IR SDK

Last Updated on : 2022-11-24 09:20:27download

Tuya Module SDK only provides the data point (DP) callback APIs for the infrared (IR) functions. To implement more IR functions with the SDK, you must implement the IR transmission and learning functions at the driver layer. This increases the difficulties and cycle of app development.

The IR SDK helps resolve this issue. Based on this application component, you do not need to be concerned about data links of IR functions. You only need to register the IR transmitter and receiver pins, and the callbacks of IR transmission and reception status to develop IR functions. The following figure shows the architecture of the SDK.

IR SDK

SDK directory structure

.
├── Doc
│   ├── Readme.md
│   ├── tuya_ir_drv_bk7231n.c
│   ├── tuya_ir_drv_bk7231n.h
│   ├── tuya_ir_drv_rtl8710bn.c
│   ├── tuya_ir_drv_rtl8710bn.h
│   ├── tuya_ir_drv_rtl8720cf.c
│   ├── tuya_ir_drv_rtl8720cf.h
│   ├── tuya_ir_drv_rtl8720cs.c
│   ├── tuya_ir_drv_rtl8720cs.h
│   ├── tuya_ir_proc.c
│   └── tuya_ir_proc.h
├── include
│   ├── tuya_ir_app.h
│   ├── tuya_ir_ctrl.h
│   ├── tuya_ir_data_handle.h
│   ├── tuya_ir_drv_struct.h
│   └── tuya_ir_user_api.h
├── local.mk
├── README.md
├── src
│   ├── tuya_ir_app.c
│   ├── tuya_ir_app.o
│   ├── tuya_ir_ctrl.c
│   ├── tuya_ir_ctrl.o
│   ├── tuya_ir_data_handle.c
│   └── tuya_ir_data_handle.o
└── svc_ir_module.yaml

File Description Manually managed
tuya_ir_app.c Logic processing of the IR application component No
tuya_ir_ctrl.c Specific logic processing of the IR application component No
tuya_ir_data_handle.c The filter processing function of the IR learning code. No
tuya_ir_user_api.h The API declaration. Yes
tuya_ir_drv_struct.h The declaration of the IR driver struct. Yes
Doc The introduction of the adapted platform driver and IR SDK. Yes

Data structure

The required driver data structure is declared in the tuya_ir_drv_struct.h header file. The driver API is described in the following code block:

typedef enum
{
	TIM_COUNT_UP_MODE   = 0,
	TIM_COUNT_DOWN_MODE = 1,
	TIM_INVALID_MODE    = 2,
}TIM_COUNT_MODE_E;

typedef struct
{
	FLOAT_T timer_mhz;
	TIM_COUNT_MODE_E count_mode;     //0:Counting-up 1:Counting-down
}TUYA_IR_TIM_INFO,*P_TUYA_IR_TIM_INFO;

//ir_ops
typedef struct
{
	VOID_T  (*tuya_ir_drv_timer_init)(VOID_T);
	VOID_T  (*tuya_ir_drv_timer_start)(IN UINT_T tim_us);
	VOID_T  (*tuya_ir_drv_timer_stop)(VOID_T);
	UINT_T  (*tuya_ir_drv_timer_getcount)(VOID_T);
	VOID_T  (*tuya_ir_drv_timer_getinfo)(INOUT TUYA_IR_TIM_INFO *tim_info);

	VOID_T  (*tuya_ir_drv_pwm_init)(IN UCHAR_T ir_txpin,IN UINT_T freq);
	VOID_T  (*tuya_ir_drv_pwm_setfreq)(IN UINT_T freq);
	VOID_T  (*tuya_ir_drv_pwm_send)(VOID_T);
	VOID_T  (*tuya_ir_drv_pwm_stop)(VOID_T);

	VOID_T  (*tuya_ir_drv_gpioirq_init)(IN UCHAR_T ir_rxpin);
	VOID_T  (*tuya_ir_drv_gpioirq_en)(IN UCHAR_T is_enable);

	VOID_T  (*tuya_ir_drv_plat_related_init)(VOID_T);
	VOID_T  (*tuya_ir_drv_irtx_start_cb)(VOID_T);
	VOID_T  (*tuya_ir_drv_irtx_finish_cb)(VOID_T);
	VOID_T  (*tuya_ir_drv_irrx_start_cb)(VOID_T);
	VOID_T  (*tuya_ir_drv_irrx_finish_cb)(VOID_T);
}TUYA_IR_DRV_OPTS,*P_TUYA_IR_DRV_OPTS;

typedef struct
{
FLOAT_T timer_mhz;
TIM_COUNT_MODE_E count_mode; //0: Counting-up 1: Counting-down
}TUYA_IR_TIM_INFO,*P_TUYA_IR_TIM_INFO;
timer_mhz: the frequency of the hardware timer.
count_mode: the count mode of the hardware timer.
VOID_T (*tuya_ir_drv_timer_init)(VOID_T); Initializes the hardware timer.
VOID_T (*tuya_ir_drv_timer_start)(IN UINT_T tim_us); Starts the hardware timer.
VOID_T (*tuya_ir_drv_timer_stop)(VOID_T); Stops the hardware timer.
UINT_T (*tuya_ir_drv_timer_getcount)(VOID_T); Returns the count value of the hardware timer.
VOID_T (*tuya_ir_drv_timer_getinfo)(INOUT TUYA_IR_TIM_INFO *tim_info); Returns the properties of the hardware timer.
VOID_T (*tuya_ir_drv_pwm_init)(IN UCHAR_T ir_txpin,IN UINT_T freq); Initializes pulse-width modulation (PWM).
VOID_T (*tuya_ir_drv_pwm_setfreq)(IN UINT_T freq); Sets the PWM frequency.
VOID_T (*tuya_ir_drv_pwm_send)(VOID_T); Sends PWM signals.
VOID_T (*tuya_ir_drv_pwm_stop)(VOID_T); Stops PWM output.
VOID_T (*tuya_ir_drv_gpioirq_init)(IN UCHAR_T ir_rxpin); Initializes external interrupts.
VOID_T (*tuya_ir_drv_gpioirq_en)(IN UCHAR_T is_enable); Enable or disable external interrupts.
VOID_T (*tuya_ir_drv_plat_related_init)(VOID_T); Initializes the chipset platform of the module. The initialization method varies based on different modules. If initialization is not required, NULL is specified.
VOID_T (*tuya_ir_drv_irtx_start_cb)(VOID_T); The IR transmitter starts driver callbacks. The callback parameters at the transmitter vary based on different modules. If callbacks are not required, NULL is specified.
VOID_T (*tuya_ir_drv_irtx_finish_cb)(VOID_T); The IR transmitter stops driver callbacks. The callback parameters at the transmitter vary based on different modules. If callbacks are not required, NULL is specified.
VOID_T (*tuya_ir_drv_irrx_start_cb)(VOID_T); The IR receiver starts driver callbacks. The callback parameters at the transmitter vary based on different modules. If callbacks are not required, NULL is specified.
VOID_T (*tuya_ir_drv_irrx_finish_cb)(VOID_T); The IR receiver stops driver callbacks. The callback parameters at the transmitter vary based on different modules. If callbacks are not required, NULL is specified.

The following code block shows the data structure for IR initialization:

typedef struct
{
	SHORT_T carr_compensation_val;
	SHORT_T lowlevel_compensation_val;
}TUYA_IRAPP_TX_CFG_S;

typedef struct
{
	UCHAR_T                 txpin;
	UCHAR_T                 rxpin;
	TUYA_IR_STAT_CB         ir_stat_cb;
	TUYA_IRAPP_TX_CFG_S     ir_tx_cfg;
} TUYA_IRAPP_CFG_S,*P_TUYA_IRAPP_CFG_S;
Parameter Description
txpin The IR transmitter pin.
rxpin The IR receiver pin.
TUYA_IR_STAT_CB The callback of IR transmitter and receiver status.
TUYA_IRAPP_TX_CFG_S The compensation value of the IR transmitter. The timing error might vary based on different hardware timers. You can set the compensation value to minimize the timing error.

Open API

OPERATE_RET tuya_irapp_module_init(IN TUYA_IRAPP_CFG_S *p_ir_cfg,IN TUYA_IR_DRV_OPTS* p_ir_opts);
VOID_T tuya_irapp_irdata_send(IN TY_IR_CODE_S *ir_code, IN UCHAR_T code_num);
VOID_T tuya_irapp_irstudy_ctrl(IN TY_IR_STUDY_CTL_E irstudy_mode);
VOID_T tuya_irapp_set_irdata_recv_cb(IN TUYA_IR_DATARECV_CB cb);
CHAR_T tuya_irapp_is_irsend_stat(VOID_T);
VOID_T tuya_irctrl_set_carrorlow(CHAR_T enable);
VOID_T tuya_irctrl_timeout_irq(VOID_T);
VOID_T tuya_irctrl_recv_irq(VOID_T);

OPERATE_RET tuya_irapp_module_init(IN TUYA_IRAPP_CFG_S p_ir_cfg,IN TUYA_IR_DRV_OPTS p_ir_opts); /**
* @brief: tuya_irapp_module_init
* @desc: tuya Infrared function initialization
*
* @param[in] TUYA_IRAPP_CFG_S: p_ir_cfg
* @param[in] TUYA_IR_DRV_OPTS: p_ir_opts
*
* @return OPERATE_RET
*
* @note none
*/
VOID_T tuya_irapp_irdata_send(IN TY_IR_CODE_S ir_code, IN UCHAR_T code_num);/*
* @brief: tuya_irapp_irdata_send
* @desc: tuya Infrared data transmission
*
* @param[in] ir_code: infrared data
* @param[in] code_num: num of ir_code
*
* @return VOID_T
*
* @note none
*/
VOID_T tuya_irapp_irstudy_ctrl(IN TY_IR_STUDY_CTL_E irstudy_mode); /**
* @brief: tuya_irapp_irstudy_ctrl
* @desc: tuya Infrared learning state control
*
* @param[in] irstudy_mode: Infrared learning state
*
* @return VOID_T
*
* @note none
*/
VOID_T tuya_irapp_set_irdata_recv_cb(IN TUYA_IR_DATARECV_CB cb); /**
* @brief: tuya_irapp_set_irdata_recv_cb
* @desc: tuya Infrared learning data callback
*
* @param[in] TUYA_IR_DATARECV_CB: Infrared learning data callback function pointer
*
* @return VOID_T
*
* @note none
*/
CHAR_T tuya_irapp_is_irsend_stat(VOID_T); /**
* @brief: tuya_irapp_is_irsend_stat
* @desc: Gets the infrared transmission status
*
* @return True OR False
*
* @note none
*/
VOID_T tuya_irctrl_set_carrorlow(CHAR_T enable); /**
* @brief: tuya_irctrl_set_carrorlow
* @desc: Set the infrared transmitting carrier or low level
*
* @return True OR False
*
* @note none
*/
VOID_T tuya_irctrl_timeout_irq(VOID_T); /**
* @brief: tuya_irctrl_timeout_irq
* @desc: Infrared timer interrupt handler function
*
* @return none
*
* @note Called by the developer in the timer interrupt callback function
*/
VOID_T tuya_irctrl_recv_irq(VOID_T); /**
* @brief: tuya_irctrl_recv_irq
* @desc: Infrared external interrupt handler function
*
* @return none
*
* @note Called by developer in external interrupt function callback
*/

Demo

The following code block shows the demo to implement the driver API:

#include"tuya_ir_drv_rtl8710bn.h"

STATIC TY_IR_DRV_S ty_irhw ={0};

STATIC VOID_T tuya_rtl8710bn_ir_drv_timer_irq_handle(VOID_T *param);
STATIC VOID_T tuya_rtl8710bn_ir_drv_gpioirq_handle(UINT_T param, gpio_irq_event event);
STATIC VOID_T tuya_rtl8710bn_ir_drv_timer_init(VOID_T);
STATIC VOID_T tuya_rtl8710bn_ir_drv_timer_start(IN UINT_T tim_us);
STATIC VOID_T tuya_rtl8710bn_ir_drv_timer_stop(VOID_T);
STATIC UINT_T tuya_rtl8710bn_ir_drv_timer_getcount(VOID_T);
STATIC VOID_T tuya_rtl8710bn_ir_drv_timer_getinfo(INOUT TUYA_IR_TIM_INFO *tim_info);
STATIC VOID_T tuya_rtl8710bn_ir_drv_pwm_init(IN CHAR_T ir_txpin,IN UINT_T freq);
STATIC VOID_T tuya_rtl8710bn_ir_drv_pwm_setfreq(IN UINT_T freq);
STATIC VOID_T tuya_rtl8710bn_ir_drv_pwm_send(VOID_T);
STATIC VOID_T tuya_rtl8710bn_ir_drv_pwm_stop(VOID_T);
STATIC VOID_T tuya_rtl8710bn_ir_drv_gpioirq_init(IN UCHAR_T ir_rxpin);
STATIC VOID_T tuya_rtl8710bn_ir_drv_gpioirq_en(IN UCHAR_T is_enable);

OPERATE_RET tuya_rtl8710bn_get_ir_drv_ops(INOUT TUYA_IR_DRV_OPTS *p_irops)
{
	if (NULL == p_irops)
	{
		return OPRT_INVALID_PARM;
	}

	p_irops->tuya_ir_drv_timer_init         = tuya_rtl8710bn_ir_drv_timer_init;
	p_irops->tuya_ir_drv_timer_start        = tuya_rtl8710bn_ir_drv_timer_start;
	p_irops->tuya_ir_drv_timer_stop         = tuya_rtl8710bn_ir_drv_timer_stop;
	p_irops->tuya_ir_drv_timer_getcount     = tuya_rtl8710bn_ir_drv_timer_getcount;
	p_irops->tuya_ir_drv_timer_getinfo      = tuya_rtl8710bn_ir_drv_timer_getinfo;

	p_irops->tuya_ir_drv_pwm_init           = tuya_rtl8710bn_ir_drv_pwm_init;
	p_irops->tuya_ir_drv_pwm_setfreq        = tuya_rtl8710bn_ir_drv_pwm_setfreq;
	p_irops->tuya_ir_drv_pwm_send           = tuya_rtl8710bn_ir_drv_pwm_send;
	p_irops->tuya_ir_drv_pwm_stop           = tuya_rtl8710bn_ir_drv_pwm_stop;

	p_irops->tuya_ir_drv_gpioirq_init       = tuya_rtl8710bn_ir_drv_gpioirq_init;
	p_irops->tuya_ir_drv_gpioirq_en         = tuya_rtl8710bn_ir_drv_gpioirq_en;

	p_irops->tuya_ir_drv_plat_related_init  = NULL;
	p_irops->tuya_ir_drv_irtx_start_cb      = NULL;
	p_irops->tuya_ir_drv_irtx_finish_cb     = NULL;
	p_irops->tuya_ir_drv_irrx_start_cb      = NULL;
	p_irops->tuya_ir_drv_irrx_finish_cb     = NULL;

	return OPRT_OK;
}

STATIC VOID_T tuya_rtl8710bn_ir_drv_timer_irq_handle(VOID_T *param)
{
	TY_IR_DRV_S *p_ty_irhw = (TY_IR_DRV_S*)param;
	RTIM_INTClear(TIMx[p_ty_irhw->timerid]);

	//call tuya ir send irq function
	tuya_irctrl_timeout_irq();
}

STATIC VOID_T tuya_rtl8710bn_ir_drv_gpioirq_handle(UINT_T param, gpio_irq_event event)
{
	TY_IR_DRV_S  *p_ty_irhw = (TY_IR_DRV_S *)param;

	if (IRQ_RISE == event)
	{
		gpio_irq_set_event(&(p_ty_irhw->irq), IRQ_FALL);
	}
	else if (IRQ_FALL == event)
	{
		gpio_irq_set_event(&(p_ty_irhw->irq), IRQ_RISE);
	}

	tuya_irctrl_recv_irq();
}

STATIC VOID_T  tuya_rtl8710bn_ir_drv_timer_init(VOID_T)
{
	RTIM_TimeBaseInitTypeDef TIM_InitStruct;

	ty_irhw.timerid = TY_IR_TIMER_ID;

	RTIM_TimeBaseStructInit(&TIM_InitStruct);
	TIM_InitStruct.TIM_Idx           = ty_irhw.timerid;
	TIM_InitStruct.TIM_Prescaler     = 39;              // prescaler =  (TIM_Prescaler+1)
	TIM_InitStruct.TIM_UpdateEvent   = TRUE;            // UEV enable
	TIM_InitStruct.TIM_UpdateSource  = TIM_UpdateSource_Overflow;
	TIM_InitStruct.TIM_ARRProtection = TRUE;
	RTIM_TimeBaseInit(TIMx[ty_irhw.timerid], &TIM_InitStruct, TIMx_irq[ty_irhw.timerid], (IRQ_FUN)tuya_rtl8710bn_ir_drv_timer_irq_handle, (UINT_T)&ty_irhw);
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_timer_start(IN UINT_T tim_us)
{
	RTIM_TypeDef *RTIM = TIMx[ty_irhw.timerid];
	UINT_T period;

	RTIM->PSC = 39;
	period = (UINT_T)((FLOAT_T)tim_us  * 40 / ((RTIM->PSC & 0xFF) + 1));
	period = (period > 0xFFFF) ? 0xFFFF : period;
	RTIM_ChangePeriod(RTIM, period);
	RTIM_INTConfig(RTIM, TIM_IT_Update, TRUE);
	RTIM_Cmd(RTIM, TRUE);
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_timer_stop(VOID_T)
{
	RTIM_Cmd(TIMx[ty_irhw.timerid], FALSE);
}
STATIC UINT_T  tuya_rtl8710bn_ir_drv_timer_getcount(VOID_T)
{
	RTIM_TypeDef *RTIM = TIMx[ty_irhw.timerid];
	return RTIM_GetCount(RTIM);
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_timer_getinfo(INOUT TUYA_IR_TIM_INFO *tim_info)
{
	tim_info->timer_mhz = 1;                //1 MHz
	tim_info->count_mode = TIM_COUNT_UP_MODE;
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_pwm_init(IN CHAR_T ir_txpin,IN UINT_T freq)
{
	ty_irhw.txpin = ir_txpin;
	pwmout_init(&(ty_irhw.pwm), ty_irhw.txpin);
	pwmout_stop(&(ty_irhw.pwm));
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_pwm_setfreq(IN UINT_T freq)
{
	pwmout_period_us(&(ty_irhw.pwm), (UINT_T)(1000000 / freq));
	pwmout_pulsewidth_us(&(ty_irhw.pwm), (UINT_T)(1000000 / freq) >> 1);
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_pwm_send(VOID_T)
{
	pwmout_start(&(ty_irhw.pwm));
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_pwm_stop(VOID_T)
{
	pwmout_stop(&(ty_irhw.pwm));
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_gpioirq_init(IN UCHAR_T ir_rxpin)
{
	ty_irhw.rxpin = ir_rxpin;
	gpio_irq_init(&(ty_irhw.irq), ty_irhw.rxpin, (gpio_irq_handler)tuya_rtl8710bn_ir_drv_gpioirq_handle, (UINT_T)&ty_irhw);
	gpio_irq_pull_ctrl(&(ty_irhw.irq), PullUp);
	gpio_irq_set(&(ty_irhw.irq), IRQ_FALL, FALSE);
	gpio_irq_disable(&(ty_irhw.irq));
}
STATIC VOID_T  tuya_rtl8710bn_ir_drv_gpioirq_en(IN UCHAR_T is_enable)
{
	if (is_enable)
	{
		gpio_irq_set(&(ty_irhw.irq), IRQ_FALL, TRUE);
		gpio_irq_enable(&(ty_irhw.irq));
	}
	else
	{
		gpio_irq_set(&(ty_irhw.irq), IRQ_FALL, FALSE);
		gpio_irq_disable(&(ty_irhw.irq));
	}
}

#ifndef __TUYA_IR_DRV_RTL8710BN_H__
#define __TUYA_IR_DRV_RTL8710BN_H__

#include "gpio_irq_api.h"
#include "pwmout_api.h"
#include "timer_api.h"
#include "tuya_gpio.h"
#include "tuya_cloud_types.h"
#include "tuya_ir_drv_struct.h"

#ifdef __cplusplus
extern "C" {
#endif

#define TY_IR_TIMER_ID              4
#define TY_IR_TX_IO_ARRAY           {TY_GPIOA_5,TY_GPIOA_12,TY_GPIOA_14,TY_GPIOA_15,TY_GPIOA_22}
#define TY_IR_RX_IO_ARRAY           {TY_GPIOA_5,TY_GPIOA_12,TY_GPIOA_14,TY_GPIOA_15,TY_GPIOA_19,TY_GPIOA_22}
#define TY_IR_TX_CARR_COMPENSATION_VAL          (0)
#define TY_IR_TX_LOWLEVEL_COMPENSATION_VAL      (-10)

typedef struct
{
	gpio_irq_t         irq;
	pwmout_t           pwm;
	UCHAR_T            timerid;
	UCHAR_T            txpin;
	UCHAR_T            rxpin;
} TY_IR_DRV_S,*P_TY_IR_DRV_S;

OPERATE_RET tuya_rtl8710bn_get_ir_drv_ops(INOUT TUYA_IR_DRV_OPTS *p_irops);

#ifdef __cplusplus
} // extern "C"
#endif

#endif

The following code block shows the demo application:

	HW_IRSET_S * ir_config = get_ir_config();
	TUYA_IRAPP_CFG_S ir_cfg = {0};
	ir_cfg.txpin = ir_config->ir_io_set.ir_send;
	ir_cfg.rxpin = ir_config->ir_io_set.ir_recv;
	ir_cfg.ir_stat_cb = irapp_stat_cb;
	ir_cfg.ir_tx_cfg.carr_compensation_val = TY_IR_TX_CARR_COMPENSATION_VAL;
	ir_cfg.ir_tx_cfg.lowlevel_compensation_val = TY_IR_TX_LOWLEVEL_COMPENSATION_VAL;
	TUYA_IR_DRV_OPTS ir_opts = {0};

	tuya_rtl8710bn_get_ir_drv_ops(&ir_opts);

	op_ret = tuya_irapp_module_init(&ir_cfg,&ir_opts);
	if (op_ret != OPRT_OK)
	{
		PR_ERR("tuya_irbox_init err:%d!",op_ret);
		return op_ret;
	}