aboutsummaryrefslogtreecommitdiff
path: root/vendor/827x_ble_remote/app_ir.c
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/827x_ble_remote/app_ir.c')
-rw-r--r--vendor/827x_ble_remote/app_ir.c1795
1 files changed, 1795 insertions, 0 deletions
diff --git a/vendor/827x_ble_remote/app_ir.c b/vendor/827x_ble_remote/app_ir.c
new file mode 100644
index 0000000..3f5f8d1
--- /dev/null
+++ b/vendor/827x_ble_remote/app_ir.c
@@ -0,0 +1,1795 @@
+/******************************************************************************
+ * @file app_ir.c
+ *
+ * @brief for TLSR chips
+ *
+ * @author public@telink-semi.com;
+ * @date Sep. 30, 2010
+ *
+ * @attention
+ *
+ * Copyright (C) 2019-2020 Telink Semiconductor (Shanghai) Co., Ltd.
+ * Copyright (C) Atmosic 2022-2023
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************/
+
+#ifdef CFG_ATM_SDK
+#include "refdesignrcu.h"
+#include "app_att.h"
+#include "app_ir.h"
+#include "bridge_att.h"
+#include "bridge_ir.h"
+#include "timer.h"
+#include "../common/blt_soft_timer.h"
+#else
+#include "tl_common.h"
+#include "drivers.h"
+#include "../common/blt_soft_timer.h"
+#include "app_ir.h"
+#include "rc_ir.h"
+#include "app_ir.h"
+#include "app_flash_write.h"
+#include "app_ui.h"
+#include "app_custom.h"
+#include "../../stack/ble/host/attr/att.h"
+#endif
+
+#if APP_IR_OVER_BLE
+
+extern void google_reset_rsp_delay(void);
+extern u8 is_mic_enable(void);
+
+//programming timeout 30s
+#define PROGRAMMING_TIMEOUT 30000000
+
+//Regularly query whether the current time can be erased
+#define FLASH_ERASE_TIMEOUT 100000
+
+#define INVALID_KEY_ID 0xFF00
+#define MAX_CODE_LENGTH 300 /* The maximum number of ir codes for each key. */
+#define MAX_KEY_COUNT 5 /* The maximum number of key for ir programming.*/
+
+#define KEY_IDX_NULL 0xff
+
+typedef struct{
+ u16 key_id; //Key ID, comes from ATV (host keyid)
+ u16 code_size;
+ u8 button_idx; //button index, based on enum in firmware
+ u8 code[MAX_CODE_LENGTH];
+}key_code_t;
+
+typedef struct{
+ u32 release_timer;
+ u32 repeat_delay;
+}ir_repeat_delay_t;
+
+typedef struct {
+ u8 programming_start;
+ u8 programmed_key_count;
+ u8 key_notification_flag;
+ u16 current_programming_key_id;
+}ir_programming_key_t;
+
+typedef struct {
+ u16 ir_code_pos;
+ u16 ir_keycode_total_len;
+ u8 ir_current_button;
+}ir_keycode_merge_t;
+
+typedef struct {
+ u8 ir_save_en;
+ u8 ir_save_button;
+ u16 ir_save_pos;
+}ir_save_t;
+
+
+typedef struct {
+ u8 duty_cycle;
+ u16 carrier_frequency;
+ u8 current_programming_key_send;
+ u8 odd_or_even_press;
+ u8 is_key_programming;
+ u8 programming_timer;
+ u8 ir_suppress[MAX_KEY_COUNT];
+ ir_repeat_delay_t ir_repeat_delay;
+ ir_programming_key_t ir_programming;
+ ir_keycode_merge_t ir_merge;
+ ir_save_t ir_save;
+}ir_app_parm_t;
+
+typedef struct {
+ u16 key_id;
+ u8 button_idx;
+ u8 button;
+}key_button_pair_t;
+
+typedef enum
+{
+ APP_NEC_IR_TABLE_PREPARE=1,
+ APP_NEC_IR_TABLE_PREPARE_END,
+ APP_NEC_IR_TABLE_START,
+ APP_NEC_IR_TABLE_WRITEFAIL,
+ APP_NEC_IR_TABLE_END
+}app_nec_ir_table_sts;
+
+_attribute_data_retention_ app_nec_ir_table_sts nec_ir_table_start = APP_NEC_IR_TABLE_END;
+
+//keyid: receive from the host. button_idx: Corresponding to the key index in the memory ir_table[].button:The actual keyid corresponding to the board
+const key_button_pair_t key_button_map_g10[MAX_KEY_COUNT] = {
+ {0x0018, KEY_IDX_VOLUP, 0x10},
+ {0x0019, KEY_IDX_VOLDN, 0x02},
+ {0x00A4, KEY_IDX_MUTE, 0x16},
+ {0x001A, KEY_IDX_POWER, 0 },
+ {0x00B2, KEY_IDX_INPUT, 0x03}
+};
+
+//keyid: receive from the host. button_idx: Corresponding to the key index in the memory ir_table[].button:The actual keyid corresponding to the board
+const key_button_pair_t key_button_map_g20[MAX_KEY_COUNT] = {
+ {0x0018, KEY_IDX_VOLUP, 0x1f},
+ {0x0019, KEY_IDX_VOLDN, 0x02},
+ {0x00A4, KEY_IDX_MUTE, 0x2B},
+ {0x001A, KEY_IDX_POWER, 0 },
+ {0x00B2, KEY_IDX_INPUT, 0x06}
+};
+
+//The following address corresponds to the flash memory address written each time. Upto 5 keys can be written at a time, and each key occupies a maximum of 256 bytes.
+const u32 if_flash_sect_addr[IR_DATA_SECT_MAX_NUM] ={IR_DATA_SECT_0_ADDR+256,IR_DATA_SECT_0_ADDR+1536,IR_DATA_SECT_0_ADDR+2816,IR_DATA_SECT_1_ADDR+256,IR_DATA_SECT_1_ADDR+1536,IR_DATA_SECT_1_ADDR+2816, \
+ IR_DATA_SECT_2_ADDR+256,IR_DATA_SECT_2_ADDR+1536,IR_DATA_SECT_2_ADDR+2816,IR_DATA_SECT_3_ADDR+256,IR_DATA_SECT_3_ADDR+1536,IR_DATA_SECT_3_ADDR+2816};
+
+
+static _attribute_data_retention_ ir_app_parm_t ir_app_parm={0};
+
+static _attribute_data_retention_ key_code_t ir_table[MAX_KEY_COUNT]={{0},{0},{0},{0},{0}};
+extern u32 ir_flash_erase_tick;
+
+
+/*
+ "ir_flash_index" is used to record the current ir code programming times.(The maximum value of
+ "ir_flash_index" is 12,when the value of "ir_flash_index" is 6,the erase operation must be performed.)
+*/
+_attribute_data_retention_ u8 ir_flash_index=0;
+
+/*
+ ir_flash_need_erase_sector:0 -> erase the IR_DATA_SECT_0_ADDR,IR_DATA_SECT_1_ADDR sector
+ ir_flash_need_erase_sector:2 -> erase the IR_DATA_SECT_2_ADDR,IR_DATA_SECT_3_ADDR sector
+
+*/
+_attribute_data_retention_ u8 ir_flash_need_erase_sector=0;
+_attribute_data_retention_ u8 ir_flash_erase_sector_step=0;
+
+_attribute_data_retention_ u8 ir_flash_erase_flag=0;
+_attribute_data_retention_ u8 ir_save_error_flag=0;
+
+
+extern _attribute_data_retention_ u8 device_in_connection_state;
+extern int blt_soft_timer_delete(blt_timer_callback_t func);
+extern int bls_ll_requestConnBrxEventDisable(void);
+extern void bls_ll_disableConnBrxEvent(void);
+extern void bls_ll_restoreConnBrxEvent(void);
+
+#if(BLT_TEST_SOFT_TIMER_ENABLE == 0)
+int blt_soft_timer_add(blt_timer_callback_t func, u32 interval_us)
+{
+}
+
+int blt_soft_timer_delete(blt_timer_callback_t func)
+{
+}
+
+#endif
+
+_attribute_data_retention_ app_ir_programming_end_Cb_t app_ir_programming_end_Cb = NULL;
+
+/**
+ * @brief This function servers to register the callback at the end of ir programming
+ * @param[in] Callback function that needs to be registered
+ * @return none
+ */
+void app_ir_programming_end_register(app_ir_programming_end_Cb_t cb)
+{
+ app_ir_programming_end_Cb = cb;
+}
+
+/**
+ * @brief This function set the programming flag
+ * @param[in] flag the progtamming key. 0x55:current key is a programming key 0:current key not is a propramming key
+ * @return none
+ */
+void programming_key_set(u8 data)
+{
+ ir_app_parm.is_key_programming = data;
+}
+
+/**
+ * @brief This function is used to determine whether the current key is a programming key
+ * @param[in] none
+ * @return 1: programming key
+ * 0: not a programming key
+ */
+u8 is_programming_key_send(void)
+{
+ if(ir_app_parm.is_key_programming == 0x55)
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * @brief This function is used to get the corresponding button index by board keyid
+ * @param[in] button: keyid on the board
+ * @return index 0-4
+ */
+u8 ir_get_button_idx_from_button(u8 button)
+{
+ u8 i;
+ for(i = 0; i < MAX_KEY_COUNT; i++)
+ {
+ if(app_custom_get_device_type() == REMOTE_G10)
+ {
+ if (key_button_map_g10[i].button == button)
+ {
+ return key_button_map_g10[i].button_idx;
+ }
+ }
+ else
+ {
+ if (key_button_map_g20[i].button == button)
+ {
+ return key_button_map_g20[i].button_idx;
+ }
+ }
+ }
+ return KEY_IDX_NULL;
+}
+
+/**
+ * @brief This function is used to get the corresponding button index by host keyid
+ * @param[in] button: keyid issued by host
+ * @return index 0-4
+ */
+u8 ir_get_button_idx_from_key_id(u16 key_id)
+{
+ u8 i;
+ for(i = 0; i < MAX_KEY_COUNT; i++)
+ {
+ if(app_custom_get_device_type() == REMOTE_G10)
+ {
+ if (key_button_map_g10[i].key_id == key_id)
+ {
+ return key_button_map_g10[i].button_idx;
+ }
+ }
+ else
+ {
+ if (key_button_map_g20[i].key_id == key_id)
+ {
+ return key_button_map_g20[i].button_idx;
+ }
+ }
+ }
+ return KEY_IDX_NULL;
+}
+
+/**
+ * @brief This function is used to get the corresponding ir data by board keyid
+ * @param[in] key_idx: keyid on the board
+ * @return ir data
+ */
+key_code_t* ir_get_key_code_from_keyid_idx(u8 key_idx)
+{
+ u8 i;
+ if(key_idx == 0) //powerkey
+ {
+ if(ir_table[KEY_IDX_POWER].button_idx == KEY_IDX_POWER)
+ {
+ ir_app_parm.current_programming_key_send = KEY_IDX_POWER;
+ return &ir_table[KEY_IDX_POWER];
+ }
+ }
+ else
+ {
+ for(i = 0; i < MAX_KEY_COUNT; i++)
+ {
+ if(ir_table[i].key_id == key_idx)
+ {
+ if(ir_table[i].button_idx == i)
+ {
+ ir_app_parm.current_programming_key_send = i;
+ return &ir_table[i];
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * @brief This function is used to get the corresponding button index by board keyid
+ * @param[in] key_idx: keyid on the board
+ * @return button index
+ */
+u8 ir_get_suppress_index_from_keyid_idx(u8 key_idx)
+{
+ u8 i;
+ //printf("ir_app_parm.ir_programming.programmed_key_count=%x\r\n",ir_app_parm.ir_programming.programmed_key_count);
+ if(key_idx == 0) //powerkey
+ {
+ if(ir_table[KEY_IDX_POWER].button_idx == KEY_IDX_POWER)
+ {
+ //printf("ir power key\r\n");
+ return KEY_IDX_POWER;
+ }
+ }
+ else
+ {
+ for(i = 0; i < MAX_KEY_COUNT; i++)
+ {
+ if(ir_table[i].key_id == key_idx)
+ {
+ if(ir_table[i].button_idx == i)
+ {
+ //printf("button index i=%x\r\n",i);
+ return i;
+ }
+ }
+ }
+ }
+ return KEY_IDX_NULL;
+}
+
+/**
+ * @brief This function is init the ir buffer
+ * @param[in] none
+ * @return none
+ */
+void ir_table_init(void)
+{
+ u8 i;
+ memset(ir_table, 0, sizeof(key_code_t) * MAX_KEY_COUNT);
+ for (i = 0; i < MAX_KEY_COUNT; i++)
+ {
+ ir_table[i].key_id = INVALID_KEY_ID;
+ }
+ ir_app_parm.ir_save.ir_save_en = 0;
+ ir_app_parm.ir_save.ir_save_pos = 0;
+ ir_app_parm.ir_save.ir_save_button = 0xff;
+ ir_app_parm.programming_timer = NULL;
+ ir_app_parm.ir_programming.programmed_key_count = 0;
+ ir_app_parm.ir_programming.current_programming_key_id = INVALID_KEY_ID;
+ ir_app_parm.ir_merge.ir_current_button = MAX_KEY_COUNT;
+}
+
+
+/*
+1)A total of 6 flash sectors are used to store ir code. Each sector can store ir code
+ programming three times. Each ir code programming occupies 5*256 bytes. 5 means that
+ each programming supports up to 5 keys, 256 Indicates the maximum number of ir codes
+ for each key.
+2)The first 6 bytes of each sector are used to check whether the ir code programming
+ data is valid for 3 times. If the value is 0xa5,0xxx, the ir code programming data for
+ this time is valid. If the value is 0x00,0xxx this time The data is invalid
+ (0xxx is a reserved byte, to be expanded).
+3)The api "ir_flash_set_flag" is used for set the ir code data to invalid. The variable
+ "ir_flash_index" is used to record the current ir code programming times.(The maximum value of
+ "ir_flash_index" is 12,when the value of "ir_flash_index" is 6,the erase operation must be performed.)
+4)Use 16 bytes as a unit for flash write operation.
+*/
+
+#define APP_IR_DATA_HEAD 0xa5
+#define APP_IR_DATA_HEAD_INVALID 0x0
+
+/**
+ * @brief Write a flag to indicate that the ir data is invalid
+ * @param[in] 0:indicate the ir data is invalid 1:indicate the ir data is valid
+ * @return none
+ */
+void ir_flash_set_flag(u8 flag)
+{
+ u8 sect= ir_flash_index/3;
+ u8 sect_index = ir_flash_index%3;
+ u8 data;
+
+ //printf("ir_flash_set_flag =%x,ir_flash_index =%x\r\n",flag,ir_flash_index);
+ u32 addr = IR_DATA_SECT_0_ADDR+sect*0x1000+sect_index*2;
+ if(flag == 0)
+ {
+ data = APP_IR_DATA_HEAD_INVALID;
+ flash_write_page(addr,1,&data);
+ }
+ else
+ {
+ data = APP_IR_DATA_HEAD;
+ flash_write_page(addr,1,&data);
+ //printf("ir_flash_set_flag addr =%x\r\n",addr);
+ }
+}
+
+/**
+ * @brief Read the ir data from the flash
+ * @param[in] flash addr
+ * @return none
+ */
+void ir_flash_check(u32 addr)
+{
+ u8 button_index=0,i;
+ u16 code_size=0;
+ u8 buf[300];
+ u16 key_id=0;
+
+ for(i=0;i<MAX_KEY_COUNT;i++)
+ {
+#ifdef CFG_ATM_SDK
+ if(!atm_ir_read_code(i, buf, sizeof(key_code_t))) {
+ continue;
+ }
+ button_index = ir_get_button_idx_from_key_id(buf[0]);
+#else
+ flash_read_page(addr+i*256, 256, buf);
+ button_index = ir_get_button_idx_from_button(buf[0]);
+#endif
+ if (button_index == KEY_IDX_NULL)
+ {
+ continue;
+ }
+ code_size = *(u16*)&buf[2];
+ key_id = buf[0]|(buf[1]<<8);
+ ir_table[button_index].key_id = key_id;
+ ir_table[button_index].code_size = code_size;
+ ir_table[button_index].button_idx = button_index;
+#ifndef CFG_ATM_SDK
+ if(code_size>256)
+ {
+ printf("addr=%x\r\n",addr-IR_SECTOR_ADD_OFFSET+i*256);
+ flash_read_page(addr-IR_SECTOR_ADD_OFFSET+i*256, code_size-251, &buf[256]);
+ }
+#endif
+ memcpy(ir_table[button_index].code, &buf[5], code_size);
+
+
+ printf("button =%x \r\n",button_index);
+ /*
+ for(u16 k=0;k<code_size;k++ )
+ {
+ printf(" %x",ir_table[button_index].code[k]);
+ }
+ printf("\r\n");
+ */
+ }
+}
+
+/**
+ * @brief Read the flag from the flash,and find the address which backup the valid ir data
+ * @param[in] none
+ * @return none
+ */
+void ir_param_init(void)
+{
+ u32 addr;
+ u8 data[6],i,j;
+ u8 nodata_flag=0;
+ u8 find_flag=0;
+
+ ir_flash_index = IR_DATA_SECT_MAX_NUM;
+ printf("ir flash head=\r\n");
+ for(i=0;i<IR_DATA_SECT_NUM;i++)
+ {
+ flash_read_page(IR_DATA_SECT_0_ADDR+i*0x1000, 6, data);
+ for(u8 k=0;k<6;k++)
+ printf(" %x",data[k]);
+ for(j=0;j<3;j++)
+ {
+ if(data[j*2] == APP_IR_DATA_HEAD)
+ {
+ ir_flash_index= i*3+j;
+ nodata_flag = 0;
+ find_flag = 1;
+ break;
+ }
+ if(data[j*2] == APP_IR_DATA_HEAD_INVALID)
+ {
+ ir_flash_index = i*3+j;
+ nodata_flag = 1;
+ }
+ }
+ if(find_flag == 1) break;
+ }
+ if(ir_flash_index == IR_DATA_SECT_MAX_NUM)
+ {
+ ir_flash_index = 0;
+ printf("\r\nno ir data\r\n");
+ return;
+ }
+
+ if(ir_flash_index >= IR_DATA_NEED_ERASE_NUM)
+ {
+ flash_read_page(IR_DATA_SECT_0_ADDR,1,&data[0]);
+ flash_read_page(IR_DATA_SECT_0_EXT_ADDR,1,&data[1]);
+ flash_read_page(IR_DATA_SECT_1_EXT_ADDR,1,&data[2]);
+ if(data[0] != 0xff)
+ {
+ printf("erase 1 part flash\r\n");
+ flash_erase_sector(IR_DATA_SECT_0_ADDR);
+ flash_erase_sector(IR_DATA_SECT_1_ADDR);
+ }
+ if(data[1]!= 0xff)
+ {
+ flash_erase_sector(IR_DATA_SECT_0_EXT_ADDR);
+ }
+ if(data[2]!= 0xff)
+ {
+ flash_erase_sector(IR_DATA_SECT_1_EXT_ADDR);
+ }
+ }
+ if(ir_flash_index < IR_DATA_NEED_ERASE_NUM)
+ {
+ flash_read_page(IR_DATA_SECT_2_ADDR,1,&data[0]);
+ flash_read_page(IR_DATA_SECT_2_EXT_ADDR,1,&data[1]);
+ flash_read_page(IR_DATA_SECT_3_EXT_ADDR,1,&data[2]);
+ if((data[0] != 0xff))
+ {
+ printf("erase 2 part flash\r\n");
+ flash_erase_sector(IR_DATA_SECT_2_ADDR);
+ flash_erase_sector(IR_DATA_SECT_3_ADDR);
+ }
+ if(data[1]!= 0xff)
+ {
+ flash_erase_sector(IR_DATA_SECT_2_EXT_ADDR);
+ }
+ if(data[2]!= 0xff)
+ {
+ flash_erase_sector(IR_DATA_SECT_3_EXT_ADDR);
+ }
+ }
+
+ if(nodata_flag == 1)
+ {
+ printf("\r\nno ir data, but ir_flash_index =%x\r\n",ir_flash_index);
+ }
+ else
+ {
+ addr = if_flash_sect_addr[ir_flash_index];
+ printf("current sector= %x app_ir_param_init addr=%x\r\n",ir_flash_index,addr);
+ ir_flash_check(addr);
+ }
+}
+
+void ir_flash_save_en(u8 button_index)
+{
+ ir_app_parm.ir_save.ir_save_en |= 1<<button_index;
+ printf("ir_flash_save_en ir_save_en=%x\r\n",ir_app_parm.ir_save.ir_save_en);
+
+}
+
+void ir_flash_save_flag_for_ext_sector(void)
+{
+ u8 index;
+ u32 addr;
+ u8 data;
+
+ index = ir_flash_index/3;
+ addr = IR_DATA_SECT_0_EXT_ADDR + index*0x1000;
+ flash_read_page(addr,1,&data);
+ if(data != APP_IR_DATA_HEAD)
+ {
+ data = APP_IR_DATA_HEAD;
+ flash_write_page(addr,1,&data);
+ printf("ir_flash_save_flag_for_ext_sector =%x",index);
+ }
+}
+
+void ir_flash_save(u8 button)
+{
+ u32 flash_addr;
+ u8 write_len_per;
+
+ flash_addr = if_flash_sect_addr[ir_flash_index] + button*256;
+ if(((ir_table[button].code_size+5) - ir_app_parm.ir_save.ir_save_pos) >= 16)
+ {
+ write_len_per = 16;
+ }
+ else
+ {
+ write_len_per = ir_table[button].code_size + 5 - ir_app_parm.ir_save.ir_save_pos;
+ }
+ if(ir_app_parm.ir_save.ir_save_pos<256)
+ {
+ if(bls_ll_requestConnBrxEventDisable() > 2)
+ {
+ bls_ll_disableConnBrxEvent();
+ //device_led_on(1);
+ flash_write_page(flash_addr+ir_app_parm.ir_save.ir_save_pos,write_len_per,(((u8*)(&ir_table[button]))+ir_app_parm.ir_save.ir_save_pos));
+ //device_led_off(1);
+ bls_ll_restoreConnBrxEvent();
+ }
+ else
+ return;
+ }
+ else
+ {
+ if(bls_ll_requestConnBrxEventDisable() > 2)
+ {
+
+ bls_ll_disableConnBrxEvent();
+ //device_led_on(1);
+ flash_write_page(flash_addr-IR_SECTOR_ADD_OFFSET+ir_app_parm.ir_save.ir_save_pos-256,write_len_per,(((u8*)(&ir_table[button]))+ir_app_parm.ir_save.ir_save_pos));
+ //device_led_off(1);
+ bls_ll_restoreConnBrxEvent();
+ ir_flash_save_flag_for_ext_sector();
+ }
+ else
+ return;
+ }
+ ir_app_parm.ir_save.ir_save_pos += write_len_per;
+ ir_app_parm.ir_save.ir_save_button = button;
+ //printf("pos=%x,button=%x\r\n",ir_app_parm.ir_save.ir_save_pos,ir_app_parm.ir_save.ir_save_button);
+ if(ir_app_parm.ir_save.ir_save_pos == (ir_table[button].code_size+5))
+ {
+ printf("\r\n w butt=%x\r\n",button);
+ ir_app_parm.ir_save.ir_save_en &= ~(1<<button);
+ ir_app_parm.ir_save.ir_save_button = 0xff;
+ }
+}
+
+
+/**
+ * @brief Backup the ir data in flash
+ * @param[in] none
+ * @return none
+ */
+int ir_flash_save_timeoutcb(void)
+{
+ u32 flash_addr;
+ u8 i,buf;
+ u8 ir_save_flag;
+
+ if((ir_app_parm.ir_save.ir_save_button == 0xff) && (ir_app_parm.ir_save.ir_save_pos == 0))
+ {
+ if(ir_save_error_flag == 0xaa)
+ {
+ if((ir_flash_erase_tick == 0) && (ir_flash_erase_sector_step == 0))
+ {
+ ir_flash_index = 0;
+ ir_save_error_flag = 0;
+ }
+ return 0;
+ }
+ else
+ {
+ flash_addr = if_flash_sect_addr[ir_flash_index];
+ flash_read_page(flash_addr, 1, &buf);
+ if(buf != 0xff)
+ {
+ printf("ir_flash_save error\r\n");
+ printf("ir_flash_save error\r\n");
+ ir_save_error_flag = 0xaa;
+ if(ir_flash_index >= IR_DATA_NEED_ERASE_NUM)
+ {
+ flash_addr = if_flash_sect_addr[0];
+ flash_read_page(flash_addr, 1, &buf);
+ if(buf == 0xff)
+ {
+ ir_flash_need_erase_sector = 2;
+ ir_flash_erase_tick = clock_time() | 1;
+ ir_flash_index = 0;
+ }
+ else
+ {
+ //erase all
+ ir_flash_need_erase_sector = 4;
+ }
+ }
+ else
+ {
+ flash_addr = if_flash_sect_addr[IR_DATA_NEED_ERASE_NUM];
+ flash_read_page(flash_addr, 1, &buf);
+ if(buf == 0xff)
+ {
+ ir_flash_need_erase_sector = 0;
+ ir_flash_erase_tick = clock_time() | 1;
+ ir_flash_index = IR_DATA_NEED_ERASE_NUM;
+ }
+ else
+ {
+ //erase all
+ ir_flash_need_erase_sector = 4;
+ }
+ }
+ return 0;
+ }
+ }
+ }
+ ir_save_flag = ir_app_parm.ir_save.ir_save_en;
+ if((ir_app_parm.ir_save.ir_save_button != 0xff) && (ir_app_parm.ir_save.ir_save_button <= 4))
+ {
+ ir_flash_save(ir_app_parm.ir_save.ir_save_button);
+ return 0;
+ }
+ else
+ {
+ for(i=0;i<MAX_KEY_COUNT;i++)
+ {
+ if(ir_save_flag & 0x01)
+ {
+ if(ir_app_parm.ir_save.ir_save_button == 0xff)
+ ir_app_parm.ir_save.ir_save_pos = 0;
+ ir_app_parm.ir_save.ir_save_button = i;
+ ir_flash_save(ir_app_parm.ir_save.ir_save_button);
+ return 0;
+ }
+ else
+ {
+ ir_save_flag = ir_save_flag>>1;
+ }
+ }
+ return -1;
+ }
+}
+
+
+void ir_init_key_event_notify(u8 value)
+{
+ ir_app_parm.ir_programming.key_notification_flag = value;
+}
+
+/**
+ * @brief Erase the flash sector
+ * @return 0: not erase success
+ -1: erase success
+ */
+int ir_flash_erase_timeoutcb(void)
+{
+#ifdef CFG_ATM_SDK
+ // TODO: erase IR data
+#else
+ //printf("ir_flash_erase_timeoutcb\r\n");
+ //u32 time;
+ u8 data;
+ u32 pos_addr=0;
+
+ if(is_mic_enable() == 1)
+ return 0;
+
+ //u32 erase_time=clock_time();
+ //printf("flash erase sector=%x \r\n",ir_flash_need_erase_sector);
+ // time = bls_ll_requestConnBrxEventDisable();
+ if(ir_flash_need_erase_sector == 0)
+ {
+ pos_addr = 0;
+ }
+ else if(ir_flash_need_erase_sector == 2)
+ {
+ pos_addr = 0x2000;
+ }
+ else
+ {
+ //erase all
+ if(bls_ll_requestConnBrxEventDisable() > 150)
+ {
+ bls_ll_disableConnBrxEvent();
+ if(ir_flash_erase_sector_step == 0)
+ {
+ flash_erase_sector(IR_DATA_SECT_0_ADDR);
+ flash_erase_sector(IR_DATA_SECT_1_ADDR);
+ ir_flash_erase_sector_step = 1;
+ }
+ else if(ir_flash_erase_sector_step == 1)
+ {
+ flash_erase_sector(IR_DATA_SECT_0_EXT_ADDR);
+ flash_erase_sector(IR_DATA_SECT_1_EXT_ADDR);
+ ir_flash_erase_sector_step = 2;
+ }
+ else if(ir_flash_erase_sector_step == 2)
+ {
+ flash_erase_sector(IR_DATA_SECT_2_ADDR);
+ flash_erase_sector(IR_DATA_SECT_3_ADDR);
+ ir_flash_erase_sector_step = 3;
+ }
+ else
+ {
+ flash_erase_sector(IR_DATA_SECT_2_EXT_ADDR);
+ flash_erase_sector(IR_DATA_SECT_3_EXT_ADDR);
+ ir_flash_erase_sector_step = 0;
+ }
+ bls_ll_restoreConnBrxEvent();
+
+ if(ir_flash_erase_sector_step)
+ return 0;
+ else
+ return -1;
+ }
+ }
+ if(bls_ll_requestConnBrxEventDisable() > 70)
+ {
+ //device_led_on(1);
+ bls_ll_disableConnBrxEvent();
+ //printf("flash erase sector=%x \r\n",ir_flash_need_erase_sector);
+
+ if(ir_flash_erase_sector_step == 0)
+ {
+ flash_erase_sector(IR_DATA_SECT_0_ADDR + pos_addr);
+ ir_flash_erase_sector_step = 1;
+ }
+ else if(ir_flash_erase_sector_step == 1)
+ {
+ flash_erase_sector(IR_DATA_SECT_1_ADDR + pos_addr);
+ ir_flash_erase_sector_step = 2;
+ }
+ else
+ {
+ if(ir_flash_erase_sector_step == 2)
+ {
+ flash_read_page(IR_DATA_SECT_0_EXT_ADDR + pos_addr,1,&data);
+ if(data == APP_IR_DATA_HEAD)
+ {
+ printf("step_2\r\n");
+ flash_erase_sector(IR_DATA_SECT_0_EXT_ADDR + pos_addr);
+ ir_flash_erase_sector_step = 3;
+ }
+ else
+ {
+ printf("step_2_2\r\n");
+ flash_read_page(IR_DATA_SECT_1_EXT_ADDR + pos_addr,1,&data);
+ if(data == APP_IR_DATA_HEAD)
+ {
+ flash_erase_sector(IR_DATA_SECT_1_EXT_ADDR + pos_addr);
+ ir_flash_erase_sector_step = 0;
+ printf("erase_succ\r\n");
+ }
+ else
+ {
+ printf("step_2_2_2\r\n");
+ ir_flash_erase_sector_step = 0;
+ }
+ }
+ }
+ else
+ {
+ printf("step_3\r\n");
+ flash_read_page(IR_DATA_SECT_1_EXT_ADDR + pos_addr,1,&data);
+ if(data == APP_IR_DATA_HEAD)
+ {
+ printf("step_3_3\r\n");
+ flash_erase_sector(IR_DATA_SECT_1_EXT_ADDR + pos_addr);
+ ir_flash_erase_sector_step = 0;
+ printf("erase_succ\r\n");
+ }
+ else
+ {
+ printf("step_3_3_3\r\n");
+ ir_flash_erase_sector_step = 0;
+ }
+ }
+ }
+ bls_ll_restoreConnBrxEvent();
+ if(ir_flash_erase_sector_step)
+ return 0;
+ else
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+#if 0
+/**
+ * @brief Add a timer for erase flash
+ * @return none
+ */
+void ir_flash_erase(void)
+{
+ printf("ir_flash_erase\r\n");
+ //blt_soft_timer_add(ir_flash_erase_timeoutcb, FLASH_ERASE_TIMEOUT);
+ ir_flash_erase_timeoutcb();
+}
+#endif
+
+/**
+ * @brief Ir flash factory
+ * @return none
+ */
+void ir_flash_factory(void)
+{
+ printf("ir_flash_factory\r\n");
+#ifdef CFG_ATM_SDK
+ atm_ir_del_code();
+#else
+ ir_flash_set_flag(0);
+#endif
+}
+
+
+/**
+ * @brief Erase the flash sector
+ * @return 0: not erase success
+ -1: erase success
+ */
+int ir_key_event_notify_erase_timeoutcb(void)
+{
+ printf("ir_key_event_notify_erase_timeoutcb\r\n");
+#ifdef CFG_ATM_SDK
+ // TODO: port erase IR key event notify
+#else
+ if(bls_ll_requestConnBrxEventDisable() > 120)
+ {
+ bls_ll_disableConnBrxEvent();
+ flash_erase_sector(IR_KEY_EVENT_NOTIFY_SECT_ADDR);
+ printf("erase_succ\r\n");
+ bls_ll_restoreConnBrxEvent();
+ write_ir_key_event_notify(ir_app_parm.ir_programming.key_notification_flag);
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+
+/**
+ * @brief ir_programming_timeoutcb
+ * @return -1: exit the timer
+ 0: exit the timer this time
+ */
+int ir_programming_timeoutcb(void)
+{
+ printf("ir_programming_timeoutcb\r\n");
+ ir_app_parm.ir_programming.programming_start = 0;
+
+ if (ir_app_parm.programming_timer)
+ {
+ ir_app_parm.programming_timer = NULL;
+ }
+ return -1;
+}
+
+/**
+ * @brief Recognize the programming key is IR mode or BLE HID modes
+ * @param[in] button_index: which button
+ * @return 1: BLE HID mode
+ 0: IR mode
+ */
+u8 ir_key_is_suppress(u8 key_idx)
+{
+ u8 index;
+ index = ir_get_suppress_index_from_keyid_idx(key_idx);
+ if (index == KEY_IDX_NULL) return KEY_IDX_NULL;
+ if(ir_app_parm.ir_suppress[index])
+ return true;
+ else
+ return false;
+}
+void ir_suppress_reinit(void)
+{
+ u8 i;
+ for (i = 0; i < MAX_KEY_COUNT; i++)
+ {
+ ir_app_parm.ir_suppress[i] = 0;
+ }
+}
+/**
+ * @brief ir_type_read
+ * @param[in] none
+ * @return 1 or 0
+ */
+int ir_type_read(void)
+{
+ u8 type;
+ u8* code = ir_table[ir_app_parm.current_programming_key_send].code;
+
+ type = code[0];
+
+ if(type == 1) //one time ir seqnence
+ {
+ return 0;
+ }
+ else if(type == 3) //one time + repeated ir sequence
+ {
+#ifndef CFG_ATM_SDK
+ u16 sequence_length = ((u16)code[4] << 8 | code[5])<<2;
+ sequence_length += 8;
+ u8* p_sequence = &code[sequence_length];
+ sequence_length = ((u16)code[6] << 8 | code[7]);
+ T_dmaData_buf.data_num = 0;
+ for(u8 i = 0; i < sequence_length; i++)
+ {
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(1, PWM0_PULSE_NORMAL,(u16)(p_sequence[0]<<8) | p_sequence[1]);
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(0, PWM0_PULSE_NORMAL,(u16)(p_sequence[2]<<8) | p_sequence[3]);
+ p_sequence += 4;
+ }
+ T_dmaData_buf.dma_len = T_dmaData_buf.data_num * 2;
+#endif
+ }
+ else if(type == 4) // two repeated ir sequence
+ {
+
+ }
+
+ return 1;
+
+}
+
+/**
+ * @brief Obtain the duty,frequency,repear delay
+ * @param[in] none
+ * @return none
+ */
+void ir_fallback_get_protocol_configure(unsigned char* p_duty_cycle, unsigned short* p_carrier_frequency,
+ unsigned short* p_repeat_delay)
+{
+ *p_duty_cycle = ir_app_parm.duty_cycle;
+ *p_carrier_frequency = ir_app_parm.carrier_frequency;
+ *p_repeat_delay = ir_app_parm.ir_repeat_delay.repeat_delay;
+}
+
+#ifndef CFG_ATM_SDK
+/**
+ * @brief Load ir data to ir send buffer
+ * @param[in] ir data
+ * @return none
+ */
+void ir_send_key_code(key_code_t* p_key_code)
+{
+ u8* code = p_key_code->code;
+ u16 sequence_length,sequence_length2,length; //4 bytes per sequence
+ u8* p_sequence;
+
+ T_dmaData_buf.data_num = 0;
+
+ u8 type = code[0];
+ if(type)
+ {
+ ir_app_parm.duty_cycle = code[1]; //as percentage
+ ir_app_parm.carrier_frequency = ((u16)code[2] << 8 | code[3]) * 100; //in unit of 100Hz
+ sequence_length = (u16)code[4] << 8 | code[5];
+ }
+ //disable button
+ if (type == 0)
+ {
+ return;
+ }
+ //one time ir sequence
+ else if (type == 1)
+ {
+ p_sequence = &code[6];
+ for(u8 i = 0; i < sequence_length; i++)
+ {
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(1, PWM0_PULSE_NORMAL,(u16)(p_sequence[0]<<8) | p_sequence[1]);
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(0, PWM0_PULSE_NORMAL,(u16)(p_sequence[2]<<8) | p_sequence[3]);
+ p_sequence += 4;
+ }
+ }
+ //repeat ir sequence
+ else if (type == 2)
+ {
+ ir_app_parm.ir_repeat_delay.repeat_delay = (u16)code[6] << 8 | code[7];
+ //printf("ir_app_parm.ir_repeat_delay_cycle=%x\r\n",ir_app_parm.ir_repeat_delay.repeat_delay);
+ ir_app_parm.ir_repeat_delay.repeat_delay = \
+ ir_app_parm.ir_repeat_delay.repeat_delay*(1000000/ir_app_parm.carrier_frequency);
+ //printf("ir_repeat_delay_us=%x\r\n",ir_app_parm.ir_repeat_delay.repeat_delay);
+ p_sequence = &code[8];
+
+ for(u8 i = 0; i < sequence_length; i++)
+ {
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(1, PWM0_PULSE_NORMAL,(u16)(p_sequence[0]<<8) | p_sequence[1]);
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(0, PWM0_PULSE_NORMAL,(u16)(p_sequence[2]<<8) | p_sequence[3]);
+ p_sequence += 4;
+ }
+ //printf("duty_cycle=%x\r\n",ir_app_parm.duty_cycle);
+ //printf("carrier_frequency=%x\r\n",ir_app_parm.carrier_frequency);
+ //printf("sequence_length=%x\r\n",sequence_length);
+ }
+ //one time + repeat ir sequence
+ else if (type == 3)
+ {
+ sequence_length2 = (u16)code[6] << 8 | code[7];
+ //printf("sequence_length=%x\r\n",sequence_length);
+ p_sequence = &code[8];
+
+ for(u8 i = 0; i < sequence_length; i++)
+ {
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(1, PWM0_PULSE_NORMAL,(u16)(p_sequence[0]<<8) | p_sequence[1]);
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(0, PWM0_PULSE_NORMAL,(u16)(p_sequence[2]<<8) | p_sequence[3]);
+ p_sequence += 4;
+ }
+ }
+ else
+ {
+ sequence_length2 = (u16)code[6] << 8 | code[7];
+ if(ir_app_parm.odd_or_even_press % 2 == 1)
+ {
+ p_sequence = &code[8];
+ length = sequence_length;
+ }
+ else
+ {
+ length = sequence_length*4 + 8;
+ p_sequence = &code[length];
+ length = sequence_length2;
+
+ }
+ for(u8 i = 0; i < length; i++)
+ {
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(1, PWM0_PULSE_NORMAL,(u16)(p_sequence[0]<<8) | p_sequence[1]);
+ T_dmaData_buf.data[T_dmaData_buf.data_num ++] = \
+ pwm_config_dma_fifo_waveform(0, PWM0_PULSE_NORMAL,(u16)(p_sequence[2]<<8) | p_sequence[3]);
+ p_sequence += 4;
+ }
+ ir_app_parm.odd_or_even_press++;
+ }
+
+ ir_send_specil(ir_app_parm.carrier_frequency,ir_app_parm.duty_cycle);
+}
+#endif
+
+extern void app_ota_status(u8 status);
+_attribute_data_retention_ u8 ir_cache_key[3]={0};
+
+/**
+ * @brief Ir_repeat_delay_release_time
+ * @param[in] none
+ * @return 0
+ */
+int ir_cache_key_timer(void)
+{
+ printf("ir_cache_key_timer\r\n");
+ if(device_in_connection_state)
+ {
+ printf("send cachekey_notify\r\n");
+ ir_cache_key[0] = 0; //down
+ bls_att_pushNotifyData(ATV_IR_KEY_EVENT_IDX, ir_cache_key, sizeof(ir_cache_key));
+#ifdef CFG_ATM_SDK
+ atm_timer_udelay(100);
+#else
+ sleep_us(100);
+#endif
+ ir_cache_key[0] = 1; //up
+ bls_att_pushNotifyData(ATV_IR_KEY_EVENT_IDX, ir_cache_key, sizeof(ir_cache_key));
+ return -1;
+ }
+ printf("send cachekey_notify timeout\r\n");
+ return -1;
+}
+
+/**
+ * @brief send ir data and send nofity
+ * @param[in] 1: down 0:up
+ * @return 0
+ */
+int ir_fallback_send(u8 key_down)
+{
+ key_code_t* p_key_code = &ir_table[ir_app_parm.current_programming_key_send];
+ u16 key_id;
+
+ //printf("ir_fallback_send\r\n");
+#ifndef CFG_ATM_SDK
+ if(key_down)
+ app_ota_status(0);
+ else
+ app_ota_status(1);
+#endif
+ if(key_down)
+ {
+ printf("key down\r\n");
+#ifdef CFG_ATM_SDK
+ atm_ir_send_key_code(p_key_code->key_id, p_key_code->code,
+ p_key_code->code_size);
+#else
+ ir_send_key_code(p_key_code);
+#endif
+ }
+
+ if (ir_app_parm.ir_programming.key_notification_flag)
+ {
+ //Besides sending IR code, also notify ATV that the key event
+ printf("send notify\r\n");
+ if(app_custom_get_device_type() == REMOTE_G10)
+ key_id = key_button_map_g10[ir_app_parm.current_programming_key_send].key_id;
+ else
+ key_id = key_button_map_g20[ir_app_parm.current_programming_key_send].key_id;
+ //printf("key_id=%x\r\n",key_id);
+ ir_cache_key[0] = key_down ? 0:1;
+ ir_cache_key[1] = (key_id >> 8);
+ ir_cache_key[2] = key_id;
+ if(device_in_connection_state)
+ bls_att_pushNotifyData(ATV_IR_KEY_EVENT_IDX, ir_cache_key, sizeof(ir_cache_key));
+ else
+ {
+ if(key_down == 1)
+ {
+ printf("add cache key\r\n");
+ blt_soft_timer_delete(ir_cache_key_timer);
+ blt_soft_timer_add(ir_cache_key_timer, 5000000);
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief Ir_repeat_delay_release_time
+ * @param[in] none
+ * @return 0
+ */
+int ir_repeat_delay_release_time(void)
+{
+ ir_app_parm.ir_repeat_delay.release_timer = clock_time();
+ //printf("ir_app_parm.ir_repeat_delay_release_time=%x\r\n",ir_app_parm.ir_repeat_delay.release_timer);
+ return 0;
+}
+
+/**
+ * @brief ir_repeat_delay_timer
+ * @param[in] none
+ * @return -1
+ */
+int ir_repeat_delay_timer(void)
+{
+ printf("ir_repeat_delay_timer\r\n");
+ if(app_is_key_released())
+ {
+ programming_key_set(0x55);
+ ir_fallback_send(1);
+ }
+ return -1;
+}
+
+/**
+ * @brief ir_fallback_send_key_code
+ * @param[in] button_idx
+ * @param[in] key_down 1:down 0:up
+ * @return false or true
+ */
+#ifdef CFG_ATM_SDK
+u8 ir_fallback_send_key_code(u8 button_idx, bool key_down)
+#else
+u8 ir_fallback_send_key_code(u8 button_idx, u8 key_down)
+#endif
+{
+ u8 last_key_send = ir_app_parm.current_programming_key_send;
+ u32 current_time;
+ u32 time;
+ key_code_t* p_key_code = ir_get_key_code_from_keyid_idx(button_idx);
+ //printf("current_programming_key=%x\r\n",ir_app_parm.current_programming_key_send);
+ u8* code = ir_table[ir_app_parm.current_programming_key_send].code;
+
+ u8 type = code[0];
+ if (p_key_code == NULL)
+ {
+ return false;
+ }
+#ifndef CFG_ATM_SDK
+ if(type == 2)
+ {
+ if((last_key_send == ir_app_parm.current_programming_key_send))
+ {
+ current_time = clock_time();
+ /*
+ printf("current_time=%x\r\n",current_time);
+ printf("current_time - ir_app_parm.ir_repeat_delay.release_timer=%x\r\n",\
+ current_time - ir_app_parm.ir_repeat_delay.release_timer);
+ */
+ time = (current_time - ir_app_parm.ir_repeat_delay.release_timer)>>4;
+ if(time < ir_app_parm.ir_repeat_delay.repeat_delay)
+ {
+ time = ir_app_parm.ir_repeat_delay.repeat_delay - time;
+ //printf("need delay=%x\r\n",time);
+ blt_soft_timer_add(ir_repeat_delay_timer, time);
+ }
+ else
+ {
+ //printf("exceed delay time\r\n");
+ programming_key_set(0x55);
+ ir_fallback_send(key_down);
+ }
+ }
+ else
+ {
+ programming_key_set(0x55);
+ ir_fallback_send(key_down);
+ }
+ }
+ else
+#endif
+ {
+ programming_key_set(0x55);
+ ir_fallback_send(key_down);
+ }
+ return true;
+}
+
+/**
+ * @brief ir_code_merge
+ * @param[in] key_id
+ * @param[in] button_index
+ * @param[in] code size: ir data length
+ * @param[in] code: ir data
+ * @return none
+ */
+void ir_code_merge(u16 key_id,u8 button_index,u16 code_size,u8* code)
+{
+ //u32 flash_addr_pos=0;
+ u32 len;
+
+
+ //printf("ir_code_merge,ir_app_parm.ir_merge.ir_current_button=%x,button_index=%x\r\n",ir_app_parm.ir_merge.ir_current_button,button_index);
+ if(ir_app_parm.ir_merge.ir_current_button != button_index)
+ {
+ ir_app_parm.ir_merge.ir_code_pos = 0;
+ ir_app_parm.ir_merge.ir_keycode_total_len = 0;
+ if(code[0] == 1)
+ {
+ ir_app_parm.ir_merge.ir_keycode_total_len = ((u16)code[4] << 8 | code[5])*4 + 6;
+ }
+ else if(code[0] == 2)
+ {
+ ir_app_parm.ir_merge.ir_keycode_total_len = ((u16)code[4] << 8 | code[5])*4 + 8;
+ }
+ else if((code[0] == 3) || (code[0] == 4))
+ {
+ ir_app_parm.ir_merge.ir_keycode_total_len = ((u16)code[4] << 8 | code[5])*4 + ((u16)code[6] << 8 | code[7])*4 + 8;
+ }
+ //printf(" ir_app_parm.ir_merge.ir_keycode_total_len=%x,codesize=%x\r\n", ir_app_parm.ir_merge.ir_keycode_total_len,code_size);
+ memcpy(ir_table[button_index].code + ir_app_parm.ir_merge.ir_code_pos, code, code_size);
+ ir_app_parm.ir_merge.ir_code_pos += code_size;
+
+ }
+ else
+ {
+ memcpy(ir_table[button_index].code + ir_app_parm.ir_merge.ir_code_pos, code, code_size);
+ ir_app_parm.ir_merge.ir_code_pos += code_size;
+ }
+ // printf("ir_code_merge: ir_app_parm.ir_merge.ir_code_pos=%x,ir_app_parm.ir_merge.ir_keycode_total_len=%x,code_size=%x",ir_app_parm.ir_merge.ir_code_pos,ir_app_parm.ir_merge.ir_keycode_total_len,code_size);
+ if(ir_app_parm.ir_merge.ir_code_pos == ir_app_parm.ir_merge.ir_keycode_total_len)
+ {
+ len = ir_app_parm.ir_merge.ir_keycode_total_len;
+ ir_table[button_index].key_id = key_id;
+ ir_table[button_index].code_size = len;
+ ir_table[button_index].button_idx = button_index;
+ //flash_addr_pos += button_index*256;
+ //ir_flash_save(button_index,flash_addr_pos,len+5);
+#ifdef CFG_ATM_SDK
+ atm_ir_write_code(button_index, (u8*)&ir_table[button_index],
+ sizeof(key_code_t));
+#else
+ ir_flash_save_en(button_index);
+#endif
+ /*
+ for(u8 i=0;i<len;i++ )
+ {
+ printf(" %x\r\n",*(ir_table[button_index].code+i));
+ }
+ */
+ ir_app_parm.ir_programming.programmed_key_count++;
+ //printf("add key\r\n");
+ }
+}
+
+/**
+ * @brief ir_table_add_key
+ * @param[in] key_id,code_size,code
+ * @return 0,11
+ */
+u8 ir_table_add_key(u16 key_id, u16 code_size, u8* code)
+{
+ u8 button_index=0;
+ u16 button;
+
+ button_index = ir_get_button_idx_from_key_id(key_id);
+ if (button_index == KEY_IDX_NULL)
+ {
+ return false;
+ }
+ if ((ir_app_parm.ir_programming.programmed_key_count < MAX_KEY_COUNT)
+ && (code_size <= MAX_CODE_LENGTH))
+ {
+ if(app_custom_get_device_type() == REMOTE_G10)
+ {
+#ifdef CFG_ATM_SDK
+ button = key_button_map_g10[button_index].key_id;
+#else
+ button = key_button_map_g10[button_index].button;
+#endif
+ //printf("ir_table[button_index].key_id=%x \r\n",button);
+ }
+ else
+ {
+#ifdef CFG_ATM_SDK
+ button = key_button_map_g20[button_index].key_id;
+#else
+ button = key_button_map_g20[button_index].button;
+#endif
+ // printf("ir_table[button_index].key_id=%x \r\n",button);
+ }
+ //printf("ir_table[button_index].button_idx=%x \r\n",button_index);
+
+ ir_code_merge(button,button_index,code_size,code);
+ }
+ return true;
+}
+
+/**
+ * @brief ir_key_event_notify_erase
+ * @param[in] none
+ * @return none
+ */
+void ir_key_event_notify_erase(void)
+{
+ blt_soft_timer_add(ir_key_event_notify_erase_timeoutcb, 100000);
+}
+
+
+/**
+ * @brief Receive ATV commands and processed
+ * @param[in] handle :ATV command
+ * @param[in] buf:command
+ * @param[in] len: command data length
+ * @return false or true
+ */
+void ir_fallback_process(u16 handle, u8* buf, u16 len)
+{
+ u8 index,data;
+ // u8 testdata[6],i;
+ // u32 addr;
+ u8 k;
+
+ switch (handle)
+ {
+ case ATV_IR_PROG_CONTROL_IDX:
+ {
+ if (len == 1)
+ {
+ ir_app_parm.ir_programming.programming_start = *buf;
+ if (ir_app_parm.ir_programming.programming_start == 1)
+ {
+ printf("ir table programming start\r\n");
+ #if BLE_AUDIO_ENABLE
+ google_reset_rsp_delay();
+ #endif
+ ir_table_init();
+#ifdef CFG_ATM_SDK
+ atm_disable_slave_latency(true);
+#else
+ ir_flash_set_flag(0);
+ if(ir_flash_index == 0)
+ {
+ flash_read_page(IR_DATA_SECT_0_ADDR,1,&data);
+ if(data == APP_IR_DATA_HEAD_INVALID)
+ ir_flash_index++;
+ }
+ else
+ ir_flash_index++;
+
+ if(ir_flash_index >= IR_DATA_SECT_MAX_NUM)
+ ir_flash_index = 0;
+ printf("ir_flash_index=%x\r\n",ir_flash_index);
+#endif
+ if (ir_app_parm.programming_timer)
+ {
+ blt_soft_timer_delete(ir_programming_timeoutcb);
+ ir_app_parm.programming_timer = NULL;
+ }
+
+ ir_app_parm.programming_timer = 1;
+ blt_soft_timer_add(ir_programming_timeoutcb, PROGRAMMING_TIMEOUT);
+ }
+ else
+ {
+ printf("ir table programming end\r\n");
+#ifdef CFG_ATM_SDK
+ atm_disable_slave_latency(false);
+#else
+ extern u32 ir_flash_erase_tick;
+ if(ir_app_parm.ir_programming.programmed_key_count == 0)
+ {
+ ir_flash_set_flag(0);
+ printf(" empty ir programming\r\n");
+ }
+ if(ir_app_parm.ir_programming.programmed_key_count >= 1)
+ {
+ ir_flash_set_flag(1);
+ }
+ if(ir_flash_index == IR_DATA_NEED_ERASE_NUM)
+ {
+ ir_flash_need_erase_sector = 0;
+ ir_flash_erase_tick = clock_time() | 1;
+ }
+ if(ir_flash_index == 0)
+ {
+ ir_flash_need_erase_sector = 2;
+ ir_flash_erase_tick = clock_time() | 1;
+ }
+#endif
+ if (ir_app_parm.programming_timer)
+ {
+ blt_soft_timer_delete(ir_programming_timeoutcb);
+ ir_app_parm.programming_timer = NULL;
+ }
+#ifndef CFG_ATM_SDK
+ printf("ir_flash_erase_tick=%x\r\n",ir_flash_erase_tick);
+ /*
+ for(i=0;i<IR_DATA_SECT_NUM;i++)
+ {
+ addr = IR_DATA_SECT_0_ADDR+i*0x1000;
+ flash_read_page(addr, 6, testdata);
+ printf("sect i=%x addr =%x\r\n",i,addr);
+ for(k=0;k<6;k++)
+ //printf(" %x",testdata[k]);
+ }
+ */
+ if(app_ir_programming_end_Cb != NULL)
+ {
+ app_ir_programming_end_Cb();
+ }
+#endif
+ }
+ }
+ break;
+ }
+ case ATV_IR_KEY_ID_IDX:
+ {
+ if ((ir_app_parm.ir_programming.programming_start == 1)
+ //&& (ir_app_parm.ir_programming.current_programming_key_id == INVALID_KEY_ID)
+ && (len == 2))
+ {
+ ir_app_parm.ir_programming.current_programming_key_id = buf[0];
+ ir_app_parm.ir_programming.current_programming_key_id <<= 8;
+ ir_app_parm.ir_programming.current_programming_key_id |= buf[1];
+ if (ir_app_parm.programming_timer)
+ {
+ blt_soft_timer_delete(ir_programming_timeoutcb);
+ ir_app_parm.programming_timer = NULL;
+ }
+ blt_soft_timer_add(ir_programming_timeoutcb, PROGRAMMING_TIMEOUT);
+ ir_app_parm.programming_timer = 1;
+ }
+ break;
+ }
+ case ATV_IR_CODE_IDX:
+ {
+ if ((ir_app_parm.ir_programming.programming_start == 1) && (len > 0))
+ {
+ if (ir_app_parm.ir_programming.current_programming_key_id != INVALID_KEY_ID)
+ {
+ u8 return_value;
+ return_value = ir_table_add_key(ir_app_parm.ir_programming.current_programming_key_id, len, buf);
+ ir_app_parm.ir_programming.current_programming_key_id = INVALID_KEY_ID;
+ }
+ else
+ {
+ //response error
+ }
+ if (ir_app_parm.programming_timer)
+ {
+ blt_soft_timer_delete(ir_programming_timeoutcb);
+ ir_app_parm.programming_timer = NULL;
+ }
+ blt_soft_timer_add(ir_programming_timeoutcb, PROGRAMMING_TIMEOUT);
+ ir_app_parm.programming_timer = 1;
+ }
+ break;
+ }
+ case ATV_IR_SUPPRESS_IDX:
+ {
+ if(len)
+ {
+ printf("switch to ble\r\n");
+ if(len%2 == 0)
+ {
+ for(k=0;k<len/2;k++)
+ {
+ u16 id = (buf[2*k]<<8) | buf[2*k+1];
+ index = ir_get_button_idx_from_key_id(id);
+ printf("index=%x\r\n",index);
+ if(ir_app_parm.ir_suppress[index] == 0)
+ {
+ ir_app_parm.ir_suppress[index] = 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ printf("switch to ir\r\n");
+ for(k=0;k<MAX_KEY_COUNT;k++)
+ {
+ if(ir_app_parm.ir_suppress[k])
+ {
+ ir_app_parm.ir_suppress[k] = 0;
+ }
+ }
+ }
+ break;
+ }
+ case ATV_IR_KEY_EVENT_CCCD_IDX:
+ {
+ if (len == 2)
+ {
+ printf("ccc buf[0]=%x\r\n",buf[0]);
+ if(buf[0] != ir_app_parm.ir_programming.key_notification_flag)
+ {
+ ir_app_parm.ir_programming.key_notification_flag = buf[0];
+#ifdef CFG_ATM_SDK
+ atm_ir_write_ccc(buf[0]);
+#else
+ if(is_ir_key_event_notify_flash_info_full() == 1)
+ {
+ ir_key_event_notify_erase();
+ }
+ else
+ write_ir_key_event_notify(buf[0]);
+#endif
+ }
+ }
+ break;
+ }
+ default:
+ {
+ //printf("!!unhandled IDX\r\n");
+ }
+ break;
+ }
+}
+#ifndef CFG_ATM_SDK
+void ir_flash_save_loop(void)
+{
+ if(ir_app_parm.ir_save.ir_save_en)
+ {
+ ir_flash_save_timeoutcb();
+ }
+}
+
+void ir_flash_erase_loop(void)
+{
+ if((ir_flash_erase_tick) && (ir_send_ctrl.is_sending== 0))
+ {
+ if(ir_flash_erase_timeoutcb() == -1)
+ {
+ ir_flash_erase_tick = 0;
+ }
+ }
+}
+
+u8 ir_flash_busy(void)
+{
+ if(ir_app_parm.ir_save.ir_save_en || ir_flash_erase_tick || ir_app_parm.ir_programming.programming_start)
+ return 1;
+ else
+ return 0;
+}
+#endif
+
+#define APP_IR_CMD_OTA_NEC_IR_TABLE_PREPARE 0xEF00
+#define APP_IR_CMD_OTA_NEC_IR_TABLE_START 0xEF01
+#define APP_IR_CMD_OTA_NEC_IR_TABLE_END 0xEF02
+
+void ir_nec_ir_table_process(u8 *data,u16 len)
+{
+#ifndef CFG_ATM_SDK
+ u8 datasend[3];
+ u16 crc=0;
+ u32 flash_addr=0,pos=0;
+ u8 readdata[16];
+ u8 result=0;
+ u16 cmd = data[0] | (data[1]<<8);
+
+ if(cmd == APP_IR_CMD_OTA_NEC_IR_TABLE_PREPARE)
+ {
+ nec_ir_table_start = APP_NEC_IR_TABLE_PREPARE;
+ }
+ else if(cmd == APP_IR_CMD_OTA_NEC_IR_TABLE_START)
+ {
+ nec_ir_table_start = APP_NEC_IR_TABLE_START;
+ }
+ else if(((data[0] == 2) && (data[1] == 0xEF))) //IR end
+ {
+ datasend[0] = 0xEE;
+ datasend[1] = 2;
+ datasend[2] = 0;
+ bls_att_pushNotifyData(OTA_CMD_OUT_DP_H, datasend, sizeof(datasend));
+ if(nec_ir_table_start == APP_NEC_IR_TABLE_START)
+ {
+ app_custom_set_new_ir_table();
+ }
+ nec_ir_table_start = APP_NEC_IR_TABLE_END;
+ }
+
+ if(nec_ir_table_start == APP_NEC_IR_TABLE_START)
+ {
+ if(len == 20)
+ {
+ crc = (data[19]<<8) | data[18];
+ pos = (data[0]) | (data[1]<<8);
+ extern unsigned short crc16 (unsigned char *pD, int len);
+ if(crc == crc16(data,18))
+ {
+ flash_addr = APP_NEC_IR_CODE_TABLE + pos*16;
+ flash_write_page(flash_addr,16,&data[2]);
+ flash_read_page(flash_addr,16, readdata);
+ if(memcmp(&data[2],readdata,16))
+ {
+ result = 1;
+ }
+ }
+ else
+ {
+ result = 1;
+ }
+ if(result == 1)
+ {
+ datasend[0] = 0xEE;
+ datasend[1] = 2;
+ datasend[2] = 1;
+ bls_att_pushNotifyData(OTA_CMD_OUT_DP_H, datasend, sizeof(datasend));
+ nec_ir_table_start = APP_NEC_IR_TABLE_WRITEFAIL; //data invalid, must erase
+ }
+ }
+ }
+#endif // CFG_ATM_SDK
+}
+
+int ir_nec_ir_table_erase_timeoutcb(void)
+{
+#ifdef CFG_ATM_SDK
+ // TODO: erase IR table
+#else
+ if(is_mic_enable() == 1)
+ return 0;
+ if(bls_ll_requestConnBrxEventDisable() > 120)
+ {
+ printf("ir_nec_ir_table_erase_timeoutcb\r\n");
+ bls_ll_disableConnBrxEvent();
+ flash_erase_sector(APP_NEC_IR_CODE_TABLE);
+ bls_ll_restoreConnBrxEvent();
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+void ir_nec_ir_table_erase_loop(void)
+{
+#ifndef CFG_ATM_SDK
+ u8 datasend[3];
+ if((nec_ir_table_start == APP_NEC_IR_TABLE_PREPARE) || (nec_ir_table_start == APP_NEC_IR_TABLE_WRITEFAIL))
+ {
+ if(ir_send_ctrl.is_sending == 0)
+ {
+ if(ir_nec_ir_table_erase_timeoutcb() == -1)
+ {
+ if(device_in_connection_state && (nec_ir_table_start == APP_NEC_IR_TABLE_PREPARE))
+ {
+ //printf("ir_nec_ir_table_erase_end\r\n");
+ datasend[0] = 0XEE;
+ datasend[1] = 0;
+ datasend[2] = 0;
+ bls_att_pushNotifyData(OTA_CMD_OUT_DP_H, datasend, sizeof(datasend));
+ }
+ nec_ir_table_start = APP_NEC_IR_TABLE_PREPARE_END;
+ }
+ }
+ }
+#endif
+}
+
+#endif
+