1 /* Copyright Statement:
3 * This software/firmware and related documentation ("MediaTek Software") are
4 * protected under relevant copyright laws. The information contained herein
5 * is confidential and proprietary to MediaTek Inc. and/or its licensors.
6 * Without the prior written permission of MediaTek inc. and/or its licensors,
7 * any reproduction, modification, use or disclosure of MediaTek Software,
8 * and information contained herein, in whole or in part, shall be strictly prohibited.
10 * MediaTek Inc. (C) 2010. All rights reserved.
12 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
13 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
14 * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
15 * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
18 * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
19 * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
20 * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
21 * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
22 * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
23 * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
24 * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
25 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
26 * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
27 * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
28 * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
29 * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
31 * The following software/firmware and/or related documentation ("MediaTek Software")
32 * have been modified by MediaTek Inc. All revisions are subject to any receiver's
33 * applicable license agreements with MediaTek Inc.
36 #include <linux/module.h>
37 #include <linux/kernel.h>
38 #include <linux/init.h>
39 #include <linux/delay.h> // udelay()
40 #include <linux/device.h> // device_create()
41 #include <linux/platform_device.h>
42 #include <linux/i2c.h>
43 #include <linux/cdev.h>
46 #include <asm/uaccess.h> // get_user()
49 #include "mt6620_fm.h"
50 #include "mt6620_fm_lib.h"
52 /******************************************************************************
54 *****************************************************************************/
55 #define MT6620_RDS_BLER_TH1 90
56 #define MT6620_RDS_BLER_TH2 60
57 #define MT6620_RDS_BLER_C1 12
58 #define MT6620_RDS_BLER_C2 6
59 #define MT6620_RDS_BLER_T1 5000
60 #define MT6620_RDS_BLER_T2 5000
62 //FM_RDS_DATA_CRC_FFOST(0xB2)
63 #define FM_RDS_GDBK_IND_A (0x08)
64 #define FM_RDS_GDBK_IND_B (0x04)
65 #define FM_RDS_GDBK_IND_C (0x02)
66 #define FM_RDS_GDBK_IND_D (0x01)
67 #define FM_RDS_DCO_FIFO_OFST (0x01E0)
68 #define FM_RDS_READ_DELAY (0x80)
71 /******************************************************************************
73 *****************************************************************************/
74 static bool bRDS_FirstIn = false;
75 static uint16_t RDS_Sync_Cnt = 0, RDS_Block_Reset_Cnt = 0;
77 extern int16_t _current_frequency;
78 uint32_t gBLER_CHK_INTERVAL = 5000;
79 static int16_t preAF_Num = 0;
80 static int16_t preAFON_Num = 0;
81 uint16_t GOOD_BLK_CNT = 0, BAD_BLK_CNT = 0;
82 uint8_t BAD_BLK_RATIO = 0;
85 #define FM_ASSERT(a) { \
87 printk("%s, invalid buf\n", __func__);\
88 return -ERR_INVALID_BUF; \
93 #define RDS_RT_MULTI_REV_TH 16
96 RDS_GRP_VER_A = 0, //group version A
100 typedef enum RDS_RT_STATE_MACHINE
108 }RDS_RT_STATE_MACHINE;
110 typedef enum RDS_BLK_T
119 static RDS_RT_STATE_MACHINE rt_state_machine = RDS_RT_START;
121 /******************************************************************************
122 * Local function extern
123 *****************************************************************************/
124 static int MT6620_RDS_enable(void);
125 static int MT6620_RDS_disable(void);
126 static int MT6620_RDS_Get_GoodBlock_Counter(uint16_t* pCnt);
127 static int MT6620_RDS_Get_BadBlock_Counter(uint16_t* pCnt);
128 static int MT6620_RDS_Reset_Block_Counter(void);
129 static int MT6620_RDS_Reset(void);
130 static int MT6620_RDS_Reset_Block(void);
131 static int MT6620_RDS_Init_Data(RDSData_Struct *pstRDSData);
132 static int MT6620_RDS_RetrieveGroup0(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData);
133 static int MT6620_RDS_RetrieveGroup1(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData);
134 static int MT6620_RDS_RetrieveGroup2(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData);
135 static int MT6620_RDS_RetrieveGroup4(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData);
136 static int MT6620_RDS_RetrieveGroup14(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData);
137 extern int MT6620_read(uint8_t addr, uint16_t *val);
138 extern int MT6620_write(uint8_t addr, uint16_t val);
139 extern int MT6620_set_bits(uint8_t addr, uint16_t bits, uint16_t mask);
140 extern int Delayms(uint32_t data);
141 extern int Delayus(uint32_t data);
145 * To get rds group count form raw data
146 * If success return 0, else return error code
148 static int rds_cnt_get(struct rds_rx *rds_raw, int raw_size, int *cnt){
150 int gap = sizeof(rds_raw->cos) + sizeof(rds_raw->sin);
154 *cnt = (raw_size - gap)/sizeof(rds_packet_struct);
155 FM_LOG_INF(D_RDS,"group cnt=%d\n", *cnt);
162 * To get rds group[n] data form raw data with index
163 * If success return 0, else return error code
165 static int rds_group_get(uint16_t *dst, struct rds_rx *raw, int idx){
170 if(idx > (MAX_RDS_RX_GROUP_CNT - 1)){
171 ret = -ERR_INVALID_PARA;
174 dst[0] = raw->data[idx].blkA;
175 dst[1] = raw->data[idx].blkB;
176 dst[2] = raw->data[idx].blkC;
177 dst[3] = raw->data[idx].blkD;
178 dst[4] = raw->data[idx].crc;
179 dst[5] = raw->data[idx].cbc;
181 FM_LOG_INF(D_RDS,"BLOCK:%04x %04x %04x %04x, CRC:%04x\n", dst[0], dst[1], dst[2], dst[3], dst[4]);
188 * To check CRC rerult, if OK, *valid=TRUE, else *valid=FALSE
189 * If success return 0, else return error code
191 static int rds_checksum_check(uint16_t crc, int mask, bool *valid){
195 if((crc & mask) == mask){
205 * rds_cbc_get - To get block_n's correct bit count form cbc
206 * @cbc, the group's correct bit count
207 * @blk, target the block
209 * If success, return block_n's cbc, else error code
211 static int rds_cbc_get(uint16_t cbc, enum RDS_BLK_T blk){
216 ret = (cbc & 0xF000) >> 12;
219 ret = (cbc & 0x0F00) >> 8;
222 ret = (cbc & 0x00F0) >> 4;
225 ret = (cbc & 0x000F) >> 0;
230 FM_LOG_INF(D_RDS,"group cbc=0x%04x\n", cbc);
236 * To set rds event, and user space can use this flag to juge which event happened
237 * If success return 0, else return error code
239 static int rds_event_set(uint16_t *events, int event_mask){
243 *events |= event_mask;
250 * To set rds event flag, and user space can use this flag to juge which event happened
251 * If success return 0, else return error code
253 static int rds_flag_set(uint32_t *flags, int flag_mask){
264 * To get rds group type form blockB
265 * If success return 0, else return error code
267 static int rds_group_type_get(uint16_t crc, uint16_t blk, uint8_t *type, uint8_t *subtype){
273 //to get the group type from block B
274 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid);
276 *type = (blk & 0xF000)>>12; //Group type(4bits)
277 *subtype = (blk & 0x0800)>>11; //version code(1bit), 0=vesionA, 1=versionB
279 FM_LOG_WAR(D_RDS,"Block1 CRC err\n");
283 FM_LOG_INF(D_RDS,"Type=%d, subtype:%s\n", (int)*type, *subtype ? "version B" : "version A");
288 * rds_group_counter_add
289 * @type -- group type, rang: 0~15
290 * @subtype -- sub group type, rang:0~1
292 * add group counter, group0a~group15b
293 * we use type value as the index
294 * If success return 0, else return error code
296 static int rds_group_counter_add(uint8_t type, uint8_t subtype, struct rds_group_cnt *gc)
301 return -ERR_INVALID_PARA;
311 return -ERR_INVALID_PARA;
315 FM_LOG_INF(D_RDS,"group counter:%d\n", (int)gc->total);
320 * rds_group_counter_get
322 * read group counter , group0a~group15b
323 * If success return 0, else return error code
325 extern int rds_group_counter_get(struct rds_group_cnt *dst, struct rds_group_cnt *src)
329 memcpy(dst, src, sizeof(struct rds_group_cnt));
334 * rds_group_counter_reset
336 * clear group counter to 0, group0a~group15b
337 * If success return 0, else return error code
339 extern int rds_group_counter_reset(struct rds_group_cnt *gc)
342 memset(gc, 0, sizeof(struct rds_group_cnt));
348 * To get rds group pi code form blockA
349 * If success return 0, else return error code
351 static int rds_group_pi_get(uint16_t crc, uint16_t blk, uint16_t *pi, bool *dirty){
358 //to get the group pi code from block A
359 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_A, &valid);
362 //PI=program Identication
364 *dirty = TRUE; // yes, we got new PI code
366 *dirty = FALSE; // PI is the same as last one
369 FM_LOG_WAR(D_RDS,"Block0 CRC err\n");
373 FM_LOG_INF(D_RDS,"PI=0x%04x, %s\n", *pi, *dirty ? "new" : "old");
379 * To get rds group pty code form blockB
380 * If success return 0, else return error code
382 static int rds_group_pty_get(uint16_t crc, uint16_t blk, uint8_t *pty, bool *dirty){
389 //to get PTY code from block B
390 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid);
392 FM_LOG_WAR(D_RDS,"Block1 CRC err\n");
396 if(*pty != ((blk & 0x03E0)>>5)){
397 //PTY=Program Type Code
398 *pty = (blk&0x03E0)>>5;
399 *dirty = TRUE; // yes, we got new PTY code
401 *dirty = FALSE; // PTY is the same as last one
404 FM_LOG_INF(D_RDS,"PTY=%d, %s\n", (int)*pty, *dirty ? "new" : "old");
410 * To get rds group tp code form blockB
411 * If success return 0, else return error code
413 static int rds_group_tp_get(uint16_t crc, uint16_t blk, uint8_t *tp, bool *dirty){
420 //to get TP code from block B
421 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid);
423 FM_LOG_WAR(D_RDS,"Block1 CRC err\n");
427 if(*tp != ((blk&0x0400)>>10)){
428 //Tranfic Program Identification
429 *tp = (blk&0x0400)>>10;
430 *dirty = TRUE; // yes, we got new TP code
432 *dirty = FALSE; // TP is the same as last one
435 FM_LOG_INF(D_RDS,"TP=%d, %s\n", (int)*tp, *dirty ? "new" : "old");
441 * To get rds group ta code form blockB
442 * If success return 0, else return error code
444 static int rds_group0_ta_get(uint16_t blk, uint8_t *ta, bool *dirty){
449 //TA=Traffic Announcement code
450 if(*ta != ((blk & 0x0010)>>4)){
451 *ta = (blk & 0x0010)>>4;
452 *dirty = TRUE; // yes, we got new TA code
454 *dirty = FALSE; // TA is the same as last one
457 FM_LOG_INF(D_G0,"TA=%d, %s\n", (int)*ta, *dirty ? "new" : "old");
462 * rds_group0_music_get
463 * To get music-speech switch code form blockB
464 * If success return 0, else return error code
466 static int rds_group0_music_get(uint16_t blk, uint8_t *music, bool *dirty){
471 //M/S=music speech switch code
472 if(*music != ((blk & 0x0008)>>3)){
473 *music = (blk & 0x0008)>>3;
474 *dirty = TRUE; // yes, we got new music code
476 *dirty = FALSE; // music is the same as last one
479 FM_LOG_INF(D_G0,"Music=%d, %s\n", (int)*music, *dirty ? "new" : "old");
484 * rds_group2_rt_addr_get
485 * To get rt addr form blockB
486 * If success return 0, else return error code
488 static int rds_group2_rt_addr_get(uint16_t blk, uint8_t *addr){
492 *addr = (uint8_t)blk & 0x0F;
494 FM_LOG_INF(D_G2,"addr=0x%02x\n", *addr);
498 static int rds_group2_txtAB_get(uint16_t blk, uint8_t *txtAB, bool *dirty){
504 if(*txtAB != ((blk&0x0010)>>4)){
505 *txtAB = (blk&0x0010)>>4;
506 *dirty = TRUE; // yes, we got new txtAB code
508 *dirty = FALSE; // txtAB is the same as last one
511 FM_LOG_INF(D_G2,"txtAB=%d, %s\n", *txtAB, *dirty ? "new" : "old");
515 static int rds_group2_rt_get(uint16_t crc, uint8_t subtype, uint16_t blkC, uint16_t blkD, uint8_t addr, uint8_t *buf){
521 //text segment addr rang 0~15
523 FM_LOG_ERR(D_RDS,"addr invalid(0x%02x)\n", addr);
524 ret = -ERR_INVALID_PARA;
530 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_C | FM_RDS_GDBK_IND_D, &valid);
533 buf[idx+1] = blkC&0xFF;
534 buf[idx+2] = blkD>>8;
535 buf[idx+3] = blkD&0xFF;
537 FM_LOG_ERR(D_RDS,"rt crc check err\n");
543 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_D, &valid);
546 buf[idx+1] = blkD&0xFF;
548 FM_LOG_ERR(D_RDS,"rt crc check err\n");
556 FM_LOG_INF(D_G2,"addr[%02x]:0x%02x 0x%02x 0x%02x 0x%02x\n", addr, buf[idx], buf[idx+1], buf[idx+2], buf[idx+3]);
560 static int rds_group2_rt_get_len(uint8_t subtype, int pos, int *len){
564 if(subtype == RDS_GRP_VER_A){
575 * this function is the most importent flow for RT parsing
576 * 1.Compare fresh buf with once buf per byte, if eque copy this byte to twice buf, else copy it to once buf
577 * 2.Check wether we got a full segment, for typeA if copyed 4bytes to twice buf, for typeB 2bytes copyed to twice buf
578 * 3.Check wether we got the end of RT, if we got 0x0D
579 * 4.If we got the end, then caculate the RT lenth
580 * If success return 0, else return error code
582 static int rds_group2_rt_cmp(uint8_t addr, uint16_t cbc, uint8_t subtype, uint8_t *fresh,
583 uint8_t *once, uint8_t *twice, bool *valid, bool *end, int *len){
595 j = (subtype == RDS_GRP_VER_A) ? 4 : 2; // RT segment width
596 if(subtype == RDS_GRP_VER_A){
597 if(rds_cbc_get(cbc, RDS_BLK_C) == 0){
598 once[j*addr+0] = fresh[j*addr+0];
599 once[j*addr+1] = fresh[j*addr+1];
601 if(rds_cbc_get(cbc, RDS_BLK_D) == 0){
602 once[j*addr+2] = fresh[j*addr+2];
603 once[j*addr+3] = fresh[j*addr+3];
605 }else if(subtype == RDS_GRP_VER_B){
606 if(rds_cbc_get(cbc, RDS_BLK_D) == 0){
607 once[j*addr+0] = fresh[j*addr+0];
608 once[j*addr+1] = fresh[j*addr+1];
612 for(i = 0; i < j; i++){
613 if(fresh[j*addr+i] == once[j*addr+i]){
614 twice[j*addr+i] = once[j*addr+i]; //get the same byte 2 times
617 once[j*addr+i] = fresh[j*addr+i]; //use new val
620 //if we got 0x0D twice, it means a RT end
621 if(twice[j*addr+i] == 0x0D){
623 *len = j*addr+i+1; //record the length of RT
627 //check if we got a valid segment 4bytes for typeA, 2bytes for typeB
633 FM_LOG_INF(D_G2,"RT seg=%s\n", *valid == TRUE ? "TRUE" : "FALSE");
634 FM_LOG_INF(D_G2,"RT end=%s\n", *end == TRUE ? "TRUE" : "FALSE");
635 FM_LOG_INF(D_G2,"RT len=%d\n", *len);
639 static uint16_t rds_group2_rt_addr_bitmap_get(uint16_t bitmap){
643 static int rds_group2_rt_addr_bitmap_get_pos(uint16_t bitmap){
645 while(!(bitmap & (1<<i)) && (i > -1)){
652 static bool rds_group2_rt_addr_bitmap_test(uint16_t bitmap, uint8_t addr){
653 return (bitmap & (1<<addr)) ? TRUE : FALSE;
657 static int rds_group2_rt_addr_bitmap_clear(uint16_t *bitmap, int *bm_cnt){
668 * rds_group2_rt_addr_bitmap_cmp - compare two bitmaps
671 * If bitmap1 > bitmap2, return positive(+)
672 * If bitmap1 = bitmap2, return 0
673 * If bitmap1 < bitmap2, return nagotive(-)
675 static int rds_group2_rt_addr_bitmap_cmp(uint16_t bitmap1, uint16_t bitmap2)
677 return (int)(bitmap1 - bitmap2);
680 static int rds_group2_rt_addr_bitmap_set(uint16_t *bitmap, int *bm_cnt, uint8_t addr){
686 //text segment addr rang 0~15
688 FM_LOG_ERR(D_RDS,"addr invalid(0x%02x)\n", addr);
689 ret = -ERR_INVALID_PARA;
693 *bitmap |= (1<<addr); //set bitmap
694 if(!rds_group2_rt_addr_bitmap_cmp(bm_old, *bitmap)){
695 (*bm_cnt)++; // multi get a segment
696 }else if(*bm_cnt > 0){
699 FM_LOG_NTC(D_G2,"RT bitmap=0x%04x, bmcnt=%d\n", *bitmap, *bm_cnt);
703 static RDS_RT_STATE_MACHINE rds_rt_state_get(void){
704 return rt_state_machine;
707 static RDS_RT_STATE_MACHINE rds_rt_state_set(RDS_RT_STATE_MACHINE state_new){
708 rt_state_machine = state_new;
709 return rt_state_machine;
713 static bool rds_group2_is_rt_finished(uint16_t *event){
715 if(*event&RDS_EVENT_LAST_RADIOTEXT){
723 static int MT6620_RDS_enable(void)
728 if((ret = MT6620_read(FM_MAIN_PGSEL, &page)))
731 if((ret = MT6620_write(0x9F, 0x0003)))
733 if((ret = MT6620_write(0xCB, 0xE016)))
735 if((ret = MT6620_write(0x9F, 0x0000)))
737 if((ret = MT6620_write(0x63, 0x0491)))
739 if((ret = MT6620_set_bits(0x6B, 0x2000, 0xFFFF)))
742 ret = MT6620_write(FM_MAIN_PGSEL, page);
747 static int MT6620_RDS_disable(void)
750 if((ret = MT6620_set_bits(0x6B, 0x0000, 0xDFFF)))
752 ret = MT6620_write(0x63, 0x0481);
757 static int MT6620_RDS_Get_GoodBlock_Counter(uint16_t* pCnt)
764 return -ERR_INVALID_BUF;
766 if((ret = MT6620_read(FM_MAIN_PGSEL, &page)))
769 if((ret = MT6620_write(0x9F, 0x0003)))
771 if((ret = MT6620_read(0xC6, &tmp_reg)))
774 ret = MT6620_write(FM_MAIN_PGSEL, page);
780 static int MT6620_RDS_Get_BadBlock_Counter(uint16_t* pCnt)
787 return -ERR_INVALID_BUF;
789 if((ret = MT6620_read(FM_MAIN_PGSEL, &page)))
792 if((ret = MT6620_write(0x9F, 0x0003)))
794 if((ret = MT6620_read(0xC7, &tmp_reg)))
797 ret = MT6620_write(FM_MAIN_PGSEL, page);
804 static int MT6620_RDS_Reset_Block_Counter(void)
809 if((ret = MT6620_read(FM_MAIN_PGSEL, &page)))
812 if((ret = MT6620_write(0x9F, 0x0003)))
814 if((ret = MT6620_write(0xC8, 0x0001)))
816 if((ret = MT6620_write(0xC8, 0x0002)))
819 ret = MT6620_write(FM_MAIN_PGSEL, page);
824 static int MT6620_RDS_Reset(void)
829 if((ret = MT6620_read(FM_MAIN_PGSEL, &page)))
832 if((ret = MT6620_write(0x9F, 0x0003)))
834 if((ret = MT6620_write(0xB0, 0x0001)))
837 ret = MT6620_write(FM_MAIN_PGSEL, page);
842 static int MT6620_RDS_Reset_Block(void)
847 if((ret = MT6620_read(FM_MAIN_PGSEL, &page)))
850 if((ret = MT6620_write(0x9F, 0x0003)))
852 if((ret = MT6620_write(0xDD, 0x0001)))
855 ret = MT6620_write(FM_MAIN_PGSEL, page);
860 int MT6620_RDS_BlerCheck(struct fm *fm)
862 RDSData_Struct *pstRDSData = fm->pstRDSData;
866 FM_LOG_DBG(D_BLKC,"+T:%d, MT6620_RDS_BlerCheck\n", jiffies_to_msecs(jiffies));
868 if(pstRDSData->AF_Data.Addr_Cnt == 0xFF){
870 pstRDSData->event_status |= RDS_EVENT_AF; //Need notfiy application
871 //loop pstRDSData->event_status then act
872 if(pstRDSData->event_status != 0){
873 fm->RDS_Data_ready = true;
874 wake_up_interruptible(&fm->read_wait);
875 FM_LOG_DBG(D_BLKC,"RDS_EVENT_AF, trigger read\n");
879 gBLER_CHK_INTERVAL = MT6620_RDS_BLER_T1;
880 if((ret = MT6620_RDS_Get_GoodBlock_Counter(&GOOD_BLK_CNT)))
882 FM_LOG_DBG(D_BLKC,"-T:%d, GOOD_BLK_CNT:%d\n", jiffies_to_msecs(jiffies), GOOD_BLK_CNT);
883 if((ret = MT6620_RDS_Get_BadBlock_Counter(&BAD_BLK_CNT)))
885 TOTAL_CNT = GOOD_BLK_CNT + BAD_BLK_CNT;
886 if((ret = MT6620_RDS_Reset_Block_Counter()))
888 FM_LOG_DBG(D_BLKC,"BLER: TOTAL_CNT:%d BAD_BLK_CNT:%d, RDS_Sync_Cnt:%d\n", TOTAL_CNT, BAD_BLK_CNT, RDS_Sync_Cnt);
890 if((GOOD_BLK_CNT==0)&&(BAD_BLK_CNT==0)){
893 BAD_BLK_RATIO = (BAD_BLK_CNT*100)/TOTAL_CNT;
896 //MT6620_RDS_BLER_TH1 90
897 //MT6620_RDS_BLER_TH2 60
898 //MT6620_RDS_BLER_C1 12
899 //MT6620_RDS_BLER_C2 6
900 //MT6620_RDS_BLER_T2 5000
901 if((BAD_BLK_RATIO < MT6620_RDS_BLER_TH2)&&(RDS_Sync_Cnt > MT6620_RDS_BLER_C1)){
902 gBLER_CHK_INTERVAL = MT6620_RDS_BLER_T2;
903 if(RDS_Block_Reset_Cnt > 1)
904 RDS_Block_Reset_Cnt--;
906 if(BAD_BLK_RATIO > MT6620_RDS_BLER_TH1){
908 if((ret = MT6620_RDS_Reset_Block_Counter()))
910 RDS_Sync_Cnt = 0; //need clear or not, Question, LCH.
911 RDS_Block_Reset_Cnt++;
912 if((RDS_Block_Reset_Cnt > MT6620_RDS_BLER_C2)||bRDS_FirstIn){
914 bRDS_FirstIn = false;
915 if((ret = MT6620_RDS_Reset()))
917 RDS_Block_Reset_Cnt = 0;
918 FM_LOG_DBG(D_BLKC,"RDS Reset, blk_cnt:%d, RDS_FirstIn:%d\n", RDS_Block_Reset_Cnt, bRDS_FirstIn);
919 }else if(TOTAL_CNT > 12){
920 //LCH question 2, why 12???
921 FM_LOG_DBG(D_BLKC,"RDS Block Reset: %x\n", RDS_Block_Reset_Cnt);
922 if((ret = MT6620_RDS_Reset_Block()))
926 RDS_Sync_Cnt++; //(60%-90%)
927 FM_LOG_DBG(D_BLKC,"RDS Sync Cnt: %d\n", RDS_Block_Reset_Cnt);
928 if(RDS_Block_Reset_Cnt > 1)
929 RDS_Block_Reset_Cnt--;
930 if(RDS_Sync_Cnt > MT6620_RDS_BLER_C1){
931 gBLER_CHK_INTERVAL = MT6620_RDS_BLER_T2;
939 static int MT6620_RDS_Init_Data(RDSData_Struct *pstRDSData)
944 memset(pstRDSData, 0 ,sizeof(RDSData_Struct));
947 pstRDSData->PTY = 0xFF; //to avoid "rx PTY == 0" case, this will cause no PTY event
949 for(indx = 0; indx < 64; indx++){
950 pstRDSData->RT_Data.TextData[0][indx]=0x20;
951 pstRDSData->RT_Data.TextData[1][indx]=0x20;
953 for(indx = 0; indx < 8; indx++){
954 pstRDSData->PS_Data.PS[0][indx] = '\0';
955 pstRDSData->PS_Data.PS[1][indx] = '\0';
956 pstRDSData->PS_Data.PS[2][indx] = '\0';
957 pstRDSData->PS_ON[indx] = 0x20;
963 static int MT6620_RDS_RetrieveGroup0(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData)
965 uint8_t indx, indx2, DI_Code, DI_Flag, PS_Num, AF_H, AF_L, num;
969 uint16_t *event = &pstRDSData->event_status;
970 uint32_t *flag = &pstRDSData->RDSFlag.flag_status;
972 ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_D, &valid);
974 FM_LOG_WAR(D_G0,"Group0 BlockD crc err\n");
978 ret = rds_group0_ta_get(block_data[1], &pstRDSData->RDSFlag.TA, &dirty);
980 FM_LOG_WAR(D_G0,"get ta failed[ret=%d]\n", ret);
981 }else if(dirty == TRUE){
982 ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new TA code
983 ret = rds_flag_set(flag, RDS_FLAG_IS_TA);
986 ret = rds_group0_music_get(block_data[1], &pstRDSData->RDSFlag.Music, &dirty);
988 FM_LOG_WAR(D_G0,"get music failed[ret=%d]\n", ret);
989 }else if(dirty == TRUE){
990 ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new MUSIC code
991 ret = rds_flag_set(flag, RDS_FLAG_IS_MUSIC);
994 if((pstRDSData->Switch_TP)&&(pstRDSData->RDSFlag.TP)&&!(pstRDSData->RDSFlag.TA)){
995 ret = rds_event_set(event, RDS_EVENT_TAON_OFF);
1000 ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_C, &valid);
1002 FM_LOG_WAR(D_G0,"Group0 BlockC crc err\n");
1003 return -ERR_RDS_CRC;
1005 AF_H = (block_data[2]&0xFF00)>>8;
1006 AF_L= block_data[2]&0x00FF;
1008 if((AF_H > 224)&&(AF_H < 250)){
1009 //Followed AF Number, see RDS spec Table 11, valid(224-249)
1010 FM_LOG_DBG(D_G0,"RetrieveGroup0 AF_H:%d, AF_L:%d\n", AF_H, AF_L);
1011 pstRDSData->AF_Data.isAFNum_Get = 0;
1012 preAF_Num = AF_H - 224; //AF Number
1013 if(preAF_Num != pstRDSData->AF_Data.AF_Num){
1014 pstRDSData->AF_Data.AF_Num = preAF_Num;
1016 //Get the same AFNum two times
1017 pstRDSData->AF_Data.isAFNum_Get = 1;
1020 if((AF_L < 205) && (AF_L > 0)){
1021 //See RDS Spec table 10, valid VHF
1022 pstRDSData->AF_Data.AF[0][0] = AF_L+875; //convert to 100KHz
1023 FM_LOG_DBG(D_G0,"RetrieveGroup0 AF[0][0]:%d\n", pstRDSData->AF_Data.AF[0][0]);
1024 if((pstRDSData->AF_Data.AF[0][0]) != (pstRDSData->AF_Data.AF[1][0])){
1025 pstRDSData->AF_Data.AF[1][0] = pstRDSData->AF_Data.AF[0][0];
1027 if(pstRDSData->AF_Data.AF[1][0] != _current_frequency)
1028 pstRDSData->AF_Data.isMethod_A = 1;
1030 pstRDSData->AF_Data.isMethod_A = 0;
1033 FM_LOG_DBG(D_G0,"RetrieveGroup0 isAFNum_Get:%d, isMethod_A:%d\n", pstRDSData->AF_Data.isAFNum_Get, pstRDSData->AF_Data.isMethod_A);
1035 //only one AF handle
1036 if((pstRDSData->AF_Data.isAFNum_Get)&& (pstRDSData->AF_Data.AF_Num == 1)){
1037 pstRDSData->AF_Data.Addr_Cnt = 0xFF;
1038 pstRDSData->event_status |= RDS_EVENT_AF_LIST;
1039 FM_LOG_DBG(D_G0,"RetrieveGroup0 RDS_EVENT_AF_LIST update\n");
1043 else if((pstRDSData->AF_Data.isAFNum_Get)&&(pstRDSData->AF_Data.Addr_Cnt != 0xFF)){
1045 num = pstRDSData->AF_Data.AF_Num;
1047 FM_LOG_DBG(D_G0,"RetrieveGroup0 +num:%d\n", num);
1049 //Put AF freq into buffer and check if AF freq is repeat again
1050 for(indx = 1; indx < (num+1); indx++){
1051 if((AF_H == (pstRDSData->AF_Data.AF[0][2*num-1]))&&(AF_L == (pstRDSData->AF_Data.AF[0][2*indx]))){
1052 FM_LOG_ERR(D_G0|D_ALL,"RetrieveGroup0 AF same as indx:%d\n", indx);
1054 }else if(!(pstRDSData->AF_Data.AF[0][2*indx-1])){
1056 pstRDSData->AF_Data.AF[0][2*indx-1] = AF_H+875; //convert to 100KHz
1057 pstRDSData->AF_Data.AF[0][2*indx] = AF_L+875;
1058 FM_LOG_DBG(D_G0,"RetrieveGroup0 AF[0][%d]:%d, AF[0][%d]:%d\n",
1059 2*indx-1, pstRDSData->AF_Data.AF[0][2*indx-1], 2*indx, pstRDSData->AF_Data.AF[0][2*indx]);
1063 num = pstRDSData->AF_Data.AF_Num;
1064 FM_LOG_DBG(D_G0,"RetrieveGroup0 ++num:%d\n", num);
1066 if((pstRDSData->AF_Data.AF[0][num-1]) != 0){
1068 FM_LOG_DBG(D_G0,"RetrieveGroup0 +++num:%d\n", num);
1069 //arrange frequency from low to high:start
1070 for(indx = 1; indx < num; indx++){
1071 for(indx2 = indx+1; indx2 < (num+1); indx2++){
1072 AF_H = pstRDSData->AF_Data.AF[0][2*indx-1];
1073 AF_L = pstRDSData->AF_Data.AF[0][2*indx];
1074 if(AF_H > (pstRDSData->AF_Data.AF[0][2*indx2-1])){
1075 pstRDSData->AF_Data.AF[0][2*indx-1] = pstRDSData->AF_Data.AF[0][2*indx2-1];
1076 pstRDSData->AF_Data.AF[0][2*indx] = pstRDSData->AF_Data.AF[0][2*indx2];
1077 pstRDSData->AF_Data.AF[0][2*indx2-1] = AF_H;
1078 pstRDSData->AF_Data.AF[0][2*indx2] = AF_L;
1079 }else if(AF_H == (pstRDSData->AF_Data.AF[0][2*indx2-1])){
1080 if(AF_L > (pstRDSData->AF_Data.AF[0][2*indx2])){
1081 pstRDSData->AF_Data.AF[0][2*indx-1] = pstRDSData->AF_Data.AF[0][2*indx2-1];
1082 pstRDSData->AF_Data.AF[0][2*indx] = pstRDSData->AF_Data.AF[0][2*indx2];
1083 pstRDSData->AF_Data.AF[0][2*indx2-1] = AF_H;
1084 pstRDSData->AF_Data.AF[0][2*indx2] = AF_L;
1089 //arrange frequency from low to high:end
1090 //compare AF buff0 and buff1 data:start
1091 num = pstRDSData->AF_Data.AF_Num;
1094 for(indx = 0; indx < num; indx++){
1095 if((pstRDSData->AF_Data.AF[1][indx]) == (pstRDSData->AF_Data.AF[0][indx])){
1096 if(pstRDSData->AF_Data.AF[1][indx] != 0)
1099 pstRDSData->AF_Data.AF[1][indx] = pstRDSData->AF_Data.AF[0][indx];
1101 FM_LOG_DBG(D_G0,"RetrieveGroup0 indx2:%d, num:%d\n", indx2, num);
1102 //compare AF buff0 and buff1 data:end
1104 pstRDSData->AF_Data.Addr_Cnt = 0xFF;
1105 pstRDSData->event_status |= RDS_EVENT_AF_LIST;
1106 FM_LOG_DBG(D_G0,"RetrieveGroup0 AF_Num:%d\n", pstRDSData->AF_Data.AF_Num);
1107 for(indx = 0; indx < num; indx++){
1108 if((pstRDSData->AF_Data.AF[1][indx]) == 0){
1109 pstRDSData->AF_Data.Addr_Cnt = 0x0F;
1110 pstRDSData->event_status &= (~RDS_EVENT_AF_LIST);
1115 pstRDSData->AF_Data.Addr_Cnt = 0x0F;
1122 /*DI_Code[1:0]: "00" = d3 *
1127 DI_Code = block_data[1]&0x0003; //DI=decoder identification code.
1128 DI_Flag = (block_data[1]&0x0004)>>2;
1132 if(pstRDSData->RDSFlag.Stereo != DI_Flag){
1133 pstRDSData->RDSFlag.Stereo = DI_Flag;
1134 pstRDSData->event_status |= RDS_EVENT_FLAGS;
1135 pstRDSData->RDSFlag.flag_status |= RDS_FLAG_IS_STEREO;
1139 if(pstRDSData->RDSFlag.Artificial_Head != DI_Flag){
1140 pstRDSData->RDSFlag.Artificial_Head = DI_Flag;
1141 pstRDSData->event_status |= RDS_EVENT_FLAGS;
1142 pstRDSData->RDSFlag.flag_status |= RDS_FLAG_IS_ARTIFICIAL_HEAD;
1146 if(pstRDSData->RDSFlag.Compressed != DI_Flag){
1147 pstRDSData->RDSFlag.Compressed = DI_Flag;
1148 pstRDSData->event_status |= RDS_EVENT_FLAGS;
1149 pstRDSData->RDSFlag.flag_status |= RDS_FLAG_IS_COMPRESSED;
1153 if(pstRDSData->RDSFlag.Dynamic_PTY != DI_Flag){
1154 pstRDSData->RDSFlag.Dynamic_PTY = DI_Flag;
1155 pstRDSData->event_status |= RDS_EVENT_FLAGS;
1156 pstRDSData->RDSFlag.flag_status |= RDS_FLAG_IS_DYNAMIC_PTY;
1163 PS_Num = block_data[1]&0x0003; //Figure 12 Type 0 group.
1164 AF_H = pstRDSData->PS_Data.PS[0][2*PS_Num];
1165 AF_L = pstRDSData->PS_Data.PS[0][2*PS_Num+1];
1166 if((AF_H == (block_data[3])>>8)&&(AF_L == (block_data[3]&0xFF))){
1167 if((!((pstRDSData->event_status)&RDS_EVENT_PROGRAMNAME))&&((PS_Num == 0)||(pstRDSData->PS_Data.Addr_Cnt))){
1168 pstRDSData->PS_Data.PS[1][2*PS_Num]=(block_data[3])>>8;
1169 pstRDSData->PS_Data.PS[1][2*PS_Num+1] = (block_data[3])&0xFF;
1170 FM_LOG_DBG(D_G0,"RetrieveGroup0 PS second time, NUM:%x H:%x L:%x\n",
1171 PS_Num, pstRDSData->PS_Data.PS[1][2*PS_Num], pstRDSData->PS_Data.PS[1][2*PS_Num+1]);
1173 //Need clear buff0, LCH question 1, should clear not not?
1174 if((PS_Num == 0)&&(pstRDSData->PS_Data.Addr_Cnt == 0)){
1175 for(indx = 2; indx < 8; indx++){
1176 pstRDSData->PS_Data.PS[0][indx] = '\0'; //clear buff0
1179 pstRDSData->PS_Data.Addr_Cnt |= 1<<PS_Num;
1180 FM_LOG_DBG(D_G0,"RetrieveGroup0, Addr_Cnt:%x\n", pstRDSData->PS_Data.Addr_Cnt);
1181 if(pstRDSData->PS_Data.Addr_Cnt == 0x0F){
1182 //Avoid PS transient:Start
1184 for(indx = 0; indx < 8; indx++){
1185 if(pstRDSData->PS_Data.PS[0][indx] == pstRDSData->PS_Data.PS[1][indx])
1188 pstRDSData->PS_Data.Addr_Cnt = 0;
1189 //Avoid PS transient:END
1192 // get same data 2 times
1194 for(indx = 0; indx < 8; indx++){
1195 if(pstRDSData->PS_Data.PS[1][indx] == pstRDSData->PS_Data.PS[2][indx])
1198 //if(num != 8) //get same data 2 times, and not same as the last show.
1199 pstRDSData->event_status |= RDS_EVENT_PROGRAMNAME;
1201 for(indx = 0; indx < 8; indx++){
1202 pstRDSData->PS_Data.PS[2][indx] = pstRDSData->PS_Data.PS[1][indx];
1203 pstRDSData->PS_Data.PS[1][indx] = '\0';
1204 pstRDSData->PS_Data.PS[0][indx] = '\0';
1207 pstRDSData->PS_Data.Addr_Cnt |= 1<<PS_Num;
1213 pstRDSData->PS_Data.PS[0][2*PS_Num]=(block_data[3])>>8;
1214 pstRDSData->PS_Data.PS[0][2*PS_Num+1] = (block_data[3])&0xFF;
1215 FM_LOG_DBG(D_G0,"RetrieveGroup0 PS, NUM:%x H:%x L:%x\n",
1216 PS_Num, pstRDSData->PS_Data.PS[0][2*PS_Num], pstRDSData->PS_Data.PS[0][2*PS_Num+1]);
1219 if((pstRDSData->event_status)&RDS_EVENT_PROGRAMNAME){
1221 for(num = 0; num < 8;num++){
1222 if(pstRDSData->PS_Data.PS[2][num] == '\0')
1226 FM_LOG_ERR(D_G0|D_ALL,"RDS PS Canncel event 0x08");
1227 pstRDSData->event_status &= (~RDS_EVENT_PROGRAMNAME);
1234 static int MT6620_RDS_RetrieveGroup1(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData)
1236 uint8_t variant_code = (block_data[2]&0x7000)>>12;
1239 if(variant_code == 0){
1240 pstRDSData->Extend_Country_Code = (uint8_t)block_data[2]&0xFF;
1241 FM_LOG_DBG(D_G1,"Extend_Country_Code:%d\n", pstRDSData->Extend_Country_Code);
1242 }else if(variant_code == 3){
1243 pstRDSData->Language_Code = block_data[2]&0xFFF;
1244 FM_LOG_DBG(D_G1,"Language_Code:%d\n", pstRDSData->Language_Code);
1247 pstRDSData->Radio_Page_Code = block_data[1]&0x001F;
1248 pstRDSData->Program_Item_Number_Code = block_data[3];
1253 #ifdef FM_RDS_G2_USE_OLD
1254 static bool PreTextABFlag;
1256 static int MT6620_RDS_RetrieveGroup2(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData)
1258 uint8_t TextAddr, indx, indx2, space, byte0, byte1;
1263 TextAddr = (uint8_t)block_data[1]&0x0F;
1265 if(pstRDSData->RDSFlag.Text_AB != ((block_data[1]&0x0010)>>4)){
1266 pstRDSData->RDSFlag.Text_AB = (block_data[1]&0x0010)>>4;
1267 pstRDSData->event_status |= RDS_EVENT_FLAGS;
1268 pstRDSData->RDSFlag.flag_status |= RDS_FLAG_TEXT_AB;
1270 FM_LOG_DBG(D_G2,"RT RetrieveGroup2 TextABFlag: %x --> %x\n", PreTextABFlag, pstRDSData->RDSFlag.Text_AB);
1272 if(PreTextABFlag != pstRDSData->RDSFlag.Text_AB){ // Text A/B changed, clear old RT, and get new RT
1273 /*DDB:Some station don't send 0x0D, it just switch TextAB if it want to send next message.*/
1274 if (pstRDSData->RT_Data.isRTDisplay == 0) {
1275 FM_LOG_WAR(D_G2,"RT_Data.isRTDisplay == 0, and TextAB changed\n");
1276 pstRDSData->event_status |= RDS_EVENT_LAST_RADIOTEXT;
1278 for(indx = 0; indx < 64; indx++){
1279 /*DDB:Why TextData[1][0] NOT TextData[2][0], Because some station just send a message one time, and then change TextAB, send another message, SUCH As Beijing 90.0*/
1280 if(pstRDSData->RT_Data.TextData[1][indx] == 0x20)
1284 pstRDSData->event_status &= (~RDS_EVENT_LAST_RADIOTEXT);
1286 if (pstRDSData->event_status & RDS_EVENT_LAST_RADIOTEXT){
1287 /*DDB:Why TextData[1][0] NOT TextData[2][0], Because some station just send a message one time, and then change TextAB, send another message, SUCH As Beijing 90.0*/
1288 memcpy(&(pstRDSData->RT_Data.TextData[3][0]), &(pstRDSData->RT_Data.TextData[1][0]), sizeof(pstRDSData->RT_Data.TextData[3]));
1289 FM_LOG_WAR(D_G2,"RT_Data.isRTDisplay = 1, no 0x0D case.\n");
1290 pstRDSData->RT_Data.isRTDisplay = 1;
1294 //to get Radio text length
1295 pstRDSData->RT_Data.TextLength = 0;
1297 while(!(pstRDSData->RT_Data.Addr_Cnt & (1<<i)) && (i > -1)){
1301 pstRDSData->RT_Data.TextLength = 4*(i+1);
1303 pstRDSData->RT_Data.TextLength = 2*(i+1);
1305 FM_LOG_INF(D_G2,"RDS RT Get Len: [AddrMap=0x%x] [Length=0x%x]\n", pstRDSData->RT_Data.Addr_Cnt, pstRDSData->RT_Data.TextLength);
1308 //clear the buffer because Text A/B changed
1309 memset(&(pstRDSData->RT_Data.TextData[0][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[0]));
1310 memset(&(pstRDSData->RT_Data.TextData[1][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[1]));
1311 memset(&(pstRDSData->RT_Data.TextData[2][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[2]));
1312 PreTextABFlag = pstRDSData->RDSFlag.Text_AB;
1313 pstRDSData->RT_Data.GetLength = 0;
1314 pstRDSData->RT_Data.Addr_Cnt = 0;
1315 //pstRDSData->RT_Data.isRTDisplay = 0;
1320 //WCN_DBG(FM_ALERT|D_MAIN,"RetrieveGroup2 Type A RT TextAddr: 0x%x Text: 0x%x 0x%x", TextAddr, block_data[2], block_data[3]);
1321 FM_LOG_NTC(D_G2,"%04x %04x %04x %04x %04x", block_data[0], block_data[1], block_data[2], block_data[3], block_data[4]);
1322 pstRDSData->RT_Data.isTypeA = 1;
1323 //to get the 4bytes RadioText
1324 if(block_data[4]&(FM_RDS_GDBK_IND_C|FM_RDS_GDBK_IND_D)){
1325 pstRDSData->RT_Data.TextData[0][4*TextAddr] = block_data[2]>>8;
1326 pstRDSData->RT_Data.TextData[0][4*TextAddr+1] = block_data[2]&0xFF;
1327 pstRDSData->RT_Data.TextData[0][4*TextAddr+2] = block_data[3]>>8;
1328 pstRDSData->RT_Data.TextData[0][4*TextAddr+3] = block_data[3]&0xFF;
1331 for(indx = 0; indx < 4;indx++){
1332 byte0 = pstRDSData->RT_Data.TextData[0][4*TextAddr+indx];
1333 byte1 = pstRDSData->RT_Data.TextData[1][4*TextAddr+indx];
1335 //WCN_DBG(FM_ALERT|D_MAIN,"RT_Data.isRTDisplay = 0\n");
1336 pstRDSData->RT_Data.isRTDisplay = 0;
1338 if((!(pstRDSData->event_status&RDS_EVENT_LAST_RADIOTEXT))&&(byte0 == byte1)){
1339 //get the same byte 2 times
1341 pstRDSData->RT_Data.TextData[2][4*TextAddr+indx] = byte0;
1343 pstRDSData->RT_Data.TextData[1][4*TextAddr+indx] = byte0;
1348 addrcnt = pstRDSData->RT_Data.Addr_Cnt;
1349 pstRDSData->RT_Data.Addr_Cnt |= (1<<TextAddr);
1350 FM_LOG_DBG(D_G2,"RetrieveGroup2 RT addrcnt:%d, RT_Data.Addr_Cnt:%d\n", addrcnt, pstRDSData->RT_Data.Addr_Cnt);
1352 if(addrcnt == pstRDSData->RT_Data.Addr_Cnt){
1353 pstRDSData->RT_Data.BufCnt++;
1354 }else if(pstRDSData->RT_Data.BufCnt > 0){
1355 pstRDSData->RT_Data.BufCnt--;
1359 FM_LOG_ERR(D_G2|D_ALL,"RT %04x %04x %04x %04x %04x CRC error.", block_data[0], block_data[1], block_data[2], block_data[3], block_data[4]);
1361 for(indx = 0; indx < 4; indx++){
1362 if(pstRDSData->RT_Data.TextData[2][4*TextAddr+indx] == 0x0D){
1363 pstRDSData->RT_Data.TextLength = 4*TextAddr+indx+1; //Add terminate charater
1364 pstRDSData->RT_Data.TextData[2][4*TextAddr+indx] = '\0';
1365 pstRDSData->RT_Data.GetLength = 1;
1366 }else if((4*TextAddr+indx) == 63 && pstRDSData->RT_Data.Addr_Cnt == 0xffff){
1367 //type A full data. /*add by dongbo, make sure it's TextData[2], Not TextData[1]*/
1368 pstRDSData->RT_Data.TextLength = 4*TextAddr+indx+1; //no terminal character
1369 pstRDSData->RT_Data.GetLength = 1;
1373 //FM_LOG_DBG(D_MAIN,"RetrieveGroup2 Type B RT NUM: 0x%x Text: 0x%x", TextAddr, block_data[3]);
1374 FM_LOG_DBG(D_G2,"RT %04x %04x %04x %04x %04x", block_data[0], block_data[1], block_data[2], block_data[3], block_data[4]);
1375 pstRDSData->RT_Data.isTypeA = 0;
1376 if(block_data[4]&FM_RDS_GDBK_IND_D){
1377 pstRDSData->RT_Data.TextData[0][2*TextAddr] = block_data[3]>>8;
1378 pstRDSData->RT_Data.TextData[0][2*TextAddr+1] = block_data[3]&0xFF;
1381 for(indx = 0; indx < 2; indx++){
1382 byte0 = pstRDSData->RT_Data.TextData[0][2*TextAddr+indx];
1383 byte1 = pstRDSData->RT_Data.TextData[1][2*TextAddr+indx];
1385 if((!((pstRDSData->event_status)&RDS_EVENT_LAST_RADIOTEXT))&&(byte0 == byte1)){
1387 pstRDSData->RT_Data.TextData[2][2*TextAddr+indx] = byte0;
1389 pstRDSData->RT_Data.TextData[1][2*TextAddr+indx] = byte0;
1393 addrcnt = pstRDSData->RT_Data.Addr_Cnt;
1394 pstRDSData->RT_Data.Addr_Cnt |= (1<<TextAddr);
1395 FM_LOG_DBG(D_G2,"RT RetrieveGroup2 RT B addrcnt: 0x%x, RT_Data.Addr_Cnt: 0x%x\n", addrcnt, pstRDSData->RT_Data.Addr_Cnt);
1397 if(addrcnt == pstRDSData->RT_Data.Addr_Cnt){
1398 pstRDSData->RT_Data.BufCnt++;
1399 }else if(pstRDSData->RT_Data.BufCnt > 0){
1400 pstRDSData->RT_Data.BufCnt--;
1404 FM_LOG_DBG(D_G2,"RT %04x %04x %04x %04x %04x CRC error.", block_data[0], block_data[1], block_data[2], block_data[3], block_data[4]);
1407 for(indx = 0; indx < 2; indx++){
1408 if((pstRDSData->RT_Data.TextData[2][2*TextAddr+indx]) == 0x0D){
1410 pstRDSData->RT_Data.TextLength = 2*TextAddr+indx+1; //Add terminate charater
1411 pstRDSData->RT_Data.TextData[2][2*TextAddr+indx] = '\0';
1412 pstRDSData->RT_Data.GetLength = 1;
1413 }else if((2*TextAddr+indx) == 31){
1415 pstRDSData->RT_Data.TextLength = 2*TextAddr+indx+1; //Add terminate charater
1416 pstRDSData->RT_Data.TextData[2][2*TextAddr+indx] = '\0';
1417 pstRDSData->RT_Data.GetLength = 1;
1422 //Check if text is fully received
1424 if(pstRDSData->RT_Data.GetLength == 1){
1425 addrcnt = 0xFFFF>>(0x0F-indx);
1426 }else if(pstRDSData->RT_Data.BufCnt > 100){
1427 pstRDSData->RT_Data.BufCnt = 0;
1428 for(indx = 15; indx >= 0; indx--){
1429 addrcnt = (pstRDSData->RT_Data.Addr_Cnt)&(1<<indx);
1434 //get valid radio text length
1435 if (pstRDSData->RT_Data.isTypeA){
1436 for(indx2 = 0; indx2 < 4; indx2++){
1437 if(pstRDSData->RT_Data.TextData[2][4*indx+indx2] == 0x0D){
1438 pstRDSData->RT_Data.TextLength = 4*indx+indx2+1;
1439 pstRDSData->RT_Data.TextData[2][4*indx+indx2] = '\0';
1443 for(indx2 = 0; indx2 < 2; indx2++){
1444 if(pstRDSData->RT_Data.TextData[2][2*indx+indx2] == 0x0D){
1445 pstRDSData->RT_Data.TextLength = 2*indx+indx2+1;
1446 pstRDSData->RT_Data.TextData[2][2*indx+indx2] = '\0';
1451 addrcnt = 0xFFFF>>(0x0F-indx);
1453 if(pstRDSData->RT_Data.TextLength > 64){
1454 pstRDSData->RT_Data.TextLength = 64;
1459 FM_LOG_NTC(D_G2,"RetrieveGroup2 RDS RT: Addr_Cnt: 0x%x Length: 0x%x addrcnt: 0x%x\n", pstRDSData->RT_Data.Addr_Cnt, pstRDSData->RT_Data.TextLength, addrcnt);
1461 if(((((pstRDSData->RT_Data.Addr_Cnt)&addrcnt) == addrcnt)||((TextAddr == 0x0f) && (pstRDSData->RT_Data.Addr_Cnt == 0xffff)))){
1462 //&&(pstRDSData->RT_Data.isRTDisplay == 0))
1463 pstRDSData->RT_Data.Addr_Cnt = 0;
1464 //pstRDSData->RT_Data.isRTDisplay = 1;
1465 pstRDSData->event_status |= RDS_EVENT_LAST_RADIOTEXT;
1466 FM_LOG_DBG(D_G2,"RT RetrieveGroup2 isRTDisplay:%d\n", pstRDSData->RT_Data.isRTDisplay);
1468 for(indx = 0; indx < 64; indx++){
1469 if(pstRDSData->RT_Data.TextData[2][indx] == 0x20)
1473 pstRDSData->event_status &= (~RDS_EVENT_LAST_RADIOTEXT);
1475 memset(&(pstRDSData->RT_Data.TextData[1][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[1]));
1476 memset(&(pstRDSData->RT_Data.TextData[0][0]), 0x20, sizeof(pstRDSData->RT_Data.TextData[0]));
1478 if (pstRDSData->event_status & RDS_EVENT_LAST_RADIOTEXT){
1479 memcpy(&(pstRDSData->RT_Data.TextData[3][0]), &(pstRDSData->RT_Data.TextData[2][0]), sizeof(pstRDSData->RT_Data.TextData[3]));
1480 FM_LOG_WAR(D_G2,"RT_Data.isRTDisplay = 1\n");
1481 pstRDSData->RT_Data.isRTDisplay = 1;
1488 static int MT6620_RDS_RetrieveGroup2(uint16_t *source, uint8_t subtype, RDSData_Struct *target)
1492 uint16_t blkA, blkB, blkC, blkD;
1493 uint8_t *fresh, *once, *twice, *display;
1497 uint8_t rt_addr = 0;
1498 bool txtAB_change = FALSE; //text AB flag 0 --> 1 or 1-->0 meas new RT incoming
1499 bool txt_end = FALSE; //0x0D means text end
1501 static uint16_t bitmap_twice;
1502 static int bitmap_cnt;
1517 fresh = target->RT_Data.TextData[0];
1518 once = target->RT_Data.TextData[1];
1519 twice = target->RT_Data.TextData[2];
1520 display = target->RT_Data.TextData[3];
1521 event = &target->event_status;
1522 flag = &target->RDSFlag.flag_status;
1523 bufsize = sizeof(target->RT_Data.TextData[0]);
1525 //get basic info: addr, txtAB
1526 if(rds_group2_rt_addr_get(blkB, &rt_addr))
1528 if(rds_group2_txtAB_get(blkB, &target->RDSFlag.Text_AB, &txtAB_change))
1531 //RT parsing state machine run
1533 switch(rds_rt_state_get()){
1535 if(txtAB_change == TRUE){
1536 rds_rt_state_set(RDS_RT_DECISION);
1539 if(rds_group2_rt_get(crc, subtype, blkC, blkD, rt_addr, fresh)){
1540 rds_rt_state_set(RDS_RT_FINISH); //if CRC error, we should not do parsing
1543 rds_group2_rt_cmp(rt_addr, cbc, subtype, fresh, once, twice,
1544 &seg_ok, &txt_end, &rt_len);
1546 rds_group2_rt_addr_bitmap_set(&bitmap_twice, &bitmap_cnt, rt_addr);
1548 rds_rt_state_set(RDS_RT_DECISION);
1551 case RDS_RT_DECISION:
1552 if(txt_end == TRUE){
1553 rds_rt_state_set(RDS_RT_GETLEN); //find 0x0D, and the lenth has been recorded when do rds_group2_rt_cmp()
1554 }else if(rds_group2_rt_addr_bitmap_get(bitmap_twice) == 0xFFFF //get max 64 chars
1555 || (txtAB_change == TRUE) //text AB changed,
1556 || (bitmap_cnt > RDS_RT_MULTI_REV_TH)){ //repeate many times, but no end char get
1557 pos = rds_group2_rt_addr_bitmap_get_pos(bitmap_twice);
1558 rds_group2_rt_get_len(subtype, pos, &rt_len);
1559 rds_rt_state_set(RDS_RT_GETLEN);
1561 rds_rt_state_set(RDS_RT_FINISH);
1565 memcpy(display, twice, bufsize);
1566 target->RT_Data.TextLength = rt_len;
1567 rds_event_set(event, RDS_EVENT_LAST_RADIOTEXT); //yes we got a new RT
1568 FM_LOG_NTC(D_G2,"Yes, get an RT! [len=%d]\n", rt_len);
1570 rds_group2_rt_addr_bitmap_clear(&bitmap_twice, &bitmap_cnt);
1572 memset(fresh, 0x20, bufsize);
1573 memset(once, 0x20, bufsize);
1574 memset(twice, 0x20, bufsize);
1575 if(txtAB_change == TRUE){
1576 txtAB_change = FALSE;
1577 //we need get new RT after show the old RT to the display
1578 rds_rt_state_set(RDS_RT_START);
1580 rds_rt_state_set(RDS_RT_FINISH);
1584 rds_rt_state_set(RDS_RT_START);
1596 static int MT6620_RDS_RetrieveGroup4(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData)
1598 uint16_t year, month, k=0, D2, minute;
1601 FM_LOG_DBG(D_G4,"RetrieveGroup4 %d\n", SubType);
1604 if((block_data[4]&FM_RDS_GDBK_IND_C)&&(block_data[4]&FM_RDS_GDBK_IND_D)){
1605 MJD = (uint32_t) (((block_data[1]&0x0003)<<15) + ((block_data[2]&0xFFFE)>>1));
1606 year = (MJD*100 - 1507820)/36525;
1607 month = (MJD*10000-149561000-3652500*year)/306001;
1608 if((month == 14)||(month == 15))
1610 D1 = (uint32_t)((36525*year)/100);
1611 D2 = (uint16_t)((306001*month)/10000);
1612 pstRDSData->CT.Year = 1900 + year + k;
1613 pstRDSData->CT.Month = month - 1 - k*12;
1614 pstRDSData->CT.Day = (uint16_t)(MJD - 14956 - D1 - D2);
1615 pstRDSData->CT.Hour = ((block_data[2]&0x0001)<<4)+((block_data[3]&0xF000)>>12);
1616 minute = (block_data[3]&0x0FC0)>>6;
1618 if(block_data[3]&0x0020){
1619 pstRDSData->CT.Local_Time_offset_signbit = 1; //0=+, 1=-
1621 pstRDSData->CT.Local_Time_offset_half_hour = block_data[3]&0x001F;
1622 if(pstRDSData->CT.Minute != minute){
1623 pstRDSData->CT.Minute = (block_data[3]&0x0FC0)>>6;
1624 pstRDSData->event_status |= RDS_EVENT_UTCDATETIME;
1632 static int MT6620_RDS_RetrieveGroup14(uint16_t *block_data, uint8_t SubType, RDSData_Struct *pstRDSData)
1634 uint8_t TP_ON, TA_ON, PI_ON, PS_Num, AF_H, AF_L, indx, indx2, num;
1636 FM_LOG_DBG(D_G14,"RetrieveGroup14 %d\n", SubType);
1637 //SubType = (*(block_data+1)&0x0800)>>11;
1638 PI_ON = block_data[3];
1639 TP_ON = block_data[1]&0x0010;
1640 if((!SubType) && (block_data[4]&FM_RDS_GDBK_IND_C)){
1642 PS_Num= block_data[1]&0x000F;
1644 for(indx = 0; indx < 2; indx++){
1645 pstRDSData->PS_ON[2*PS_Num] = block_data[2]>>8;
1646 pstRDSData->PS_ON[2*PS_Num+1] = block_data[2]&0xFF;
1648 }else if(PS_Num == 4){
1649 AF_H = (block_data[2]&0xFF00)>>8;
1650 AF_L = block_data[2]&0x00FF;
1651 if((AF_H > 223)&&(AF_H < 250)){
1652 //Followed AF Number
1653 pstRDSData->AFON_Data.isAFNum_Get = 0;
1654 preAFON_Num = AF_H - 224;
1655 if(pstRDSData->AFON_Data.AF_Num != preAFON_Num){
1656 pstRDSData->AFON_Data.AF_Num = preAFON_Num;
1658 pstRDSData->AFON_Data.isAFNum_Get= 1;
1661 pstRDSData->AFON_Data.AF[0][0] = AF_L+875;
1662 if((pstRDSData->AFON_Data.AF[0][0]) != (pstRDSData->AFON_Data.AF[1][0])){
1663 pstRDSData->AFON_Data.AF[1][0] = pstRDSData->AFON_Data.AF[0][0];
1665 pstRDSData->AFON_Data.isMethod_A = 1;
1668 }else if((pstRDSData->AFON_Data.isAFNum_Get)&&((pstRDSData->AFON_Data.Addr_Cnt) != 0xFF)){
1670 num = pstRDSData->AFON_Data.AF_Num;
1672 //Put AF freq into buffer and check if AF freq is repeat again
1673 for(indx = 1; indx < (num+1); indx++){
1674 if((AF_H == (pstRDSData->AFON_Data.AF[0][2*indx-1]))&&(AF_L == (pstRDSData->AFON_Data.AF[0][2*indx]))){
1675 FM_LOG_NTC(D_G14,"RetrieveGroup14 AFON same as indx:%d\n", indx);
1677 }else if(!(pstRDSData->AFON_Data.AF[0][2*indx-1])){
1679 pstRDSData->AFON_Data.AF[0][2*indx-1] = AF_H+875;
1680 pstRDSData->AFON_Data.AF[0][2*indx] = AF_L+875;
1684 num = pstRDSData->AFON_Data.AF_Num;
1686 if((pstRDSData->AFON_Data.AF[0][num-1]) != 0){
1688 //arrange frequency from low to high:start
1689 for(indx = 1; indx < num; indx++){
1690 for(indx2 = indx+1; indx2 < (num+1); indx2++){
1691 AF_H = pstRDSData->AFON_Data.AF[0][2*indx-1];
1692 AF_L = pstRDSData->AFON_Data.AF[0][2*indx];
1693 if(AF_H > (pstRDSData->AFON_Data.AF[0][2*indx2-1])){
1694 pstRDSData->AFON_Data.AF[0][2*indx-1] = pstRDSData->AFON_Data.AF[0][2*indx2-1];
1695 pstRDSData->AFON_Data.AF[0][2*indx] = pstRDSData->AFON_Data.AF[0][2*indx2];
1696 pstRDSData->AFON_Data.AF[0][2*indx2-1] = AF_H;
1697 pstRDSData->AFON_Data.AF[0][2*indx2] = AF_L;
1698 }else if(AF_H == (pstRDSData->AFON_Data.AF[0][2*indx2-1])){
1699 if(AF_L > (pstRDSData->AFON_Data.AF[0][2*indx2])){
1700 pstRDSData->AFON_Data.AF[0][2*indx-1] = pstRDSData->AFON_Data.AF[0][2*indx2-1];
1701 pstRDSData->AFON_Data.AF[0][2*indx] = pstRDSData->AFON_Data.AF[0][2*indx2];
1702 pstRDSData->AFON_Data.AF[0][2*indx2-1] = AF_H;
1703 pstRDSData->AFON_Data.AF[0][2*indx2] = AF_L;
1708 //arrange frequency from low to high:end
1709 //compare AF buff0 and buff1 data:start
1710 num = pstRDSData->AFON_Data.AF_Num;
1712 for(indx = 0; indx < num; indx++){
1713 if((pstRDSData->AFON_Data.AF[1][indx]) == (pstRDSData->AFON_Data.AF[0][indx])){
1714 if(pstRDSData->AFON_Data.AF[1][indx] != 0)
1717 pstRDSData->AFON_Data.AF[1][indx] = pstRDSData->AFON_Data.AF[0][indx];
1719 //compare AF buff0 and buff1 data:end
1721 pstRDSData->AFON_Data.Addr_Cnt = 0xFF;
1722 pstRDSData->event_status |= RDS_EVENT_AFON_LIST;
1723 for(indx = 0; indx < num; indx++){
1724 if((pstRDSData->AFON_Data.AF[1][indx]) == 0){
1725 pstRDSData->AFON_Data.Addr_Cnt = 0x0F;
1726 pstRDSData->event_status &= (~RDS_EVENT_AFON_LIST);
1730 pstRDSData->AFON_Data.Addr_Cnt = 0x0F;
1737 TA_ON = block_data[1]&0x0008;
1738 FM_LOG_DBG(D_G14,"TA group14 typeB pstRDSData->RDSFlag.TP=%d pstRDSData->RDSFlag.TA=%d TP_ON=%d TA_ON=%d\n", pstRDSData->RDSFlag.TP, pstRDSData->RDSFlag.TA, TP_ON, TA_ON);
1739 if((!pstRDSData->RDSFlag.TP)&&(pstRDSData->RDSFlag.TA)&&TP_ON&&TA_ON){
1741 for (num=0;num<25;num++){
1742 if (pstRDSData->AFON_Data.AF[1][num] != 0){
1748 FM_LOG_NTC(D_G14,"TA set RDS_EVENT_TAON");
1749 if (TA_num == pstRDSData->AFON_Data.AF_Num){
1750 pstRDSData->event_status |= RDS_EVENT_TAON;
1758 int MT6620_RDS_OnOff(struct fm *fm, bool bFlag)
1761 RDSData_Struct *pstRDSData = fm->pstRDSData;
1764 if((ret = MT6620_RDS_Init_Data(pstRDSData)))
1766 if((ret = MT6620_RDS_enable()))
1769 if((ret = MT6620_RDS_disable()))
1777 Block0: PI code(16bits)
1778 Block1: Group type(4bits), B0=version code(1bit), TP=traffic program code(1bit),
1779 PTY=program type code(5bits), other(5bits)
1783 int MT6620_RDS_Eint_Handler(struct fm *fm, struct rds_rx *rds_raw, int rds_size)
1786 uint16_t block_data[6];
1787 uint8_t GroupType, SubType = 0;
1791 //target to fill the result in
1792 RDSData_Struct *pstRDSData = fm->pstRDSData;
1793 uint16_t *event = &pstRDSData->event_status;
1794 uint32_t *flag = &pstRDSData->RDSFlag.flag_status;
1796 ret = rds_cnt_get(rds_raw, rds_size, &rds_cnt);
1798 FM_LOG_WAR(D_RDS,"get cnt err[ret=%d]\n", ret);
1801 //pstRDSData->EINT_Flag = 1;
1803 ret = rds_group_get(&block_data[0], rds_raw, i);
1805 FM_LOG_WAR(D_RDS,"get group err[ret=%d]\n", ret);
1809 ret = rds_group_type_get(block_data[4], block_data[1], &GroupType, &SubType);
1811 FM_LOG_WAR(D_RDS,"get group type err[ret=%d]\n", ret);
1815 ret = rds_group_counter_add(GroupType, SubType, &fm->rds_gc);
1817 ret = rds_group_pi_get(block_data[4], block_data[0], &pstRDSData->PI, &dirty);
1819 FM_LOG_WAR(D_RDS,"get group pi err[ret=%d]\n", ret);
1821 }else if(dirty == TRUE){
1822 ret = rds_event_set(event, RDS_EVENT_PI_CODE); //yes, we got new PI code
1825 ret = rds_group_pty_get(block_data[4], block_data[1], &pstRDSData->PTY, &dirty);
1827 FM_LOG_WAR(D_RDS,"get group pty err[ret=%d]\n", ret);
1829 }else if(dirty == TRUE){
1830 ret = rds_event_set(event, RDS_EVENT_PTY_CODE); // yes, we got new PTY code
1833 ret = rds_group_tp_get(block_data[4], block_data[1], &pstRDSData->RDSFlag.TP, &dirty);
1835 FM_LOG_WAR(D_RDS,"get group tp err[ret=%d]\n", ret);
1837 }else if(dirty == TRUE){
1838 ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new TP code
1839 ret = rds_flag_set(flag, RDS_FLAG_IS_TP);
1844 if((ret = MT6620_RDS_RetrieveGroup0(&block_data[0], SubType, pstRDSData)))
1848 if((ret = MT6620_RDS_RetrieveGroup1(&block_data[0], SubType, pstRDSData)))
1852 if((ret = MT6620_RDS_RetrieveGroup2(&block_data[0], SubType, pstRDSData)))
1856 if((ret = MT6620_RDS_RetrieveGroup4(&block_data[0], SubType, pstRDSData)))
1860 if((ret = MT6620_RDS_RetrieveGroup14(&block_data[0], SubType, pstRDSData)))
1868 if(ret && (ret != -ERR_RDS_CRC)){
1869 FM_LOG_ERR(D_RDS,"parsing err[ret=%d]\n", ret);