Browse Source

[first commit] Support NEC decoding

tangweikang 7 years ago
parent
commit
6b596fe69d
9 changed files with 900 additions and 2 deletions
  1. 74 2
      README.md
  2. 15 0
      SConscript
  3. BIN
      doc/infrared_frame.png
  4. 30 0
      inc/decoder.h
  5. 18 0
      inc/drv_infrared.h
  6. 71 0
      inc/infrared.h
  7. 266 0
      src/drv_infrared.c
  8. 157 0
      src/infrared.c
  9. 269 0
      src/nec_decoder.c

+ 74 - 2
README.md

@@ -1,2 +1,74 @@
-# infrared_framework
-Infrared framework based on RT-Thread's pin,pwm and hwtimer driver.
+# 红外框架
+
+## 简介
+
+红外框架,基于 `rt-thread` 的 `pin` 和 `hwtimer` 驱动实现的红外框架。
+
+## 驱动框架
+
+![infrared_frame](./doc/infrared_frame.png) 
+
+### 目录结构
+
+infrared 软件包目录结构如下所示:
+
+```c 
+infrared
+├───docs                            // 文档
+├───inc                             // 头文件
+├───src                             // 源文件				
+├───samples                         // 示例代码
+│───LICENSE                         // 软件包许可证
+│───README.md                       // 软件包使用说明
+└───SConscript                      // RT-Thread 默认的构建脚本
+```
+
+###  许可证
+
+infrared 软件包遵循 Apache-2.0 许可,详见 LICENSE 文件。
+
+### 获取软件包
+
+使用 infrared 软件包需要在 RT-Thread 的包管理中选中它,具体路径如下:
+
+```c
+RT-Thread online packages
+    peripheral libraries and drivers  --->
+         [*] infrared : infrared is base on rt-thread pin,hwtimer and pwm.  --->
+             Select infrared decoder  --->
+             [ ] infrared send enable
+             [ ] infrared receive enable
+                 Version (latest)  --->
+```
+
+### 使用示例
+
+```c
+    /* 选择解码器 */
+    ir_select_decoder("nec");
+    while (1)
+    {
+        /* 读取数据 */
+        if(user_read_api("nec",&infrared_data) == RT_EOK)
+        {
+            if(infrared_data.data.nec.repeat)
+            {
+                rt_printf("repeat%d\n",infrared_data.data.nec.repeat);
+            }
+            else
+            {
+                rt_printf("APP addr:0x%02X key:0x%02X\n",infrared_data.data.nec.addr,infrared_data.data.nec.key);
+                /* 发送数据 */
+                user_write_api("nec",&infrared_data);
+            }
+        }
+
+        rt_thread_mdelay(10);
+
+    }
+```
+
+### 联系方式 & 感谢
+
+- 维护:来一颗糖
+- 主页:https://github.com/balanceTWK/Infrared_frame

+ 15 - 0
SConscript

@@ -0,0 +1,15 @@
+from building import *
+
+cwd     = GetCurrentDir()
+src     = []
+path    = [cwd + '/inc']
+
+src += ['src/infrared.c']
+src += ['src/drv_infrared.c']
+
+if GetDepend(['INFRARED_NEC_DECODER']):
+    src += ['src/nec_decoder.c']
+
+group = DefineGroup('Infrared_frame', src, depend = ['PKG_USING_INFRARED'], CPPPATH = path)
+
+Return('group')

BIN
doc/infrared_frame.png


+ 30 - 0
inc/decoder.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2018-08-26     balanceTWK        the first version
+ */
+
+#ifndef __DECODER_H__
+#define __DECODER_H__
+#include <rtthread.h>
+
+struct nec_data_struct
+{
+    rt_uint8_t addr;
+    rt_uint8_t key;
+    rt_uint8_t repeat;
+};
+
+struct infrared_decoder_data
+{
+    union 
+    {
+        struct nec_data_struct    nec;          /* Temperature.         unit: dCelsius    */
+    }data;
+};
+
+#endif

+ 18 - 0
inc/drv_infrared.h

@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2018-08-26     balanceTWK        the first version
+ */
+
+#ifndef __DRV_INFRARED_H__
+#define __DRV_INFRARED_H__
+
+#include <rtthread.h>
+
+int drv_infrared_init(void);
+
+#endif

+ 71 - 0
inc/infrared.h

@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2006-2019, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-03-25     balanceTWK   the first version
+ */
+ 
+#ifndef __INFRARED__
+#define __INFRARED__
+
+#include <rtthread.h>
+#include "decoder.h"
+
+#define CARRIER_WAVE         0xA
+#define IDLE_SIGNAL          0xB
+#define NO_SIGNAL            0x0
+
+#define MAX_SIZE             5
+#define INFRARED_BUFF_SIZE   200
+
+struct ir_raw_data
+{
+    rt_uint32_t level : 4,
+                us    : 28;
+};
+
+struct decoder_ops
+{
+    rt_err_t (*init)(void);
+    rt_err_t (*deinit)(void);
+    rt_err_t (*read)(struct infrared_decoder_data* data);
+    rt_err_t (*write)(struct infrared_decoder_data* data);
+    rt_err_t (*decode)(rt_size_t size);
+    rt_err_t (*control)(int cmd, void *arg);
+};
+
+struct decoder_class 
+{
+    char* name;
+    struct decoder_ops* ops;
+    void* user_data;
+};
+
+struct infrared_class
+{
+    struct decoder_class* current_decoder;
+    struct decoder_class* decoder_tab[MAX_SIZE];
+    rt_uint32_t count;
+    struct rt_ringbuffer *ringbuff;
+    rt_size_t (*send)(struct ir_raw_data* data, rt_size_t size);
+};
+
+rt_err_t driver_report_raw_data(rt_uint8_t level, rt_uint32_t us);
+
+struct infrared_class* infrared_init(void);
+int infrared_deinit(void);
+
+rt_err_t ir_decoder_register(struct decoder_class *decoder);
+
+rt_err_t ir_select_decoder(const char* name);
+
+rt_err_t decoder_read_data(struct ir_raw_data* data);
+rt_err_t decoder_write_data(struct ir_raw_data* data, rt_size_t size);
+
+rt_err_t infrared_read(const char* decoder_name,struct infrared_decoder_data* data);
+rt_err_t infrared_write(const char* decoder_name, struct infrared_decoder_data* data);
+
+#endif /* __INFRARED__ */

+ 266 - 0
src/drv_infrared.c

@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2006-2019, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-03-25     balanceTWK   the first version
+ */
+
+#include <rthw.h>
+#include <rtdevice.h>
+#include <board.h>
+#include "infrared.h"
+#include "drv_infrared.h"
+
+#define DBG_SECTION_NAME     "drv.infrared"
+#define DBG_LEVEL     DBG_INFO
+#include <rtdbg.h>
+
+#ifdef PKG_USING_INFRARED
+
+static struct infrared_class* infrared;
+
+#ifdef INFRARED_SEND
+
+/* Infrared transmission configuration parameters */
+#define PWM_DEV_NAME              INFRARED_SEND_PWM         /* PWM name */
+#define PWM_DEV_CHANNEL           INFRARED_PWM_DEV_CHANNEL
+#define SEND_HWTIMER              INFRARED_SEND_HWTIMER     /* Timer name */
+#define MAX_SEND_SIZE             INFRARED_MAX_SEND_SIZE
+
+struct rt_device_pwm         *pwm_dev;
+static rt_uint32_t  infrared_send_buf[MAX_SEND_SIZE];
+static rt_device_t           send_time_dev ;
+static rt_hwtimerval_t       timeout_s;
+
+static rt_err_t send_timeout_callback(rt_device_t dev, rt_size_t size)
+{
+    static rt_size_t i = 0;
+    rt_pwm_disable(pwm_dev, PWM_DEV_CHANNEL);
+    if ((infrared_send_buf[i] != 0x5A5A5A5A))/* Determine if it is a stop bit */
+    {
+        if ((infrared_send_buf[i] & 0xF0000000) == 0xA0000000) /* Determine if it is a carrier signal */
+        {
+            rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
+        }
+        timeout_s.sec = 0;
+        timeout_s.usec = (infrared_send_buf[i] & 0x0FFFFFFF); /* Get the delay time */
+        rt_device_write(send_time_dev, 0, &timeout_s, sizeof(timeout_s));
+        i++;
+    }
+    else
+    {
+        i = 0;
+    }
+    return 0;
+}
+
+rt_err_t infrared_send_init(void)
+{
+    rt_err_t ret = RT_EOK;
+    rt_hwtimer_mode_t mode;
+    rt_uint32_t freq = 1000000;
+
+    pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
+    if (pwm_dev == RT_NULL)
+    {
+        LOG_E("pwm sample run failed! can't find %s device!", PWM_DEV_NAME);
+        return RT_ERROR;
+    }
+
+    rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, 26316, 8770);
+    rt_pwm_disable(pwm_dev, PWM_DEV_CHANNEL);
+
+    send_time_dev = rt_device_find(SEND_HWTIMER);
+    if (send_time_dev == RT_NULL)
+    {
+        LOG_E("hwtimer sample run failed! can't find %s device!", SEND_HWTIMER);
+        return RT_ERROR;
+    }
+    ret = rt_device_open(send_time_dev, RT_DEVICE_OFLAG_RDWR);
+    if (ret != RT_EOK)
+    {
+        LOG_E("open %s device failed!\n", SEND_HWTIMER);
+        return ret;
+    }
+    rt_device_set_rx_indicate(send_time_dev, send_timeout_callback);
+    ret = rt_device_control(send_time_dev, HWTIMER_CTRL_FREQ_SET, &freq);
+    if (ret != RT_EOK)
+    {
+        LOG_E("set frequency failed! ret is :%d", ret);
+        return ret;
+    }
+    mode = HWTIMER_MODE_ONESHOT;
+    ret = rt_device_control(send_time_dev, HWTIMER_CTRL_MODE_SET, &mode);
+    if (ret != RT_EOK)
+    {
+        LOG_E("set mode failed! ret is :%d", ret);
+        return ret;
+    }
+    return ret;
+}
+
+static rt_size_t infrared_send(struct ir_raw_data* data, rt_size_t size)
+{
+    rt_size_t send_size;
+    if(size >= MAX_SEND_SIZE)
+    {
+        LOG_E("The length of the sent data exceeds the MAX_SEND_SIZE.");
+        return 0;
+    }
+    for (send_size = 0; send_size < size; send_size++)
+    {
+        infrared_send_buf[send_size] = (data[send_size].level<<28) + (data[send_size].us);
+    }
+    infrared_send_buf[size] = 0x5A5A5A5A;
+
+    timeout_s.sec = 0;
+    timeout_s.usec = 500;
+    rt_device_write(send_time_dev, 0, &timeout_s, sizeof(timeout_s));
+    rt_thread_mdelay(100);
+    return send_size;
+}
+
+#endif /* INFRARED_SEND */
+
+
+#ifdef INFRARED_RECEIVE
+
+/* Infrared receiver configuration parameters */
+#define RECEIVE_PIN              INFRARED_RECEIVE_PIN       /* receive pin */
+#define RECEIVE_HWTIMER          INFRARED_RECEIVE_HWTIMER   /* Timer name */
+
+#define RECEIVE_HWTIMEER_SEC      0
+#define RECEIVE_HWTIMEER_USEC     1000 * 1000
+
+static rt_device_t           receive_time_dev ;
+static rt_uint32_t diff_us;
+static rt_uint32_t receive_flag = 0x00000000;
+
+static void receive_pin_callback(void* param)
+{
+    static rt_hwtimerval_t receive_time;
+    static rt_uint32_t last_us = 0 ,now_us;
+
+    if( (receive_flag & (1<<0)) )
+    {
+        rt_device_read(receive_time_dev,0,&receive_time,sizeof(receive_time));
+        now_us = (receive_time.sec * 1000000) + receive_time.usec;
+
+        if(now_us >= last_us)
+        {
+            diff_us = now_us - last_us;
+        }
+        else
+        {
+            diff_us = now_us + RECEIVE_HWTIMEER_SEC * 1000000 + RECEIVE_HWTIMEER_USEC;
+        }
+
+        if(rt_pin_read(RECEIVE_PIN) == PIN_HIGH)
+        {
+            driver_report_raw_data(CARRIER_WAVE,diff_us);
+            LOG_D("H%d",diff_us);
+        }
+        else
+        {
+            driver_report_raw_data(IDLE_SIGNAL,diff_us);
+            LOG_D("L%d",diff_us);
+        }
+
+        last_us = now_us;
+    }
+    else
+    {
+        receive_time.sec = RECEIVE_HWTIMEER_SEC;
+        receive_time.usec = RECEIVE_HWTIMEER_USEC;
+
+        rt_device_write(receive_time_dev, 0, &receive_time, sizeof(receive_time));
+
+        receive_flag |= 1<<0;
+
+        last_us = 0;
+
+        LOG_D("Start timer");
+    }
+}
+
+static rt_err_t receive_timeout_callback(rt_device_t dev, rt_size_t size)
+{
+    if(diff_us > (1000*1000))
+    {
+        rt_device_control(receive_time_dev, HWTIMER_CTRL_STOP, RT_NULL);
+        LOG_D("timeout and stop");
+
+        receive_flag &= ~(1<<0);
+    }
+    diff_us = diff_us + RECEIVE_HWTIMEER_SEC * 1000000 + RECEIVE_HWTIMEER_USEC;
+    return 0;
+}
+rt_err_t infrared_receive_init(void)
+{
+    rt_err_t ret = RT_EOK;
+    rt_hwtimer_mode_t mode;
+    rt_uint32_t freq = 100000;
+
+    rt_pin_mode(RECEIVE_PIN,PIN_MODE_INPUT_PULLUP);
+    rt_pin_attach_irq(RECEIVE_PIN,PIN_IRQ_MODE_RISING_FALLING,receive_pin_callback,RT_NULL);
+    rt_pin_irq_enable(RECEIVE_PIN,PIN_IRQ_ENABLE);
+
+    receive_time_dev = rt_device_find(RECEIVE_HWTIMER);
+    if (receive_time_dev == RT_NULL)
+    {
+        LOG_E("hwtimer sample run failed! can't find %s device!", RECEIVE_HWTIMER);
+        return RT_ERROR;
+    }
+    ret = rt_device_open(receive_time_dev, RT_DEVICE_OFLAG_RDWR);
+    if (ret != RT_EOK)
+    {
+        LOG_E("open %s device failed!\n", RECEIVE_HWTIMER);
+        return ret;
+    }
+    rt_device_set_rx_indicate(receive_time_dev, receive_timeout_callback);
+    ret = rt_device_control(receive_time_dev, HWTIMER_CTRL_FREQ_SET, &freq);
+    if (ret != RT_EOK)
+    {
+        LOG_E("set frequency failed! ret is :%d", ret);
+        return ret;
+    }
+    mode = HWTIMER_MODE_PERIOD;
+    ret = rt_device_control(receive_time_dev, HWTIMER_CTRL_MODE_SET, &mode);
+    if (ret != RT_EOK)
+    {
+        LOG_E("set mode failed! ret is :%d", ret);
+        return ret;
+    }
+
+    return ret;
+}
+
+#endif /* INFRARED_RECEIVE */
+
+
+int drv_infrared_init()
+{
+    infrared = infrared_init();
+
+    if(infrared == RT_NULL)
+    {
+        return -1;
+    }
+
+#ifdef INFRARED_SEND
+    infrared_send_init();
+    infrared->send = infrared_send;
+#endif /* INFRARED_SEND */
+
+#ifdef INFRARED_RECEIVE
+    infrared_receive_init();
+#endif /* INFRARED_RECEIVE */
+
+    return 0;
+}
+INIT_APP_EXPORT(drv_infrared_init);
+
+#endif /* PKG_USING_INFRARED */

+ 157 - 0
src/infrared.c

@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2006-2019, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-03-25     balanceTWK   the first version
+ */
+
+#include <infrared.h>
+#include "ipc/ringbuffer.h"
+
+#define DBG_SECTION_NAME     "infrared"
+#define DBG_LEVEL     DBG_INFO
+#include <rtdbg.h>
+
+static struct infrared_class infrared;
+
+struct decoder_class* ir_find_decoder(const char* name)
+{
+    for(rt_uint8_t i = 0;i<infrared.count;i++)
+    {
+        if(rt_strcmp(infrared.decoder_tab[i]->name,name) == 0)
+        {
+            return infrared.decoder_tab[i];
+        }
+    }
+    return RT_NULL;
+}
+
+rt_err_t ir_select_decoder(const char* name)/* Selective decoder */
+{
+    struct decoder_class* decoder;
+
+    decoder = ir_find_decoder(name);
+
+    if(decoder)
+    {
+        if(infrared.current_decoder)
+        {
+            infrared.current_decoder->ops->deinit();
+        }
+        infrared.current_decoder = decoder;
+        if(infrared.current_decoder->ops->init)
+        {
+            infrared.current_decoder->ops->init();
+        }
+        LOG_D("select decoder name:%s\n",infrared.decoder_tab[i]->name);
+        return RT_EOK;
+    }
+    LOG_W("The decoder%s cannot be found",name);
+
+    return -RT_ERROR;
+}
+
+rt_err_t ir_decoder_register(struct decoder_class *decoder)/* Registered decoder */
+{
+    infrared.decoder_tab[infrared.count] = decoder;
+    infrared.count++;
+    return RT_EOK;
+}
+
+rt_err_t decoder_read_data(struct ir_raw_data* data)
+{
+    if(rt_ringbuffer_get(infrared.ringbuff, (rt_uint8_t*)data, 4) == sizeof(struct ir_raw_data))
+    {
+        LOG_D("rt_ringbuffer get success | %01X:%d",data->level,data->us);
+        return RT_EOK;
+    }
+    else
+    {
+        return -RT_ERROR;
+    }
+}
+
+rt_err_t driver_report_raw_data(rt_uint8_t level,rt_uint32_t us)/* Low-level driver usage */
+{
+    struct ir_raw_data data;
+
+    if(infrared.current_decoder)
+    {
+        data.level = level;
+        data.us = us;
+
+        if( rt_ringbuffer_put(infrared.ringbuff, (rt_uint8_t*)&data, sizeof(struct ir_raw_data)) == sizeof(struct ir_raw_data) )
+        {
+            LOG_D("it_ringbuffer put success | count:%d;0x%01X;us:%d",(rt_ringbuffer_data_len(&infrared.ir_ringbuff)/sizeof(struct ir_raw_data)),data.level,data.us);
+            infrared.current_decoder->ops->decode(rt_ringbuffer_data_len(infrared.ringbuff)/4);
+        }
+        else
+        {
+            LOG_E("ir_ringbuffer put fail");
+        }
+
+        return RT_EOK;
+    }
+    return -RT_ERROR;
+}
+
+struct infrared_class* infrared_init(void)/* Initializes the necessary functions of the decoder */
+{
+    infrared.ringbuff = rt_ringbuffer_create((INFRARED_BUFF_SIZE*(sizeof(struct ir_raw_data))));
+
+    return &infrared;
+}
+
+int infrared_deinit(void)/* release resource */
+{
+    rt_ringbuffer_destroy(infrared.ringbuff);
+    return 0;
+}
+
+rt_err_t decoder_write_data(struct ir_raw_data* data, rt_size_t size)
+{
+    infrared.send(data, size);
+    return RT_EOK;
+}
+rt_err_t infrared_read(const char* decoder_name, struct infrared_decoder_data* data)
+{
+    struct decoder_class *decoder;
+
+    if(decoder_name)
+    {
+        decoder = ir_find_decoder(decoder_name);
+    }
+    else
+    {
+        decoder = infrared.current_decoder;
+    }
+
+    if(decoder)
+    {
+        return decoder->ops->read(data);
+    }
+    return -RT_ERROR;
+}
+
+rt_err_t infrared_write(const char* decoder_name, struct infrared_decoder_data* data)
+{
+    struct decoder_class *decoder;
+
+    if(decoder_name)
+    {
+        decoder = ir_find_decoder(decoder_name);
+    }
+    else
+    {
+        decoder = infrared.current_decoder;
+    }
+
+    if(decoder)
+    {
+        return decoder->ops->write(data);
+    }
+    return -RT_ERROR;
+}

+ 269 - 0
src/nec_decoder.c

@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2006-2019, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-03-25     balanceTWK   the first version
+ */
+
+#include <infrared.h>
+#include "ipc/ringbuffer.h"
+
+#define DBG_SECTION_NAME     "nec.decoder"
+#define DBG_LEVEL     DBG_INFO
+#include <rtdbg.h>
+
+#ifdef INFRARED_NEC_DECODER
+
+#define NEC_BUFF_SIZE  32
+
+static struct decoder_class nec_decoder;
+static struct rt_ringbuffer *ringbuff;
+
+struct nec_data_struct nec_data_buf[NEC_BUFF_SIZE];
+
+static rt_err_t nec_decoder_init(void)
+{
+    ringbuff = rt_ringbuffer_create(sizeof(nec_data_buf));
+    if(ringbuff)
+    {
+        nec_decoder.user_data = ringbuff;
+        return RT_EOK;
+    }
+    else
+    {
+        return -RT_ERROR;
+    }
+}
+
+static rt_err_t nec_decoder_deinit(void)
+{
+    rt_ringbuffer_destroy(ringbuff);
+    return RT_EOK;
+}
+
+static rt_err_t nec_decoder_read(struct infrared_decoder_data* nec_data)
+{
+    if( rt_ringbuffer_get(ringbuff, (rt_uint8_t*)&(nec_data->data.nec), sizeof(struct nec_data_struct)) == sizeof(struct nec_data_struct) ) //;//== struct nec_data_struct
+    {
+        LOG_D("NEC addr:0x%01X key:0x%01X repeat:%d",nec_data->data.nec.addr,nec_data->data.nec.key,nec_data->data.nec.repeat);
+        return RT_EOK;
+    }
+    else
+    {
+        return -RT_ERROR;
+    }
+}
+
+static rt_err_t nec_decoder_control(int cmd, void *arg)
+{
+    return RT_EOK;
+}
+
+static rt_err_t nec_decoder_decode(rt_size_t size)
+{
+    static rt_uint8_t nec_state = 0;
+    struct ir_raw_data raw_data[200];
+    
+    static struct ir_raw_data state_code[2];
+    
+    static struct nec_data_struct nec_data;
+
+    static rt_uint32_t command;
+    rt_uint8_t t1, t2;
+
+    LOG_D("size:%d",size);
+    if(nec_state == 0x01)
+    {
+        if(size==65)
+        {
+            for(rt_uint8_t i=0; i<65; i++)
+            {
+                decoder_read_data(&raw_data[i]);
+                if(raw_data[i].level == IDLE_SIGNAL)
+                {
+                    LOG_D("IDLE_SIGNAL,LINE:%d",__LINE__);
+                    if((raw_data[i].us>1600)&&(raw_data[i].us<1800))
+                    {
+                        LOG_D(" 1 LINE:%d",__LINE__);
+                        command <<= 1;
+                        command |= 1;
+                    }
+                    else if((raw_data[i].us>450)&&(raw_data[i].us<650))
+                    {
+                        LOG_D(" 0 LINE:%d",__LINE__);
+                        command <<= 1;
+                        command |= 0;
+                    }
+                }
+                else if((i == 64)&&((raw_data[i].us>450)&&(raw_data[i].us<650)))
+                {
+                    t1 = command >> 8;
+                    t2 = command;
+                    LOG_D("1 t1:0x%01X t2:0x%01X",t1,t2);
+                    if (t1 == (rt_uint8_t)~t2)
+                    {
+                        nec_data.key = t1;
+
+                        t1 = command >> 24;
+                        t2 = command >>16;
+                        LOG_D("2 t1:0x%01X t2:0x%01X",t1,t2);
+                        if(t1 == (rt_uint8_t)~t2)
+                        {
+                            nec_data.addr = t1;
+                            nec_data.repeat = 0;
+                            rt_ringbuffer_put(ringbuff, (rt_uint8_t*)&nec_data, sizeof(struct nec_data_struct));
+                            LOG_D("OK");
+                            nec_state = 0x00;
+                        }
+                        else
+                        {
+                            nec_state = 0x00;
+                            nec_data.addr = 0;
+                            nec_data.key = 0;
+                            nec_data.repeat = 0;
+                        }
+                    }
+                    else
+                    {
+                        nec_state = 0x00;
+                        nec_data.addr = 0;
+                        nec_data.key = 0;
+                        nec_data.repeat = 0;
+                    }
+                }
+            }
+        }
+    }
+    else if(nec_state == 0x04)
+    {
+        decoder_read_data(&state_code[1]);
+        if((state_code[1].level == IDLE_SIGNAL) && ((state_code[1].us > 4000)&&(state_code[1].us < 5000)))//判断是引导码
+        {
+            nec_state = 0x01;
+            LOG_D("guidance");
+        }
+        else if((state_code[1].level == IDLE_SIGNAL) && ((state_code[1].us > 2150)&&(state_code[1].us < 2350)))//判断是重复码
+        {
+            nec_data.repeat++;
+            nec_state = 0x00;
+            rt_ringbuffer_put(ringbuff, (rt_uint8_t*)&nec_data, sizeof(struct nec_data_struct));
+            LOG_D("repeat");
+        }
+        else
+        {
+            nec_data.repeat = 0;
+            nec_state = 0x00;
+            LOG_D("no guidance");
+            state_code[0].level = NO_SIGNAL;
+            state_code[1].level = NO_SIGNAL;
+            return -RT_ERROR;
+        }
+    }
+    else
+    {
+        decoder_read_data(&state_code[0]);
+        if((state_code[0].level == CARRIER_WAVE) && ((state_code[0].us > 8500)&&(state_code[0].us < 9500)))//判断是否是(引导码 | 重复码)
+        {
+            nec_state = 0x04;
+        }
+        else
+        {
+            nec_state = 0x00;
+            LOG_D("no 9000us:%d",state_code[0].us);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+static rt_err_t nec_decoder_write(struct infrared_decoder_data* data)
+{
+    struct ir_raw_data raw_data[100];
+    rt_uint8_t addr,key;
+    rt_uint32_t data_buff;
+
+    addr = data->data.nec.addr;
+    key = data->data.nec.key;
+
+    data_buff = ((addr & 0xFF) << 24) + ((~addr & 0xFF) << 16) + ((key & 0xff) << 8) + (~key & 0xFF);
+
+    /* guidance code */
+    raw_data[0].level = CARRIER_WAVE;
+    raw_data[0].us = 9000;
+    raw_data[1].level = IDLE_SIGNAL;
+    raw_data[1].us = 4500;
+
+    for(rt_uint8_t index = 0; index < 64; index+=2)
+    {
+        if(((data_buff << (index/2)) & 0x80000000))  /* Logic 1 */
+        {
+            raw_data[2+index].level = CARRIER_WAVE;
+            raw_data[2+index].us = 560;
+            raw_data[2+index+1].level = IDLE_SIGNAL;
+            raw_data[2+index+1].us = 1690;
+        }
+        else                                         /* Logic 0 */
+        {
+            raw_data[2+index].level = CARRIER_WAVE;
+            raw_data[2+index].us = 560;
+            raw_data[2+index+1].level = IDLE_SIGNAL;
+            raw_data[2+index+1].us = 560;
+        }
+    }
+
+    /* epilog code */
+    raw_data[66].level = CARRIER_WAVE;
+    raw_data[66].us = 560;
+    raw_data[67].level = IDLE_SIGNAL;
+    raw_data[67].us = 43580;
+
+    if(data->data.nec.repeat>8)
+    {
+        data->data.nec.repeat = 8;
+    }
+    /* repetition code */
+    for(rt_uint32_t i=0; i<(4 * data->data.nec.repeat); i+=4)
+    {
+        raw_data[68+i].level = CARRIER_WAVE;
+        raw_data[68+i].us = 9000;
+        raw_data[68+i+1].level = IDLE_SIGNAL;
+        raw_data[68+i+1].us = 2250;
+        raw_data[68+i+2].level = CARRIER_WAVE;
+        raw_data[68+i+2].us = 560;
+        raw_data[68+i+3].level = IDLE_SIGNAL;
+        raw_data[68+i+3].us = 43580;
+    }
+
+    LOG_D("%d size:%d + %d",sizeof(struct ir_raw_data),68 ,(data->data.nec.repeat) * 4);
+    decoder_write_data(raw_data,68 + (data->data.nec.repeat) * 4);
+
+    rt_thread_mdelay(200);
+
+    return RT_EOK;
+}
+
+static struct decoder_ops ops;
+
+int nec_decoder_register()
+{
+    nec_decoder.name = "nec";
+
+    ops.control = nec_decoder_control;
+    ops.decode = nec_decoder_decode;
+    ops.init = nec_decoder_init;
+    ops.deinit = nec_decoder_deinit;
+    ops.read = nec_decoder_read;
+    ops.write = nec_decoder_write;
+
+    nec_decoder.ops = &ops;
+
+    ir_decoder_register(&nec_decoder);
+    return 0;
+}
+INIT_APP_EXPORT(nec_decoder_register);
+
+#endif /* INFRARED_NEC_DECODER */