diff --git a/android-example/app/build.gradle b/android-example/app/build.gradle
index 623642e..21930da 100644
--- a/android-example/app/build.gradle
+++ b/android-example/app/build.gradle
@@ -1,7 +1,6 @@
apply plugin: 'com.android.application'
android {
- compileSdk 36
defaultConfig {
applicationId "net.irext.ircontrol"
targetSdkVersion 36
diff --git a/arduino-example/.gitignore b/arduino-example/.gitignore
index e2611ad..9b58f44 100644
--- a/arduino-example/.gitignore
+++ b/arduino-example/.gitignore
@@ -34,12 +34,10 @@ cmake-build-release/
*.lib
# CLion specific files
-.idea/workspace.xml
-.idea/user.prefs
-.idea/vcs.xml
-.idea/misc.xml
-.idea/*.iml
-.idea/*.xml
+.idea/*
+.idea/**
+*/.idea
+**/.idea
# Other temporary files
*.log
diff --git a/arduino-example/.idea/.gitignore b/arduino-example/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/arduino-example/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/arduino-example/.idea/editor.xml b/arduino-example/.idea/editor.xml
deleted file mode 100644
index 0b8104f..0000000
--- a/arduino-example/.idea/editor.xml
+++ /dev/null
@@ -1,255 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/arduino-example/.idea/misc.xml b/arduino-example/.idea/misc.xml
deleted file mode 100644
index d858eb1..0000000
--- a/arduino-example/.idea/misc.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/arduino-example/.idea/vcs.xml b/arduino-example/.idea/vcs.xml
deleted file mode 100644
index 6c0b863..0000000
--- a/arduino-example/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/arduino-example/include/README b/arduino-example/include/README
deleted file mode 100644
index 49819c0..0000000
--- a/arduino-example/include/README
+++ /dev/null
@@ -1,37 +0,0 @@
-
-This directory is intended for project header files.
-
-A header file is a file containing C declarations and macro definitions
-to be shared between several project source files. You request the use of a
-header file in your project source file (C, C++, etc) located in `src` folder
-by including it, with the C preprocessing directive `#include'.
-
-```src/main.c
-
-#include "header.h"
-
-int main (void)
-{
- ...
-}
-```
-
-Including a header file produces the same results as copying the header file
-into each source file that needs it. Such copying would be time-consuming
-and error-prone. With a header file, the related declarations appear
-in only one place. If they need to be changed, they can be changed in one
-place, and programs that include the header file will automatically use the
-new version when next recompiled. The header file eliminates the labor of
-finding and changing all the copies as well as the risk that a failure to
-find one copy will result in inconsistencies within a program.
-
-In C, the convention is to give header files names that end with `.h'.
-
-Read more about using header files in official GCC documentation:
-
-* Include Syntax
-* Include Operation
-* Once-Only Headers
-* Computed Includes
-
-https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/arduino-example/lib/README b/arduino-example/lib/README
deleted file mode 100644
index 9379397..0000000
--- a/arduino-example/lib/README
+++ /dev/null
@@ -1,46 +0,0 @@
-
-This directory is intended for project specific (private) libraries.
-PlatformIO will compile them to static libraries and link into the executable file.
-
-The source code of each library should be placed in a separate directory
-("lib/your_library_name/[Code]").
-
-For example, see the structure of the following example libraries `Foo` and `Bar`:
-
-|--lib
-| |
-| |--Bar
-| | |--docs
-| | |--examples
-| | |--src
-| | |- Bar.c
-| | |- Bar.h
-| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
-| |
-| |--Foo
-| | |- Foo.c
-| | |- Foo.h
-| |
-| |- README --> THIS FILE
-|
-|- platformio.ini
-|--src
- |- main.c
-
-Example contents of `src/main.c` using Foo and Bar:
-```
-#include
-#include
-
-int main (void)
-{
- ...
-}
-
-```
-
-The PlatformIO Library Dependency Finder will find automatically dependent
-libraries by scanning project source files.
-
-More information about PlatformIO Library Dependency Finder
-- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/arduino-example/platformio.ini b/arduino-example/platformio.ini
index f40a5b9..423f0d7 100644
--- a/arduino-example/platformio.ini
+++ b/arduino-example/platformio.ini
@@ -16,4 +16,6 @@ upload_port = /dev/ttyACM0
monitor_port = /dev/ttyACM0
monitor_speed = 115200
lib_deps =
- WiFiS3
\ No newline at end of file
+ WiFiS3
+ ArduinoGraphics
+ Arduino_LED_Matrix
\ No newline at end of file
diff --git a/arduino-example/src/configure.h b/arduino-example/src/configure.h
index 28cb877..ef4fc6e 100644
--- a/arduino-example/src/configure.h
+++ b/arduino-example/src/configure.h
@@ -1,11 +1,64 @@
-//
-// Created by strawmanbobi on 10/14/25.
-//
+/**
+ *
+ * Copyright (c) 2020-2025 IRext Opensource Organization
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
#ifndef ARDUINO_EXAMPLE_CONFIGURE_H
#define ARDUINO_EXAMPLE_CONFIGURE_H
-#define SECRET_SSID "Maomao的小房子"
-#define SECRET_PASS "Maomao121207"
+#include
+
+// Wi-Fi Configs
+#define SECRET_SSID "maomao"
+#define SECRET_PASS "20121207"
+
+// LED Matrix Definitions
+constexpr uint32_t chip[] = {
+ 0x1503f811,
+ 0x3181103,
+ 0xf8150000
+};
+
+constexpr uint32_t danger[] = {
+ 0x400a015,
+ 0x1502082,
+ 0x484047fc
+};
+
+constexpr uint32_t happy[] = {
+ 0x19819,
+ 0x80000001,
+ 0x81f8000
+};
+
+constexpr uint32_t heart[] = {
+ 0x3184a444,
+ 0x44042081,
+ 0x100a0040
+};
+
+constexpr uint32_t fullOn[] = {
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff
+};
#endif //ARDUINO_EXAMPLE_CONFIGURE_H
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_ac_apply.h b/arduino-example/src/ir_decode/include/ir_ac_apply.h
new file mode 100644
index 0000000..af68831
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_ac_apply.h
@@ -0,0 +1,47 @@
+/**************************************************************************************
+Filename: ir_ac_apply.h
+Revised: Date: 2016-10-12
+Revision: Revision: 1.0
+
+Description: This file provides methods for AC IR applying functionalities
+
+Revision log:
+* 2016-10-12: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_APPLY_H_
+#define _IR_APPLY_H_
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "OCUnusedMacroInspection"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_decode.h"
+
+#define MIN_TAG_LENGTH_TYPE_1 4
+#define MIN_TAG_LENGTH_TYPE_2 6
+
+INT8 apply_power(t_remote_ac_status ac_status, UINT8 function_code);
+
+INT8 apply_mode(t_remote_ac_status ac_status, UINT8 function_code);
+
+INT8 apply_wind_speed(t_remote_ac_status ac_status, UINT8 function_code);
+
+INT8 apply_swing(t_remote_ac_status ac_status, UINT8 function_code);
+
+INT8 apply_temperature(t_remote_ac_status ac_status, UINT8 function_code);
+
+INT8 apply_function(struct ac_protocol *protocol, UINT8 function);
+
+INT8 apply_checksum(struct ac_protocol *protocol);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IR_APPLY_H_
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_ac_binary_parse.h b/arduino-example/src/ir_decode/include/ir_ac_binary_parse.h
new file mode 100644
index 0000000..a24ed79
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_ac_binary_parse.h
@@ -0,0 +1,35 @@
+/**************************************************************************************
+Filename: ir_ac_binary_parse.h
+Revised: Date: 2017-01-03
+Revision: Revision: 1.0
+
+Description: This file provides methods for AC binary parse
+
+Revision log:
+* 2017-01-03: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_DECODER_IR_AC_BINARY_PARSE_H
+#define _IR_DECODER_IR_AC_BINARY_PARSE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_defs.h"
+
+extern INT8 binary_parse_offset();
+
+extern INT8 binary_parse_len();
+
+extern void binary_tags_info();
+
+extern INT8 binary_parse_data();
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _IR_DECODER_IR_AC_BINARY_PARSE_H
diff --git a/arduino-example/src/ir_decode/include/ir_ac_build_frame.h b/arduino-example/src/ir_decode/include/ir_ac_build_frame.h
new file mode 100644
index 0000000..f77274d
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_ac_build_frame.h
@@ -0,0 +1,28 @@
+/**************************************************************************************
+Filename: ir_ac_build_frame.h
+Revised: Date: 2016-10-26
+Revision: Revision: 1.0
+
+Description: This file provides generic utils for IR frame build
+
+Revision log:
+* 2016-10-01: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_IRFRAME_H_
+#define _IR_IRFRAME_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_defs.h"
+
+extern UINT16 create_ir_frame();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IR_IRFRAME_H_
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_ac_control.h b/arduino-example/src/ir_decode/include/ir_ac_control.h
new file mode 100644
index 0000000..68bf99f
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_ac_control.h
@@ -0,0 +1,443 @@
+/**************************************************************************************
+Filename: ir_ac_control.h
+Revised: Date: 2016-12-31
+Revision: Revision: 1.0
+
+Description: This file provides methods for AC IR control
+
+Revision log:
+* 2016-10-12: created by strawmanbobi
+**************************************************************************************/
+#ifndef _IR_DECODER_IR_AC_CONTROL_H
+#define _IR_DECODER_IR_AC_CONTROL_H
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_defs.h"
+
+
+#define TAG_COUNT_FOR_PROTOCOL 29
+
+#define TAG_INVALID 0xffff
+
+#define MAX_DELAYCODE_NUM 16
+#define MAX_BITNUM 16
+
+#define AC_PARAMETER_TYPE_1 0
+#define AC_PARAMETER_TYPE_2 1
+
+typedef enum
+{
+ AC_POWER_ON = 0,
+ AC_POWER_OFF,
+ AC_POWER_MAX
+} t_ac_power;
+
+typedef enum
+{
+ AC_TEMP_16 = 0,
+ AC_TEMP_17,
+ AC_TEMP_18,
+ AC_TEMP_19,
+ AC_TEMP_20,
+ AC_TEMP_21,
+ AC_TEMP_22,
+ AC_TEMP_23,
+ AC_TEMP_24,
+ AC_TEMP_25,
+ AC_TEMP_26,
+ AC_TEMP_27,
+ AC_TEMP_28,
+ AC_TEMP_29,
+ AC_TEMP_30,
+ AC_TEMP_MAX
+} t_ac_temperature;
+
+typedef enum
+{
+ AC_MODE_COOL = 0,
+ AC_MODE_HEAT,
+ AC_MODE_AUTO,
+ AC_MODE_FAN,
+ AC_MODE_DRY,
+ AC_MODE_MAX
+} t_ac_mode;
+
+typedef enum
+{
+ AC_FUNCTION_POWER = 1,
+ AC_FUNCTION_MODE,
+ AC_FUNCTION_TEMPERATURE_UP,
+ AC_FUNCTION_TEMPERATURE_DOWN,
+ AC_FUNCTION_WIND_SPEED,
+ AC_FUNCTION_WIND_SWING,
+ AC_FUNCTION_WIND_FIX,
+ AC_FUNCTION_MAX,
+} t_ac_function;
+
+typedef enum
+{
+ AC_WS_AUTO = 0,
+ AC_WS_LOW,
+ AC_WS_MEDIUM,
+ AC_WS_HIGH,
+ AC_WS_MAX
+} t_ac_wind_speed;
+
+typedef enum
+{
+ AC_SWING_ON = 0,
+ AC_SWING_OFF,
+ AC_SWING_MAX
+} t_ac_swing;
+
+typedef enum
+{
+ SWING_TYPE_SWING_ONLY = 0,
+ SWING_TYPE_NORMAL,
+ SWING_TYPE_NOT_SPECIFIED,
+ SWING_TYPE_MAX
+} swing_type;
+
+typedef enum
+{
+ TEMP_TYPE_DYNAMIC = 0,
+ TEMP_TYPE_STATIC,
+ TEMP_TYPE_MAX,
+} t_temp_type;
+
+// enumeration for application polymorphism
+typedef enum
+{
+ AC_APPLY_POWER = 0,
+ AC_APPLY_MODE,
+ AC_APPLY_TEMPERATURE_UP,
+ AC_APPLY_TEMPERATURE_DOWN,
+ AC_APPLY_WIND_SPEED,
+ AC_APPLY_WIND_SWING,
+ AC_APPLY_WIND_FIX,
+ AC_APPLY_MAX
+} t_ac_apply;
+
+typedef struct ac_hex
+{
+ UINT8 len;
+ UINT8 *data;
+} t_ac_hex;
+
+typedef struct ac_level
+{
+ UINT16 low;
+ UINT16 high;
+} t_ac_level;
+
+typedef struct ac_bootcode
+{
+ UINT16 len;
+ UINT16 data[16];
+} t_ac_boot_code;
+
+typedef struct ac_delay_code
+{
+ INT16 pos;
+ UINT16 time[8];
+ UINT16 time_cnt;
+} t_ac_delay_code;
+
+/*
+ * the array of tag_100X application data
+ * seg_len : length for each segment
+ * byte_pos : the position of update byte
+ * byte_value : the value to be updated to position
+ */
+typedef struct tag_comp_type_1
+{
+ UINT8 seg_len;
+ UINT8 *segment;
+} t_tag_comp;
+
+typedef struct tag_swing_info
+{
+ swing_type type;
+ UINT8 mode_count;
+ UINT8 dir_index;
+} t_swing_info;
+
+typedef struct tag_power_1
+{
+ UINT8 len;
+ t_tag_comp comp_data[AC_POWER_MAX];
+} t_power_1;
+
+typedef struct tag_temp_1
+{
+ UINT8 len;
+ UINT8 type;
+ t_tag_comp comp_data[AC_TEMP_MAX];
+} t_temp_1;
+
+typedef struct tag_mode_1
+{
+ UINT8 len;
+ t_tag_comp comp_data[AC_MODE_MAX];
+} t_mode_1;
+
+typedef struct tag_speed_1
+{
+ UINT8 len;
+ t_tag_comp comp_data[AC_WS_MAX];
+} t_speed_1;
+
+typedef struct tag_swing_1
+{
+ UINT8 len;
+ UINT16 count;
+ t_tag_comp *comp_data;
+} t_swing_1;
+
+typedef struct tag_temp_2
+{
+ UINT8 len;
+ UINT8 type;
+ t_tag_comp comp_data[AC_TEMP_MAX];
+} t_temp_2;
+
+typedef struct tag_mode_2
+{
+ UINT8 len;
+ t_tag_comp comp_data[AC_MODE_MAX];
+} t_mode_2;
+
+typedef struct tag_speed_2
+{
+ UINT8 len;
+ t_tag_comp comp_data[AC_WS_MAX];
+} t_speed_2;
+
+typedef struct tag_swing_2
+{
+ UINT8 len;
+ UINT16 count;
+ t_tag_comp *comp_data;
+} t_swing_2;
+
+#if defined SUPPORT_HORIZONTAL_SWING
+typedef struct tag_horiswing_1
+{
+ UINT16 len;
+ t_tag_comp comp_data[AC_HORI_SWING_MAX];
+} hori_swing_1;
+#endif
+
+typedef struct tag_checksum_data
+{
+ UINT8 len;
+ UINT8 type;
+ UINT8 start_byte_pos;
+ UINT8 end_byte_pos;
+ UINT8 checksum_byte_pos;
+ UINT8 checksum_plus;
+ UINT8 *spec_pos;
+} t_tag_checksum_data;
+
+typedef struct tag_checksum
+{
+ UINT8 len;
+ UINT16 count;
+ t_tag_checksum_data *checksum_data;
+} t_checksum;
+
+typedef struct tag_function_1
+{
+ UINT8 len;
+ t_tag_comp comp_data[AC_FUNCTION_MAX - 1];
+} t_function_1;
+
+typedef struct tag_function_2
+{
+ UINT8 len;
+ t_tag_comp comp_data[AC_FUNCTION_MAX - 1];
+} t_function_2;
+
+typedef struct tag_solo_code
+{
+ UINT8 len;
+ UINT8 solo_func_count;
+ UINT8 solo_function_codes[AC_FUNCTION_MAX - 1];
+} t_solo_code;
+
+typedef struct ac_bitnum
+{
+ INT16 pos;
+ UINT16 bits;
+} t_ac_bit_num;
+
+typedef enum
+{
+ N_COOL = 0,
+ N_HEAT,
+ N_AUTO,
+ N_FAN,
+ N_DRY,
+ N_MODE_MAX,
+} t_ac_n_mode;
+
+typedef enum
+{
+ CHECKSUM_TYPE_BYTE = 1,
+ CHECKSUM_TYPE_BYTE_INVERSE,
+ CHECKSUM_TYPE_HALF_BYTE,
+ CHECKSUM_TYPE_HALF_BYTE_INVERSE,
+ CHECKSUM_TYPE_SPEC_HALF_BYTE,
+ CHECKSUM_TYPE_SPEC_HALF_BYTE_INVERSE,
+ CHECKSUM_TYPE_SPEC_HALF_BYTE_ONE_BYTE,
+ CHECKSUM_TYPE_SPEC_HALF_BYTE_INVERSE_ONE_BYTE,
+ CHECKSUM_TYPE_MAX,
+} t_checksum_type;
+
+typedef struct ac_n_mode_info
+{
+ UINT8 enable;
+ UINT8 all_speed;
+ UINT8 all_temp;
+ UINT8 temp[AC_TEMP_MAX];
+ UINT8 temp_cnt;
+ UINT8 speed[AC_WS_MAX];
+ UINT8 speed_cnt;
+} t_ac_n_mode_info;
+
+typedef struct ac_protocol
+{
+ UINT8 endian;
+ // t_ac_hex default_code;
+ t_ac_hex default_code;
+ t_ac_level zero;
+ t_ac_level one;
+ t_ac_boot_code boot_code;
+ t_ac_delay_code dc[MAX_DELAYCODE_NUM];
+ t_power_1 power1;
+ t_temp_1 temp1;
+ t_mode_1 mode1;
+ t_speed_1 speed1;
+ t_swing_1 swing1;
+ t_checksum checksum;
+
+ t_function_1 function1;
+ t_function_2 function2;
+
+ t_temp_2 temp2;
+ t_mode_2 mode2;
+ t_speed_2 speed2;
+ t_swing_2 swing2;
+
+ t_swing_info si;
+ t_solo_code sc;
+
+ UINT8 swing_status;
+
+ BOOL change_wind_direction;
+
+ UINT16 dc_cnt;
+ t_ac_bit_num bit_num[MAX_BITNUM];
+ UINT16 bit_num_cnt;
+ UINT16 repeat_times;
+ t_ac_n_mode_info n_mode[N_MODE_MAX];
+ UINT16 code_cnt;
+ UINT8 last_bit;
+ UINT16 *time;
+ UINT8 solo_function_mark;
+
+ UINT16 frame_length;
+} t_ac_protocol;
+
+typedef struct tag_head
+{
+ UINT16 tag;
+ UINT16 len;
+ UINT16 offset;
+ UINT8 *p_data;
+} t_tag_head;
+
+struct ir_bin_buffer
+{
+ UINT8 *data;
+ UINT16 len;
+ UINT16 offset;
+};
+
+typedef struct REMOTE_AC_STATUS
+{
+ t_ac_power ac_power;
+ t_ac_temperature ac_temp;
+ t_ac_mode ac_mode;
+ t_ac_swing ac_wind_dir;
+ t_ac_wind_speed ac_wind_speed;
+ UINT8 ac_display;
+ UINT8 ac_sleep;
+ UINT8 ac_timer;
+} t_remote_ac_status;
+
+// function polymorphism
+typedef INT8 (*lp_apply_ac_parameter)(t_remote_ac_status ac_status, UINT8 function_code);
+
+#define TAG_AC_BOOT_CODE 1
+#define TAG_AC_ZERO 2
+#define TAG_AC_ONE 3
+#define TAG_AC_DELAY_CODE 4
+#define TAG_AC_FRAME_LENGTH 5
+#define TAG_AC_ENDIAN 6
+#define TAG_AC_LAST_BIT 7
+
+#define TAG_AC_POWER_1 21
+#define TAG_AC_DEFAULT_CODE 22
+#define TAG_AC_TEMP_1 23
+#define TAG_AC_MODE_1 24
+#define TAG_AC_SPEED_1 25
+#define TAG_AC_SWING_1 26
+#define TAG_AC_CHECKSUM_TYPE 27
+#define TAG_AC_SOLO_FUNCTION 28
+#define TAG_AC_FUNCTION_1 29
+#define TAG_AC_TEMP_2 30
+#define TAG_AC_MODE_2 31
+#define TAG_AC_SPEED_2 32
+#define TAG_AC_SWING_2 33
+#define TAG_AC_FUNCTION_2 34
+
+#define TAG_AC_BAN_FUNCTION_IN_COOL_MODE 41
+#define TAG_AC_BAN_FUNCTION_IN_HEAT_MODE 42
+#define TAG_AC_BAN_FUNCTION_IN_AUTO_MODE 43
+#define TAG_AC_BAN_FUNCTION_IN_FAN_MODE 44
+#define TAG_AC_BAN_FUNCTION_IN_DRY_MODE 45
+#define TAG_AC_SWING_INFO 46
+#define TAG_AC_REPEAT_TIMES 47
+#define TAG_AC_BIT_NUM 48
+
+
+// definition about size
+
+#define PROTOCOL_SIZE (sizeof(t_ac_protocol))
+
+/* exported variables */
+extern UINT8 *ir_hex_code;
+extern UINT8 ir_hex_len;
+extern t_ac_protocol *context;
+
+
+extern INT8 ir_ac_lib_parse();
+
+extern INT8 free_ac_context();
+
+extern BOOL is_solo_function(UINT8 function_code);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IR_DECODER_IR_AC_CONTROL_H
diff --git a/arduino-example/src/ir_decode/include/ir_ac_parse_forbidden_info.h b/arduino-example/src/ir_decode/include/ir_ac_parse_forbidden_info.h
new file mode 100644
index 0000000..ce86c1e
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_ac_parse_forbidden_info.h
@@ -0,0 +1,29 @@
+/**************************************************************************************
+Filename: ir_ac_parse_forbidden_info.h
+Revised: Date: 2016-10-05
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for forbidden area of AC code
+
+Revision log:
+* 2016-10-05: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_PARSE_PARSE_H_
+#define _IR_PARSE_PARSE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_decode.h"
+
+extern INT8 parse_nmode(struct tag_head *tag, t_ac_n_mode index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IR_PARSE_PARSE_H_
+
diff --git a/arduino-example/src/ir_decode/include/ir_ac_parse_frame_info.h b/arduino-example/src/ir_decode/include/ir_ac_parse_frame_info.h
new file mode 100644
index 0000000..3ca3667
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_ac_parse_frame_info.h
@@ -0,0 +1,44 @@
+/**************************************************************************************
+Filename: ir_ac_parse_frame_info.h
+Revised: Date: 2016-10-11
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode for AC frame parameters
+
+Revision log:
+* 2016-10-11: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_PARSE_FRAME_PARAMETER_H_
+#define _IR_PARSE_FRAME_PARAMETER_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_decode.h"
+
+extern INT8 parse_boot_code(struct tag_head *tag);
+
+extern INT8 parse_zero(struct tag_head *tag);
+
+extern INT8 parse_one(struct tag_head *tag);
+
+extern INT8 parse_delay_code(struct tag_head *tag);
+
+extern INT8 parse_frame_len(struct tag_head *tag, UINT16 len);
+
+extern INT8 parse_endian(struct tag_head *tag);
+
+extern INT8 parse_lastbit(struct tag_head *tag);
+
+extern INT8 parse_repeat_times(struct tag_head *tag);
+
+extern INT8 parse_bit_num(struct tag_head *tag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IR_PARSE_FRAME_PARAMETER_H_
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_ac_parse_parameter.h b/arduino-example/src/ir_decode/include/ir_ac_parse_parameter.h
new file mode 100644
index 0000000..78680e8
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_ac_parse_parameter.h
@@ -0,0 +1,58 @@
+/**************************************************************************************
+Filename: ir_ac_parse_parameter.h
+Revised: Date: 2016-10-12
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode for AC functionality parameters
+
+Revision log:
+* 2016-10-12: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_PARSE_AC_PARAMETER_H_
+#define _IR_PARSE_AC_PARAMETER_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_decode.h"
+
+extern INT8 parse_common_ac_parameter(t_tag_head *tag, t_tag_comp *comp_data, UINT8 with_end, UINT8 type);
+
+extern INT8 parse_default_code(struct tag_head *tag, t_ac_hex *default_code);
+
+extern INT8 parse_power_1(struct tag_head *tag, t_power_1 *power1);
+
+extern INT8 parse_temp_1(struct tag_head *tag, t_temp_1 *temp1);
+
+extern INT8 parse_mode_1(struct tag_head *tag, t_mode_1 *mode1);
+
+extern INT8 parse_speed_1(struct tag_head *tag, t_speed_1 *speed1);
+
+extern INT8 parse_swing_1(struct tag_head *tag, t_swing_1 *swing1, UINT16 swing_count);
+
+extern INT8 parse_checksum(struct tag_head *tag, t_checksum *checksum);
+
+extern INT8 parse_function_1_tag29(struct tag_head *tag, t_function_1 *function1);
+
+extern INT8 parse_temp_2(struct tag_head *tag, t_temp_2 *temp2);
+
+extern INT8 parse_mode_2(struct tag_head *tag, t_mode_2 *mode2);
+
+extern INT8 parse_speed_2(struct tag_head *tag, t_speed_2 *speed2);
+
+extern INT8 parse_swing_2(struct tag_head *tag, t_swing_2 *swing2, UINT16 swing_count);
+
+extern INT8 parse_function_2_tag34(struct tag_head *tag, t_function_2 *function2);
+
+extern INT8 parse_swing_info(struct tag_head *tag, t_swing_info *si);
+
+extern INT8 parse_solo_code(struct tag_head *tag, t_solo_code *sc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IR_PARSE_AC_PARAMETER_H_
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_decode.h b/arduino-example/src/ir_decode/include/ir_decode.h
new file mode 100644
index 0000000..6d7ebeb
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_decode.h
@@ -0,0 +1,371 @@
+/**************************************************************************************
+Filename: ir_decode.h
+Revised: Date: 2016-10-01
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode
+
+Revision log:
+* 2016-10-01: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_DECODE_H_
+#define _IR_DECODE_H_
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
+#pragma ide diagnostic ignored "OCUnusedMacroInspection"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include
+#include "ir_defs.h"
+#include "ir_ac_control.h"
+#include "ir_tv_control.h"
+
+#define IR_DECODE_FAILED (-1)
+#define IR_DECODE_SUCCEEDED (0)
+
+#define IR_TYPE_STATUS 0
+#define IR_TYPE_COMMANDS 1
+
+// remote control key definition
+#define KEY_TV_POWER 0
+#define KEY_TV_MUTE 1
+#define KEY_TV_UP 2
+#define KEY_TV_DOWN 3
+#define KEY_TV_LEFT 4
+#define KEY_TV_RIGHT 5
+#define KEY_TV_OK 6
+#define KEY_TV_VOL_PLUS 7
+#define KEY_TV_VOL_MINUS 8
+#define KEY_TV_BACK 9
+#define KEY_TV_INPUT 10
+#define KEY_TV_MENU 11
+#define KEY_TV_HOME 12
+#define KEY_TV_SETTINGS 13
+
+#define KEY_AC_POWER 0
+#define KEY_AC_MODE_SWITCH 1
+#define KEY_AC_TEMP_PLUS 2
+#define KEY_AC_TEMP_MINUS 3
+#define KEY_AC_WIND_SPEED 9
+#define KEY_AC_WIND_SWING 10
+#define KEY_AC_WIND_FIX 11
+
+#define KEY_STB_POWER 0
+#define KEY_STB_MUTE 1
+#define KEY_STB_UP 2
+#define KEY_STB_DOWN 3
+#define KEY_STB_LEFT 4
+#define KEY_STB_RIGHT 5
+#define KEY_STB_OK 6
+#define KEY_STB_VOL_PLUS 7
+#define KEY_STB_VOL_MINUS 8
+#define KEY_STB_BACK 9
+#define KEY_STB_INPUT 10
+#define KEY_STB_MENU 11
+#define KEY_STB_PAGE_UP 12
+#define KEY_STB_PAGE_DOWN 13
+
+#define KEY_NETBOX_POWER 0
+#define KEY_NETBOX_UP 1
+#define KEY_NETBOX_DOWN 2
+#define KEY_NETBOX_LEFT 3
+#define KEY_NETBOX_RIGHT 4
+#define KEY_NETBOX_OK 5
+#define KEY_NETBOX_VOL_PLUS 6
+#define KEY_NETBOX_VOL_MINUS 7
+#define KEY_NETBOX_BACK 8
+#define KEY_NETBOX_MENU 9
+#define KEY_NETBOX_HOME 10
+
+#define KEY_IPTV_POWER 0
+#define KEY_IPTV_MUTE 1
+#define KEY_IPTV_UP 2
+#define KEY_IPTV_DOWN 3
+#define KEY_IPTV_LEFT 4
+#define KEY_IPTV_RIGHT 5
+#define KEY_IPTV_OK 6
+#define KEY_IPTV_VOL_PLUS 7
+#define KEY_IPTV_VOL_MINUS 8
+#define KEY_IPTV_BACK 9
+#define KEY_IPTV_INPUT 10
+#define KEY_IPTV_MENU 11
+#define KEY_IPTV_PAGE_UP 12
+#define KEY_IPTV_PAGE_DOWN 13
+
+#define KEY_DVD_POWER 0
+#define KEY_DVD_UP 1
+#define KEY_DVD_DOWN 2
+#define KEY_DVD_LEFT 3
+#define KEY_DVD_RIGHT 4
+#define KEY_DVD_OK 5
+#define KEY_DVD_VOL_PLUS 6
+#define KEY_DVD_VOL_MINUS 7
+#define KEY_DVD_PLAY 8
+#define KEY_DVD_PAUSE 9
+#define KEY_DVD_EJECT 10
+#define KEY_DVD_REWIND 11
+#define KEY_DVD_FASTFORWARD 12
+#define KEY_DVD_MENU 13
+
+#define KEY_FAN_POWER 0
+#define KEY_FAN_WIND_PLUS 6
+#define KEY_FAN_WIND_MUNIS 7
+#define KEY_FAN_SWING 8
+#define KEY_FAN_WIND_SPEED 9
+#define KEY_FAN_WIND_TYPE 10
+
+#define KEY_PROJECTOR_POWER 0
+#define KEY_PROJECTOR_UP 1
+#define KEY_PROJECTOR_DOWN 2
+#define KEY_PROJECTOR_LEFT 3
+#define KEY_PROJECTOR_RIGHT 4
+#define KEY_PROJECTOR_OK 5
+#define KEY_PROJECTOR_VOL_PLUS 6
+#define KEY_PROJECTOR_VOL_MINUS 7
+#define KEY_PROJECTOR_ZOOM_OUT 8
+#define KEY_PROJECTOR_MENU 9
+#define KEY_PROJECTOR_ZOOM_IN 10
+#define KEY_PROJECTOR_BACK 11
+
+#define KEY_STEREO_POWER 0
+#define KEY_STEREO_UP 1
+#define KEY_STEREO_DOWN 2
+#define KEY_STEREO_LEFT 3
+#define KEY_STEREO_RIGHT 4
+#define KEY_STEREO_OK 5
+#define KEY_STEREO_VOL_PLUS 6
+#define KEY_STEREO_VOL_MINUS 7
+#define KEY_STEREO_MUTE 8
+#define KEY_STEREO_MENU 9
+
+#define KEY_BULB_POWER 0
+#define KEY_BULB_COLOR_1 1
+#define KEY_BULB_COLOR_2 2
+#define KEY_BULB_COLOR_3 3
+#define KEY_BULB_COLOR_4 4
+#define KEY_BULB_COLOR_0 5
+#define KEY_BULB_BRIGHT_PLUS 6
+#define KEY_BULB_BRIGHT_MINUS 7
+#define KEY_BULB_BRIGHT_POWER_ON 8
+#define KEY_BULB_BRIGHT_RAINBOW 9
+#define KEY_BULB_BRIGHT_POWER_OFF 10
+
+#define KEY_CLEANROBOT_POWER 0
+#define KEY_CLEANROBOT_FOWWARD 1
+#define KEY_CLEANROBOT_BACKWARD 2
+#define KEY_CLEANROBOT_LEFT 3
+#define KEY_CLEANROBOT_RIGHT 4
+#define KEY_CLEANROBOT_START 5
+#define KEY_CLEANROBOT_STOP 6
+#define KEY_CLEANROBOT_AUTO 8
+#define KEY_CLEANROBOT_SPOT 9
+#define KEY_CLEANROBOT_SPEED 10
+#define KEY_CLEANROBOT_TIMER 11
+#define KEY_CLEANROBOT_CHARGE 12
+#define KEY_CLEANROBOT_PRESERVE 13
+
+#define KEY_AIRCLEANER_POWER 0
+#define KEY_AIRCLEANER_ION 5
+#define KEY_AIRCLEANER_AUTO 8
+#define KEY_AIRCLEANER_WIND_SPEED 9
+#define KEY_AIRCLEANER_MODE_SWITCH 10
+#define KEY_AIRCLEANER_TIMER 11
+#define KEY_AIRCLEANER_LIGHT 12
+#define KEY_AIRCLEANER_FORCE 13
+
+#define KEY_DYSON_POWER 0
+#define KEY_DYSON_WIND_SPEED_PLUS 1
+#define KEY_DYSON_WIND_SPEED_MINUS 2
+#define KEY_DYSON_TIMER_MINUS 3
+#define KEY_DYSON_TIMER_PLUS 4
+#define KEY_DYSON_AUTO 5
+#define KEY_DYSON_TEMP_PLUS 6
+#define KEY_DYSON_TEMP_MINUS 7
+#define KEY_DYSON_SWING 8
+#define KEY_DYSON_DIFFUSION 9
+#define KEY_DYSON_FAV 10
+#define KEY_DYSON_TIMER 11
+#define KEY_DYSON_SLEEP 12
+#define KEY_DYSON_COOL 13
+
+#define STANDARD_KEY_COUNT 14
+#define CHANNEL_KEY_COUNT 10
+
+typedef enum
+{
+ REMOTE_CATEGORY_NONE = 0,
+ REMOTE_CATEGORY_AC = 1,
+ REMOTE_CATEGORY_TV = 2,
+ REMOTE_CATEGORY_STB = 3,
+ REMOTE_CATEGORY_NETBOX = 4,
+ REMOTE_CATEGORY_IPTV = 5,
+ REMOTE_CATEGORY_DVD = 6,
+ REMOTE_CATEGORY_FAN = 7,
+ REMOTE_CATEGORY_PROJECTOR = 8,
+ REMOTE_CATEGORY_STEREO = 9,
+ REMOTE_CATEGORY_LIGHT = 10,
+ REMOTE_CATEGORY_BSTB = 11,
+ REMOTE_CATEGORY_CLEANING_ROBOT = 12,
+ REMOTE_CATEGORY_AREMOTE_CLEANER = 13,
+ REMOTE_CATEGORY_DYSON = 14,
+ REMOTE_CATEGORY_NEXT,
+ REMOTE_CATEGORY_MAX = 64,
+} t_remote_category;
+
+typedef enum
+{
+ SUB_CATEGORY_BINARY = 0, // deprecated
+ SUB_CATEGORY_QUATERNARY = 1,
+ SUB_CATEGORY_HEXADECIMAL = 2,
+ SUB_CATEGORY_NEXT = 3,
+ SUB_CATEGORY_MAX = 4,
+} t_remote_sub_category;
+
+/**
+ * function get_lib_version
+ *
+ * description: get version of library
+ *
+ * parameters: N/A
+ *
+ * returns: the string contains library version
+ *
+ */
+extern const char* get_lib_version();
+
+/**
+ * function ir_file_open
+ *
+ * description: open IR binary code from file
+ *
+ * parameters: category (in) - category ID get from indexing API
+ * sub_category (in) - subcategory ID get from indexing API
+ * file_name (in) - file name of IR binary
+ *
+ * returns: IR_DECODE_SUCCEEDED / IR_DECODE_FAILED
+ *
+ */
+extern INT8 ir_file_open(const UINT8 category, const UINT8 sub_category, const char* file_name);
+
+/**
+ * function ir_binary_open
+ *
+ * description: open IR binary code from buffer
+ *
+ * parameters: category (in) - category ID get from indexing API
+ * sub_category (in) - subcategory ID get from indexing API
+ * binary (in) - pointer to binary buffer
+ * bin_length (in) - binary buffer size
+ *
+ * returns: IR_DECODE_SUCCEEDED / IR_DECODE_FAILED
+ */
+extern INT8 ir_binary_open(const UINT8 category, const UINT8 sub_category, UINT8* binary, UINT16 bin_length);
+
+/**
+ * function ir_decode
+ *
+ * description: decode IR binary into INT16 array which indicates the IR levels
+ *
+ * parameters: key_code (in) - the code of pressed key
+ * user_data (out) - output decoded data in INT16 array format
+ * ac_status(in) - pointer to AC status (optional)
+ * change_wind_direction (in) - if control changes wind direction for AC (for AC only)
+ *
+ * returns: length of decoded data (0 indicates decode failure)
+ */
+extern UINT16 ir_decode(UINT8 key_code, UINT16* user_data, t_remote_ac_status* ac_status, BOOL change_wind_direction);
+
+/**
+ * function ir_close
+ *
+ * description: close IR binary code
+ *
+ * parameters: N/A
+ *
+ * returns: IR_DECODE_SUCCEEDED / IR_DECODE_FAILED
+ */
+extern INT8 ir_close();
+
+/**
+ * function get_temperature_range
+ *
+ * description: get the supported temperature range [min, max] for the opened AC IR binary
+ *
+ * parameters: ac_mode (in) specify in which AC mode the application need to get temperature info
+ * temp_min (out) the min temperature supported in a specified AC mode
+ * temp_max (out) the max temperature supported in a specified AC mode
+ *
+ * returns: IR_DECODE_SUCCEEDED / IR_DECODE_FAILED
+ */
+extern INT8 get_temperature_range(UINT8 ac_mode, INT8 *temp_min, INT8 *temp_max);
+
+/**
+ * function get_supported_mode
+ *
+ * description: get supported mode for the opened AC IR binary
+ *
+ * parameters: supported_mode (out) mode supported by the remote in lower 5 bits
+ *
+ * returns: IR_DECODE_SUCCEEDED / IR_DECODE_FAILED
+ */
+extern INT8 get_supported_mode(UINT8 *supported_mode);
+
+/**
+ * function get_supported_wind_speed
+ *
+ * description: get supported wind speed levels for the opened AC IR binary in certain mode
+ *
+ * parameters: ac_mode (in) specify in which AC mode the application need to get wind speed info
+ * supported_wind_speed (out) wind speed supported by the remote in lower 4 bits
+ *
+ * returns: IR_DECODE_SUCCEEDED / IR_DECODE_FAILED
+ */
+extern INT8 get_supported_wind_speed(UINT8 ac_mode, UINT8 *supported_wind_speed);
+
+/**
+ * function get_supported_swing
+ *
+ * description: get supported swing functions for the opened AC IR binary in certain mode
+ *
+ * parameters: ac_mode (in) specify in which AC mode the application need to get swing info
+ * supported_swing (out) swing supported by the remote in lower 2 bits
+ *
+ * returns: IR_DECODE_SUCCEEDED / IR_DECODE_FAILED
+ */
+extern INT8 get_supported_swing(UINT8 ac_mode, UINT8 *supported_swing);
+
+/**
+ * function get_supported_wind_direction
+ *
+ * description: get supported wind directions for the opened AC IR binary in certain mode
+ *
+ * parameters: supported_wind_direction (out) swing supported by the remote in lower 2 bits
+ *
+ * returns: IR_DECODE_SUCCEEDED / IR_DECODE_FAILED
+ */
+extern INT8 get_supported_wind_direction(UINT8 *supported_wind_direction);
+
+
+// private extern function
+#if (defined BOARD_PC || defined BOARD_PC_DLL)
+extern void ir_lib_free_inner_buffer();
+#endif
+
+// this function is preferred being called by JNI only
+UINT16 ir_decode_combo(const UINT8 category, const UINT8 sub_category,
+ UINT8* binary, UINT16 bin_length,
+ UINT8 key_code, UINT16* user_data,
+ t_remote_ac_status* ac_status, BOOL change_wind_direction);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IR_DECODE_H_
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_defs.h b/arduino-example/src/ir_decode/include/ir_defs.h
new file mode 100644
index 0000000..dc471ec
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_defs.h
@@ -0,0 +1,71 @@
+/**************************************************************************************
+Filename: ir_defs.h
+Revised: Date: 2016-10-26
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode
+
+Revision log:
+* 2016-10-01: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_DEFS_H
+#define _IR_DEFS_H
+
+#define IR_DECODE_LIB_VER "1.5.0"
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
+#pragma ide diagnostic ignored "OCUnusedMacroInspection"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined BOARD_ANDROID
+#include
+#define LOG_TAG "ir_decode"
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#define FORMAT_HEX 16
+#define FORMAT_DECIMAL 10
+
+// #define USE_DYNAMIC_TAG 1
+
+#if defined USE_DYNAMIC_TAG
+#include
+#endif
+
+typedef unsigned char UINT8;
+typedef signed char INT8;
+typedef unsigned short UINT16;
+typedef signed short INT16;
+typedef signed int INT;
+typedef unsigned int UINT;
+typedef int BOOL;
+
+void noprint(const char *fmt, ...);
+
+#define ir_malloc(A) malloc(A)
+#define ir_free(A) free(A)
+
+#define ir_memcpy(A, B, C) memcpy(A, B, C)
+#define ir_memset(A, B, C) memset(A, B, C)
+#define ir_strlen(A) strlen(A)
+#if ((defined BOARD_PC) || (defined BOARD_PC_JNI)) && (defined DEBUG)
+#define ir_printf(...) do { printf(__VA_ARGS__); fflush(stdout); } while(0)
+#else
+#define ir_printf noprint
+#endif
+#define USER_DATA_SIZE 1636
+// #define USER_DATA_SIZE 4096
+
+#ifdef __cplusplus
+}
+#endif
+#endif //_IR_DEFS_H
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_tv_control.h b/arduino-example/src/ir_decode/include/ir_tv_control.h
new file mode 100644
index 0000000..83f5bd4
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_tv_control.h
@@ -0,0 +1,219 @@
+/**************************************************************************************
+Filename: ir_tv_control.h
+Revised: Date: 2016-02-23
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode (compressed command type)
+
+Revision log:
+* 2016-10-21: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_TV_CONTROL_H_
+#define _IR_TV_CONTROL_H_
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "OCUnusedMacroInspection"
+#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_defs.h"
+
+#define STB_CHANNEL_OFFSET 14
+
+#define IRDA_FLAG_NORMAL 0
+#define IRDA_FLAG_INVERSE 1
+
+#define IRDA_LEVEL_LOW 0
+#define IRDA_LEVEL_HIGH 1
+
+#define IRDA_LSB 0
+#define IRDA_MSB 1
+
+enum
+{
+ IRDA_DECODE_1_BIT = 0,
+ IRDA_DECODE_2_BITS,
+ IRDA_DECODE_4_BITS,
+};
+
+/*
+ * global type definitions
+ */
+typedef enum ir_flags
+{
+ IRDA_BOOT = 0,
+ IRDA_STOP,
+ IRDA_SEP,
+ IRDA_ONE,
+ IRDA_ZERO,
+ IRDA_FLIP,
+ IRDA_TWO,
+ IRDA_THREE = 7,
+ IRDA_FOUR,
+ IRDA_FIVE,
+ IRDA_SIX,
+ IRDA_SEVEN,
+ IRDA_EIGHT,
+ IRDA_NINE,
+ IRDA_A,
+ IRDA_B,
+ IRDA_C,
+ IRDA_D,
+ IRDA_E,
+ IRDA_F,
+ IRDA_MAX = 20,
+} t_ir_flags;
+
+typedef struct ir_data
+{
+ UINT8 bits;
+ UINT8 lsb;
+ UINT8 mode;
+ UINT8 index;
+} t_ir_data;
+
+#if !defined BOARD_SOC
+#pragma pack(1)
+#endif
+typedef struct ir_cycles
+{
+ UINT8 flag;
+ UINT16 mask;
+ UINT16 space;
+} t_ir_cycles;
+
+#if !defined BOARD_SOC
+#pragma pack()
+#endif
+
+typedef enum tv_key_value
+{
+ TV_POWER = 0,
+ TV_MUTE,
+ TV_UP,
+ TV_DOWN,
+ TV_LEFT,
+ TV_RIGHT,
+ TV_OK,
+ TV_VOL_UP,
+ TV_VOL_DOWN,
+ TV_BACK,
+ TV_INPUT,
+ TV_MENU,
+ TV_HOME,
+ TV_SET,
+ TV_0,
+ TV_1,
+ TV_2,
+ TV_3,
+ TV_4,
+ TV_5,
+ TV_6,
+ TV_7,
+ TV_8,
+ TV_9,
+ TV_KEY_MAX,
+} t_tv_key_value;
+
+
+typedef enum stb_key_value
+{
+ STB_POWER = 0,
+ STB_MUTE,
+ STB_UP,
+ STB_DOWN,
+ STB_LEFT,
+ STB_RIGHT,
+ STB_OK,
+ STB_VOL_UP,
+ STB_VOL_DOWN,
+ STB_BACK,
+ STB_INPUT,
+ STB_MENU,
+ STB_PAGE_UP,
+ STB_PAGE_DOWN,
+ STB_0,
+ STB_1,
+ STB_2,
+ STB_3,
+ STB_4,
+ STB_5,
+ STB_6,
+ STB_7,
+ STB_8,
+ STB_9,
+ STB_KEY_MAX,
+} t_stb_key_value;
+
+typedef enum nw_key_value
+{
+ NW_POWER = 0,
+ NW_UP,
+ NW_DOWN,
+ NW_LEFT,
+ NW_RIGHT,
+ NW_OK,
+ NW_VOL_UP,
+ NW_VOL_DOWN,
+ NW_BACK,
+ NW_MENU,
+ NW_HOME,
+ NW_0,
+ NW_1,
+ NW_2,
+ NW_3,
+ NW_4,
+ NW_5,
+ NW_6,
+ NW_7,
+ NW_8,
+ NW_9,
+ NW_KEY_MAX,
+} t_nw_key_value;
+
+typedef enum cm_key_value
+{
+ CM_POWER = 0,
+ CM_UP,
+ CM_DOWN,
+ CM_LEFT,
+ CM_RIGHT,
+ CM_OK,
+ CM_VOL_UP,
+ CM_VOL_DOWN,
+ CM_FUNC_1,
+ CM_FUNC_2,
+ CM_FUNC_3,
+ CM_BACK,
+ CM_HOME,
+ CM_MENU,
+ CM_MODE,
+ CM_KEY_MAX,
+} t_cm_key_value;
+
+typedef struct ir_data_tv
+{
+ char magic[4];
+ UINT8 per_keycode_bytes;
+} t_ir_data_tv;
+
+
+extern INT8 tv_binary_open(UINT8 *binary, UINT16 binary_length);
+
+extern BOOL tv_binary_parse(UINT8 encode_type);
+
+extern UINT16 tv_binary_decode(UINT8 key, UINT16 *user_data);
+
+extern UINT8 tv_lib_close();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IR_TV_CONTROL_H_
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/include/ir_utils.h b/arduino-example/src/ir_decode/include/ir_utils.h
new file mode 100644
index 0000000..842ac16
--- /dev/null
+++ b/arduino-example/src/ir_decode/include/ir_utils.h
@@ -0,0 +1,40 @@
+/**************************************************************************************
+Filename: ir_utils.c
+Revised: Date: 2016-10-26
+Revision: Revision: 1.0
+
+Description: This file provides generic utils for IRDA algorithms
+
+Revision log:
+* 2016-10-01: created by strawmanbobi
+**************************************************************************************/
+
+#ifndef _IR_UTILS_H_
+#define _IR_UTILS_H_
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ir_defs.h"
+#include "ir_decode.h"
+
+#include
+
+extern void string_to_hex(UINT8 *p, t_ac_hex *pac_hex);
+
+extern void string_to_hex_common(UINT8 *p, UINT8 *hex_data, UINT16 len);
+
+extern BOOL is_in(const UINT8 *array, UINT8 value, UINT8 len);
+
+extern void hex_byte_to_double_char(char *dest, UINT8 length, UINT8 src);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // _IR_UTILS_H_
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/ir_ac_apply.c b/arduino-example/src/ir_decode/ir_ac_apply.c
new file mode 100644
index 0000000..1dc8881
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_ac_apply.c
@@ -0,0 +1,790 @@
+/**************************************************************************************
+Filename: ir_ac_apply.c
+Revised: Date: 2016-10-12
+Revision: Revision: 1.0
+
+Description: This file provides methods for AC IR applying functionalities
+
+Revision log:
+* 2016-10-12: created by strawmanbobi
+**************************************************************************************/
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "bugprone-branch-clone"
+#pragma ide diagnostic ignored "hicpp-signed-bitwise"
+#endif
+
+#include "include/ir_utils.h"
+#include "include/ir_ac_apply.h"
+
+static INT8 apply_ac_power(struct ac_protocol *protocol, UINT8 power_status);
+
+static INT8 apply_ac_mode(struct ac_protocol *protocol, UINT8 mode_status);
+
+static INT8 apply_ac_temperature(struct ac_protocol *protocol, UINT8 temp_diff);
+
+static INT8 apply_ac_wind_speed(struct ac_protocol *protocol, UINT8 wind_speed);
+
+static INT8 apply_ac_swing(struct ac_protocol *protocol, UINT8 swing_mode);
+
+static UINT8 has_function(struct ac_protocol *protocol, UINT8 function);
+
+
+INT8 apply_ac_parameter_type_1(UINT8 *dc_data, t_tag_comp *comp_data, UINT8 current_seg, UINT8 is_temp)
+{
+ if (0 != (comp_data->seg_len & 0x01))
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (1 == is_temp)
+ {
+ dc_data[comp_data->segment[current_seg]] += comp_data->segment[current_seg + 1];
+ }
+ else
+ {
+ dc_data[comp_data->segment[current_seg]] = comp_data->segment[current_seg + 1];
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 apply_ac_parameter_type_2(UINT8 *dc_data, t_tag_comp *comp_data, UINT8 current_seg, UINT8 is_temp)
+{
+ UINT8 start_bit = 0;
+ UINT8 end_bit = 0;
+ UINT8 cover_byte_pos_hi = 0;
+ UINT8 cover_byte_pos_lo = 0;
+ UINT8 value;
+ UINT8 move_bit = 0;
+
+ if (0 != (comp_data->seg_len % 3))
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ start_bit = comp_data->segment[current_seg];
+ end_bit = comp_data->segment[current_seg + 1];
+ cover_byte_pos_hi = start_bit >> 3;
+ cover_byte_pos_lo = (UINT8) (end_bit - 1) >> 3;
+ if (cover_byte_pos_hi == cover_byte_pos_lo)
+ {
+ // cover_byte_pos_hi or cover_bytes_pos_lo is target byte to be applied with AC parameter
+ // try get raw value of byte to be applied
+ UINT8 raw_value = comp_data->segment[current_seg + 2];
+ UINT8 int_start_bit = start_bit - (cover_byte_pos_hi << 3);
+ UINT8 int_end_bit = end_bit - (cover_byte_pos_lo << 3);
+ UINT8 bit_range = end_bit - start_bit;
+ UINT8 mask = (UINT8) ((0xFF << (8 - int_start_bit)) | (0xFF >> int_end_bit));
+ UINT8 origin = dc_data[cover_byte_pos_lo];
+
+ if (TRUE == is_temp)
+ {
+ move_bit = (UINT8) (8 - int_end_bit);
+ value = (origin & mask) | (((((origin & ~mask) >> move_bit) + raw_value) << move_bit) & ~mask);
+ }
+ else
+ {
+ value = (origin & mask) | ((raw_value << (8 - int_start_bit - bit_range)) & ~mask);
+ }
+ dc_data[cover_byte_pos_lo] = value;
+ }
+ else
+ {
+ UINT8 origin_hi = 0;
+ UINT8 origin_lo = 0;
+ UINT8 mask_hi = 0;
+ UINT8 mask_lo = 0;
+ UINT8 raw_value = 0;
+ UINT8 int_start_bit = 0;
+ UINT8 int_end_bit = 0;
+
+ if (cover_byte_pos_hi > cover_byte_pos_lo)
+ {
+ return IR_DECODE_FAILED;
+ }
+ // calculate the bit scope
+ UINT8 bit_range = end_bit - start_bit;
+
+ raw_value = comp_data->segment[current_seg + 2];
+ origin_hi = dc_data[cover_byte_pos_hi];
+ origin_lo = dc_data[cover_byte_pos_lo];
+
+ int_start_bit = start_bit - (cover_byte_pos_hi << 3);
+ int_end_bit = end_bit - (cover_byte_pos_lo << 3);
+
+ mask_hi = (UINT8) 0xFF << (8 - int_start_bit);
+ mask_lo = (UINT8) 0xFF >> int_end_bit;
+
+ value = ((origin_hi & ~mask_hi) << int_end_bit) | ((origin_lo & ~mask_lo) >> (8 - int_end_bit));
+
+ if (TRUE == is_temp)
+ {
+ raw_value += value;
+ }
+
+ dc_data[cover_byte_pos_hi] = (UINT8) ((origin_hi & mask_hi) |
+ (((0xFF >> (8 - bit_range)) & raw_value) >> int_end_bit));
+
+ dc_data[cover_byte_pos_lo] = (UINT8) ((origin_lo & mask_lo) |
+ (((0xFF >> (8 - bit_range)) & raw_value) << (8 - int_end_bit)));
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_ac_power(struct ac_protocol *protocol, UINT8 power_status)
+{
+ UINT16 i = 0;
+ if (0 == protocol->power1.len)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ if (0 == protocol->power1.comp_data[power_status].seg_len)
+ {
+ // force to apply power in any cases
+ return IR_DECODE_SUCCEEDED;
+ }
+ for (i = 0; i < protocol->power1.comp_data[power_status].seg_len; i += 2)
+ {
+ apply_ac_parameter_type_1(ir_hex_code, &(protocol->power1.comp_data[power_status]), (UINT8) i, FALSE);
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_ac_mode(struct ac_protocol *protocol, UINT8 mode_status)
+{
+ UINT16 i = 0;
+
+ if (0 == protocol->mode1.len)
+ {
+ goto try_applying_mode2;
+ }
+
+ if (0 == protocol->mode1.comp_data[mode_status].seg_len)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < protocol->mode1.comp_data[mode_status].seg_len; i += 2)
+ {
+ apply_ac_parameter_type_1(ir_hex_code, &(protocol->mode1.comp_data[mode_status]), (UINT8) i, FALSE);
+ }
+
+ // get return here since wind mode 1 is already applied
+ return IR_DECODE_SUCCEEDED;
+
+ try_applying_mode2:
+ if (0 == protocol->mode2.len)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ if (0 == protocol->mode2.comp_data[mode_status].seg_len)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < protocol->mode2.comp_data[mode_status].seg_len; i += 3)
+ {
+ apply_ac_parameter_type_2(ir_hex_code,
+ &(protocol->mode2.comp_data[mode_status]),
+ (UINT8) i, FALSE);
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_ac_wind_speed(struct ac_protocol *protocol, UINT8 wind_speed)
+{
+ UINT16 i = 0;
+
+ if (0 == protocol->speed1.len)
+ {
+ goto try_applying_wind_speed2;
+ }
+
+ if (0 == protocol->speed1.comp_data[wind_speed].seg_len)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < protocol->speed1.comp_data[wind_speed].seg_len; i += 2)
+ {
+ apply_ac_parameter_type_1(ir_hex_code, &(protocol->speed1.comp_data[wind_speed]), (UINT8) i, FALSE);
+ }
+
+ // get return here since wind speed 1 is already applied
+ return IR_DECODE_SUCCEEDED;
+
+ try_applying_wind_speed2:
+ if (0 == protocol->speed2.len)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ if (0 == protocol->speed2.comp_data[wind_speed].seg_len)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < protocol->speed2.comp_data[wind_speed].seg_len; i += 3)
+ {
+ apply_ac_parameter_type_2(ir_hex_code,
+ &(protocol->speed2.comp_data[wind_speed]),
+ (UINT8) i, FALSE);
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_ac_temperature(struct ac_protocol *protocol, UINT8 temp_diff)
+{
+ UINT16 i = 0;
+
+ if (0 == protocol->temp1.len)
+ {
+ goto try_applying_temp2;
+ }
+
+ if (0 == protocol->temp1.comp_data[temp_diff].seg_len)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < protocol->temp1.comp_data[temp_diff].seg_len; i += 2)
+ {
+ if (TEMP_TYPE_DYNAMIC == protocol->temp1.type)
+ {
+ apply_ac_parameter_type_1(ir_hex_code, &(protocol->temp1.comp_data[temp_diff]), (UINT8) i, TRUE);
+ }
+ else if (TEMP_TYPE_STATIC == protocol->temp1.type)
+ {
+ apply_ac_parameter_type_1(ir_hex_code, &(protocol->temp1.comp_data[temp_diff]), (UINT8) i, FALSE);
+ }
+ }
+
+ // get return here since temperature 1 is already applied
+ return IR_DECODE_SUCCEEDED;
+
+ try_applying_temp2:
+ if (0 == protocol->temp2.len)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ if (0 == protocol->temp2.comp_data[temp_diff].seg_len)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < protocol->temp2.comp_data[temp_diff].seg_len; i += 3)
+ {
+ if (0 != protocol->temp2.comp_data[temp_diff].seg_len)
+ {
+ if (TEMP_TYPE_DYNAMIC == protocol->temp2.type)
+ {
+ apply_ac_parameter_type_2(ir_hex_code, &(protocol->temp2.comp_data[temp_diff]), (UINT8) i, TRUE);
+ }
+ else if (TEMP_TYPE_STATIC == protocol->temp2.type)
+ {
+ apply_ac_parameter_type_2(ir_hex_code, &(protocol->temp2.comp_data[temp_diff]), (UINT8) i, FALSE);
+ }
+ }
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_ac_swing(struct ac_protocol *protocol, UINT8 swing_mode)
+{
+ UINT16 i = 0;
+
+ if (0 == protocol->swing1.len)
+ {
+ goto try_applying_swing2;
+ }
+
+ if (swing_mode >= protocol->swing1.count)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (0 == protocol->swing1.comp_data[swing_mode].seg_len)
+ {
+ // swing does not have any empty data segment
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < protocol->swing1.comp_data[swing_mode].seg_len; i += 2)
+ {
+ apply_ac_parameter_type_1(ir_hex_code, &(protocol->swing1.comp_data[swing_mode]), (UINT8) i, FALSE);
+ }
+
+ // get return here since temperature 1 is already applied
+ return IR_DECODE_SUCCEEDED;
+
+ try_applying_swing2:
+ if (0 == protocol->swing2.len)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ if (swing_mode >= protocol->swing2.count)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (0 == protocol->swing2.comp_data[swing_mode].seg_len)
+ {
+ // swing does not have any empty data segment
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < protocol->swing2.comp_data[swing_mode].seg_len; i += 3)
+ {
+ apply_ac_parameter_type_2(ir_hex_code,
+ &(protocol->swing2.comp_data[swing_mode]),
+ (UINT8) i, FALSE);
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_checksum_byte(UINT8 *ac_code, t_tag_checksum_data cs, BOOL inverse)
+{
+ UINT16 i = 0;
+ UINT8 checksum = 0x00;
+
+ if (cs.len < 3)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ for (i = cs.start_byte_pos; i < cs.end_byte_pos; i++)
+ {
+ checksum += ac_code[i];
+ }
+
+ checksum += cs.checksum_plus;
+
+ if (TRUE == inverse)
+ {
+ checksum = ~checksum;
+ }
+
+ // apply checksum
+ ac_code[cs.checksum_byte_pos] = checksum;
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_checksum_halfbyte(UINT8 *ac_code, t_tag_checksum_data cs, BOOL inverse)
+{
+ UINT16 i = 0;
+ UINT8 checksum = 0x00;
+
+ if (cs.len < 3)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ for (i = cs.start_byte_pos; i < cs.end_byte_pos; i++)
+ {
+ checksum += (ac_code[i] >> 4) + (ac_code[i] & 0x0F);
+ }
+
+ checksum += cs.checksum_plus;
+
+ if (TRUE == inverse)
+ {
+ checksum = ~checksum;
+ }
+
+ // apply checksum
+ ac_code[cs.checksum_byte_pos] = checksum;
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_checksum_spec_byte(UINT8 *ac_code, t_tag_checksum_data cs, BOOL inverse)
+{
+ UINT16 i = 0;
+ UINT8 apply_byte_pos = 0;
+ UINT8 checksum = 0x00;
+
+#if 1
+ if (cs.len < 4)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+#endif
+
+ for (i = 0; i < cs.len - 3; i++)
+ {
+ UINT8 pos = cs.spec_pos[i];
+ UINT8 byte_pos = pos >> 1;
+
+ if (0 == (pos & 0x01))
+ {
+ checksum += ac_code[byte_pos] >> 4;
+ }
+ else
+ {
+ checksum += ac_code[byte_pos] & 0x0F;
+ }
+ }
+
+ checksum += cs.checksum_plus;
+
+ if (TRUE == inverse)
+ {
+ checksum = ~checksum;
+ }
+
+ // apply checksum, for specific-half-byte checksum, the byte pos actually indicates the half-byte pos
+ apply_byte_pos = cs.checksum_byte_pos >> 1;
+ if (0 == (cs.checksum_byte_pos & 0x01))
+ {
+ // save low bits and add checksum as high bits
+ ac_code[apply_byte_pos] = (UINT8) ((ac_code[apply_byte_pos] & 0x0F) | (checksum << 4));
+ }
+ else
+ {
+ // save high bits and add checksum as low bits
+ ac_code[apply_byte_pos] = (UINT8) ((ac_code[apply_byte_pos] & 0xF0) | (checksum & 0x0F));
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 apply_checksum_spec_byte_onebyte(UINT8 *ac_code, t_tag_checksum_data cs, BOOL inverse)
+{
+ UINT16 i = 0;
+ UINT8 apply_byte_pos = 0;
+ UINT8 checksum = 0x00;
+
+#if 1
+ if (cs.len < 4)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+#endif
+
+ for (i = 0; i < cs.len - 3; i++)
+ {
+ UINT8 pos = cs.spec_pos[i];
+ UINT8 byte_pos = pos >> 1;
+
+ if (0 == (pos & 0x01))
+ {
+ checksum += ac_code[byte_pos] >> 4;
+ }
+ else
+ {
+ checksum += ac_code[byte_pos] & 0x0F;
+ }
+ }
+
+ checksum += cs.checksum_plus;
+
+ if (TRUE == inverse)
+ {
+ checksum = ~checksum;
+ }
+
+ // apply checksum, for specific-half-byte checksum, the byte pos actually indicates the half-byte pos
+ apply_byte_pos = cs.checksum_byte_pos >> 1;
+ ac_code[apply_byte_pos] = checksum;
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+static UINT8 has_function(struct ac_protocol *protocol, UINT8 function)
+{
+ if (function < AC_FUNCTION_POWER || function > AC_FUNCTION_WIND_FIX)
+ {
+ return FALSE;
+ }
+
+ if (0 != protocol->function1.len)
+ {
+ if (0 != protocol->function1.comp_data[function - 1].seg_len)
+ {
+ return TRUE;
+ }
+ }
+
+ if (0 != protocol->function2.len)
+ {
+ if (0 != protocol->function2.comp_data[function - 1].seg_len)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+INT8 apply_function(struct ac_protocol *protocol, UINT8 function)
+{
+ UINT16 i = 0;
+
+ if (function < AC_FUNCTION_POWER || function > AC_FUNCTION_WIND_FIX)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ // function index starts from 1 (AC_FUNCTION_POWER), do -1 operation at first
+ if (0 == protocol->function1.len)
+ {
+ goto try_applying_function2;
+ }
+
+ if (0 == protocol->function1.comp_data[function - 1].seg_len)
+ {
+ // force to apply function in any case
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ for (i = 0; i < protocol->function1.comp_data[function - 1].seg_len; i += 2)
+ {
+ apply_ac_parameter_type_1(ir_hex_code, &(protocol->function1.comp_data[function - 1]), (UINT8) i, FALSE);
+ }
+
+ // get return here since function 1 is already applied
+ return IR_DECODE_SUCCEEDED;
+
+ try_applying_function2:
+ if (0 == protocol->function2.len)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ if (0 == protocol->function2.comp_data[function - 1].seg_len)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ for (i = 0; i < protocol->function2.comp_data[function - 1].seg_len; i += 3)
+ {
+ apply_ac_parameter_type_2(ir_hex_code,
+ &(protocol->function2.comp_data[function - 1]),
+ (UINT8) i, FALSE);
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 apply_checksum(struct ac_protocol *protocol)
+{
+ UINT16 i = 0;
+
+ if (0 == protocol->checksum.len)
+ {
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ for (i = 0; i < protocol->checksum.count; i++)
+ {
+ switch (protocol->checksum.checksum_data[i].type)
+ {
+ case CHECKSUM_TYPE_BYTE:
+ apply_checksum_byte(ir_hex_code, protocol->checksum.checksum_data[i], FALSE);
+ break;
+ case CHECKSUM_TYPE_BYTE_INVERSE:
+ apply_checksum_byte(ir_hex_code, protocol->checksum.checksum_data[i], TRUE);
+ break;
+ case CHECKSUM_TYPE_HALF_BYTE:
+ apply_checksum_halfbyte(ir_hex_code, protocol->checksum.checksum_data[i], FALSE);
+ break;
+ case CHECKSUM_TYPE_HALF_BYTE_INVERSE:
+ apply_checksum_halfbyte(ir_hex_code, protocol->checksum.checksum_data[i], TRUE);
+ break;
+ case CHECKSUM_TYPE_SPEC_HALF_BYTE:
+ apply_checksum_spec_byte(ir_hex_code, protocol->checksum.checksum_data[i], FALSE);
+ break;
+ case CHECKSUM_TYPE_SPEC_HALF_BYTE_INVERSE:
+ apply_checksum_spec_byte(ir_hex_code, protocol->checksum.checksum_data[i], TRUE);
+ break;
+ case CHECKSUM_TYPE_SPEC_HALF_BYTE_ONE_BYTE:
+ apply_checksum_spec_byte_onebyte(ir_hex_code, protocol->checksum.checksum_data[i], FALSE);
+ break;
+ case CHECKSUM_TYPE_SPEC_HALF_BYTE_INVERSE_ONE_BYTE:
+ apply_checksum_spec_byte_onebyte(ir_hex_code, protocol->checksum.checksum_data[i], TRUE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 apply_power(t_remote_ac_status ac_status, UINT8 function_code)
+{
+ (void) function_code;
+ apply_ac_power(context, ac_status.ac_power);
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 apply_mode(t_remote_ac_status ac_status, UINT8 function_code)
+{
+ (void) function_code;
+ if (IR_DECODE_FAILED == apply_ac_mode(context, ac_status.ac_mode))
+ {
+ // do not implement this mechanism since mode, temperature, wind
+ // speed would have unspecified function
+ //if(FALSE == has_function(context, AC_FUNCTION_MODE))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 apply_wind_speed(t_remote_ac_status ac_status, UINT8 function_code)
+{
+ if (FALSE == context->n_mode[ac_status.ac_mode].all_speed)
+ {
+ // if this level is not in black list
+ if (!is_in(context->n_mode[ac_status.ac_mode].speed,
+ ac_status.ac_wind_speed,
+ context->n_mode[ac_status.ac_mode].speed_cnt))
+ {
+ if (IR_DECODE_FAILED == apply_ac_wind_speed(context, ac_status.ac_wind_speed) &&
+ function_code == AC_FUNCTION_WIND_SPEED)
+ {
+ // do not implement this mechanism since mode, temperature, wind
+ // speed would have unspecified function
+ //if(FALSE == has_function(context, AC_FUNCTION_WIND_SPEED))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ }
+ else
+ {
+ // if this level is in black list, do not send IR wave if user want to apply this function
+ if (function_code == AC_FUNCTION_WIND_SPEED)
+ {
+ // do not implement this mechanism since mode, temperature, wind
+ // speed would have unspecified function
+ //if(FALSE == has_function(context, AC_FUNCTION_WIND_SPEED))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ }
+ }
+ else
+ {
+ // if this level is in black list, do not send IR wave if user want to apply this function
+ if (function_code == AC_FUNCTION_WIND_SPEED)
+ {
+ // do not implement this mechanism since mode, temperature, wind
+ // speed would have unspecified function
+ //if(FALSE == has_function(context, AC_FUNCTION_WIND_SPEED))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 apply_swing(t_remote_ac_status ac_status, UINT8 function_code)
+{
+ (void) ac_status;
+ if (function_code == AC_FUNCTION_WIND_FIX)
+ {
+ // adjust fixed wind direction according to current status
+ if (context->si.type == SWING_TYPE_NORMAL && context->si.mode_count > 1)
+ {
+ if (TRUE == context->change_wind_direction)
+ {
+ context->si.dir_index++;
+ }
+
+ if (context->si.dir_index == context->si.mode_count)
+ {
+ // reset dir index
+ context->si.dir_index = 1;
+ }
+ context->swing_status = context->si.dir_index;
+ }
+ }
+ else if (function_code == AC_FUNCTION_WIND_SWING)
+ {
+ context->swing_status = 0;
+ }
+ else
+ {
+ // do nothing
+ }
+
+ if (IR_DECODE_FAILED == apply_ac_swing(context, context->swing_status))
+ {
+ if (function_code == AC_FUNCTION_WIND_SWING &&
+ FALSE == has_function(context, AC_FUNCTION_WIND_SWING))
+ {
+ return IR_DECODE_FAILED;
+ }
+ else if (function_code == AC_FUNCTION_WIND_FIX &&
+ FALSE == has_function(context, AC_FUNCTION_WIND_FIX))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 apply_temperature(t_remote_ac_status ac_status, UINT8 function_code)
+{
+ if (FALSE == context->n_mode[ac_status.ac_mode].all_temp)
+ {
+ if (!is_in(context->n_mode[ac_status.ac_mode].temp,
+ ac_status.ac_temp,
+ context->n_mode[ac_status.ac_mode].temp_cnt))
+ {
+ if (IR_DECODE_FAILED == apply_ac_temperature(context, ac_status.ac_temp))
+ {
+ if (function_code == AC_FUNCTION_TEMPERATURE_UP
+ /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_UP)*/)
+ {
+ return IR_DECODE_FAILED;
+ }
+ else if (function_code == AC_FUNCTION_TEMPERATURE_DOWN
+ /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_DOWN)*/)
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ }
+ else
+ {
+ // if this level is in black list, do not send IR wave if user want to apply this function
+ if (function_code == AC_FUNCTION_TEMPERATURE_UP
+ /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_UP)*/)
+ {
+ return IR_DECODE_FAILED;
+ }
+ else if (function_code == AC_FUNCTION_TEMPERATURE_DOWN
+ /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_DOWN)*/)
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ }
+ else
+ {
+ // if this level is in black list, do not send IR wave if user want to apply this function
+ if (function_code == AC_FUNCTION_TEMPERATURE_UP
+ /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_UP)*/)
+ {
+ return IR_DECODE_FAILED;
+ }
+ else if (function_code == AC_FUNCTION_TEMPERATURE_DOWN
+ /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_DOWN)*/)
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ return IR_DECODE_SUCCEEDED;
+}
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/ir_ac_binary_parse.c b/arduino-example/src/ir_decode/ir_ac_binary_parse.c
new file mode 100644
index 0000000..de1f016
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_ac_binary_parse.c
@@ -0,0 +1,141 @@
+/**************************************************************************************
+Filename: ir_ac_binary_parse.c
+Revised: Date: 2017-01-03
+Revision: Revision: 1.0
+
+Description: This file provides methods for AC binary parse
+
+Revision log:
+* 2017-01-03: created by strawmanbobi
+**************************************************************************************/
+
+#include "include/ir_ac_binary_parse.h"
+#include "include/ir_decode.h"
+
+UINT16 tag_head_offset = 0;
+
+extern struct ir_bin_buffer *p_ir_buffer;
+
+#if defined USE_DYNAMIC_TAG
+extern struct tag_head* tags;
+#else
+extern struct tag_head tags[];
+#endif
+
+UINT8 tag_count = 0;
+const UINT16 tag_index[TAG_COUNT_FOR_PROTOCOL] =
+{
+ 1, 2, 3, 4, 5, 6, 7,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 41, 42, 43, 44, 45, 46, 47, 48
+};
+
+INT8 binary_parse_offset()
+{
+ int i = 0;
+#if defined(ESP8266) || defined(ESP32)
+ UINT8 *phead = (UINT8 *)&p_ir_buffer->data[1];
+#else
+ UINT16 *phead = (UINT16 *)&p_ir_buffer->data[1];
+#endif // ESPRESSIF
+
+ tag_count = p_ir_buffer->data[0];
+ if (TAG_COUNT_FOR_PROTOCOL != tag_count)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ tag_head_offset = (UINT16) ((tag_count << (UINT16) 1) + 1);
+
+#if defined USE_DYNAMIC_TAG
+ tags = (t_tag_head *) ir_malloc(tag_count * sizeof(t_tag_head));
+
+ if (NULL == tags)
+ {
+ return IR_DECODE_FAILED;
+ }
+#endif
+
+ for (i = 0; i < tag_count; i++)
+ {
+ tags[i].tag = tag_index[i];
+
+#if defined BOARD_STM8 && defined COMPILER_IAR
+ UINT16 offset = *(phead + i);
+ tags[i].offset = (offset >> 8) | (offset << 8);
+#elif defined(ESP8266) || defined(ESP32)
+ UINT16 tmp_a = *(phead + i * 2);
+ UINT16 tmp_b = *(phead + i * 2 + 1);
+ tags[i].offset = tmp_b << 8 | tmp_a;
+#else
+ tags[i].offset = *(phead + i);
+#endif
+
+ if (tags[i].offset == TAG_INVALID)
+ {
+ tags[i].len = 0;
+ }
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 binary_parse_len()
+{
+ UINT16 i = 0, j = 0;
+ for (i = 0; i < (tag_count - 1); i++)
+ {
+ if (tags[i].offset == TAG_INVALID)
+ {
+ continue;
+ }
+
+ for (j = (UINT16) (i + 1); j < tag_count; j++)
+ {
+ if (tags[j].offset != TAG_INVALID)
+ {
+ break;
+ }
+ }
+ if (j < tag_count)
+ {
+ tags[i].len = tags[j].offset - tags[i].offset;
+ }
+ else
+ {
+ tags[i].len = p_ir_buffer->len - tags[i].offset - tag_head_offset;
+ return IR_DECODE_SUCCEEDED;
+ }
+ }
+ if (tags[tag_count - 1].offset != TAG_INVALID)
+ {
+ tags[tag_count - 1].len = p_ir_buffer->len - tag_head_offset - tags[tag_count - 1].offset;
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+void binary_tags_info()
+{
+#if defined BOARD_PC && defined DEBUG
+ UINT16 i = 0;
+ for (i = 0; i < tag_count; i++)
+ {
+ if (tags[i].len == 0)
+ {
+ continue;
+ }
+ ir_printf("tag(%d).len = %d\n", tags[i].tag, tags[i].len);
+ }
+#endif
+}
+
+INT8 binary_parse_data()
+{
+ UINT16 i = 0;
+ for (i = 0; i < tag_count; i++)
+ {
+ tags[i].p_data = p_ir_buffer->data + tags[i].offset + tag_head_offset;
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/ir_ac_build_frame.c b/arduino-example/src/ir_decode/ir_ac_build_frame.c
new file mode 100644
index 0000000..366e08c
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_ac_build_frame.c
@@ -0,0 +1,146 @@
+/**************************************************************************************
+Filename: ir_ac_build_frame.c
+Revised: Date: 2016-10-01
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR frame build
+
+Revision log:
+* 2016-10-01: created by strawmanbobi
+**************************************************************************************/
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "hicpp-signed-bitwise"
+#pragma ide diagnostic ignored "readability-redundant-declaration"
+#endif
+
+#include "include/ir_ac_build_frame.h"
+#include "include/ir_decode.h"
+
+extern t_ac_protocol* context;
+
+
+//return bit number per byte,default value is 8
+UINT8 bits_per_byte(UINT8 index)
+{
+ UINT8 i = 0;
+ UINT8 size = 0;
+
+ if (context->bit_num_cnt == 0)
+ return 8; //defaut value
+
+ if (context->bit_num_cnt >= MAX_BITNUM)
+ size = MAX_BITNUM;
+ else
+ size = (UINT8) context->bit_num_cnt;
+
+ for (i = 0; i < size; i++)
+ {
+ if (context->bit_num[i].pos == index)
+ return (UINT8) context->bit_num[i].bits;
+ if (context->bit_num[i].pos > index)
+ return 8;
+ }
+ return 8;
+}
+
+UINT16 add_delaycode(UINT8 index)
+{
+ UINT16 i = 0;
+ UINT16 j = 0;
+ UINT8 size = 0;
+ UINT8 tail_delay_code = 0;
+ UINT16 tail_pos = 0;
+
+ if (context->dc_cnt != 0)
+ {
+ size = (UINT8) context->dc_cnt;
+
+ for (i = 0; i < size; i++)
+ {
+ if (context->dc[i].pos == index)
+ {
+ for (j = 0; j < context->dc[i].time_cnt; j++)
+ {
+ context->time[context->code_cnt++] = context->dc[i].time[j];
+ }
+ }
+ else if (context->dc[i].pos == -1)
+ {
+ tail_delay_code = 1;
+ tail_pos = i;
+ }
+ }
+ }
+
+ if ((context->last_bit == 0) && (index == (ir_hex_len - 1)))
+ {
+ context->time[context->code_cnt++] = context->one.low; //high
+ }
+
+ if (context->dc_cnt != 0)
+ {
+ if ((index == (ir_hex_len - 1)) && (tail_delay_code == 1))
+ {
+ for (i = 0; i < context->dc[tail_pos].time_cnt; i++)
+ {
+ context->time[context->code_cnt++] = context->dc[tail_pos].time[i];
+ }
+ }
+ }
+
+ return context->dc[i].time_cnt;
+}
+
+UINT16 create_ir_frame()
+{
+ UINT16 i = 0, j = 0;
+ UINT8 bit_num = 0;
+ UINT8 *ir_data = ir_hex_code;
+ UINT8 mask = 0;
+ UINT16 frame_length = 0;
+
+ context->code_cnt = 0;
+
+ // boot code
+ for (i = 0; i < context->boot_code.len; i++)
+ {
+ context->time[context->code_cnt++] = context->boot_code.data[i];
+ }
+
+ for (i = 0; i < ir_hex_len; i++)
+ {
+ bit_num = bits_per_byte((UINT8) i);
+ for (j = 0; j < bit_num; j++)
+ {
+ if (context->endian == 0)
+ mask = (UINT8) ((1 << (bit_num - 1)) >> j);
+ else
+ mask = (UINT8) (1 << j);
+
+ if (ir_data[i] & mask)
+ {
+ context->time[context->code_cnt++] = context->one.low;
+ context->time[context->code_cnt++] = context->one.high;
+ }
+ else
+ {
+ context->time[context->code_cnt++] = context->zero.low;
+ context->time[context->code_cnt++] = context->zero.high;
+ }
+ }
+ add_delaycode((UINT8) i);
+ }
+
+ frame_length = context->code_cnt;
+
+ for (i = 0; i < (context->repeat_times - 1); i++)
+ {
+ for (j = 0; j < frame_length; j++)
+ {
+ context->time[context->code_cnt++] = context->time[j];
+ }
+ }
+
+ return context->code_cnt;
+}
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/ir_ac_control.c b/arduino-example/src/ir_decode/ir_ac_control.c
new file mode 100644
index 0000000..e6ee7b7
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_ac_control.c
@@ -0,0 +1,560 @@
+/**************************************************************************************
+Filename: ir_ac_control.c
+Revised: Date: 2017-01-02
+Revision: Revision: 1.0
+
+Description: This file provides methods for AC IR control
+
+Revision log:
+* 2016-10-12: created by strawmanbobi
+**************************************************************************************/
+
+#include
+#include
+#include
+
+#include "include/ir_ac_control.h"
+#include "include/ir_ac_binary_parse.h"
+#include "include/ir_decode.h"
+#include "include/ir_ac_parse_parameter.h"
+#include "include/ir_ac_parse_forbidden_info.h"
+#include "include/ir_ac_parse_frame_info.h"
+#include "include/ir_utils.h"
+
+
+#if defined USE_DYNAMIC_TAG
+extern struct tag_head *tags;
+#else
+extern struct tag_head tags[];
+#endif
+
+extern UINT8 tag_count;
+
+static INT8 ir_context_init();
+
+
+static INT8 ir_context_init()
+{
+ ir_memset(context, 0, sizeof(t_ac_protocol));
+ return IR_DECODE_SUCCEEDED;
+}
+
+
+INT8 ir_ac_lib_parse()
+{
+ UINT i = 0;
+ // suggest not to call init function here for de-couple purpose
+ ir_context_init();
+
+ if (IR_DECODE_FAILED == binary_parse_offset())
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (IR_DECODE_FAILED == binary_parse_len())
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (IR_DECODE_FAILED == binary_parse_data())
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ binary_tags_info();
+
+ context->endian = 0;
+ context->last_bit = 0;
+ context->repeat_times = 1;
+
+ for (i = 0; i < N_MODE_MAX; i++)
+ {
+ context->n_mode[i].enable = TRUE;
+ context->n_mode[i].all_speed = FALSE;
+ context->n_mode[i].all_temp = FALSE;
+ ir_memset(context->n_mode[i].speed, 0x00, AC_WS_MAX);
+ context->n_mode[i].speed_cnt = 0;
+ ir_memset(context->n_mode[i].temp, 0x00, AC_TEMP_MAX);
+ context->n_mode[i].temp_cnt = 0;
+ }
+
+ // parse TAG 46 in first priority
+ for (i = 0; i < tag_count; i++)
+ {
+ if (tags[i].tag == TAG_AC_SWING_INFO)
+ {
+ if (tags[i].len != 0)
+ {
+ parse_swing_info(&tags[i], &(context->si));
+ }
+ else
+ {
+ context->si.type = SWING_TYPE_NORMAL;
+ context->si.mode_count = 2;
+ }
+ context->si.dir_index = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < tag_count; i++)
+ {
+ if (tags[i].len == 0)
+ {
+ continue;
+ }
+ // then parse TAG 26 or 33
+ if (context->si.type == SWING_TYPE_NORMAL)
+ {
+ UINT16 swing_space_size = 0;
+ if (tags[i].tag == TAG_AC_SWING_1)
+ {
+ context->swing1.count = context->si.mode_count;
+ context->swing1.len = (UINT8) tags[i].len >> (UINT8) 1;
+ swing_space_size = sizeof(t_tag_comp) * context->si.mode_count;
+ context->swing1.comp_data = (t_tag_comp *) ir_malloc(swing_space_size);
+ if (NULL == context->swing1.comp_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ ir_memset(context->swing1.comp_data, 0x00, swing_space_size);
+ if (IR_DECODE_FAILED == parse_common_ac_parameter(&tags[i],
+ context->swing1.comp_data,
+ context->si.mode_count,
+ AC_PARAMETER_TYPE_1))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_SWING_2)
+ {
+ context->swing2.count = context->si.mode_count;
+ context->swing2.len = (UINT8) tags[i].len >> (UINT8) 1;
+ swing_space_size = sizeof(t_tag_comp) * context->si.mode_count;
+ context->swing2.comp_data = (t_tag_comp *) ir_malloc(swing_space_size);
+ if (NULL == context->swing2.comp_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+ ir_memset(context->swing2.comp_data, 0x00, swing_space_size);
+ if (IR_DECODE_FAILED == parse_common_ac_parameter(&tags[i],
+ context->swing2.comp_data,
+ context->si.mode_count,
+ AC_PARAMETER_TYPE_2))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ }
+
+ if (tags[i].tag == TAG_AC_DEFAULT_CODE) // default code TAG
+ {
+ context->default_code.data = (UINT8 *) ir_malloc(((size_t) tags[i].len - 2) >> (UINT8) 1);
+ if (NULL == context->default_code.data)
+ {
+ return IR_DECODE_FAILED;
+ }
+ if (IR_DECODE_FAILED == parse_default_code(&tags[i], &(context->default_code)))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_POWER_1) // power tag
+ {
+ context->power1.len = (UINT8) tags[i].len >> (UINT8) 1;
+ if (IR_DECODE_FAILED == parse_common_ac_parameter(&tags[i],
+ context->power1.comp_data,
+ AC_POWER_MAX,
+ AC_PARAMETER_TYPE_1))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_TEMP_1) // temperature tag type 1
+ {
+ if (IR_DECODE_FAILED == parse_temp_1(&tags[i], &(context->temp1)))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_MODE_1) // mode tag
+ {
+ context->mode1.len = (UINT8) tags[i].len >> (UINT8) 1;
+ if (IR_DECODE_FAILED == parse_common_ac_parameter(&tags[i],
+ context->mode1.comp_data,
+ AC_MODE_MAX,
+ AC_PARAMETER_TYPE_1))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_SPEED_1) // wind speed tag
+ {
+ context->speed1.len = (UINT8) tags[i].len >> (UINT8) 1;
+ if (IR_DECODE_FAILED == parse_common_ac_parameter(&tags[i],
+ context->speed1.comp_data,
+ AC_WS_MAX,
+ AC_PARAMETER_TYPE_1))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_CHECKSUM_TYPE)
+ {
+ if (IR_DECODE_FAILED == parse_checksum(&tags[i], &(context->checksum)))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_MODE_2)
+ {
+ context->mode2.len = (UINT8) tags[i].len >> (UINT8) 1;
+ if (IR_DECODE_FAILED ==
+ parse_common_ac_parameter(&tags[i],
+ context->mode2.comp_data, AC_MODE_MAX, AC_PARAMETER_TYPE_1))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_SPEED_2)
+ {
+ context->speed2.len = (UINT8) tags[i].len >> (UINT8) 1;
+ if (IR_DECODE_FAILED ==
+ parse_common_ac_parameter(&tags[i],
+ context->speed2.comp_data, AC_WS_MAX, AC_PARAMETER_TYPE_1))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_TEMP_2)
+ {
+ if (IR_DECODE_FAILED == parse_temp_2(&tags[i], &(context->temp2)))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_SOLO_FUNCTION)
+ {
+ if (IR_DECODE_FAILED == parse_solo_code(&tags[i], &(context->sc)))
+ {
+ return IR_DECODE_FAILED;
+ }
+ context->solo_function_mark = 1;
+ }
+ else if (tags[i].tag == TAG_AC_FUNCTION_1)
+ {
+ if (IR_DECODE_FAILED == parse_function_1_tag29(&tags[i], &(context->function1)))
+ {
+ ir_printf("\nfunction code parse error\n");
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_FUNCTION_2)
+ {
+ if (IR_DECODE_FAILED == parse_function_2_tag34(&tags[i], &(context->function2)))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_FRAME_LENGTH)
+ {
+ if (IR_DECODE_FAILED == parse_frame_len(&tags[i], tags[i].len))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_ZERO)
+ {
+ if (IR_DECODE_FAILED == parse_zero(&tags[i]))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_ONE)
+ {
+ if (IR_DECODE_FAILED == parse_one(&tags[i]))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_BOOT_CODE)
+ {
+ if (IR_DECODE_FAILED == parse_boot_code(&tags[i]))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_REPEAT_TIMES)
+ {
+ if (IR_DECODE_FAILED == parse_repeat_times(&tags[i]))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_BIT_NUM)
+ {
+ if (IR_DECODE_FAILED == parse_bit_num(&tags[i]))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_ENDIAN)
+ {
+ if (IR_DECODE_FAILED == parse_endian(&tags[i]))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_BAN_FUNCTION_IN_COOL_MODE)
+ {
+ if (IR_DECODE_FAILED == parse_nmode(&tags[i], N_COOL))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_BAN_FUNCTION_IN_HEAT_MODE)
+ {
+ if (IR_DECODE_FAILED == parse_nmode(&tags[i], N_HEAT))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_BAN_FUNCTION_IN_AUTO_MODE)
+ {
+ if (IR_DECODE_FAILED == parse_nmode(&tags[i], N_AUTO))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_BAN_FUNCTION_IN_FAN_MODE)
+ {
+ if (IR_DECODE_FAILED == parse_nmode(&tags[i], N_FAN))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ else if (tags[i].tag == TAG_AC_BAN_FUNCTION_IN_DRY_MODE)
+ {
+ if (IR_DECODE_FAILED == parse_nmode(&tags[i], N_DRY))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ }
+
+ for (i = 0; i < tag_count; i++)
+ {
+ if (tags[i].len == 0)
+ {
+ continue;
+ }
+ if (tags[i].tag == TAG_AC_DELAY_CODE)
+ {
+ if (IR_DECODE_FAILED == parse_delay_code(&tags[i]))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ if (tags[i].tag == TAG_AC_LAST_BIT)
+ {
+ if (IR_DECODE_FAILED == parse_lastbit(&tags[i]))
+ {
+ return IR_DECODE_FAILED;
+ }
+ }
+ }
+
+#if defined USE_DYNAMIC_TAG
+ if (NULL != tags)
+ {
+ ir_free(tags);
+ tags = NULL;
+ }
+#endif
+
+ ir_hex_code = (UINT8 *) ir_malloc(context->default_code.len);
+ if (NULL == ir_hex_code)
+ {
+ // warning: this AC bin contains no default code
+ return IR_DECODE_FAILED;
+ }
+
+ ir_hex_len = context->default_code.len;
+ ir_memset(ir_hex_code, 0x00, ir_hex_len);
+
+ // pre-calculate solo function status after parse phase
+ if (1 == context->solo_function_mark)
+ {
+ context->solo_function_mark = 0x00;
+ // bit order from right to left : power, mode, temp+, temp-, wind_speed, swing, fix
+ for (i = AC_FUNCTION_POWER; i < AC_FUNCTION_MAX; i++)
+ {
+ if (is_in(context->sc.solo_function_codes, i, context->sc.solo_func_count))
+ {
+ context->solo_function_mark |= (UINT8) ((UINT8) 1 << (i - 1));
+ }
+ }
+ }
+
+ // it is strongly recommended that we free p_ir_buffer
+ // or make global buffer shared in extreme memory case
+ /* in case of running with test - begin */
+#if (defined BOARD_PC || defined BOARD_PC_DLL)
+ ir_lib_free_inner_buffer();
+ ir_printf("AC parse done\n");
+#endif
+ /* in case of running with test - end */
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+
+INT8 free_ac_context()
+{
+ UINT16 i = 0;
+
+ if (ir_hex_code != NULL)
+ {
+ ir_free(ir_hex_code);
+ ir_hex_code = NULL;
+ }
+ ir_hex_len = 0;
+
+ if (context->default_code.data != NULL)
+ {
+ ir_free(context->default_code.data);
+ context->default_code.data = NULL;
+ context->default_code.len = 0;
+ }
+
+ for (i = 0; i < (UINT16) AC_POWER_MAX; i++)
+ {
+ if (context->power1.comp_data[i].segment != NULL)
+ {
+ ir_free(context->power1.comp_data[i].segment);
+ context->power1.comp_data[i].segment = NULL;
+ context->power1.comp_data[i].seg_len = 0;
+ }
+ }
+
+ for (i = 0; i < (UINT16) AC_TEMP_MAX; i++)
+ {
+ if (context->temp1.comp_data[i].segment != NULL)
+ {
+ ir_free(context->temp1.comp_data[i].segment);
+ context->temp1.comp_data[i].segment = NULL;
+ context->temp1.comp_data[i].seg_len = 0;
+ }
+ if (context->temp2.comp_data[i].segment != NULL)
+ {
+ ir_free(context->temp2.comp_data[i].segment);
+ context->temp2.comp_data[i].segment = NULL;
+ context->temp2.comp_data[i].seg_len = 0;
+ }
+ }
+
+ for (i = 0; i < (UINT16) AC_MODE_MAX; i++)
+ {
+ if (context->mode1.comp_data[i].segment != NULL)
+ {
+ ir_free(context->mode1.comp_data[i].segment);
+ context->mode1.comp_data[i].segment = NULL;
+ context->mode1.comp_data[i].seg_len = 0;
+ }
+ if (context->mode2.comp_data[i].segment != NULL)
+ {
+ ir_free(context->mode2.comp_data[i].segment);
+ context->mode2.comp_data[i].segment = NULL;
+ context->mode2.comp_data[i].seg_len = 0;
+ }
+ }
+ for (i = 0; i < (UINT16) AC_WS_MAX; i++)
+ {
+ if (context->speed1.comp_data[i].segment != NULL)
+ {
+ ir_free(context->speed1.comp_data[i].segment);
+ context->speed1.comp_data[i].segment = NULL;
+ context->speed1.comp_data[i].seg_len = 0;
+ }
+ if (context->speed2.comp_data[i].segment != NULL)
+ {
+ ir_free(context->speed2.comp_data[i].segment);
+ context->speed2.comp_data[i].segment = NULL;
+ context->speed2.comp_data[i].seg_len = 0;
+ }
+ }
+
+ for (i = 0; i < context->si.mode_count; i++)
+ {
+ if (context->swing1.comp_data != NULL &&
+ context->swing1.comp_data[i].segment != NULL)
+ {
+ ir_free(context->swing1.comp_data[i].segment);
+ context->swing1.comp_data[i].segment = NULL;
+ context->swing1.comp_data[i].seg_len = 0;
+ }
+ if (context->swing2.comp_data != NULL &&
+ context->swing2.comp_data[i].segment != NULL)
+ {
+ ir_free(context->swing2.comp_data[i].segment);
+ context->swing2.comp_data[i].segment = NULL;
+ context->swing2.comp_data[i].seg_len = 0;
+ }
+ }
+
+ for (i = 0; i < (UINT16) AC_FUNCTION_MAX - 1; i++)
+ {
+ if (context->function1.comp_data[i].segment != NULL)
+ {
+ ir_free(context->function1.comp_data[i].segment);
+ context->function1.comp_data[i].segment = NULL;
+ context->function1.comp_data[i].seg_len = 0;
+ }
+ if (context->function2.comp_data[i].segment != NULL)
+ {
+ ir_free(context->function2.comp_data[i].segment);
+ context->function2.comp_data[i].segment = NULL;
+ context->function2.comp_data[i].seg_len = 0;
+ }
+ }
+
+ // free composite data for swing1 and swing 2
+ if (context->swing1.comp_data != NULL)
+ {
+ ir_free(context->swing1.comp_data);
+ context->swing1.comp_data = NULL;
+ }
+ if (context->swing2.comp_data != NULL)
+ {
+ ir_free(context->swing2.comp_data);
+ context->swing2.comp_data = NULL;
+ }
+
+ for (i = 0; i < context->checksum.count; i++)
+ {
+ if (context->checksum.checksum_data != NULL &&
+ context->checksum.checksum_data[i].spec_pos != NULL)
+ {
+ ir_free(context->checksum.checksum_data[i].spec_pos);
+ context->checksum.checksum_data[i].len = 0;
+ context->checksum.checksum_data[i].spec_pos = NULL;
+ }
+ }
+ if (context->checksum.checksum_data != NULL)
+ {
+ ir_free(context->checksum.checksum_data);
+ context->checksum.checksum_data = NULL;
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "hicpp-signed-bitwise"
+#endif
+
+BOOL is_solo_function(UINT8 function_code)
+{
+ return (((context->solo_function_mark >> (function_code - 1)) & 0x01) == 0x01) ? TRUE : FALSE;
+}
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/ir_ac_parse_forbidden_info.c b/arduino-example/src/ir_decode/ir_ac_parse_forbidden_info.c
new file mode 100644
index 0000000..5121932
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_ac_parse_forbidden_info.c
@@ -0,0 +1,149 @@
+/**************************************************************************************
+Filename: ir_parse_forbidden_info.c
+Revised: Date: 2016-10-05
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for forbidden area of AC code
+
+Revision log:
+* 2016-10-05: created by strawmanbobi
+**************************************************************************************/
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "readability-redundant-declaration"
+#endif
+
+#include
+#include
+#include
+
+#include "include/ir_decode.h"
+#include "include/ir_ac_parse_forbidden_info.h"
+
+
+extern t_ac_protocol *context;
+
+
+INT8 parse_nmode_data_speed(char *pdata, t_ac_n_mode seq)
+{
+ char buf[16] = { 0 };
+ char *p = pdata;
+ char *ptr = NULL;
+ UINT16 pos = 0;
+ UINT16 cnt = 0, index = 0;
+
+ while (index <= ir_strlen(pdata))
+ {
+ while ((index != ir_strlen(pdata)) && (*(p++) != ','))
+ {
+ index++;
+ }
+ ir_memcpy(buf, pdata + pos, index - pos);
+ pos = (UINT16) (index + 1);
+ index = pos;
+ context->n_mode[seq].speed[cnt++] = (UINT8) strtol(buf, &ptr, 10);
+ context->n_mode[seq].speed_cnt = (UINT8) cnt;
+ ir_memset(buf, 0, 16);
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_nmode_data_temp(char *pdata, t_ac_n_mode seq)
+{
+
+ char buf[16] = { 0 };
+ char *p = pdata;
+ char *ptr = NULL;
+ UINT16 pos = 0;
+ UINT16 cnt = 0, index = 0;
+
+ while (index <= ir_strlen(pdata))
+ {
+ while ((index != ir_strlen(pdata)) && (*(p++) != ','))
+ {
+ index++;
+ }
+ ir_memcpy(buf, pdata + pos, index - pos);
+ pos = (UINT16) (index + 1);
+ index = pos;
+ context->n_mode[seq].temp[cnt++] = (UINT8) (strtol(buf, &ptr, 10) - 16);
+ context->n_mode[seq].temp_cnt = (UINT8) cnt;
+ ir_memset(buf, 0, 16);
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_nmode_pos(char *buf, t_ac_n_mode index)
+{
+ UINT16 i = 0;
+ char data[64] = { 0 };
+ // char start[8] = { 0 };
+ if (ir_strlen(buf) == 1)
+ {
+ if (buf[0] == 'S' || buf[0] == 's')
+ {
+ context->n_mode[index].all_speed = 1;
+ }
+ else if (buf[0] == 'T' || buf[0] == 't')
+ {
+ context->n_mode[index].all_temp = 1;
+ }
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ for (i = 0; i < (UINT16) ir_strlen(buf); i++)
+ {
+ if (buf[i] == '&')
+ {
+ ir_memcpy(data, buf + i + 1, ir_strlen(buf) - i - 1);
+ break;
+ }
+ }
+ if (buf[0] == 'S')
+ {
+ parse_nmode_data_speed(data, index);
+ }
+ else
+ {
+ parse_nmode_data_temp(data, index);
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_nmode(struct tag_head *tag, t_ac_n_mode index)
+{
+ UINT16 i = 0;
+ UINT16 preindex = 0;
+
+ char buf[64] = { 0 };
+
+ if (tag->p_data[0] == 'N' && tag->p_data[1] == 'A')
+ {
+ // ban this function directly
+ context->n_mode[index].enable = 0;
+ return IR_DECODE_SUCCEEDED;
+ }
+ else
+ {
+ context->n_mode[index].enable = 1;
+ }
+
+ preindex = 0;
+ for (i = 0; i < tag->len; i++)
+ {
+ if (tag->p_data[i] == '|')
+ {
+ ir_memcpy(buf, tag->p_data + preindex, i - preindex);
+ preindex = (UINT16) (i + 1);
+ parse_nmode_pos(buf, index);
+ ir_memset(buf, 0, 64);
+ }
+
+ }
+ ir_memcpy(buf, tag->p_data + preindex, i - preindex);
+ parse_nmode_pos(buf, index);
+ ir_memset(buf, 0, 64);
+ return IR_DECODE_SUCCEEDED;
+}
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/ir_ac_parse_frame_info.c b/arduino-example/src/ir_decode/ir_ac_parse_frame_info.c
new file mode 100644
index 0000000..d103815
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_ac_parse_frame_info.c
@@ -0,0 +1,345 @@
+/**************************************************************************************
+Filename: ir_ac_parse_frame_info.c
+Revised: Date: 2016-10-11
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode for AC frame parameters
+
+Revision log:
+* 2016-10-11: created by strawmanbobi
+**************************************************************************************/
+
+#include
+#include
+#include
+
+#include "include/ir_utils.h"
+#include "include/ir_ac_parse_frame_info.h"
+
+
+INT8 parse_boot_code(struct tag_head *tag)
+{
+ UINT8 buf[16] = { 0 };
+ UINT8 *p = NULL;
+ char *ptr = NULL;
+ UINT16 pos = 0;
+ UINT16 cnt = 0, index = 0;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+ p = tag->p_data;
+
+ if (NULL == p)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ while (index <= tag->len)
+ {
+ while ((index != (tag->len)) && (*(p++) != ','))
+ {
+ index++;
+ }
+ ir_memcpy(buf, tag->p_data + pos, index - pos);
+ pos = (UINT16) (index + 1);
+ index = pos;
+ context->boot_code.data[cnt++] = (UINT16) (strtol((char *) buf, &ptr, 10));
+ ir_memset(buf, 0, 16);
+ }
+ context->boot_code.len = cnt;
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_zero(struct tag_head *tag)
+{
+ UINT8 low[16] = { 0 };
+ UINT8 high[16] = { 0 };
+ UINT16 index = 0;
+ UINT8 *p = NULL;
+ char *ptr_low = NULL;
+ char *ptr_high = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+ p = tag->p_data;
+
+ if (NULL == p)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ while (*(p++) != ',')
+ {
+ index++;
+ }
+
+ ir_memcpy(low, tag->p_data, index);
+ ir_memcpy(high, tag->p_data + index + 1, (size_t) (tag->len - index - 1));
+
+ context->zero.low = (UINT16) (strtol((char *) low, &ptr_low, 10));
+ context->zero.high = (UINT16) (strtol((char *) high, &ptr_high, 10));
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_one(struct tag_head *tag)
+{
+ UINT8 low[16] = { 0 };
+ UINT8 high[16] = { 0 };
+ UINT16 index = 0;
+ UINT8 *p = NULL;
+ char *ptr_low = NULL;
+ char *ptr_high = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+ p = tag->p_data;
+
+ if (NULL == p)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ while (*(p++) != ',')
+ {
+ index++;
+ }
+ ir_memcpy(low, tag->p_data, index);
+ ir_memcpy(high, tag->p_data + index + 1, (size_t) (tag->len - index - 1));
+
+ context->one.low = (UINT16) (strtol((char *) low, &ptr_low, 10));
+ context->one.high = (UINT16) (strtol((char *) high, &ptr_high, 10));
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_delay_code_data(UINT8 *pdata)
+{
+ UINT8 buf[16] = { 0 };
+ UINT8 *p = NULL;
+ UINT16 pos = 0;
+ UINT16 cnt = 0, index = 0;
+ char *ptr = NULL;
+
+ if (NULL == pdata)
+ {
+ return IR_DECODE_FAILED;
+ }
+ p = pdata;
+
+ while (index <= ir_strlen((char *) pdata))
+ {
+ while ((index != ir_strlen((char *) pdata)) && (*(p++) != ','))
+ {
+ index++;
+ }
+ ir_memcpy(buf, pdata + pos, index - pos);
+ pos = (UINT16) (index + 1);
+ index = pos;
+ context->dc[context->dc_cnt].time[cnt++] = (UINT16) (strtol((char *) buf, &ptr, 10));
+ context->dc[context->dc_cnt].time_cnt = cnt;
+ ir_memset(buf, 0, 16);
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_delay_code_pos(UINT8 *buf)
+{
+ UINT16 i = 0;
+ UINT8 data[64] = { 0 };
+ UINT8 start[8] = { 0 };
+ char *ptr = NULL;
+
+ if (NULL == buf)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < (UINT16) ir_strlen((char *) buf); i++)
+ {
+ if (buf[i] == '&')
+ {
+ ir_memcpy(start, buf, i);
+ ir_memcpy(data, buf + i + 1, ir_strlen((char *) buf) - i - 1);
+ break;
+ }
+ }
+ parse_delay_code_data(data);
+ context->dc[context->dc_cnt].pos = (UINT16) (strtol((char *) start, &ptr, 10));
+
+ context->dc_cnt++;
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_delay_code(struct tag_head *tag)
+{
+ UINT8 buf[64] = { 0 };
+ UINT16 i = 0;
+ UINT16 preindex = 0;
+ preindex = 0;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < tag->len; i++)
+ {
+ if (tag->p_data[i] == '|')
+ {
+ ir_memcpy(buf, tag->p_data + preindex, i - preindex);
+ preindex = (UINT16) (i + 1);
+ parse_delay_code_pos(buf);
+ ir_memset(buf, 0, 64);
+ }
+
+ }
+ ir_memcpy(buf, tag->p_data + preindex, i - preindex);
+ parse_delay_code_pos(buf);
+ ir_memset(buf, 0, 64);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_frame_len(struct tag_head *tag, UINT16 len)
+{
+ UINT8 *temp = NULL;
+ char *ptr = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ temp = (UINT8 *) ir_malloc(len + 1);
+
+ if (NULL == temp)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ ir_memset(temp, 0x00, len + 1);
+
+ ir_memcpy(temp, tag->p_data, len);
+ temp[len] = '\0';
+
+ context->frame_length = (UINT16) (strtol((char *) temp, &ptr, 10));
+
+ ir_free(temp);
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_endian(struct tag_head *tag)
+{
+ UINT8 buf[8] = { 0 };
+ char *ptr = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+ ir_memcpy(buf, tag->p_data, tag->len);
+ context->endian = (UINT8) (strtol((char *) buf, &ptr, 10));
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_lastbit(struct tag_head *tag)
+{
+ UINT8 buf[8] = { 0 };
+ char *ptr = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+ ir_memcpy(buf, tag->p_data, tag->len);
+ context->last_bit = (UINT8) (strtol((char *) buf, &ptr, 10));
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_repeat_times(struct tag_head *tag)
+{
+ char asc_code[8] = { 0 };
+ char *ptr = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ ir_memcpy(asc_code, tag->p_data, tag->len);
+
+ context->repeat_times = (UINT16) (strtol((char *) asc_code, &ptr, 10));
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_delay_code_tag48_pos(UINT8 *buf)
+{
+ UINT16 i = 0;
+ UINT8 data[64] = { 0 };
+ UINT8 start[8] = { 0 };
+ char *ptr_start = NULL;
+ char *ptr_data = NULL;
+
+ if (NULL == buf)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < (UINT16) ir_strlen((char *) buf); i++)
+ {
+ if (buf[i] == '&')
+ {
+ ir_memcpy(start, buf, i);
+ ir_memcpy(data, buf + i + 1, ir_strlen((char *) buf) - i - 1);
+ break;
+ }
+ }
+
+ context->bit_num[context->bit_num_cnt].pos = (UINT16) (strtol((char *) start, &ptr_start, 10));
+ context->bit_num[context->bit_num_cnt].bits = (UINT16) (strtol((char *) data, &ptr_data, 10));
+ context->bit_num_cnt++;
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_bit_num(struct tag_head *tag)
+{
+ UINT16 i = 0;
+ UINT16 preindex = 0;
+ UINT8 buf[64] = { 0 };
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ preindex = 0;
+ for (i = 0; i < tag->len; i++)
+ {
+ if (tag->p_data[i] == '|')
+ {
+ ir_memcpy(buf, tag->p_data + preindex, i - preindex);
+ preindex = (UINT16) (i + 1);
+ parse_delay_code_tag48_pos(buf);
+ ir_memset(buf, 0, 64);
+ }
+
+ }
+ ir_memcpy(buf, tag->p_data + preindex, i - preindex);
+ parse_delay_code_tag48_pos(buf);
+ ir_memset(buf, 0, 64);
+
+ for (i = 0; i < context->bit_num_cnt; i++)
+ {
+ if (context->bit_num[i].pos == -1)
+ context->bit_num[i].pos = (UINT16) (context->default_code.len - 1); //convert -1 to last data pos
+ }
+ return IR_DECODE_SUCCEEDED;
+}
diff --git a/arduino-example/src/ir_decode/ir_ac_parse_parameter.c b/arduino-example/src/ir_decode/ir_ac_parse_parameter.c
new file mode 100644
index 0000000..d8d2a03
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_ac_parse_parameter.c
@@ -0,0 +1,1204 @@
+/**************************************************************************************
+Filename: ir_ac_parse_parameter.c
+Revised: Date: 2016-10-12
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode for AC functionality parameters
+
+Revision log:
+* 2016-10-12: created by strawmanbobi
+**************************************************************************************/
+
+#include
+#include
+#include
+
+#include "include/ir_utils.h"
+#include "include/ir_ac_parse_parameter.h"
+
+static INT8 parse_checksum_byte_typed(const UINT8 *csdata, t_tag_checksum_data *checksum, UINT16 len);
+
+static INT8 parse_checksum_half_byte_typed(const UINT8 *csdata, t_tag_checksum_data *checksum, UINT16 len);
+
+static INT8 parse_checksum_spec_half_byte_typed(const UINT8 *csdata, t_tag_checksum_data *checksum, UINT16 len);
+
+static INT8 parse_checksum_malloc(struct tag_head *tag, t_checksum *checksum);
+
+
+INT8 parse_comp_data_type_1(UINT8 *data, UINT16 *trav_offset, t_tag_comp *comp)
+{
+ UINT8 seg_len = data[*trav_offset];
+ (*trav_offset)++;
+
+ if (0 == seg_len)
+ {
+ // do alloc memory to this power segment and return SUCCESS
+ comp->seg_len = 0;
+ comp->segment = NULL;
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ comp->seg_len = seg_len;
+ comp->segment = (UINT8 *) ir_malloc(seg_len);
+ if (NULL == comp->segment)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ ir_memcpy(comp->segment, &data[*trav_offset], seg_len);
+ *trav_offset += seg_len;
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_comp_data_type_2(UINT8 *data, UINT16 *trav_offset, t_tag_comp *comp)
+{
+ UINT8 seg_len = data[*trav_offset];
+ (*trav_offset)++;
+
+ if (0 == seg_len)
+ {
+ // do alloc memory to this temp segment and return SUCCESS
+ comp->seg_len = 0;
+ comp->segment = NULL;
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ comp->seg_len = seg_len;
+ comp->segment = (UINT8 *) ir_malloc(seg_len);
+ if (NULL == comp->segment)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ ir_memcpy(comp->segment, &data[*trav_offset], seg_len);
+ *trav_offset += seg_len;
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_common_ac_parameter(t_tag_head *tag, t_tag_comp *comp_data, UINT8 with_end, UINT8 type)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == comp_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to AC data structure
+
+ if (AC_PARAMETER_TYPE_1 == type)
+ {
+ for (seg_index = 0; seg_index < with_end; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_1(hex_data, &trav_offset, &comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (seg_index = 0; seg_index < with_end; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_2(hex_data, &trav_offset, &comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_default_code(struct tag_head *tag, t_ac_hex *default_code)
+{
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex(tag->p_data, default_code);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_power_1(struct tag_head *tag, t_power_1 *power1)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == power1)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to power1 data structure
+ power1->len = (UINT8) hex_len;
+
+ for (seg_index = AC_POWER_ON; seg_index < (UINT16) AC_POWER_MAX; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_1(hex_data, &trav_offset, &power1->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ // prevent from buffer over flowing
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_temp_1(struct tag_head *tag, t_temp_1 *temp1)
+{
+ UINT16 hex_len = 0;
+ UINT16 i = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data according to length
+ if (hex_data[0] == hex_len - 1)
+ {
+ // dynamic temperature tag
+ temp1->type = TEMP_TYPE_DYNAMIC;
+ temp1->len = (UINT8) hex_len;
+ UINT8 seg_len = hex_data[0];
+
+ for (seg_index = AC_TEMP_16; seg_index < (UINT16) AC_TEMP_MAX; seg_index++)
+ {
+ // 020210 indicates set the 02nd byte to [default] +10, +11, +12, +...
+ temp1->comp_data[seg_index].seg_len = seg_len;
+ temp1->comp_data[seg_index].segment = (UINT8 *) ir_malloc(seg_len);
+ if (NULL == temp1->comp_data[seg_index].segment)
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 1; i < seg_len; i += 2)
+ {
+ temp1->comp_data[seg_index].segment[i - 1] = hex_data[i];
+
+ // get the default value of temperature
+ temp1->comp_data[seg_index].segment[i] = (UINT8) (hex_data[i + 1] * seg_index);
+ }
+ }
+ }
+ else
+ {
+ // static temperature tag
+ temp1->len = (UINT8) hex_len;
+ temp1->type = TEMP_TYPE_STATIC;
+ for (seg_index = AC_TEMP_16; seg_index < (UINT16) AC_TEMP_MAX; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_1(hex_data, &trav_offset, &temp1->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+ }
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_mode_1(struct tag_head *tag, t_mode_1 *mode1)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to mode1 data structure
+ mode1->len = (UINT8) hex_len;
+
+ for (seg_index = AC_MODE_COOL; seg_index < (UINT16) AC_MODE_MAX; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_1(hex_data, &trav_offset, &mode1->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_speed_1(struct tag_head *tag, t_speed_1 *speed1)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to speed1 data structure
+ speed1->len = (UINT8) hex_len;
+
+ for (seg_index = AC_WS_AUTO; seg_index < (UINT16) AC_WS_MAX; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_1(hex_data, &trav_offset, &speed1->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_swing_1(struct tag_head *tag, t_swing_1 *swing1, UINT16 swing_count)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to swing1 data structure
+ swing1->count = swing_count;
+ swing1->len = (UINT8) hex_len;
+ swing1->comp_data = (t_tag_comp *) ir_malloc(sizeof(t_tag_comp) * swing_count);
+ if (NULL == swing1->comp_data)
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ for (seg_index = 0; seg_index < swing_count; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_1(hex_data, &trav_offset, &swing1->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_checksum_data(UINT8 *buf, t_tag_checksum_data *checksum, UINT8 length)
+{
+ UINT8 *hex_data = NULL;
+ UINT16 hex_len = 0;
+
+ if (NULL == buf)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == checksum)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = length;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(buf, hex_data, hex_len);
+
+ if (length != hex_data[0] + 1)
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ checksum->len = hex_data[0];
+ checksum->type = hex_data[1];
+ switch (checksum->type)
+ {
+ case CHECKSUM_TYPE_BYTE:
+ case CHECKSUM_TYPE_BYTE_INVERSE:
+ if (IR_DECODE_FAILED == parse_checksum_byte_typed(hex_data, checksum, hex_len))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+ break;
+ case CHECKSUM_TYPE_HALF_BYTE:
+ case CHECKSUM_TYPE_HALF_BYTE_INVERSE:
+ if (IR_DECODE_FAILED == parse_checksum_half_byte_typed(hex_data, checksum, hex_len))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+ break;
+ case CHECKSUM_TYPE_SPEC_HALF_BYTE:
+ case CHECKSUM_TYPE_SPEC_HALF_BYTE_INVERSE:
+ case CHECKSUM_TYPE_SPEC_HALF_BYTE_ONE_BYTE:
+ case CHECKSUM_TYPE_SPEC_HALF_BYTE_INVERSE_ONE_BYTE:
+ if (IR_DECODE_FAILED == parse_checksum_spec_half_byte_typed(hex_data, checksum, hex_len))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+ break;
+ default:
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ ir_free(hex_data);
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_checksum(struct tag_head *tag, t_checksum *checksum)
+{
+ UINT8 i = 0;
+ UINT8 num = 0;
+ UINT16 preindex = 0;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == checksum)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (IR_DECODE_FAILED == parse_checksum_malloc(tag, checksum))
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ for (i = 0; i < (UINT8) tag->len; i++)
+ {
+ if (tag->p_data[i] == '|')
+ {
+ if (IR_DECODE_FAILED == parse_checksum_data(tag->p_data + preindex,
+ checksum->checksum_data + num,
+ (UINT8) (i - preindex) >> (UINT8) 1))
+ {
+ return IR_DECODE_FAILED;
+ }
+ preindex = (UINT16) (i + 1);
+ num++;
+ }
+ }
+
+ if (IR_DECODE_FAILED == parse_checksum_data(tag->p_data + preindex,
+ checksum->checksum_data + num,
+ (UINT8) (i - preindex) >> (UINT8) 1))
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_function_1(UINT8 *data, UINT16 *trav_offset, t_tag_comp *mode_seg)
+{
+ UINT8 seg_len = 0;
+ BOOL valid_function_id = TRUE;
+
+ if (NULL == data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == trav_offset)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == mode_seg)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ seg_len = data[*trav_offset];
+ (*trav_offset)++;
+
+ // function id starts from 1 (POWER)
+ UINT8 function_id = (UINT8) (data[*trav_offset] - 1);
+
+ if (function_id > AC_FUNCTION_MAX - 1)
+ {
+ // ignore unsupported function ID
+ ir_printf("\nunsupported function id : %d\n", function_id);
+ valid_function_id = FALSE;
+ }
+
+ (*trav_offset)++;
+
+ if (0 == seg_len)
+ {
+ // do alloc memory to this mode segment and return SUCCESS
+ if (TRUE == valid_function_id)
+ {
+ mode_seg[function_id].seg_len = 0;
+
+ if (NULL != mode_seg[function_id].segment)
+ {
+ ir_free(mode_seg[function_id].segment);
+ mode_seg[function_id].segment = NULL;
+ }
+ }
+
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ if (TRUE == valid_function_id)
+ {
+ mode_seg[function_id].seg_len = (UINT8) (seg_len - 1);
+ mode_seg[function_id].segment = (UINT8 *) ir_malloc((size_t) (seg_len - 1));
+ if (NULL == mode_seg[function_id].segment)
+ {
+ return IR_DECODE_FAILED;
+ }
+ ir_memcpy(mode_seg[function_id].segment, &data[*trav_offset], (size_t) (seg_len - 1));
+ }
+ *trav_offset += seg_len - 1;
+
+ return function_id;
+}
+
+INT8 parse_function_1_tag29(struct tag_head *tag, t_function_1 *function1)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == function1)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to mode1 data structure
+ function1->len = (UINT8) hex_len;
+
+ // seg_index in TAG only refers to functional count
+ for (seg_index = AC_FUNCTION_POWER; seg_index < (UINT16) AC_FUNCTION_MAX; seg_index++)
+ {
+ /** WARNING: for strict mode only **/
+ /**
+ INT8 fid = parse_function_1(hex_data, &trav_offset, &function1->comp_data[0]);
+ if (fid > AC_FUNCTION_MAX - 1)
+ {
+ irda_free(hex_data);
+ hex_data = NULL;
+ return IR_DECODE_FAILED;
+ }
+ **/
+
+ parse_function_1(hex_data, &trav_offset, &function1->comp_data[0]);
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_temp_2(struct tag_head *tag, t_temp_2 *temp2)
+{
+ UINT16 hex_len = 0;
+ UINT16 i = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == temp2)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data according to length
+ if (hex_data[0] == hex_len - 1)
+ {
+ // dynamic temperature tag
+ temp2->type = TEMP_TYPE_DYNAMIC;
+ temp2->len = (UINT8) hex_len;
+ UINT8 seg_len = hex_data[0];
+
+ for (seg_index = AC_TEMP_16; seg_index < (UINT16) AC_TEMP_MAX; seg_index++)
+ {
+ // 020210 indicates set the 02nd byte to [default] +10, +11, +12, +...
+ temp2->comp_data[seg_index].seg_len = seg_len;
+ temp2->comp_data[seg_index].segment = (UINT8 *) ir_malloc(seg_len);
+ if (NULL == temp2->comp_data[seg_index].segment)
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+ for (i = 2; i < seg_len; i += 3)
+ {
+ temp2->comp_data[seg_index].segment[i - 2] = hex_data[i - 1];
+ temp2->comp_data[seg_index].segment[i - 1] = hex_data[i];
+
+ // for this second type (TAG 30) temperature update, apply the change in run time.
+ temp2->comp_data[seg_index].segment[i] = (UINT8) (hex_data[i + 1] * seg_index);
+ }
+ }
+ }
+ else
+ {
+ // static temperature tag
+ temp2->len = (UINT8) hex_len;
+ temp2->type = TEMP_TYPE_STATIC;
+ for (seg_index = AC_TEMP_16; seg_index < (UINT16) AC_TEMP_MAX; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_2(hex_data, &trav_offset, &temp2->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+ }
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_mode_2(struct tag_head *tag, t_mode_2 *mode2)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == mode2)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to mode1 data structure
+ mode2->len = (UINT8) hex_len;
+
+ for (seg_index = AC_MODE_COOL; seg_index < (UINT16) AC_MODE_MAX; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_2(hex_data, &trav_offset, &mode2->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_speed_2(struct tag_head *tag, t_speed_2 *speed2)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == speed2)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to speed1 data structure
+ speed2->len = (UINT8) hex_len;
+
+ for (seg_index = AC_WS_AUTO; seg_index < (UINT16) AC_WS_MAX; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_2(hex_data, &trav_offset, &speed2->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_swing_2(struct tag_head *tag, t_swing_2 *swing2, UINT16 swing_count)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == swing2)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to swing2 data structure
+ swing2->count = swing_count;
+ swing2->len = (UINT8) hex_len;
+ swing2->comp_data = (t_tag_comp *) ir_malloc(sizeof(t_tag_comp) * swing_count);
+ if (NULL == swing2->comp_data)
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ for (seg_index = 0; seg_index < swing_count; seg_index++)
+ {
+ if (IR_DECODE_FAILED == parse_comp_data_type_2(hex_data, &trav_offset, &swing2->comp_data[seg_index]))
+ {
+ ir_free(hex_data);
+ return IR_DECODE_FAILED;
+ }
+
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_function_2(UINT8 *data, UINT16 *trav_offset, t_tag_comp *mode_seg)
+{
+ UINT8 seg_len = 0;
+ BOOL valid_function_id = TRUE;
+
+ if (NULL == data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == trav_offset)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == mode_seg)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ seg_len = data[*trav_offset];
+ (*trav_offset)++;
+
+ // function id starts from 1 (POWER)
+ UINT8 function_id = (UINT8) (data[*trav_offset] - 1);
+ if (function_id > AC_FUNCTION_MAX - 1)
+ {
+ // ignore unsupported function ID
+ ir_printf("\nunsupported function id : %d\n", function_id);
+ valid_function_id = FALSE;
+ }
+
+ (*trav_offset)++;
+
+ if (0 == seg_len)
+ {
+ if (TRUE == valid_function_id)
+ {
+ // do alloc memory to this mode segment and return SUCCESS
+ mode_seg[function_id].seg_len = 0;
+
+ if (NULL != mode_seg[function_id].segment)
+ {
+ ir_free(mode_seg[function_id].segment);
+ mode_seg[function_id].segment = NULL;
+ }
+ }
+
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ if (TRUE == valid_function_id)
+ {
+ mode_seg[function_id].seg_len = (UINT8) (seg_len - 1);
+ mode_seg[function_id].segment = (UINT8 *) ir_malloc((size_t) (seg_len - 1));
+
+ if (NULL == mode_seg[function_id].segment)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ ir_memcpy(mode_seg[function_id].segment, &data[*trav_offset], (size_t) (seg_len - 1));
+ }
+ *trav_offset += seg_len - 1;
+
+ return function_id;
+}
+
+INT8 parse_function_2_tag34(struct tag_head *tag, t_function_2 *function2)
+{
+ UINT16 hex_len = 0;
+ UINT16 trav_offset = 0;
+ UINT16 seg_index = 0;
+ UINT8 *hex_data = NULL;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == function2)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to mode1 data structure
+ function2->len = (UINT8) hex_len;
+
+ // seg_index in TAG only refers to functional count
+ for (seg_index = AC_FUNCTION_POWER; seg_index < (UINT16) AC_FUNCTION_MAX; seg_index++)
+ {
+ /** WARNING: for strict mode only **/
+ /**
+ INT8 fid = parse_function_2(hex_data, &trav_offset, &function2->comp_data[0]);
+ if (fid > AC_FUNCTION_MAX - 1)
+ {
+ irda_free(hex_data);
+ hex_data = NULL;
+ return IR_DECODE_FAILED;
+ }
+ **/
+
+ parse_function_2(hex_data, &trav_offset, &function2->comp_data[0]);
+ if (trav_offset >= hex_len)
+ {
+ break;
+ }
+ }
+
+ ir_free(hex_data);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_swing_info(struct tag_head *tag, t_swing_info *si)
+{
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == si)
+ {
+ return IR_DECODE_FAILED;
+ }
+ /*
+ * 0 or 1 only - indicates swing info
+ */
+ if (1 == tag->len)
+ {
+ if ('0' == tag->p_data[0])
+ {
+ // to identify if there is only 1 status in TAG 26 OR 33
+ si->type = SWING_TYPE_NOT_SPECIFIED;
+ si->mode_count = 0;
+ }
+ else if ('1' == tag->p_data[0])
+ {
+ si->type = SWING_TYPE_SWING_ONLY;
+ si->mode_count = 1;
+ }
+ else
+ {
+ return IR_DECODE_FAILED;
+ }
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ /*
+ * length greater than 1 indicates both auto-swing and some swing angles are supported
+ */
+ // count how many swing types are there
+ si->type = SWING_TYPE_NORMAL;
+ si->mode_count = 1;
+ for (int i = 0; i < tag->len; i++)
+ {
+ if (tag->p_data[i] == ',')
+ {
+ si->mode_count++;
+ }
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 parse_solo_code(struct tag_head *tag, t_solo_code *sc)
+{
+ UINT16 hex_len = 0;
+ UINT8 *hex_data = NULL;
+ UINT8 i = 0;
+
+ if (NULL == tag)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == sc)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ hex_len = tag->len >> (UINT16) 1;
+
+ if (hex_len > AC_FUNCTION_MAX)
+ {
+ ir_printf("\nsolo function code exceeded!!\n");
+ return IR_DECODE_FAILED;
+ }
+
+ hex_data = (UINT8 *) ir_malloc(hex_len);
+
+ if (NULL == hex_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+ string_to_hex_common(tag->p_data, hex_data, hex_len);
+
+ // parse hex data to mode1 data structure
+ sc->len = (UINT8) hex_len;
+ sc->solo_func_count = (UINT8) (hex_len - 1);
+
+ // per each function takes just 1 byte of length
+ sc->solo_func_count = hex_data[0];
+ for (i = 1; i < (UINT8) hex_len; i++)
+ {
+ sc->solo_function_codes[i - 1] = hex_data[i];
+ }
+
+ ir_free(hex_data);
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 parse_checksum_byte_typed(const UINT8 *csdata, t_tag_checksum_data *checksum, UINT16 len)
+{
+ checksum->start_byte_pos = csdata[2];
+ checksum->end_byte_pos = csdata[3];
+ checksum->checksum_byte_pos = csdata[4];
+
+ if (len > 5)
+ {
+ checksum->checksum_plus = csdata[5];
+ }
+ else
+ {
+ checksum->checksum_plus = 0;
+ }
+ checksum->spec_pos = NULL;
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 parse_checksum_half_byte_typed(const UINT8 *csdata, t_tag_checksum_data *checksum, UINT16 len)
+{
+ checksum->start_byte_pos = csdata[2];
+ checksum->end_byte_pos = csdata[3];
+ checksum->checksum_byte_pos = csdata[4];
+
+ if (len > 5)
+ {
+ checksum->checksum_plus = csdata[5];
+ }
+ else
+ {
+ checksum->checksum_plus = 0;
+ }
+ checksum->spec_pos = NULL;
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 parse_checksum_spec_half_byte_typed(const UINT8 *csdata, t_tag_checksum_data *checksum, UINT16 len)
+{
+ /*
+ * note:
+ * for the type of specified half byte checksum algorithm,
+ * the checksum byte positions are in unit of HALF BYTE, rather than in unit of BYTE
+ * as well as the specified half byte positions (spec_pos).
+ * Thus the specified half byte checksum only affects 4 bits of a position
+ * of half byte specified by check_sum_byte_pos property.
+ */
+ UINT16 spec_pos_size = (UINT16) (len - 4);
+
+ checksum->checksum_byte_pos = csdata[2];
+ checksum->checksum_plus = csdata[3];
+ checksum->start_byte_pos = 0;
+ checksum->end_byte_pos = 0;
+ checksum->spec_pos = (UINT8 *) ir_malloc(spec_pos_size);
+ if (NULL == checksum->spec_pos)
+ {
+ return IR_DECODE_FAILED;
+ }
+ ir_memcpy(checksum->spec_pos, &csdata[4], spec_pos_size);
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+static INT8 parse_checksum_malloc(struct tag_head *tag, t_checksum *checksum)
+{
+ UINT8 i = 0;
+ UINT8 cnt = 0;
+
+ for (i = 0; i < (UINT8) tag->len; i++)
+ {
+ if (tag->p_data[i] == '|')
+ {
+ cnt++;
+ }
+ }
+
+ checksum->len = (UINT8) ((UINT8) (tag->len - cnt) >> (UINT8) 1);
+ checksum->count = (UINT16) (cnt + 1);
+ checksum->checksum_data = (t_tag_checksum_data *) ir_malloc(sizeof(t_tag_checksum_data) * checksum->count);
+
+ if (NULL == checksum->checksum_data)
+ {
+ return IR_DECODE_FAILED;
+ }
+ ir_memset(checksum->checksum_data, 0x00, sizeof(t_tag_checksum_data) * checksum->count);
+
+ return IR_DECODE_SUCCEEDED;
+}
diff --git a/arduino-example/src/ir_decode/ir_decode.c b/arduino-example/src/ir_decode/ir_decode.c
new file mode 100644
index 0000000..0865f42
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_decode.c
@@ -0,0 +1,820 @@
+/**************************************************************************************
+Filename: ir_decode.c
+Revised: Date: 2016-10-01
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode (status type)
+
+Revision log:
+* 2016-10-01: created by strawmanbobi
+**************************************************************************************/
+
+#include
+#include
+
+#include
+
+#include "include/ir_decode.h"
+#include "include/ir_utils.h"
+#include "include/ir_ac_build_frame.h"
+#include "include/ir_ac_apply.h"
+
+struct ir_bin_buffer binary_file;
+struct ir_bin_buffer *p_ir_buffer = &binary_file;
+
+static const char* version = IR_DECODE_LIB_VER;
+
+#if defined USE_DYNAMIC_TAG
+struct tag_head *tags;
+#else
+struct tag_head tags[TAG_COUNT_FOR_PROTOCOL];
+#endif
+
+static UINT8 byte_array[PROTOCOL_SIZE] = { 0 };
+#if !defined NO_FS
+static size_t binary_length = 0;
+static UINT8 *binary_content = NULL;
+#endif
+
+static t_remote_category remote_category = REMOTE_CATEGORY_NONE;
+static UINT8 ir_binary_type = IR_TYPE_STATUS;
+static UINT8 ir_hexadecimal = SUB_CATEGORY_QUATERNARY;
+
+static int KEY_CODE_MAX[] =
+{
+ 0,
+ STANDARD_KEY_COUNT,
+ STANDARD_KEY_COUNT + CHANNEL_KEY_COUNT,
+ STANDARD_KEY_COUNT + CHANNEL_KEY_COUNT,
+ STANDARD_KEY_COUNT,
+ STANDARD_KEY_COUNT + CHANNEL_KEY_COUNT,
+ STANDARD_KEY_COUNT,
+ STANDARD_KEY_COUNT,
+ STANDARD_KEY_COUNT,
+ STANDARD_KEY_COUNT,
+ STANDARD_KEY_COUNT,
+ STANDARD_KEY_COUNT + CHANNEL_KEY_COUNT,
+ STANDARD_KEY_COUNT,
+ STANDARD_KEY_COUNT,
+};
+
+UINT8 *ir_hex_code = NULL;
+UINT8 ir_hex_len = 0;
+t_ac_protocol *context = (t_ac_protocol *) byte_array;
+
+static lp_apply_ac_parameter apply_table[AC_APPLY_MAX] =
+{
+ apply_power,
+ apply_mode,
+ apply_temperature,
+ apply_temperature,
+ apply_wind_speed,
+ apply_swing,
+ apply_swing
+};
+
+// static functions declarations
+#if !defined NO_FS
+static INT8 ir_ac_file_open(const char *file_name);
+#endif
+
+static INT8 ir_ac_binary_open(UINT8 *binary, UINT16 bin_length);
+static UINT16 ir_ac_control(t_remote_ac_status ac_status, UINT16* user_data, UINT8 key_code,
+ BOOL change_wind_direction);
+static INT8 ir_ac_binary_close();
+static BOOL validate_ac_status(t_remote_ac_status* ac_status, BOOL change_wind_dir);
+
+#if !defined NO_FS
+static INT8 ir_tv_file_open(const char *file_name);
+#endif
+
+static INT8 ir_tv_binary_open(UINT8 *binary, UINT16 bin_length);
+static INT8 ir_tv_binary_parse(UINT8 ir_hex_encode);
+static UINT16 ir_tv_control(UINT8 key, UINT16 *l_user_data);
+static INT8 ir_tv_binary_close();
+
+
+void noprint(const char *fmt, ...)
+{
+ (void) fmt;
+}
+
+// pubic function definitions
+const char* get_lib_version()
+{
+ return version;
+}
+
+#if (!defined BOARD_SOC)
+INT8 ir_file_open(const UINT8 category, const UINT8 sub_category, const char* file_name)
+{
+ INT8 ret = 0;
+ if (category < REMOTE_CATEGORY_AC ||
+ category >= REMOTE_CATEGORY_NEXT)
+ {
+ ir_printf("wrong remote category : %d\n", category);
+ return IR_DECODE_FAILED;
+ }
+ remote_category = category;
+
+ if (sub_category < SUB_CATEGORY_QUATERNARY ||
+ sub_category >= SUB_CATEGORY_NEXT)
+ {
+ ir_printf("wrong remote sub category : %d\n", sub_category);
+ return IR_DECODE_FAILED;
+ }
+
+ if (category == REMOTE_CATEGORY_AC)
+ {
+ ir_binary_type = IR_TYPE_STATUS;
+ ret = ir_ac_file_open(file_name);
+ if (IR_DECODE_SUCCEEDED == ret)
+ {
+ return ir_ac_lib_parse();
+ }
+ else
+ {
+ return ret;
+ }
+ }
+ else
+ {
+ ir_binary_type = IR_TYPE_COMMANDS;
+ if (SUB_CATEGORY_QUATERNARY == sub_category)
+ {
+ ir_hexadecimal = 0;
+ }
+ else if (SUB_CATEGORY_HEXADECIMAL == sub_category)
+ {
+ ir_hexadecimal = 1;
+ }
+ else
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ ret = ir_tv_file_open(file_name);
+ if (IR_DECODE_SUCCEEDED == ret)
+ {
+ return ir_tv_binary_parse(ir_hexadecimal);
+ }
+ else
+ {
+ return ret;
+ }
+ }
+}
+#else
+INT8 ir_file_open(const UINT8 category, const UINT8 sub_category, const char* file_name)
+{
+ return IR_DECODE_SUCCEEDED;
+}
+#endif
+
+INT8 ir_binary_open(const UINT8 category, const UINT8 sub_category, UINT8* binary, UINT16 bin_length)
+{
+ INT8 ret = 0;
+
+ if (category < REMOTE_CATEGORY_AC ||
+ category >= REMOTE_CATEGORY_NEXT)
+ {
+ ir_printf("wrong remote category\n");
+ return IR_DECODE_FAILED;
+ }
+ remote_category = (t_remote_category) category;
+
+ if (sub_category < SUB_CATEGORY_QUATERNARY ||
+ sub_category >= SUB_CATEGORY_NEXT)
+ {
+ ir_printf("wrong remote sub category : %d\n", sub_category);
+ return IR_DECODE_FAILED;
+ }
+
+ if (category == REMOTE_CATEGORY_AC)
+ {
+ ir_binary_type = IR_TYPE_STATUS;
+ ret = ir_ac_binary_open(binary, bin_length);
+ if (IR_DECODE_SUCCEEDED == ret)
+ {
+ return ir_ac_lib_parse();
+ }
+ else
+ {
+ return ret;
+ }
+ }
+ else
+ {
+ ir_binary_type = IR_TYPE_COMMANDS;
+ if (SUB_CATEGORY_QUATERNARY == sub_category)
+ {
+ ir_hexadecimal = 0;
+ }
+ else if (SUB_CATEGORY_HEXADECIMAL == sub_category)
+ {
+ ir_hexadecimal = 1;
+ }
+ else
+ {
+ return IR_DECODE_FAILED;
+ }
+
+#if (defined(BOARD_PC) || defined (BOARD_PC_DLL) || defined (BOARD_ANDROID))
+ binary_content = (UINT8 *) ir_malloc(bin_length);
+ if (NULL == binary_content)
+ {
+ ir_printf("failed to malloc memory for binary\n");
+ return IR_DECODE_FAILED;
+ }
+ memcpy(binary_content, binary, bin_length);
+#else
+ binary_content = binary;
+#endif
+
+ ret = ir_tv_binary_open(binary_content, bin_length);
+ if (IR_DECODE_SUCCEEDED == ret)
+ {
+ return ir_tv_binary_parse(ir_hexadecimal);
+ }
+ else
+ {
+ return ret;
+ }
+ }
+}
+
+/** the main entry of decode algorithm **/
+UINT16 ir_decode(UINT8 key_code, UINT16* user_data,
+ t_remote_ac_status* ac_status, BOOL change_wind_direction)
+{
+ ir_printf("remote_category = %d, KEY_CODE_MAX = %d\n", remote_category, KEY_CODE_MAX[remote_category]);
+
+ if (key_code < 0 || key_code >= KEY_CODE_MAX[remote_category])
+ {
+ ir_printf("key_code exceeded!\n");
+ return 0;
+ }
+
+ if (IR_TYPE_COMMANDS == ir_binary_type)
+ {
+ return ir_tv_control(key_code, user_data);
+ }
+ else
+ {
+ if (NULL == ac_status)
+ {
+ return 0;
+ }
+ ir_printf("ac status is not null in decode core : power = %d, mode = %d, "
+ "temp = %d, wind_dir = %d, wind_speed = %d, "
+ "key_code = %d, change_wind_direction = %d\n",
+ ac_status->ac_power, ac_status->ac_mode,
+ ac_status->ac_temp, ac_status->ac_wind_dir,
+ ac_status->ac_wind_speed,
+ key_code, change_wind_direction);
+ // ac status validation
+ if (FALSE == validate_ac_status(ac_status, change_wind_direction)) {
+ return 0;
+ }
+ return ir_ac_control(*ac_status, user_data, key_code, change_wind_direction);
+ }
+}
+
+
+INT8 ir_close()
+{
+ if (IR_TYPE_COMMANDS == ir_binary_type)
+ {
+ ir_printf("tv binary close\n");
+ return ir_tv_binary_close();
+ }
+ else
+ {
+ ir_printf("ac binary close\n");
+ return ir_ac_binary_close();
+ }
+}
+
+
+// static function definitions
+
+//////// AC Begin ////////
+#if !defined NO_FS
+static INT8 ir_ac_file_open(const char *file_name)
+{
+ size_t ret = 0;
+#if !defined WIN32
+ FILE *stream = fopen(file_name, "rb");
+#else
+ FILE *stream;
+ fopen_s(&stream, file_name, "rb");
+#endif
+ if (NULL == stream)
+ {
+ ir_printf("\nfile open failed\n");
+ return IR_DECODE_FAILED;
+ }
+
+ fseek(stream, 0, SEEK_END);
+ binary_length = (size_t) ftell(stream);
+ binary_content = (UINT8 *) ir_malloc(binary_length);
+
+ if (NULL == binary_content)
+ {
+ ir_printf("\nfailed to alloc memory for binary\n");
+ fclose(stream);
+ return IR_DECODE_FAILED;
+ }
+
+ fseek(stream, 0, SEEK_SET);
+ ret = fread(binary_content, binary_length, 1, stream);
+
+ if (ret <= 0)
+ {
+ fclose(stream);
+ ir_free(binary_content);
+ binary_length = 0;
+ return IR_DECODE_FAILED;
+ }
+
+ fclose(stream);
+
+ if (IR_DECODE_FAILED == ir_ac_binary_open(binary_content, (UINT16) binary_length))
+ {
+ ir_free(binary_content);
+ binary_length = 0;
+ return IR_DECODE_FAILED;
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+#endif
+
+static INT8 ir_ac_binary_open(UINT8 *binary, UINT16 bin_length)
+{
+ // it is recommended that the parameter binary pointing to
+ // a global memory block in embedded platform environment
+ p_ir_buffer->data = binary;
+ p_ir_buffer->len = bin_length;
+ p_ir_buffer->offset = 0;
+ return IR_DECODE_SUCCEEDED;
+}
+
+static UINT16 ir_ac_control(t_remote_ac_status ac_status, UINT16* user_data, UINT8 key_code,
+ BOOL change_wind_direction)
+{
+ UINT16 time_length = 0;
+ UINT8 function_code = 0;
+
+ switch(key_code)
+ {
+ case 0:
+ function_code = AC_FUNCTION_POWER;
+ break;
+ case 1:
+ function_code = AC_FUNCTION_MODE;
+ break;
+ case 2:
+ case 7:
+ function_code = AC_FUNCTION_TEMPERATURE_UP;
+ break;
+ case 3:
+ case 8:
+ function_code = AC_FUNCTION_TEMPERATURE_DOWN;
+ break;
+ case 9:
+ function_code = AC_FUNCTION_WIND_SPEED;
+ break;
+ case 10:
+ function_code = AC_FUNCTION_WIND_SWING;
+ break;
+ case 11:
+ function_code = AC_FUNCTION_WIND_FIX;
+ break;
+ default:
+ ir_printf("unsupported key_code\n");
+ return 0;
+ }
+
+ if (0 == context->default_code.len)
+ {
+ ir_printf("\ndefault code is empty\n");
+ return 0;
+ }
+
+ // pre-set change wind direction flag here
+ context->change_wind_direction = change_wind_direction;
+
+ context->time = user_data;
+
+ // generate temp buffer for frame calculation
+ ir_memcpy(ir_hex_code, context->default_code.data, context->default_code.len);
+
+#if defined USE_APPLY_TABLE
+ if(ac_status.ac_power != AC_POWER_OFF)
+ {
+ for (i = AC_APPLY_POWER; i < AC_APPLY_MAX; i++)
+ {
+ apply_table[i](context, parameter_array[i]);
+ }
+ }
+#else
+ if (ac_status.ac_power == AC_POWER_OFF)
+ {
+ // otherwise, power should always be applied
+ apply_power(ac_status, function_code);
+ }
+ else
+ {
+ // check the mode as the first priority, despite any other status
+ if (TRUE == context->n_mode[ac_status.ac_mode].enable)
+ {
+ if (is_solo_function(function_code))
+ {
+ // this key press function needs to send solo code
+ apply_table[function_code - 1](ac_status, function_code);
+ }
+ else
+ {
+ if (!is_solo_function(AC_FUNCTION_POWER))
+ {
+ apply_power(ac_status, function_code);
+ }
+
+ if (!is_solo_function(AC_FUNCTION_MODE))
+ {
+ if (IR_DECODE_FAILED == apply_mode(ac_status, function_code))
+ {
+ return 0;
+ }
+ }
+
+ if (!is_solo_function(AC_FUNCTION_WIND_SPEED))
+ {
+ if (IR_DECODE_FAILED == apply_wind_speed(ac_status, function_code))
+ {
+ return 0;
+ }
+ }
+
+ if (!is_solo_function(AC_FUNCTION_WIND_SWING) &&
+ !is_solo_function(AC_FUNCTION_WIND_FIX))
+ {
+ if (IR_DECODE_FAILED == apply_swing(ac_status, function_code))
+ {
+ return 0;
+ }
+ }
+
+ if (!is_solo_function(AC_FUNCTION_TEMPERATURE_UP) &&
+ !is_solo_function(AC_FUNCTION_TEMPERATURE_DOWN))
+ {
+ if (IR_DECODE_FAILED == apply_temperature(ac_status, function_code))
+ {
+ return 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ return 0;
+ }
+ }
+#endif
+ apply_function(context, function_code);
+ // checksum should always be applied
+ apply_checksum(context);
+
+ time_length = create_ir_frame();
+
+ return time_length;
+}
+
+static INT8 ir_ac_binary_close()
+{
+#if defined USE_DYNAMIC_TAG
+ // free context
+ if (NULL != tags)
+ {
+ ir_free(tags);
+ tags = NULL;
+ }
+#endif
+
+ free_ac_context();
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+static BOOL validate_ac_status(t_remote_ac_status* ac_status, BOOL change_wind_dir)
+{
+ if (AC_POWER_OFF != ac_status->ac_power && AC_POWER_ON != ac_status->ac_power)
+ {
+ return FALSE;
+ }
+ if (ac_status->ac_mode < AC_MODE_COOL || ac_status->ac_mode >= AC_MODE_MAX)
+ {
+ return FALSE;
+ }
+ if (ac_status->ac_temp < AC_TEMP_16 || ac_status->ac_temp >= AC_TEMP_MAX)
+ {
+ return FALSE;
+ }
+ if (ac_status->ac_wind_speed < AC_WS_AUTO || ac_status->ac_wind_speed >= AC_WS_MAX)
+ {
+ return FALSE;
+ }
+ if (ac_status->ac_wind_dir < AC_SWING_ON || ac_status->ac_wind_dir >= AC_SWING_MAX)
+ {
+ return FALSE;
+ }
+ if (0 != change_wind_dir && 1 != change_wind_dir)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// utils
+INT8 get_temperature_range(UINT8 ac_mode, INT8 *temp_min, INT8 *temp_max)
+{
+ UINT8 i = 0;
+
+ if (ac_mode >= AC_MODE_MAX)
+ {
+ return IR_DECODE_FAILED;
+ }
+ if (NULL == temp_min || NULL == temp_max)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (1 == context->n_mode[ac_mode].all_temp)
+ {
+ *temp_min = *temp_max = -1;
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ *temp_min = -1;
+ *temp_max = -1;
+ for (i = 0; i < (UINT8) AC_TEMP_MAX; i++)
+ {
+ if (is_in(context->n_mode[ac_mode].temp, i, context->n_mode[ac_mode].temp_cnt) ||
+ (context->temp1.len != 0 && 0 == context->temp1.comp_data[i].seg_len) ||
+ (context->temp2.len != 0 && 0 == context->temp2.comp_data[i].seg_len))
+ {
+ continue;
+ }
+ if (-1 == *temp_min)
+ {
+ *temp_min = i;
+ }
+ if (-1 == *temp_max || i > *temp_max)
+ {
+ *temp_max = i;
+ }
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 get_supported_mode(UINT8 *supported_mode)
+{
+ UINT8 i = 0;
+ if (NULL == supported_mode)
+ {
+ return IR_DECODE_FAILED;
+ }
+ *supported_mode = 0x1F;
+
+ for (i = 0; i < (UINT8) AC_MODE_MAX; i++)
+ {
+ if (0 == context->n_mode[i].enable ||
+ (context->mode1.len != 0 && 0 == context->mode1.comp_data[i].seg_len) ||
+ (context->mode2.len != 0 && 0 == context->mode2.comp_data[i].seg_len))
+ {
+ *supported_mode &= (UINT8)(~(UINT8)((UINT8)1 << (UINT8)i));
+ }
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 get_supported_wind_speed(UINT8 ac_mode, UINT8 *supported_wind_speed)
+{
+ UINT8 i = 0;
+ if (ac_mode >= AC_MODE_MAX)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == supported_wind_speed)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (1 == context->n_mode[ac_mode].all_speed)
+ {
+ *supported_wind_speed = 0;
+ return IR_DECODE_SUCCEEDED;
+ }
+
+ *supported_wind_speed = 0x0F;
+
+ for (i = 0; i < (UINT8) AC_WS_MAX; i++)
+ {
+ if (is_in(context->n_mode[ac_mode].speed, i, context->n_mode[ac_mode].speed_cnt) ||
+ (context->speed1.len != 0 && 0 == context->speed1.comp_data[i].seg_len) ||
+ (context->speed2.len != 0 && 0 == context->speed2.comp_data[i].seg_len))
+ {
+ *supported_wind_speed &= (UINT8)(~(UINT8)((UINT8)1 << (UINT8)i));
+ }
+ }
+
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 get_supported_swing(UINT8 ac_mode, UINT8 *supported_swing)
+{
+ if (ac_mode >= AC_MODE_MAX)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (NULL == supported_swing)
+ {
+ return IR_DECODE_FAILED;
+ }
+
+ if (context->si.type == SWING_TYPE_NORMAL)
+ {
+ *supported_swing = 0x03;
+ }
+ else if (context->si.type == SWING_TYPE_SWING_ONLY)
+ {
+ *supported_swing = 0x02;
+ }
+ else if (context->si.type == SWING_TYPE_NOT_SPECIFIED)
+ {
+ *supported_swing = 0x00;
+ }
+ else
+ {
+ *supported_swing = 0x01;
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+INT8 get_supported_wind_direction(UINT8 *supported_wind_direction)
+{
+ if (NULL != context)
+ {
+ *supported_wind_direction = (UINT8) (context->si.mode_count - 1);
+ if (*supported_wind_direction < 0)
+ {
+ *supported_wind_direction = 0;
+ }
+ return IR_DECODE_SUCCEEDED;
+ }
+ else
+ {
+ return IR_DECODE_FAILED;
+ }
+}
+
+//////// AC End ////////
+
+//////// TV Begin ////////
+#if !defined NO_FS
+static INT8 ir_tv_file_open(const char *file_name)
+{
+ size_t ret = 0;
+
+#if !defined WIN32
+ FILE *stream = fopen(file_name, "rb");
+#else
+ FILE *stream;
+ fopen_s(&stream, file_name, "rb");
+#endif
+
+ if (stream == NULL)
+ {
+ ir_printf("file open failed\n");
+ return IR_DECODE_FAILED;
+ }
+
+ fseek(stream, 0, SEEK_END);
+ binary_length = (size_t) ftell(stream);
+
+ binary_content = (UINT8 *) ir_malloc(binary_length);
+ if (NULL == binary_content)
+ {
+ ir_printf("failed to malloc memory for binary\n");
+ fclose(stream);
+ return IR_DECODE_FAILED;
+ }
+
+ fseek(stream, 0, SEEK_SET);
+ ret = fread(binary_content, binary_length, 1, stream);
+ if (ret <= 0)
+ {
+ fclose(stream);
+ ir_free(binary_content);
+ binary_length = 0;
+ return IR_DECODE_FAILED;
+ }
+
+ fclose(stream);
+
+ if (IR_DECODE_FAILED == ir_tv_binary_open(binary_content, (UINT16) binary_length))
+ {
+ ir_printf("failed to parse command type binary\n");
+ ir_free(binary_content);
+ binary_length = 0;
+ return IR_DECODE_FAILED;
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+#endif
+
+static INT8 ir_tv_binary_open(UINT8 *binary, UINT16 bin_length)
+{
+ return tv_binary_open(binary, bin_length);
+}
+
+static INT8 ir_tv_binary_parse(UINT8 ir_hex_encode)
+{
+ if (FALSE == tv_binary_parse(ir_hex_encode))
+ {
+ ir_printf("parse irda binary failed\n");
+ return IR_DECODE_FAILED;
+ }
+ return IR_DECODE_SUCCEEDED;
+}
+
+static UINT16 ir_tv_control(UINT8 key, UINT16 *l_user_data)
+{
+#if defined BOARD_PC
+ UINT16 print_index = 0;
+#endif
+ UINT16 ir_code_length = 0;
+ memset(l_user_data, 0x00, USER_DATA_SIZE);
+ ir_code_length = tv_binary_decode(key, l_user_data);
+
+ return ir_code_length;
+}
+
+static INT8 ir_tv_binary_close()
+{
+#if (defined BOARD_PC || defined BOARD_PC_DLL)
+ ir_lib_free_inner_buffer();
+#endif
+ return IR_DECODE_SUCCEEDED;
+}
+//////// TV End ////////
+
+// combo decode for JNI which means call open, decode and then close in one JNI call
+UINT16 ir_decode_combo(const UINT8 category, const UINT8 sub_category,
+ UINT8* binary, UINT16 bin_length,
+ UINT8 key_code, UINT16* user_data,
+ t_remote_ac_status* ac_status, BOOL change_wind_direction)
+{
+ UINT16 decoded_length = 0;
+
+ if (category < REMOTE_CATEGORY_AC ||
+ category >= REMOTE_CATEGORY_NEXT)
+ {
+ ir_printf("wrong remote category\n");
+ return IR_DECODE_FAILED;
+ }
+
+ remote_category = (t_remote_category) category;
+
+ if (key_code < 0 || key_code >= KEY_CODE_MAX[remote_category])
+ {
+ ir_printf("key_code exceeded!\n");
+ return 0;
+ }
+
+ if (IR_DECODE_SUCCEEDED ==
+ ir_binary_open(category, sub_category, binary, bin_length))
+ {
+ decoded_length = ir_decode(key_code, user_data, ac_status, change_wind_direction);
+ ir_close();
+ return decoded_length;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#if (defined BOARD_PC || defined BOARD_PC_DLL)
+void ir_lib_free_inner_buffer()
+{
+ if (NULL != binary_content)
+ {
+ ir_free(binary_content);
+ binary_content = NULL;
+ }
+}
+#endif
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/ir_tv_control.c b/arduino-example/src/ir_decode/ir_tv_control.c
new file mode 100644
index 0000000..53a3e80
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_tv_control.c
@@ -0,0 +1,453 @@
+/**************************************************************************************
+Filename: ir_tv_control.c
+Revised: Date: 2016-10-21
+Revision: Revision: 1.0
+
+Description: This file provides algorithms for IR decode (compressed command type)
+
+Revision log:
+* 2016-10-21: created by strawmanbobi
+**************************************************************************************/
+
+#if defined (BOARD_PC)
+#pragma ide diagnostic ignored "hicpp-signed-bitwise"
+#endif
+
+#include
+
+#include "include/ir_defs.h"
+#include "include/ir_decode.h"
+#include "include/ir_tv_control.h"
+
+
+struct buffer
+{
+ UINT8 *data;
+ UINT16 len;
+ UINT16 offset;
+} ir_file;
+
+
+static struct buffer *pbuffer = &ir_file;
+
+static UINT8 *prot_cycles_num = NULL;
+static t_ir_cycles *prot_cycles_data[IRDA_MAX];
+static UINT8 prot_items_cnt = 0;
+static t_ir_data *prot_items_data = NULL;
+static t_ir_data_tv *remote_p;
+static UINT8 *remote_pdata = NULL;
+
+static UINT16 time_index = 0;
+static UINT8 ir_level = IRDA_LEVEL_LOW;
+static UINT8 ir_toggle_bit = FALSE;
+static UINT8 ir_decode_flag = IRDA_DECODE_1_BIT;
+static UINT8 cycles_num_size = 0;
+
+
+static BOOL get_ir_protocol(UINT8 encode_type);
+
+static BOOL get_ir_keymap(void);
+
+static void print_ir_time(t_ir_data *data, UINT8 key_index, UINT16 *ir_time);
+
+static void process_decode_number(UINT8 keycode, t_ir_data *data, UINT8 valid_bits, UINT16 *ir_time);
+
+static void convert_to_ir_time(UINT8 value, UINT16 *ir_time);
+
+static void replace_with(t_ir_cycles *pcycles_num, UINT16 *ir_time);
+
+
+INT8 tv_binary_open(UINT8 *binary, UINT16 binary_length)
+{
+ // load binary to buffer
+ pbuffer->data = binary;
+ pbuffer->len = binary_length;
+ pbuffer->offset = 0;
+ return IR_DECODE_SUCCEEDED;
+}
+
+BOOL tv_binary_parse(UINT8 encode_type)
+{
+ if (FALSE == get_ir_protocol(encode_type))
+ {
+ return FALSE;
+ }
+
+ return get_ir_keymap();
+}
+
+UINT16 tv_binary_decode(UINT8 key, UINT16 *user_data)
+{
+ UINT16 i = 0;
+
+ time_index = 0;
+ ir_level = IRDA_LEVEL_LOW;
+
+ for (i = 0; i < prot_items_cnt; i++)
+ {
+ print_ir_time(&prot_items_data[i], key, user_data);
+ }
+
+ // next flip
+ if (2 == prot_cycles_num[IRDA_FLIP])
+ {
+ ir_toggle_bit = (ir_toggle_bit == FALSE) ? TRUE : FALSE;
+ }
+
+ return time_index;
+}
+
+
+static BOOL get_ir_protocol(UINT8 encode_type)
+{
+ UINT8 i = 0;
+ UINT8 name_size = 20;
+ UINT8 *prot_cycles = NULL;
+ UINT8 cycles_sum = 0;
+
+ if (pbuffer->data == NULL)
+ {
+ return FALSE;
+ }
+
+ pbuffer->offset = 0;
+
+ /* t_ac_protocol name */
+ pbuffer->offset += name_size;
+
+ /* cycles number */
+ prot_cycles_num = pbuffer->data + pbuffer->offset;
+
+ if (encode_type == 0)
+ {
+ cycles_num_size = 8;
+ /* "BOOT", "STOP", "SEP", "ONE", "ZERO", "FLIP", "TWO", "THREE" */
+ if (prot_cycles_num[IRDA_TWO] == 0 && prot_cycles_num[IRDA_THREE] == 0)
+ {
+ ir_decode_flag = IRDA_DECODE_1_BIT;
+ }
+ else
+ {
+ ir_decode_flag = IRDA_DECODE_2_BITS;
+ }
+ }
+ else if (encode_type == 1)
+ {
+ cycles_num_size = IRDA_MAX;
+ ir_decode_flag = IRDA_DECODE_4_BITS;
+ }
+ else
+ {
+ return FALSE;
+ }
+ pbuffer->offset += cycles_num_size;
+
+ /* cycles data */
+ prot_cycles = pbuffer->data + pbuffer->offset;
+ for (i = 0; i < cycles_num_size; i++)
+ {
+ if (0 != prot_cycles_num[i])
+ {
+ prot_cycles_data[i] = (t_ir_cycles *) (&prot_cycles[sizeof(t_ir_cycles) * cycles_sum]);
+ }
+ else
+ {
+ prot_cycles_data[i] = NULL;
+ }
+ cycles_sum += prot_cycles_num[i];
+ }
+ pbuffer->offset += sizeof(t_ir_cycles) * cycles_sum;
+
+ /* items count */
+ prot_items_cnt = pbuffer->data[pbuffer->offset];
+ pbuffer->offset += sizeof(UINT8);
+
+ /* items data */
+ prot_items_data = (t_ir_data *) (pbuffer->data + pbuffer->offset);
+ pbuffer->offset += prot_items_cnt * sizeof(t_ir_data);
+
+ ir_toggle_bit = FALSE;
+
+ return TRUE;
+}
+
+static BOOL get_ir_keymap(void)
+{
+ remote_p = (t_ir_data_tv *) (pbuffer->data + pbuffer->offset);
+ pbuffer->offset += sizeof(t_ir_data_tv);
+
+ if (strncmp(remote_p->magic, "irda", 4) == 0)
+ {
+ remote_pdata = pbuffer->data + pbuffer->offset;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void print_ir_time(t_ir_data *data, UINT8 key_index, UINT16 *ir_time)
+{
+ UINT8 i = 0;
+ UINT8 cycles_num = 0;
+ t_ir_cycles *pcycles = NULL;
+ UINT8 key_code = 0;
+
+ if (NULL == data || NULL == ir_time)
+ {
+ ir_printf("data or ir_time is null\n");
+ return;
+ }
+
+ pcycles = prot_cycles_data[data->index];
+ key_code = remote_pdata[remote_p->per_keycode_bytes * key_index + data->index - 1];
+
+ if (prot_cycles_num[IRDA_ONE] != 1 || prot_cycles_num[IRDA_ZERO] != 1)
+ {
+ ir_printf("logical 1 or 0 is invalid\n");
+ return;
+ }
+
+ if (time_index >= USER_DATA_SIZE)
+ {
+ ir_printf("time index exceeded\n");
+ return;
+ }
+
+ if (data->bits == 1)
+ {
+ if (pcycles == NULL)
+ {
+ ir_printf("pcycles is null\n");
+ return;
+ }
+
+ cycles_num = prot_cycles_num[data->index];
+ if (cycles_num > 5)
+ {
+ ir_printf("cycles number exceeded\n");
+ return;
+ }
+
+ for (i = cycles_num; i > 0; i--)
+ {
+ if (cycles_num == 2 && data->index == IRDA_FLIP)
+ {
+ if (ir_toggle_bit == TRUE)
+ {
+ pcycles += 1;
+ }
+ }
+
+ if (pcycles->mask && pcycles->space)
+ {
+ if (pcycles->flag == IRDA_FLAG_NORMAL)
+ {
+ if (ir_level == IRDA_LEVEL_HIGH && time_index != 0)
+ {
+ time_index--;
+ ir_time[time_index++] += pcycles->mask;
+ }
+ else if (ir_level == IRDA_LEVEL_LOW)
+ {
+ ir_time[time_index++] = pcycles->mask;
+ }
+ ir_time[time_index++] = pcycles->space;
+ ir_level = IRDA_LEVEL_LOW;
+ }
+ else if (pcycles->flag == IRDA_FLAG_INVERSE)
+ {
+ if (ir_level == IRDA_LEVEL_LOW && time_index != 0)
+ {
+ time_index--;
+ ir_time[time_index++] += pcycles->space;
+ }
+ else if (ir_level == IRDA_LEVEL_HIGH)
+ {
+ ir_time[time_index++] = pcycles->space;
+ }
+ ir_time[time_index++] = pcycles->mask;
+ ir_level = IRDA_LEVEL_HIGH;
+ }
+ }
+ else if (0 == pcycles->mask && 0 != pcycles->space)
+ {
+ if (ir_level == IRDA_LEVEL_LOW && time_index != 0)
+ {
+ time_index--;
+ ir_time[time_index++] += pcycles->space;
+ }
+ else if (ir_level == IRDA_LEVEL_HIGH)
+ {
+ ir_time[time_index++] = pcycles->space;
+ }
+ ir_level = IRDA_LEVEL_LOW;
+ }
+ else if (0 == pcycles->space && 0 != pcycles->mask)
+ {
+ if (ir_level == IRDA_LEVEL_HIGH && time_index != 0)
+ {
+ time_index--;
+ ir_time[time_index++] += pcycles->mask;
+ }
+ else if (ir_level == IRDA_LEVEL_LOW)
+ {
+ ir_time[time_index++] = pcycles->mask;
+ }
+ ir_level = IRDA_LEVEL_HIGH;
+ }
+ else
+ {
+ // do nothing
+ }
+
+ if (cycles_num == 2 && data->index == IRDA_FLIP)
+ {
+ break;
+ }
+ pcycles++;
+ }
+ }
+ else
+ {
+ // mode: inverse
+ if (data->mode == 1)
+ key_code = ~key_code;
+
+ if (ir_decode_flag == IRDA_DECODE_1_BIT)
+ {
+ // for binary formatted code
+ process_decode_number(key_code, data, 1, ir_time);
+ }
+ else if (ir_decode_flag == IRDA_DECODE_2_BITS)
+ {
+ // for quaternary formatted code
+ process_decode_number(key_code, data, 2, ir_time);
+ }
+ else if (ir_decode_flag == IRDA_DECODE_4_BITS)
+ {
+ // for hexadecimal formatted code
+ process_decode_number(key_code, data, 4, ir_time);
+ }
+ }
+}
+
+static void process_decode_number(UINT8 keycode, t_ir_data *data, UINT8 valid_bits, UINT16 *ir_time)
+{
+ UINT8 i = 0;
+ UINT8 value = 0;
+ UINT8 bit_num = data->bits / valid_bits;
+ UINT8 valid_value = 0;
+
+ valid_value = (UINT8) ((valid_bits == 1) ? 1 : (valid_bits * valid_bits - 1));
+
+ if (data->lsb == IRDA_LSB)
+ {
+ for (i = 0; i < bit_num; i++)
+ {
+ value = (keycode >> (valid_bits * i)) & valid_value;
+ convert_to_ir_time(value, ir_time);
+ }
+ }
+ else if (data->lsb == IRDA_MSB)
+ {
+ for (i = 0; i < bit_num; i++)
+ {
+ value = (keycode >> (data->bits - valid_bits * (i + 1))) & valid_value;
+ convert_to_ir_time(value, ir_time);
+ }
+ }
+}
+
+static void convert_to_ir_time(UINT8 value, UINT16 *ir_time)
+{
+ switch (value)
+ {
+ case 0:
+ replace_with(prot_cycles_data[IRDA_ZERO], ir_time);
+ break;
+ case 1:
+ replace_with(prot_cycles_data[IRDA_ONE], ir_time);
+ break;
+ case 2:
+ replace_with(prot_cycles_data[IRDA_TWO], ir_time);
+ break;
+ case 3:
+ replace_with(prot_cycles_data[IRDA_THREE], ir_time);
+ break;
+ case 4:
+ replace_with(prot_cycles_data[IRDA_FOUR], ir_time);
+ break;
+ case 5:
+ replace_with(prot_cycles_data[IRDA_FIVE], ir_time);
+ break;
+ case 6:
+ replace_with(prot_cycles_data[IRDA_SIX], ir_time);
+ break;
+ case 7:
+ replace_with(prot_cycles_data[IRDA_SEVEN], ir_time);
+ break;
+ case 8:
+ replace_with(prot_cycles_data[IRDA_EIGHT], ir_time);
+ break;
+ case 9:
+ replace_with(prot_cycles_data[IRDA_NINE], ir_time);
+ break;
+ case 0x0A:
+ replace_with(prot_cycles_data[IRDA_A], ir_time);
+ break;
+ case 0x0B:
+ replace_with(prot_cycles_data[IRDA_B], ir_time);
+ break;
+ case 0x0C:
+ replace_with(prot_cycles_data[IRDA_C], ir_time);
+ break;
+ case 0x0D:
+ replace_with(prot_cycles_data[IRDA_D], ir_time);
+ break;
+ case 0x0E:
+ replace_with(prot_cycles_data[IRDA_E], ir_time);
+ break;
+ case 0x0F:
+ replace_with(prot_cycles_data[IRDA_F], ir_time);
+ break;
+ default:
+ break;
+ }
+}
+
+static void replace_with(t_ir_cycles *pcycles_num, UINT16 *ir_time)
+{
+ if (NULL == pcycles_num || NULL == ir_time)
+ {
+ return;
+ }
+
+ if (pcycles_num->flag == IRDA_FLAG_NORMAL)
+ {
+ if (ir_level == IRDA_LEVEL_HIGH && time_index != 0)
+ {
+ time_index--;
+ ir_time[time_index++] += pcycles_num->mask;
+ }
+ else if (ir_level == IRDA_LEVEL_LOW)
+ {
+ ir_time[time_index++] = pcycles_num->mask;
+ }
+ ir_time[time_index++] = pcycles_num->space;
+ ir_level = IRDA_LEVEL_LOW;
+ }
+ else if (pcycles_num->flag == IRDA_FLAG_INVERSE)
+ {
+ if (ir_level == IRDA_LEVEL_LOW && time_index != 0)
+ {
+ time_index--;
+ ir_time[time_index++] += pcycles_num->space;
+ }
+ else if (ir_level == IRDA_LEVEL_HIGH)
+ {
+ ir_time[time_index++] = pcycles_num->space;
+ }
+ ir_time[time_index++] = pcycles_num->mask;
+ ir_level = IRDA_LEVEL_HIGH;
+ }
+}
\ No newline at end of file
diff --git a/arduino-example/src/ir_decode/ir_utils.c b/arduino-example/src/ir_decode/ir_utils.c
new file mode 100644
index 0000000..9045a52
--- /dev/null
+++ b/arduino-example/src/ir_decode/ir_utils.c
@@ -0,0 +1,98 @@
+/**************************************************************************************
+Filename: ir_utils.c
+Revised: Date: 2016-10-26
+Revision: Revision: 1.0
+
+Description: This file provides generic utils for IRDA algorithms
+
+Revision log:
+* 2016-10-01: created by strawmanbobi
+**************************************************************************************/
+
+#include "include/ir_utils.h"
+
+UINT8 char_to_hex(char chr)
+{
+ UINT8 value = 0;
+ if (chr >= '0' && chr <= '9')
+ value = (UINT8) (chr - '0');
+ if (chr >= 'a' && chr <= 'f')
+ value = (UINT8) (chr - 'a' + 10);
+ if (chr >= 'A' && chr <= 'F')
+ value = (UINT8) (chr - 'A' + 10);
+ return value;
+}
+
+UINT8 chars_to_hex(const UINT8 *p)
+{
+ return ((UINT8) char_to_hex(*p) << (UINT8) 4) + char_to_hex(*(p + 1));
+}
+
+void string_to_hex_common(UINT8 *p, UINT8 *hex_data, UINT16 len)
+{
+ // in condition of hex_code is already assigned
+ UINT16 i = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ hex_data[i] = chars_to_hex(p);
+ p = p + 2;
+ }
+}
+
+void string_to_hex(UINT8 *p, t_ac_hex *pac_hex)
+{
+ UINT8 i = 0;
+
+ pac_hex->len = chars_to_hex(p);
+ p = p + 2;
+ for (i = 0; i < pac_hex->len; i++)
+ {
+ pac_hex->data[i] = chars_to_hex(p);
+ p = p + 2;
+ }
+}
+
+char hex_half_byte_to_single_char(UINT8 length, UINT8 half_byte)
+{
+ if (1 != length || half_byte >= 16)
+ {
+ return '0';
+ }
+ if (half_byte >= 10 && half_byte < 16)
+ {
+ return (char) (half_byte - 10 + 0x41);
+ }
+ else
+ {
+ return (char) (half_byte + 0x30);
+ }
+}
+
+void hex_byte_to_double_char(char *dest, UINT8 length, UINT8 src)
+{
+ UINT8 hi_num = 0;
+ UINT8 lo_num = 0;
+ if (NULL == dest || 2 != length)
+ {
+ return;
+ }
+ hi_num = (UINT8) ((UINT8) (src >> (UINT8) 4) & (UINT8) 0x0F);
+ lo_num = (UINT8) (src & (UINT8) 0x0F);
+
+ dest[0] = hex_half_byte_to_single_char(1, hi_num);
+ dest[1] = hex_half_byte_to_single_char(1, lo_num);
+}
+
+BOOL is_in(const UINT8 *array, UINT8 value, UINT8 len)
+{
+ UINT16 i = 0;
+ for (i = 0; i < len; i++)
+ {
+ if (array[i] == value)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
\ No newline at end of file
diff --git a/arduino-example/src/main.cpp b/arduino-example/src/main.cpp
index 88dd863..cf75c28 100644
--- a/arduino-example/src/main.cpp
+++ b/arduino-example/src/main.cpp
@@ -1,77 +1,153 @@
-//
-// Created by strawmanbobi on 10/14/25.
-//
+/**
+ *
+ * Copyright (c) 2020-2025 IRext Opensource Organization
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
#include
-#include // Library for the UNO R4 WiFi connectivity
-#include "configure.h" // Your secret credentials file
+#include
-// --- Global Variables ---
-// Read credentials from the secrets file
-const char ssid[] = SECRET_SSID;
-const char pass[] = SECRET_PASS;
+#include "ArduinoGraphics.h"
+#include "Arduino_LED_Matrix.h"
+
+#include "configure.h"
+
+#define WIFI_SERVER_PORT (8000)
+
+
+// global variable definitions
+constexpr char ssid[] = SECRET_SSID;
+constexpr char pass[] = SECRET_PASS;
int status = WL_IDLE_STATUS;
+unsigned long lastStatusCheck = 0;
+boolean wifiStatusPrinted = false;
+ArduinoLEDMatrix matrix;
+
+WiFiServer server(WIFI_SERVER_PORT);
+WiFiClient client;
+boolean clientConnected = false;
+
+void drawIp(const char *ipAddr) {
+ matrix.beginDraw();
+
+ matrix.stroke(0xFFFFFFFF);
+ matrix.textScrollSpeed(100);
+
+ matrix.textFont(Font_5x7);
+ matrix.beginText(0, 1, 0xFFFFFF);
+ matrix.println(ipAddr);
+ matrix.endText(SCROLL_LEFT);
+ matrix.endDraw();
+}
-// --- Function to print connection details ---
void printWiFiStatus() {
- // Print the SSID of the network you're attached to
- Serial.print("SSID: ");
- Serial.println(WiFi.SSID());
+ unsigned long currentMillis = millis();
+ if (currentMillis - lastStatusCheck >= 10000 && !wifiStatusPrinted) {
+ IPAddress ip = WiFi.localIP();
+ if (0 == strcmp(ip.toString().c_str(), "0.0.0.0")) {
+ lastStatusCheck = currentMillis;
+ return;
+ }
+ Serial.print("SSID: ");
+ Serial.println(WiFi.SSID());
- // Print the UNO R4's IP address
- IPAddress ip = WiFi.localIP();
- Serial.print("IP Address: ");
- Serial.println(ip);
+ Serial.print("IP Address: ");
+ Serial.println(ip);
- // Print the received signal strength (RSSI)
- long rssi = WiFi.RSSI();
- Serial.print("Signal Strength (RSSI): ");
- Serial.print(rssi);
- Serial.println(" dBm");
-}
+ long rssi = WiFi.RSSI();
+ Serial.print("Signal Strength (RSSI): ");
+ Serial.print(rssi);
+ Serial.println(" dBm");
-// ----------------------------------------------------------------------
-void setup() {
- Serial.begin(115200);
- while (!Serial); // Wait for serial port to connect
-
- Serial.println("--- Arduino UNO R4 WiFi: Station Mode ---");
-
- // Set the board to Wi-Fi Station (client) mode
- // The WiFiS3 library handles this mode implicitly with WiFi.begin()
-
- // Attempt to connect to the Wi-Fi network
- Serial.print("Attempting to connect to SSID: ");
- Serial.println(ssid);
-
- // Connect to the Wi-Fi network
- // This is a blocking call that retries until a connection is made or times out
- status = WiFi.begin(ssid, pass);
-
- if (status == WL_CONNECTED) {
- // If connected successfully
- Serial.println("\nConnection Successful!");
- printWiFiStatus();
- } else {
- // If connection failed
- Serial.print("\nConnection Failed! Status: ");
- Serial.println(status);
- }
-}
-
-// ----------------------------------------------------------------------
-void loop() {
- // Check WiFi status and attempt to reconnect if disconnected
- if (WiFi.status() != WL_CONNECTED) {
- Serial.print("Connection lost. Reconnecting...");
- status = WiFi.begin(ssid, pass);
- if (status == WL_CONNECTED) {
- Serial.println("Reconnected!");
- printWiFiStatus();
+ drawIp(ip.toString().c_str());
+ lastStatusCheck = currentMillis;
+ wifiStatusPrinted = true;
}
- }
+}
- // Your main application logic goes here
- delay(5000);
-}
\ No newline at end of file
+void setup() {
+ Serial.begin(115200);
+ while (!Serial) {
+ delay(100);
+ }
+
+ matrix.begin();
+ matrix.beginDraw();
+
+ matrix.stroke(0xFFFFFFFF);
+ matrix.textScrollSpeed(100);
+
+ constexpr char text[] = "IRext Example";
+ matrix.textFont(Font_4x6);
+ matrix.beginText(0, 1, 0xFFFFFF);
+ matrix.println(text);
+ matrix.endText(SCROLL_LEFT);
+ matrix.endDraw();
+
+ Serial.println("Wi-Fi: Station Mode");
+
+ Serial.print("Attempting to connect to SSID: ");
+ Serial.println(ssid);
+
+ status = WiFi.begin(ssid, pass);
+
+ if (status == WL_CONNECTED) {
+ Serial.println("\nConnection Successful!");
+ server.begin();
+ }
+ else {
+ Serial.print("\nConnection Failed! Status: ");
+ Serial.println(status);
+ }
+}
+
+void loop() {
+ if (WiFi.status() != WL_CONNECTED) {
+ Serial.print("Connection lost. Reconnecting...");
+ status = WiFi.begin(ssid, pass);
+ if (status == WL_CONNECTED) {
+ Serial.println("Reconnected!");
+ }
+ } else {
+ printWiFiStatus();
+ client = server.available();
+ if (client.connected()) {
+ if (false == clientConnected) {
+ client.flush();
+ Serial.println("We have a new client");
+ client.println("Hello, client");
+ clientConnected = true;
+ }
+
+ if (client.available() > 0) {
+ String received = client.readStringUntil('\n');
+ Serial.println(received);
+ }
+ } else {
+ if (clientConnected) {
+ client.stop();
+ Serial.println("Client disconnected");
+ }
+ clientConnected = false;
+ }
+ }
+ delay(10);
+}
diff --git a/arduino-example/test/README b/arduino-example/test/README
deleted file mode 100644
index 9b1e87b..0000000
--- a/arduino-example/test/README
+++ /dev/null
@@ -1,11 +0,0 @@
-
-This directory is intended for PlatformIO Test Runner and project tests.
-
-Unit Testing is a software testing method by which individual units of
-source code, sets of one or more MCU program modules together with associated
-control data, usage procedures, and operating procedures, are tested to
-determine whether they are fit for use. Unit testing finds problems early
-in the development cycle.
-
-More information about PlatformIO Unit Testing:
-- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html