blob: d6fed7aefcddfb3ee5c463ae9a5fa0b629403270 [file] [log] [blame]
/******************************************************************************
* @file app_info.c
*
* @brief for TLSR chips
*
* @author public@telink-semi.com;
* @date Sep. 30, 2010
*
* @attention
*
* Copyright (C) 2019-2020 Telink Semiconductor (Shanghai) Co., Ltd.
*
* 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.
*
*****************************************************************************/
#include "tl_common.h"
#include "drivers.h"
#include "app_flash_write.h"
_attribute_data_retention_ u8 flag_ccc_data = 0;
_attribute_data_retention_ u8 peer_mac[6] = {0};
/**********************************************************
**** operate flash function
**********************************************************/
/**
* @brief This function can make more effective use of flash.
* @param[in] addr the start address of the page
* @param[in] Number of sectors used to save this data type
* @param[in] Space occupied by a piece of data.Less than 256£¬
* @return -1:No data found,others:address offset
*/
s16 bsearch_without_recursion(unsigned long addr, u8 used_sector, u8 used_block)
{
s16 low=0, high=(4*1024/used_block)*used_sector -1;
u8 rbuf[2];
u8 cmp1[] = {U16_LO(FLASH_FLAG),U16_HI(FLASH_FLAG)};//{0xa5,0xff};
u8 cmp2[] = {0x00,0x00};
u8 cmp3[] = {0xff,0xff};
while(low<=high)
{
//DEBUG("low: %d high: %d\n",low,high);
s16 mid=(low+high)/2;
flash_read_page(addr + mid*used_block,2,rbuf);
//printf("bsearchWithoutRecursion tmp:");
//arrayPrint(tmp,2);
//printf("\n:");
if(!memcmp(rbuf, cmp3, 2)) high = mid - 1;
else if(!memcmp(rbuf, cmp2, 2)) low = mid + 1;
else if(!memcmp(rbuf, cmp1, 2)) return mid;//return mid*used_block;
else return -1;
}
return -1;
}
/**
* @brief This function can make more effective use of flash.
* @param[in] addr the start address of the page
* @param[in] Number of sectors used to save this data type
* @param[in] Space occupied by a piece of data.Less than 256£¬
* @param[in] len the length(in byte) of content needs to read out from the page
* @param[out] buf the start address of the buffer
* @return 0:Success,1:flash is empty,2:sector data error
*/
u8 flash_pos_info(unsigned long addr, u8 used_sector, u8 used_block){
u8 ret = 0;
u8 begin_data[2]; //beginning of sector data.byte 0,1 is 1st sector data,byte 2,3 is 2nd sector data.
s16 high=(4*1024/used_block)*used_sector -1;
//Read the beginning and end data of the 1st sector
flash_read_page(addr, 2, begin_data);
//flash_read_page(addr, 2, end_data);
u8 allff[2] = {0xff,0xff};
/**** start check flash ****/
if(!memcmp(begin_data, allff, 2)){
//beginning of 1st sector data(2byte) is all 0xff.
//Indicates whether the RCU is brand new or factory set
ret = 1; //return 1; //No data in flash
}else{
//search data in flash
s16 offset = bsearch_without_recursion(addr,used_sector,used_block);
//printf("offset=%x \r\n", (u16)offset);
if(offset == -1){
ret = 2; //return 2; //sector data error
}
else
{
if(offset>(high/10*9))
return 3;
}
}
return ret;
}
/**
* @brief This function can make more effective use of flash.
* @param[in] addr the start address of the page
* @param[in] Number of sectors used to save this data type
* @param[in] Space occupied by a piece of data.Less than 256£¬
* @param[in] len the length(in byte) of content needs to read out from the page
* @param[out] buf the start address of the buffer
* @return 0:Success,1:flash is empty,2:sector data error
*/
u8 flash_read_info(unsigned long addr, u8 used_sector, u8 used_block, unsigned long len, u8 *rbuf){
u8 ret = 0;
u8 begin_data[2]; //beginning of sector data.byte 0,1 is 1st sector data,byte 2,3 is 2nd sector data.
//Read the beginning and end data of the 1st sector
flash_read_page(addr, 2, begin_data);
//flash_read_page(addr, 2, end_data);
u8 allff[2] = {0xff,0xff};
/**** start check flash ****/
if(!memcmp(begin_data, allff, 2)){
//beginning of 1st sector data(2byte) is all 0xff.
//Indicates whether the RCU is brand new or factory set
ret = 1; //return 1; //No data in flash
}else{
//search data in flash
s16 offset = bsearch_without_recursion(addr,used_sector,used_block);
if(offset == -1){
ret = 2; //return 2; //sector data error
}else{
flash_read_page(addr + offset*used_block, len, rbuf);
}
}
return ret;
}
/**
* @brief This function can make more effective use of flash.
* @param[in] addr the start address of the page
* @param[in] Number of sectors used to save this data type
* @param[in] Space occupied by a piece of data.Less than 256£¬
* @param[in] len the length(in byte) of content needs to read out from the page
* @param[out] buf the start address of the buffer
* @return 0:Success,1:flash is empty,2:sector data error,3:read data error
*/
u8 flash_write_info(unsigned long addr, u8 used_sector, u8 used_block, unsigned long len, u8 *wbuf ){
u8 ret = 0;
u8 begin_data[2]; //beginning of sector data.byte 0,1 is 1st sector data,byte 2,3 is 2nd sector data.
//u8 end_data[4]; //end of sector data.byte 0,1 is 1st sector data,byte 2,3 is 2nd sector data.
//Read the beginning and end data of the 1st sector
flash_read_page(addr, 2, begin_data);
//flash_read_page(addr, 2, end_data);
u8 allff[2] = {0xff,0xff};
/**** start check flash ****/
if(!memcmp(begin_data, allff, 2)){
//beginning of 1st sector data(2byte) is all 0xff.
//Indicates whether the RCU is brand new or factory set
ret = 1; //No data in flash
}else{
//search data in flash
s16 offset = bsearch_without_recursion(addr,used_sector,used_block);
if(offset == -1){
ret = 2; //sector data error
}else{
u8 clr[2] = {0};
flash_write_page(addr + offset*used_block, 2, clr);
//if(offset + 1 >= 4*1024*used_sector/used_block) offtset = -1; //2nd sector is full.so set offset to beginning of 1st sector
//write data to flash
flash_write_page(addr + (offset + 1)*used_block, len, wbuf);
//Confirm that writing data is correct
//u8 temp[256] = {0};
u8 temp[16] = {0};
flash_read_page(addr + (offset + 1)*used_block, len, temp);
if(memcmp(wbuf, temp, len)) ret = 3; //The data written and read does not match
}
}
switch(ret){
case 3:
case 2:
break;
case 1:
{
flash_write_page(addr, len, wbuf);
break;
}
case 0:
default:
break;
}
return ret;
}
void flash_check_area(unsigned long addr, u8 used_sector, u8 used_block, unsigned long len){
u8 begin_data[2]; //beginning of sector data.byte 0,1 is 1st sector data,byte 2,3 is 2nd sector data.
u8 allff[2] = {0xff,0xff};
//Read the beginning and end data of the 1st sector
flash_read_page(addr, 2, begin_data);
if(!memcmp(begin_data, allff, 2)){
//beginning of 1st sector data(2byte) is all 0xff.
//Indicates whether the RCU is brand new or factory set
return;
}
s16 offset = bsearch_without_recursion(addr,used_sector,used_block);
if(offset == -1){
//sector data error
for(u8 i=0;i<used_sector;i++){
flash_erase_sector(addr+i*0x1000);
}
return;
}
//If the area usage exceeds 70%, erase the area
// if(offset > (4*1024/used_block)*used_sector/10*8){
// u8 rbuf[256] = {0};
// flash_read_page(addr + offset*used_block,len,rbuf);
// //flash_read_page(addr + offset*used_block,used_block,rbuf);
// for(u8 i=0;i<used_sector;i++){
// flash_erase_sector(addr+i*0x1000);
// }
// //Move the data to the beginning of the 2st sector
// flash_write_page(addr,len,rbuf);
// //flash_write_page(addr,used_block,rbuf);
// }
}
void write_ccc_info(u8 *ccc){
u8 dat[4] ={0xA5,0xFF,0xFF,0xFF};
memcpy(dat+2,ccc,1);
u8 ret = flash_write_info(CCC_DATA_AREA,1,4,3,dat);
printf("write_ccc_info:0x%x",ret);
}
u8 read_ccc_info(u8 *ccc){
u8 dat[4] ={0};
u8 ret = flash_read_info(CCC_DATA_AREA,1,4,3,dat);
if(!ret){
ccc[0] = dat[2];
}
//return 0:Success,1:flash is empty,2:sector data error
return ret;
}
extern u16 atv_char_ctl_ccc;
extern u16 atv_char_rx_ccc;
void init_ccc_value(){
read_ccc_info(&flag_ccc_data);
atv_char_ctl_ccc = (flag_ccc_data & FLAG_GOOGLE_CTL_CCC)?1:0;
atv_char_rx_ccc = (flag_ccc_data & FLAG_GOOGLE_RX_CCC)?1:0;
printf("atv_char_ctl_ccc:%d\n",atv_char_ctl_ccc);
printf("atv_char_rx_ccc:%d\n",atv_char_rx_ccc);
}
void is_flash_info_full(void)
{
if(flash_pos_info(CCC_DATA_AREA,1,4) == 0x03)
{
flash_erase_sector(CCC_DATA_AREA);
write_ccc_info(&flag_ccc_data);
}
}
void write_peer_mac_info(u8 *mac){
u8 dat[8] ={0xA5,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
memcpy(dat+2,mac,6);
u8 ret = flash_write_info(MAC_DATA_SECT_ADDR,1,8,8,dat);
printf("write_mac_info:0x%x\r\n",ret);
}
u8 read_peer_mac_info(u8 *mac){
u8 dat[8] ={0};
u8 ret = flash_read_info(MAC_DATA_SECT_ADDR,1,8,8,dat);
if(!ret){
for(u8 i=0;i<6;i++)
mac[i] = dat[2+i];
}
//return 0:Success,1:flash is empty,2:sector data error
return ret;
}
u8 is_peer_mac_flash_info_full(void)
{
if(flash_pos_info(MAC_DATA_SECT_ADDR,1,8) == 0x03)
{
return 1;
}
return 0;
}
void init_peer_mac(void)
{
u8 i;
u8 dat;
for(i=0;i<5;i++)
{
dat = read_peer_mac_info(peer_mac);
if(dat == 0)
{
printf("peer_mac =\r\n");
for(u8 i=0;i<6;i++)
printf(" %x",peer_mac[i]);
printf("\r\n");
if(is_peer_mac_flash_info_full())
{
flash_erase_sector(MAC_DATA_SECT_ADDR);
write_peer_mac_info(peer_mac);
}
break;
}
else if(dat == 1)
{
printf("no_peer_mac\r\n");
break;
}
}
}
void write_wakeup_keyindex_info(u8 index){
u8 dat[4] ={0xA5,0xff,0xff,0xff};
dat[2] = index;
u8 ret = flash_write_info(WAKEUP_KEYINDEX_DATA_SECT_ADDR,2,4,3,dat);
printf("write_wakeup_keyindex_info:0x%x\r\n",ret);
}
u8 read_wakeup_keyindex_info(u8 *index){
u8 dat[4] ={0};
u8 ret = flash_read_info(WAKEUP_KEYINDEX_DATA_SECT_ADDR,2,4,3,dat);
if(!ret){
*index = dat[2];
}
//return 0:Success,1:flash is empty,2:sector data error
return ret;
}
u8 is_wakeup_keyindex_flash_info_full(void)
{
if(flash_pos_info(WAKEUP_KEYINDEX_DATA_SECT_ADDR,2,4) == 0x03)
{
return 1;
}
return 0;
}
void init_wakeup_keyindex(void)
{
u8 index=0;
if(read_wakeup_keyindex_info(&index) == 0)
{
if(is_wakeup_keyindex_flash_info_full())
{
flash_erase_sector(WAKEUP_KEYINDEX_DATA_SECT_ADDR);
flash_erase_sector(WAKEUP_KEYINDEX_DATA_SECT_ADDR+0x1000);
write_wakeup_keyindex_info(index);
}
printf("wakeup_keyindex=%x\r\n",index);
}
else
{
printf("no_wakeup_keyindex\r\n");
}
}
void write_ir_key_event_notify(u8 index){
u8 dat[4] ={0xA5,0xff,0xff,0xff};
dat[2] = index;
u8 ret = flash_write_info(IR_KEY_EVENT_NOTIFY_SECT_ADDR,1,4,3,dat);
printf("write_ir_key_event_notify index =%x,ret=0x%x\r\n",index,ret);
}
u8 read_ir_key_event_notify(u8 *index){
u8 dat[4] ={0};
u8 ret = flash_read_info(IR_KEY_EVENT_NOTIFY_SECT_ADDR,1,4,3,dat);
if(!ret){
*index = dat[2];
}
//return 0:Success,1:flash is empty,2:sector data error
return ret;
}
u8 is_ir_key_event_notify_flash_info_full(void)
{
if(flash_pos_info(IR_KEY_EVENT_NOTIFY_SECT_ADDR,1,4) == 0x03)
{
return 1;
}
return 0;
}
u8 init_ir_key_event_notify(void)
{
u8 index=0xff;
if(read_ir_key_event_notify(&index) == 0)
{
if(is_ir_key_event_notify_flash_info_full())
{
flash_erase_sector(IR_KEY_EVENT_NOTIFY_SECT_ADDR);
write_ir_key_event_notify(index);
}
printf("ir_key_event_notify ccc=%x\r\n",index);
}
else
{
printf("no ir_key_event_notify\r\n");
}
return index;
}