4 * MediaTek <www.MediaTek.com>
5 * hongcheng <hongcheng.xia@MediaTek.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/string.h>
25 #include "fm_typedef.h"
29 #include "fm_stdlib.h"
31 //static rds_ps_state_machine_t ps_state_machine = RDS_PS_START;
32 //static rds_rt_state_machine_t rt_state_machine = RDS_RT_START;
33 struct fm_state_machine {
35 fm_s32(*state_get)(struct fm_state_machine *thiz);
36 fm_s32(*state_set)(struct fm_state_machine *thiz, fm_s32 new_state);
39 static fm_s32 fm_state_get(struct fm_state_machine *thiz)
44 static fm_s32 fm_state_set(struct fm_state_machine *thiz, fm_s32 new_state)
46 return thiz->state = new_state;
49 #define STATE_SET(a, s) \
52 (a)->state_set((a), (s)); \
56 #define STATE_GET(a) \
60 __ret = (a)->state_get((a)); \
65 static fm_u16(*rds_get_freq)(void) = NULL;
67 //RDS spec related handle flow
70 * To get rds group count form raw data
71 * If success return 0, else return error code
73 static fm_s32 rds_cnt_get(struct rds_rx_t *rds_raw, fm_s32 raw_size, fm_s32 *cnt)
75 fm_s32 gap = sizeof(rds_raw->cos) + sizeof(rds_raw->sin);
79 *cnt = (raw_size - gap) / sizeof(rds_packet_t);
80 WCN_DBG(FM_INF | RDSC, "group cnt=%d\n", *cnt);
87 * To get rds group[n] data form raw data with index
88 * If success return 0, else return error code
90 static fm_s32 rds_grp_get(fm_u16 *dst, struct rds_rx_t *raw, fm_s32 idx)
95 if (idx > (MAX_RDS_RX_GROUP_CNT - 1)) {
99 dst[0] = raw->data[idx].blkA;
100 dst[1] = raw->data[idx].blkB;
101 dst[2] = raw->data[idx].blkC;
102 dst[3] = raw->data[idx].blkD;
103 dst[4] = raw->data[idx].crc;
104 dst[5] = raw->data[idx].cbc;
106 WCN_DBG(FM_NTC | RDSC, "BLOCK:%04x %04x %04x %04x, CRC:%04x CBC:%04x\n", dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
113 * To check CRC rerult, if OK, *valid=fm_true, else *valid=fm_false
114 * If success return 0, else return error code
116 static fm_s32 rds_checksum_check(fm_u16 crc, fm_s32 mask, fm_bool *valid)
120 if ((crc & mask) == mask) {
130 * rds_cbc_get - To get block_n's correct bit count form cbc
131 * @cbc, the group's correct bit count
132 * @blk, target the block
134 * If success, return block_n's cbc, else error code
137 static fm_s32 rds_cbc_get(fm_u16 cbc, enum rds_blk_t blk)
143 ret = (cbc & 0xF000) >> 12;
146 ret = (cbc & 0x0F00) >> 8;
149 ret = (cbc & 0x00F0) >> 4;
152 ret = (cbc & 0x000F) >> 0;
158 WCN_DBG(FM_INF | RDSC, "group cbc=0x%04x\n", cbc);
164 * To set rds event, and user space can use this flag to juge which event happened
165 * If success return 0, else return error code
167 static fm_s32 rds_event_set(fm_u16 *events, fm_s32 event_mask)
170 WCN_DBG(FM_NTC | RDSC, "rds set event[%x->%x]\n", event_mask,*events);
171 *events |= event_mask;
178 * To set rds event flag, and user space can use this flag to juge which event happened
179 * If success return 0, else return error code
181 static fm_s32 rds_flag_set(fm_u32 *flags, fm_s32 flag_mask)
185 WCN_DBG(FM_NTC | RDSC, "rds set flag[%x->%x]\n", flag_mask,*flags);
192 * To get rds group type form blockB
193 * If success return 0, else return error code
195 static fm_s32 rds_grp_type_get(fm_u16 crc, fm_u16 blk, fm_u8 *type, fm_u8 *subtype)
197 fm_bool valid = fm_false;
201 //to get the group type from block B
202 rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid);
204 if (valid == fm_true) {
205 *type = (blk & 0xF000) >> 12; //Group type(4bits)
206 *subtype = (blk & 0x0800) >> 11; //version code(1bit), 0=vesionA, 1=versionB
208 WCN_DBG(FM_WAR | RDSC, "Block1 CRC err\n");
212 WCN_DBG(FM_DBG | RDSC, "Type=%d, subtype:%s\n", (fm_s32)*type, *subtype ? "version B" : "version A");
217 * rds_grp_counter_add
218 * @type -- group type, rang: 0~15
219 * @subtype -- sub group type, rang:0~1
221 * add group counter, g0a~g15b
222 * we use type value as the index
223 * If success return 0, else return error code
225 static fm_s32 rds_grp_counter_add(fm_u8 type, fm_u8 subtype, struct rds_group_cnt_t *gc)
246 WCN_DBG(FM_INF | RDSC, "group counter:%d\n", (fm_s32)gc->total);
251 * rds_grp_counter_get
253 * read group counter , g0a~g15b
254 * If success return 0, else return error code
256 extern fm_s32 rds_grp_counter_get(struct rds_group_cnt_t *dst, struct rds_group_cnt_t *src)
260 fm_memcpy(dst, src, sizeof(struct rds_group_cnt_t));
261 WCN_DBG(FM_DBG | RDSC, "rds gc get[total=%d]\n", (fm_s32)dst->total);
266 * rds_grp_counter_reset
268 * clear group counter to 0, g0a~g15b
269 * If success return 0, else return error code
271 extern fm_s32 rds_grp_counter_reset(struct rds_group_cnt_t *gc)
274 fm_memset(gc, 0, sizeof(struct rds_group_cnt_t));
278 extern fm_s32 rds_log_in(struct rds_log_t *thiz, struct rds_rx_t *new_log, fm_s32 new_len)
282 if (thiz->len < thiz->size) {
283 new_len = (new_len < sizeof(struct rds_rx_t)) ? new_len : sizeof(struct rds_rx_t);
284 fm_memcpy(&(thiz->rds_log[thiz->in]), new_log, new_len);
285 thiz->log_len[thiz->in] = new_len;
286 thiz->in = (thiz->in + 1) % thiz->size;
288 WCN_DBG(FM_DBG | RDSC, "add a new log[len=%d]\n", thiz->len);
290 WCN_DBG(FM_WAR | RDSC, "rds log buf is full\n");
297 extern fm_s32 rds_log_out(struct rds_log_t *thiz, struct rds_rx_t *dst, fm_s32 *dst_len)
303 *dst_len = thiz->log_len[thiz->out];
304 *dst_len = (*dst_len < sizeof(struct rds_rx_t)) ? *dst_len : sizeof(struct rds_rx_t);
305 fm_memcpy(dst, &(thiz->rds_log[thiz->out]), *dst_len);
306 thiz->out = (thiz->out + 1) % thiz->size;
308 WCN_DBG(FM_DBG | RDSC, "del a new log[len=%d]\n", thiz->len);
311 WCN_DBG(FM_WAR | RDSC, "rds log buf is empty\n");
319 * To get rds group pi code form blockA
320 * If success return 0, else return error code
322 static fm_s32 rds_grp_pi_get(fm_u16 crc, fm_u16 blk, fm_u16 *pi, fm_bool *dirty)
325 fm_bool valid = fm_false;
330 //to get the group pi code from block A
331 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_A, &valid);
333 if (valid == fm_true) {
335 //PI=program Identication
337 *dirty = fm_true; // yes, we got new PI code
339 *dirty = fm_false; // PI is the same as last one
342 WCN_DBG(FM_WAR | RDSC, "Block0 CRC err\n");
346 WCN_DBG(FM_INF | RDSC, "PI=0x%04x, %s\n", *pi, *dirty ? "new" : "old");
352 * To get rds group pty code form blockB
353 * If success return 0, else return error code
355 static fm_s32 rds_grp_pty_get(fm_u16 crc, fm_u16 blk, fm_u8 *pty, fm_bool *dirty)
358 // fm_bool valid = fm_false;
363 //to get PTY code from block B
364 // ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid);
366 // if (valid == fm_false) {
367 // WCN_DBG(FM_WAR | RDSC, "Block1 CRC err\n");
371 if (*pty != ((blk & 0x03E0) >> 5)) {
372 //PTY=Program Type Code
373 *pty = (blk & 0x03E0) >> 5;
374 *dirty = fm_true; // yes, we got new PTY code
376 *dirty = fm_false; // PTY is the same as last one
379 WCN_DBG(FM_INF | RDSC, "PTY=%d, %s\n", (fm_s32)*pty, *dirty ? "new" : "old");
385 * To get rds group tp code form blockB
386 * If success return 0, else return error code
388 static fm_s32 rds_grp_tp_get(fm_u16 crc, fm_u16 blk, fm_u8 *tp, fm_bool *dirty)
391 // fm_bool valid = fm_false;
396 //to get TP code from block B
397 // ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid);
399 // if (valid == fm_false) {
400 // WCN_DBG(FM_WAR | RDSC, "Block1 CRC err\n");
404 if (*tp != ((blk&0x0400) >> 10)) {
405 //Tranfic Program Identification
406 *tp = (blk & 0x0400) >> 10;
407 *dirty = fm_true; // yes, we got new TP code
409 *dirty = fm_false; // TP is the same as last one
412 WCN_DBG(FM_NTC | RDSC, "TP=%d, %s\n", (fm_s32)*tp, *dirty ? "new" : "old");
418 * To get rds group ta code form blockB
419 * If success return 0, else return error code
421 static fm_s32 rds_g0_ta_get(fm_u16 blk, fm_u8 *ta, fm_bool *dirty)
428 //TA=Traffic Announcement code
429 if (*ta != ((blk & 0x0010) >> 4)) {
430 *ta = (blk & 0x0010) >> 4;
431 *dirty = fm_true; // yes, we got new TA code
433 *dirty = fm_false; // TA is the same as last one
436 WCN_DBG(FM_INF | RDSC, "TA=%d, %s\n", (fm_s32)*ta, *dirty ? "new" : "old");
442 * To get music-speech switch code form blockB
443 * If success return 0, else return error code
445 static fm_s32 rds_g0_music_get(fm_u16 blk, fm_u8 *music, fm_bool *dirty)
452 //M/S=music speech switch code
453 if (*music != ((blk & 0x0008) >> 3)) {
454 *music = (blk & 0x0008) >> 3;
455 *dirty = fm_true; // yes, we got new music code
457 *dirty = fm_false; // music is the same as last one
460 WCN_DBG(FM_INF | RDSC, "Music=%d, %s\n", (fm_s32)*music, *dirty ? "new" : "old");
466 * To get ps addr form blockB, blkB b0~b1
467 * If success return 0, else return error code
469 static fm_s32 rds_g0_ps_addr_get(fm_u16 blkB, fm_u8 *addr)
472 *addr = (fm_u8)blkB & 0x03;
474 WCN_DBG(FM_INF | RDSC, "addr=0x%02x\n", *addr);
480 * To get DI segment flag form blockB, blkB b2
481 * If success return 0, else return error code
483 static fm_s32 rds_g0_di_flag_get(fm_u16 blkB, fm_u8 *flag)
486 *flag = (fm_u8)((blkB & 0x0004) >> 2);
488 WCN_DBG(FM_INF | RDSC, "flag=0x%02x\n", *flag);
492 static fm_s32 rds_g0_ps_get(fm_u16 crc, fm_u16 blkD, fm_u8 addr, fm_u8 *buf)
494 // fm_bool valid = fm_false;
499 //ps segment addr rang 0~3
501 WCN_DBG(FM_ERR | RDSC, "addr invalid(0x%02x)\n", addr);
507 buf[idx] = blkD >> 8;
508 buf[idx+1] = blkD & 0xFF;
510 rds_checksum_check(crc, FM_RDS_GDBK_IND_D, &valid);
512 if (valid == fm_true) {
513 buf[idx] = blkD >> 8;
514 buf[idx+1] = blkD & 0xFF;
516 WCN_DBG(FM_ERR | RDSC, "ps crc check err\n");
521 WCN_DBG(FM_NTC | RDSC, "PS:addr[%02x]:0x%02x 0x%02x\n", addr, buf[idx], buf[idx+1]);
527 * this function is the most importent flow for PS parsing
528 * 1.Compare fresh buf with once buf per byte, if eque copy this byte to twice buf, else copy it to once buf
529 * 2.Check wether we got a full segment
530 * If success return 0, else return error code
532 static fm_s32 rds_g0_ps_cmp(fm_u8 addr, fm_u16 cbc, fm_u8 *fresh,
533 fm_u8 *once, fm_u8 *twice, /*fm_bool *valid,*/fm_u8 *bm)
539 fm_u8 AF_H, AF_L,PS_Num;
540 //fm_u8 corrBitCnt_BlkB, corrBitCnt_BlkD;
541 static fm_s8 Pre_PS_Num = -1;
546 // FMR_ASSERT(valid);
548 //j = 2; // PS segment width
550 //corrBitCnt_BlkB = rds_cbc_get(cbc, RDS_BLK_B);
551 //corrBitCnt_BlkD = rds_cbc_get(cbc, RDS_BLK_D);
553 AF_H = once[2*PS_Num];
554 AF_L = once[2*PS_Num+1];
555 if((AF_H == fresh[2*PS_Num])&&(AF_L == fresh[2*PS_Num+1]))
557 twice[2*PS_Num] = once[2*PS_Num];
558 twice[2*PS_Num+1] = once[2*PS_Num+1];
563 if (PS_Num-Pre_PS_Num > 1)
565 for (indx=Pre_PS_Num+1; indx<PS_Num; indx++)
569 once[2*indx+1] = 0x00;
570 twice[2*indx] = 0x00;
571 twice[2*indx+1] = 0x00;
574 else if (PS_Num-Pre_PS_Num < 1)
576 for (indx=0; indx<PS_Num; indx++)
580 once[2*indx+1] = 0x00;
581 twice[2*indx] = 0x00;
582 twice[2*indx+1] = 0x00;
586 if ((once[2*PS_Num] != 0) || (once[2*PS_Num+1] != 0))
588 for (indx=PS_Num; indx<4; indx++)
593 //if((corrBitCnt_BlkB == 0) && (corrBitCnt_BlkD == 0))
597 once[2*PS_Num]=fresh[2*PS_Num];
598 once[2*PS_Num+1] = fresh[2*PS_Num+1];
599 twice[2*PS_Num]=fresh[2*PS_Num];
600 twice[2*PS_Num+1] = fresh[2*PS_Num+1];
604 once[2*PS_Num]=fresh[2*PS_Num];
605 once[2*PS_Num+1] = fresh[2*PS_Num+1];
611 if (rds_cbc_get(cbc, RDS_BLK_D) == 0) {
612 once[j*addr] = fresh[j*addr];
613 once[j*addr+1] = fresh[j*addr+1];
615 if((once[j*addr] == fresh[j*addr])&&(once[j*addr+1] == fresh[j*addr+1]))
617 twice[j*addr] = once[j*addr];
618 twice[j*addr+1] = once[j*addr+1];
623 once[j*addr] = fresh[j*addr];
624 once[j*addr+1] = fresh[j*addr+1];
629 for (i = 0; i < j; i++) {
630 if (fresh[j*addr+i] == once[j*addr+i]) {
631 twice[j*addr+i] = once[j*addr+i]; //get the same byte 2 times
634 once[j*addr+i] = fresh[j*addr+i]; //use new val
638 //check if we got a valid segment
645 //WCN_DBG(FM_NTC | RDSC, "PS seg=%s\n", *valid == fm_true ? "fm_true" : "fm_false");
646 WCN_DBG(FM_NTC | RDSC, "bitmap=%x\n", *bm);
647 WCN_DBG(FM_NTC | RDSC, "PS[1]=%x %x %x %x %x %x %x %x\n", once[0],once[1],once[2],once[3],once[4],once[5],once[6],once[7]);
648 WCN_DBG(FM_NTC | RDSC, "PS[2]=%x %x %x %x %x %x %x %x\n", twice[0],twice[1],twice[2],twice[3],twice[4],twice[5],twice[6],twice[7]);
656 fm_u16(*bm_get)(struct rds_bitmap *thiz);
657 fm_s32(*bm_cnt_get)(struct rds_bitmap *thiz);
658 fm_s32(*bm_get_pos)(struct rds_bitmap *thiz);
659 fm_s32(*bm_clr)(struct rds_bitmap *thiz);
660 fm_s32(*bm_cmp)(struct rds_bitmap *thiz, struct rds_bitmap *that);
661 fm_s32(*bm_set)(struct rds_bitmap *thiz, fm_u8 addr);
664 static fm_u16 rds_bm_get(struct rds_bitmap *thiz)
669 static fm_s32 rds_bm_cnt_get(struct rds_bitmap *thiz)
674 #define FM_RDS_USE_SOLUTION_B
676 static fm_s32 rds_bm_get_pos(struct rds_bitmap *thiz)
678 fm_s32 i = thiz->max_addr;
683 while (!(thiz->bm & (1 << i)) && (i > -1)) {
687 #ifdef FM_RDS_USE_SOLUTION_B
688 for (j = i; j >= 0; j--) {
689 if (!(thiz->bm & (1 << j))) {
690 WCN_DBG(FM_NTC | RDSC, "uncomplete msg 0x%04x, delete it\n", thiz->bm);
699 static fm_s32 rds_bm_clr(struct rds_bitmap *thiz)
706 static fm_s32 rds_bm_cmp(struct rds_bitmap *bitmap1, struct rds_bitmap *bitmap2)
708 return (fm_s32)(bitmap1->bm - bitmap2->bm);
711 static fm_s32 rds_bm_set(struct rds_bitmap *thiz, fm_u8 addr)
713 struct rds_bitmap bm_old;
715 //text segment addr rang
716 if (addr > thiz->max_addr) {
717 WCN_DBG(FM_ERR | RDSC, "addr invalid(0x%02x)\n", addr);
721 bm_old.bm = thiz->bm;
722 thiz->bm |= (1 << addr); //set bitmap
724 if (!rds_bm_cmp(&bm_old, thiz)) {
725 thiz->cnt++; // multi get a segment
726 } else if (thiz->cnt > 0) {
736 * To get rt addr form blockB
737 * If success return 0, else return error code
739 static fm_s32 rds_g2_rt_addr_get(fm_u16 blkB, fm_u8 *addr)
744 *addr = (fm_u8)blkB & 0x0F;
746 WCN_DBG(FM_INF | RDSC, "addr=0x%02x\n", *addr);
750 static fm_s32 rds_g2_txtAB_get(fm_u16 blk, fm_u8 *txtAB, fm_bool *dirty)
757 if (*txtAB != ((blk&0x0010) >> 4))
759 *txtAB = (blk & 0x0010) >> 4;
760 *dirty = fm_true; // yes, we got new txtAB code
761 WCN_DBG(FM_INF | RDSC, "changed! txtAB=%d\n", *txtAB);
763 *dirty = fm_false; // txtAB is the same as last one
766 WCN_DBG(FM_INF | RDSC, "txtAB=%d, %s\n", *txtAB, *dirty ? "new" : "old");
770 static fm_s32 rds_g2_rt_get(fm_u16 crc, fm_u8 subtype, fm_u16 blkC, fm_u16 blkD, fm_u8 addr, fm_u8 *buf)
773 fm_bool valid = fm_false;
778 //text segment addr rang 0~15
780 WCN_DBG(FM_ERR | RDSC, "addr invalid(0x%02x)\n", addr);
788 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_C | FM_RDS_GDBK_IND_D, &valid);
790 if (valid == fm_true) {
791 buf[idx] = blkC >> 8;
792 buf[idx+1] = blkC & 0xFF;
793 buf[idx+2] = blkD >> 8;
794 buf[idx+3] = blkD & 0xFF;
796 WCN_DBG(FM_ERR | RDSC, "rt crc check err\n");
803 ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_D, &valid);
805 if (valid == fm_true) {
806 buf[idx] = blkD >> 8;
807 buf[idx+1] = blkD & 0xFF;
809 WCN_DBG(FM_ERR | RDSC, "rt crc check err\n");
818 WCN_DBG(FM_NTC | RDSC, "fresh addr[%02x]:0x%02x%02x 0x%02x%02x\n", addr, buf[idx], buf[idx+1], buf[idx+2], buf[idx+3]);
822 static fm_s32 rds_g2_rt_get_len(fm_u8 subtype, fm_s32 pos, fm_s32 *len)
828 if (subtype == RDS_GRP_VER_A) {
829 *len = 4 * (pos + 1);
831 *len = 2 * (pos + 1);
839 * this function is the most importent flow for RT parsing
840 * 1.Compare fresh buf with once buf per byte, if eque copy this byte to twice buf, else copy it to once buf
841 * 2.Check wether we got a full segment, for typeA if copyed 4bytes to twice buf, for typeB 2bytes copyed to twice buf
842 * 3.Check wether we got the end of RT, if we got 0x0D
843 * 4.If we got the end, then caculate the RT lenth
844 * If success return 0, else return error code
846 static fm_s32 rds_g2_rt_cmp(fm_u8 addr, fm_u16 cbc, fm_u8 subtype, fm_u8 *fresh,
847 fm_u8 *once, fm_u8 *twice, fm_bool *valid/*, fm_bool *end, fm_s32 *len*/)
860 j = (subtype == RDS_GRP_VER_A) ? 4 : 2; // RT segment width
862 if (subtype == RDS_GRP_VER_A) {
863 //if (rds_cbc_get(cbc, RDS_BLK_C) == 0)
866 once[j*addr+0] = fresh[j*addr+0];
867 once[j*addr+1] = fresh[j*addr+1];
870 //if (rds_cbc_get(cbc, RDS_BLK_D) == 0)
872 once[j*addr+2] = fresh[j*addr+2];
873 once[j*addr+3] = fresh[j*addr+3];
875 } else if (subtype == RDS_GRP_VER_B) {
876 //if (rds_cbc_get(cbc, RDS_BLK_D) == 0)
879 once[j*addr+0] = fresh[j*addr+0];
880 once[j*addr+1] = fresh[j*addr+1];
884 for (i = 0; i < j; i++) {
885 if (fresh[j*addr+i] == once[j*addr+i]) {
886 twice[j*addr+i] = once[j*addr+i]; //get the same byte 2 times
888 WCN_DBG(FM_NTC | RDSC, "twice=%d\n", j*addr+i);
890 once[j*addr+i] = fresh[j*addr+i]; //use new val
891 WCN_DBG(FM_NTC | RDSC, "once=%d\n", j*addr+i);
894 //if we got 0x0D twice, it means a RT end
895 if (twice[j*addr+i] == 0x0D) {
897 *len = j * addr + i + 1; //record the length of RT
898 WCN_DBG(FM_NTC | RDSC, "get 0D=%d\n", *len);
903 //check if we got a valid segment 4bytes for typeA, 2bytes for typeB
910 WCN_DBG(FM_INF | RDSC, "RT seg=%s\n", *valid == fm_true ? "fm_true" : "fm_false");
911 // WCN_DBG(FM_INF | RDSC, "RT end=%s\n", *end == fm_true ? "fm_true" : "fm_false");
912 // WCN_DBG(FM_INF | RDSC, "RT len=%d\n", *len);
917 * rds_g2_rt_check_end
918 * check 0x0D end flag
919 * If we got the end, then caculate the RT lenth
920 * If success return 0, else return error code
922 static fm_s32 rds_g2_rt_check_end(fm_u8 addr, fm_u8 subtype, fm_u8 *twice,fm_bool *end)
930 j = (subtype == RDS_GRP_VER_A) ? 4 : 2; // RT segment width
933 for (i = 0; i < j; i++)
935 //if we got 0x0D twice, it means a RT end
936 if (twice[j*addr+i] == 0x0D)
939 WCN_DBG(FM_NTC | RDSC, "get 0x0D\n");
947 static fm_s32 rds_retrieve_g0_af(fm_u16 *block_data, fm_u8 SubType, rds_t *pstRDSData)
949 static fm_s16 preAF_Num = 0;
950 fm_u8 indx, indx2, AF_H, AF_L, num;
952 fm_bool valid = fm_false;
953 fm_bool dirty = fm_false;
954 fm_u16 *event = &pstRDSData->event_status;
955 fm_u32 *flag = &pstRDSData->RDSFlag.flag_status;
957 // ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_D, &valid);
959 // if (valid == fm_false) {
960 // WCN_DBG(FM_WAR | RDSC, "Group0 BlockD crc err\n");
964 ret = rds_g0_ta_get(block_data[1], &pstRDSData->RDSFlag.TA, &dirty);
967 WCN_DBG(FM_WAR | RDSC, "get ta failed[ret=%d]\n", ret);
968 } else if (dirty == fm_true) {
969 ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new TA code
970 ret = rds_flag_set(flag, RDS_FLAG_IS_TA);
973 ret = rds_g0_music_get(block_data[1], &pstRDSData->RDSFlag.Music, &dirty);
976 WCN_DBG(FM_WAR | RDSC, "get music failed[ret=%d]\n", ret);
977 } else if (dirty == fm_true) {
978 ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new MUSIC code
979 ret = rds_flag_set(flag, RDS_FLAG_IS_MUSIC);
982 if ((pstRDSData->Switch_TP) && (pstRDSData->RDSFlag.TP) && !(pstRDSData->RDSFlag.TA)) {
983 ret = rds_event_set(event, RDS_EVENT_TAON_OFF);
988 ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_C, &valid);
990 if (valid == fm_false) {
991 WCN_DBG(FM_WAR | RDSC, "Group0 BlockC crc err\n");
994 AF_H = (block_data[2] & 0xFF00) >> 8;
995 AF_L = block_data[2] & 0x00FF;
997 if ((AF_H > 224) && (AF_H < 250)) {
998 //Followed AF Number, see RDS spec Table 11, valid(224-249)
999 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 AF_H:%d, AF_L:%d\n", AF_H, AF_L);
1000 preAF_Num = AF_H - 224; //AF Number
1002 if (preAF_Num != pstRDSData->AF_Data.AF_Num) {
1003 pstRDSData->AF_Data.AF_Num = preAF_Num;
1004 pstRDSData->AF_Data.isAFNum_Get = 0;
1006 //Get the same AFNum two times
1007 pstRDSData->AF_Data.isAFNum_Get = 1;
1010 if ((AF_L < 205) && (AF_L > 0)) {
1011 //See RDS Spec table 10, valid VHF
1012 pstRDSData->AF_Data.AF[0][0] = AF_L + 875; //convert to 100KHz
1013 #ifdef MTK_FM_50KHZ_SUPPORT
1014 pstRDSData->AF_Data.AF[0][0] *= 10;
1016 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 AF[0][0]:%d\n", pstRDSData->AF_Data.AF[0][0]);
1018 if ((pstRDSData->AF_Data.AF[0][0]) != (pstRDSData->AF_Data.AF[1][0])) {
1019 pstRDSData->AF_Data.AF[1][0] = pstRDSData->AF_Data.AF[0][0];
1021 if (pstRDSData->AF_Data.AF[1][0] != rds_get_freq())
1022 pstRDSData->AF_Data.isMethod_A = 1;
1024 pstRDSData->AF_Data.isMethod_A = 0;
1027 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 isAFNum_Get:%d, isMethod_A:%d\n", pstRDSData->AF_Data.isAFNum_Get, pstRDSData->AF_Data.isMethod_A);
1029 //only one AF handle
1030 if ((pstRDSData->AF_Data.isAFNum_Get) && (pstRDSData->AF_Data.AF_Num == 1)) {
1031 pstRDSData->AF_Data.Addr_Cnt = 0xFF;
1032 pstRDSData->event_status |= RDS_EVENT_AF_LIST;
1033 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 RDS_EVENT_AF_LIST update\n");
1037 else if ((pstRDSData->AF_Data.isAFNum_Get) && (pstRDSData->AF_Data.Addr_Cnt != 0xFF)) {
1039 num = pstRDSData->AF_Data.AF_Num;
1041 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 +num:%d\n", num);
1043 //Put AF freq fm_s32o buffer and check if AF freq is repeat again
1044 for (indx = 1; indx < (num + 1); indx++) {
1045 if ((AF_H == (pstRDSData->AF_Data.AF[0][2*indx-1])) && (AF_L == (pstRDSData->AF_Data.AF[0][2*indx]))) {
1046 WCN_DBG(FM_ERR | RDSC, "RetrieveGroup0 AF same as indx:%d\n", indx);
1048 } else if (!(pstRDSData->AF_Data.AF[0][2*indx-1])) {
1050 pstRDSData->AF_Data.AF[0][2*indx-1] = AF_H + 875; //convert to 100KHz
1051 pstRDSData->AF_Data.AF[0][2*indx] = AF_L + 875;
1053 #ifdef MTK_FM_50KHZ_SUPPORT
1054 pstRDSData->AF_Data.AF[0][2*indx-1] *= 10;
1055 pstRDSData->AF_Data.AF[0][2*indx] *= 10;
1057 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 AF[0][%d]:%d, AF[0][%d]:%d\n",
1058 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 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 ++num:%d\n", num);
1067 if ((pstRDSData->AF_Data.AF[0][num-1]) != 0) {
1069 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 +++num:%d\n", num);
1071 //arrange frequency from low to high:start
1072 for (indx = 1; indx < num; indx++) {
1073 for (indx2 = indx + 1; indx2 < (num + 1); indx2++) {
1074 AF_H = pstRDSData->AF_Data.AF[0][2*indx-1];
1075 AF_L = pstRDSData->AF_Data.AF[0][2*indx];
1077 if (AF_H > (pstRDSData->AF_Data.AF[0][2*indx2-1])) {
1078 pstRDSData->AF_Data.AF[0][2*indx-1] = pstRDSData->AF_Data.AF[0][2*indx2-1];
1079 pstRDSData->AF_Data.AF[0][2*indx] = pstRDSData->AF_Data.AF[0][2*indx2];
1080 pstRDSData->AF_Data.AF[0][2*indx2-1] = AF_H;
1081 pstRDSData->AF_Data.AF[0][2*indx2] = AF_L;
1082 } else if (AF_H == (pstRDSData->AF_Data.AF[0][2*indx2-1])) {
1083 if (AF_L > (pstRDSData->AF_Data.AF[0][2*indx2])) {
1084 pstRDSData->AF_Data.AF[0][2*indx-1] = pstRDSData->AF_Data.AF[0][2*indx2-1];
1085 pstRDSData->AF_Data.AF[0][2*indx] = pstRDSData->AF_Data.AF[0][2*indx2];
1086 pstRDSData->AF_Data.AF[0][2*indx2-1] = AF_H;
1087 pstRDSData->AF_Data.AF[0][2*indx2] = AF_L;
1093 //arrange frequency from low to high:end
1094 //compare AF buff0 and buff1 data:start
1095 num = pstRDSData->AF_Data.AF_Num;
1098 for (indx = 0; indx < num; indx++) {
1099 if ((pstRDSData->AF_Data.AF[1][indx]) == (pstRDSData->AF_Data.AF[0][indx])) {
1100 if (pstRDSData->AF_Data.AF[1][indx] != 0)
1103 pstRDSData->AF_Data.AF[1][indx] = pstRDSData->AF_Data.AF[0][indx];
1106 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 indx2:%d, num:%d\n", indx2, num);
1108 //compare AF buff0 and buff1 data:end
1110 pstRDSData->AF_Data.Addr_Cnt = 0xFF;
1111 pstRDSData->event_status |= RDS_EVENT_AF_LIST;
1112 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 AF_Num:%d\n", pstRDSData->AF_Data.AF_Num);
1114 for (indx = 0; indx < num; indx++) {
1115 if ((pstRDSData->AF_Data.AF[1][indx]) == 0) {
1116 pstRDSData->AF_Data.Addr_Cnt = 0x0F;
1117 pstRDSData->event_status &= (~RDS_EVENT_AF_LIST);
1121 pstRDSData->AF_Data.Addr_Cnt = 0x0F;
1131 static fm_s32 rds_retrieve_g0_di(fm_u16 *block_data, fm_u8 SubType, rds_t *pstRDSData)
1133 fm_u8 DI_Code, DI_Flag;
1135 // fm_bool valid = fm_false;
1137 fm_u16 *event = &pstRDSData->event_status;
1138 fm_u32 *flag = &pstRDSData->RDSFlag.flag_status;
1140 //parsing Program service name segment (in BlockD)
1141 // ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_D, &valid);
1143 // if (valid == fm_false) {
1144 // WCN_DBG(FM_WAR | RDSC, "Group0 BlockD crc err\n");
1148 rds_g0_ps_addr_get(block_data[1], &DI_Code);
1149 rds_g0_di_flag_get(block_data[1], &DI_Flag);
1154 if (pstRDSData->RDSFlag.Stereo != DI_Flag) {
1155 pstRDSData->RDSFlag.Stereo = DI_Flag;
1156 ret = rds_event_set(event, RDS_EVENT_FLAGS);
1157 ret = rds_flag_set(flag, RDS_FLAG_IS_STEREO);
1163 if (pstRDSData->RDSFlag.Artificial_Head != DI_Flag) {
1164 pstRDSData->RDSFlag.Artificial_Head = DI_Flag;
1165 ret = rds_event_set(event, RDS_EVENT_FLAGS);
1166 ret = rds_flag_set(flag, RDS_FLAG_IS_ARTIFICIAL_HEAD);
1172 if (pstRDSData->RDSFlag.Compressed != DI_Flag) {
1173 pstRDSData->RDSFlag.Compressed = DI_Flag;
1174 ret = rds_event_set(event, RDS_EVENT_FLAGS);
1175 ret = rds_flag_set(flag, RDS_FLAG_IS_COMPRESSED);
1181 if (pstRDSData->RDSFlag.Dynamic_PTY != DI_Flag) {
1182 pstRDSData->RDSFlag.Dynamic_PTY = DI_Flag;
1183 ret = rds_event_set(event, RDS_EVENT_FLAGS);
1184 ret = rds_flag_set(flag, RDS_FLAG_IS_DYNAMIC_PTY);
1195 static fm_s32 rds_retrieve_g0_ps(fm_u16 *block_data, fm_u8 SubType, rds_t *pstRDSData)
1198 fm_s32 ret = 0,i,num;
1199 fm_bool valid = fm_false;
1201 static struct fm_state_machine ps_sm = {
1202 .state = RDS_PS_START,
1203 .state_get = fm_state_get,
1204 .state_set = fm_state_set,
1207 static struct rds_bitmap ps_bm = {
1211 .bm_get = rds_bm_get,
1212 .bm_cnt_get = rds_bm_cnt_get,
1213 .bm_set = rds_bm_set,
1214 .bm_get_pos = rds_bm_get_pos,
1215 .bm_clr = rds_bm_clr,
1216 .bm_cmp = rds_bm_cmp,
1219 fm_u16 *event = &pstRDSData->event_status;
1221 //parsing Program service name segment (in BlockD)
1222 ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_D, &valid);
1224 if (valid == fm_false) {
1225 WCN_DBG(FM_WAR | RDSC, "Group0 BlockD crc err\n");
1229 rds_g0_ps_addr_get(block_data[1], &ps_addr);
1231 //PS parsing state machine run
1233 switch (STATE_GET(&ps_sm)) {
1236 if (rds_g0_ps_get(block_data[4], block_data[3], ps_addr, pstRDSData->PS_Data.PS[0])) {
1237 STATE_SET(&ps_sm, RDS_PS_FINISH); //if CRC error, we should not do parsing
1241 rds_g0_ps_cmp(ps_addr, block_data[5], pstRDSData->PS_Data.PS[0],
1242 pstRDSData->PS_Data.PS[1], pstRDSData->PS_Data.PS[2], /*&valid,*/&pstRDSData->PS_Data.Addr_Cnt);
1244 // if (valid == fm_true) {
1245 // ps_bm.bm_set(&ps_bm, ps_addr);
1248 STATE_SET(&ps_sm, RDS_PS_DECISION);
1250 case RDS_PS_DECISION:
1252 if (pstRDSData->PS_Data.Addr_Cnt == 0x000F) //get max 8 chars
1253 //ps shouldn't check bm_cnt
1254 // || (ps_bm.bm_cnt_get(&ps_bm) > RDS_RT_MULTI_REV_TH)) { //repeate many times, but no end char get
1256 //pos = ps_bm.bm_get_pos(&ps_bm);
1257 STATE_SET(&ps_sm, RDS_PS_GETLEN);
1261 STATE_SET(&ps_sm, RDS_PS_FINISH);
1267 //if (pos == ps_bm.max_addr)
1270 WCN_DBG(FM_NTC | RDSC, "PS[3]=%x %x %x %x %x %x %x %x\n",
1271 pstRDSData->PS_Data.PS[3][0],
1272 pstRDSData->PS_Data.PS[3][1],
1273 pstRDSData->PS_Data.PS[3][2],
1274 pstRDSData->PS_Data.PS[3][3],
1275 pstRDSData->PS_Data.PS[3][4],
1276 pstRDSData->PS_Data.PS[3][5],
1277 pstRDSData->PS_Data.PS[3][6],
1278 pstRDSData->PS_Data.PS[3][7]);
1279 for(i=0;i<8;i++)//compare with last PS.
1281 if(pstRDSData->PS_Data.PS[3][i]==pstRDSData->PS_Data.PS[2][i])
1291 if((pstRDSData->PS_Data.PS[2][i]==0x20)||(pstRDSData->PS_Data.PS[2][i]==0x0))
1298 fm_memcpy(pstRDSData->PS_Data.PS[3], pstRDSData->PS_Data.PS[2], 8);
1299 rds_event_set(event, RDS_EVENT_PROGRAMNAME); //yes we got a new PS
1300 WCN_DBG(FM_NTC | RDSC, "Yes, get an PS!\n");
1305 pstRDSData->PS_Data.Addr_Cnt=0;
1307 fm_memset(pstRDSData->PS_Data.PS[0], 0x20, 8);
1308 fm_memset(pstRDSData->PS_Data.PS[1], 0x20, 8);
1309 fm_memset(pstRDSData->PS_Data.PS[2], 0x20, 8);
1313 ps_bm.bm_clr(&ps_bm);
1315 fm_memset(pstRDSData->PS_Data.PS[0], 0x20, 8);
1316 fm_memset(pstRDSData->PS_Data.PS[1], 0x20, 8);
1317 fm_memset(pstRDSData->PS_Data.PS[2], 0x20, 8);
1319 STATE_SET(&ps_sm, RDS_PS_FINISH);
1322 STATE_SET(&ps_sm, RDS_PS_START);
1334 static fm_s32 rds_retrieve_g0(fm_u16 *block_data, fm_u8 SubType, rds_t *pstRDSData)
1338 ret = rds_retrieve_g0_af(block_data, SubType, pstRDSData);
1344 ret = rds_retrieve_g0_di(block_data, SubType, pstRDSData);
1350 ret = rds_retrieve_g0_ps(block_data, SubType, pstRDSData);
1359 static fm_s32 rds_retrieve_g1(fm_u16 *block_data, fm_u8 SubType, rds_t *pstRDSData)
1361 fm_u8 variant_code = (block_data[2] & 0x7000) >> 12;
1364 if (variant_code == 0) {
1365 pstRDSData->Extend_Country_Code = (fm_u8)block_data[2] & 0xFF;
1366 WCN_DBG(FM_DBG | RDSC, "Extend_Country_Code:%d\n", pstRDSData->Extend_Country_Code);
1367 } else if (variant_code == 3) {
1368 pstRDSData->Language_Code = block_data[2] & 0xFFF;
1369 WCN_DBG(FM_DBG | RDSC, "Language_Code:%d\n", pstRDSData->Language_Code);
1372 pstRDSData->Radio_Page_Code = block_data[1] & 0x001F;
1373 pstRDSData->Program_Item_Number_Code = block_data[3];
1378 static fm_s32 rds_retrieve_g2(fm_u16 *source, fm_u8 subtype, rds_t *target)
1382 fm_u16 blkA, blkB, blkC, blkD;
1383 fm_u8 *fresh, *once, *twice, *display;
1386 static struct fm_state_machine rt_sm = {
1387 .state = RDS_RT_START,
1388 .state_get = fm_state_get,
1389 .state_set = fm_state_set,
1391 static struct rds_bitmap rt_bm = {
1395 .bm_get = rds_bm_get,
1396 .bm_cnt_get = rds_bm_cnt_get,
1397 .bm_set = rds_bm_set,
1398 .bm_get_pos = rds_bm_get_pos,
1399 .bm_clr = rds_bm_clr,
1400 .bm_cmp = rds_bm_cmp,
1403 fm_bool txtAB_change = fm_false; //text AB flag 0 --> 1 or 1-->0 meas new RT incoming
1404 fm_bool txt_end = fm_false; //0x0D means text end
1407 fm_s32 rt_len = 0,indx=0,invalid_cnt=0;
1420 fresh = target->RT_Data.TextData[0];
1421 once = target->RT_Data.TextData[1];
1422 twice = target->RT_Data.TextData[2];
1423 display = target->RT_Data.TextData[3];
1424 event = &target->event_status;
1425 flag = &target->RDSFlag.flag_status;
1426 bufsize = sizeof(target->RT_Data.TextData[0]);
1427 rt_bm.bm = target->RT_Data.Addr_Cnt;
1429 //get basic info: addr, txtAB
1430 if (rds_g2_rt_addr_get(blkB, &rt_addr))
1433 if (rds_g2_txtAB_get(blkB, &target->RDSFlag.Text_AB, &txtAB_change))
1435 if(txtAB_change == fm_true)
1438 fm_memset(fresh, 0x20, bufsize);
1439 fm_memset(once, 0x20, bufsize);
1440 fm_memset(twice, 0x20, bufsize);
1441 rt_bm.bm_clr(&rt_bm);
1443 //RT parsing state machine run
1445 switch (STATE_GET(&rt_sm)) {
1449 if (txtAB_change == fm_true)
1451 STATE_SET(&rt_sm, RDS_RT_DECISION);
1456 if (rds_g2_rt_get(crc, subtype, blkC, blkD, rt_addr, fresh) == 0)
1458 //STATE_SET(&rt_sm, RDS_RT_FINISH); //if CRC error, we should not do parsing
1460 rds_g2_rt_cmp(rt_addr, cbc, subtype, fresh, once, twice,
1461 &seg_ok/*, &txt_end, &rt_len*/);
1463 if (seg_ok == fm_true)
1465 rt_bm.bm_set(&rt_bm, rt_addr);
1467 else//clear bitmap of rt_addr
1469 rt_bm.bm &= ~(1<<rt_addr);
1472 WCN_DBG(FM_NTC | RDSC, "bitmap=0x%04x, bmcnt=%d\n", rt_bm.bm, rt_bm.cnt);
1473 rds_g2_rt_check_end(rt_addr,subtype,twice,&txt_end);
1475 STATE_SET(&rt_sm, RDS_RT_DECISION);
1479 case RDS_RT_DECISION:
1481 if ((txt_end == fm_true)
1482 || (rt_bm.bm_get(&rt_bm) == 0xFFFF) //get max 64 chars
1483 || (rt_bm.bm_cnt_get(&rt_bm) > RDS_RT_MULTI_REV_TH))//repeate many times, but no end char get
1485 pos = rt_bm.bm_get_pos(&rt_bm);
1486 rds_g2_rt_get_len(subtype, pos, &rt_len);
1487 STATE_SET(&rt_sm, RDS_RT_GETLEN);
1491 STATE_SET(&rt_sm, RDS_RT_FINISH);
1498 if (rt_len > 0 /*&& ((txt_end == fm_true) || (rt_bm.bm_get(&rt_bm) == 0xFFFF))*/)
1500 for(indx=0; indx<rt_len; indx++)
1502 if(twice[indx] == 0x20)
1505 if(invalid_cnt != rt_len)
1507 if(memcmp(display,twice,bufsize)!=0)
1509 fm_memcpy(display, twice, bufsize);
1510 target->RT_Data.TextLength = rt_len;
1511 rds_event_set(event, RDS_EVENT_LAST_RADIOTEXT); //yes we got a new RT
1512 WCN_DBG(FM_NTC | RDSC, "Yes, get an RT! [len=%d]\n", rt_len);
1514 rt_bm.bm_clr(&rt_bm);
1516 fm_memset(fresh, 0x20, bufsize);
1517 fm_memset(once, 0x20, bufsize);
1518 fm_memset(twice, 0x20, bufsize);
1521 WCN_DBG(FM_NTC | RDSC, "Get 0x20 RT %d\n", invalid_cnt);
1525 if (txtAB_change == fm_true) {
1526 txtAB_change = fm_false;
1527 //we need get new RT after show the old RT to the display
1528 STATE_SET(&rt_sm, RDS_RT_START);
1533 STATE_SET(&rt_sm, RDS_RT_FINISH);
1537 STATE_SET(&rt_sm, RDS_RT_START);
1546 target->RT_Data.Addr_Cnt = rt_bm.bm;
1550 static fm_s32 rds_retrieve_g4(fm_u16 *block_data, fm_u8 SubType, rds_t *pstRDSData)
1552 fm_u16 year, month, k = 0, D2, minute;
1555 WCN_DBG(FM_DBG | RDSC, "RetrieveGroup4 %d\n", SubType);
1559 if ((block_data[4]&FM_RDS_GDBK_IND_C) && (block_data[4]&FM_RDS_GDBK_IND_D)) {
1560 MJD = (fm_u32)(((block_data[1] & 0x0003) << 15) + ((block_data[2] & 0xFFFE) >> 1));
1561 year = (MJD * 100 - 1507820) / 36525;
1562 month = (MJD * 10000 - 149561000 - 3652500 * year) / 306001;
1564 if ((month == 14) || (month == 15))
1567 D1 = (fm_u32)((36525 * year) / 100);
1568 D2 = (fm_u16)((306001 * month) / 10000);
1569 pstRDSData->CT.Year = 1900 + year + k;
1570 pstRDSData->CT.Month = month - 1 - k * 12;
1571 pstRDSData->CT.Day = (fm_u16)(MJD - 14956 - D1 - D2);
1572 pstRDSData->CT.Hour = ((block_data[2] & 0x0001) << 4) + ((block_data[3] & 0xF000) >> 12);
1573 minute = (block_data[3] & 0x0FC0) >> 6;
1575 if (block_data[3]&0x0020) {
1576 pstRDSData->CT.Local_Time_offset_signbit = 1; //0=+, 1=-
1579 pstRDSData->CT.Local_Time_offset_half_hour = block_data[3] & 0x001F;
1581 if (pstRDSData->CT.Minute != minute) {
1582 pstRDSData->CT.Minute = (block_data[3] & 0x0FC0) >> 6;
1583 pstRDSData->event_status |= RDS_EVENT_UTCDATETIME;
1591 static fm_s32 rds_retrieve_g14(fm_u16 *block_data, fm_u8 SubType, rds_t *pstRDSData)
1593 static fm_s16 preAFON_Num = 0;
1594 fm_u8 TP_ON, TA_ON, PI_ON, PS_Num, AF_H, AF_L, indx, indx2, num;
1596 WCN_DBG(FM_DBG | RDSC, "RetrieveGroup14 %d\n", SubType);
1597 //SubType = (*(block_data+1)&0x0800)>>11;
1598 PI_ON = block_data[3];
1599 TP_ON = block_data[1] & 0x0010;
1601 if ((!SubType) && (block_data[4]&FM_RDS_GDBK_IND_C)) {
1603 PS_Num = block_data[1] & 0x000F;
1606 for (indx = 0; indx < 2; indx++) {
1607 pstRDSData->PS_ON[2*PS_Num] = block_data[2] >> 8;
1608 pstRDSData->PS_ON[2*PS_Num+1] = block_data[2] & 0xFF;
1610 } else if (PS_Num == 4) {
1611 AF_H = (block_data[2] & 0xFF00) >> 8;
1612 AF_L = block_data[2] & 0x00FF;
1614 if ((AF_H > 224) && (AF_H < 250)) {
1615 //Followed AF Number
1616 pstRDSData->AFON_Data.isAFNum_Get = 0;
1617 preAFON_Num = AF_H - 224;
1619 if (pstRDSData->AFON_Data.AF_Num != preAFON_Num) {
1620 pstRDSData->AFON_Data.AF_Num = preAFON_Num;
1622 pstRDSData->AFON_Data.isAFNum_Get = 1;
1625 pstRDSData->AFON_Data.AF[0][0] = AF_L + 875;
1627 if ((pstRDSData->AFON_Data.AF[0][0]) != (pstRDSData->AFON_Data.AF[1][0])) {
1628 pstRDSData->AFON_Data.AF[1][0] = pstRDSData->AFON_Data.AF[0][0];
1630 pstRDSData->AFON_Data.isMethod_A = 1;
1634 else if ((pstRDSData->AFON_Data.isAFNum_Get) && ((pstRDSData->AFON_Data.Addr_Cnt) != 0xFF)) {
1636 num = pstRDSData->AFON_Data.AF_Num;
1639 //Put AF freq fm_s32o buffer and check if AF freq is repeat again
1640 for (indx = 1; indx < (num + 1); indx++) {
1641 if ((AF_H == (pstRDSData->AFON_Data.AF[0][2*indx-1])) && (AF_L == (pstRDSData->AFON_Data.AF[0][2*indx]))) {
1642 WCN_DBG(FM_NTC | RDSC, "RetrieveGroup14 AFON same as indx:%d\n", indx);
1644 } else if (!(pstRDSData->AFON_Data.AF[0][2*indx-1])) {
1646 pstRDSData->AFON_Data.AF[0][2*indx-1] = AF_H + 875;
1647 pstRDSData->AFON_Data.AF[0][2*indx] = AF_L + 875;
1652 num = pstRDSData->AFON_Data.AF_Num;
1655 if ((pstRDSData->AFON_Data.AF[0][num-1]) != 0) {
1658 //arrange frequency from low to high:start
1659 for (indx = 1; indx < num; indx++) {
1660 for (indx2 = indx + 1; indx2 < (num + 1); indx2++) {
1661 AF_H = pstRDSData->AFON_Data.AF[0][2*indx-1];
1662 AF_L = pstRDSData->AFON_Data.AF[0][2*indx];
1664 if (AF_H > (pstRDSData->AFON_Data.AF[0][2*indx2-1])) {
1665 pstRDSData->AFON_Data.AF[0][2*indx-1] = pstRDSData->AFON_Data.AF[0][2*indx2-1];
1666 pstRDSData->AFON_Data.AF[0][2*indx] = pstRDSData->AFON_Data.AF[0][2*indx2];
1667 pstRDSData->AFON_Data.AF[0][2*indx2-1] = AF_H;
1668 pstRDSData->AFON_Data.AF[0][2*indx2] = AF_L;
1669 } else if (AF_H == (pstRDSData->AFON_Data.AF[0][2*indx2-1])) {
1670 if (AF_L > (pstRDSData->AFON_Data.AF[0][2*indx2])) {
1671 pstRDSData->AFON_Data.AF[0][2*indx-1] = pstRDSData->AFON_Data.AF[0][2*indx2-1];
1672 pstRDSData->AFON_Data.AF[0][2*indx] = pstRDSData->AFON_Data.AF[0][2*indx2];
1673 pstRDSData->AFON_Data.AF[0][2*indx2-1] = AF_H;
1674 pstRDSData->AFON_Data.AF[0][2*indx2] = AF_L;
1680 //arrange frequency from low to high:end
1681 //compare AF buff0 and buff1 data:start
1682 num = pstRDSData->AFON_Data.AF_Num;
1685 for (indx = 0; indx < num; indx++) {
1686 if ((pstRDSData->AFON_Data.AF[1][indx]) == (pstRDSData->AFON_Data.AF[0][indx])) {
1687 if (pstRDSData->AFON_Data.AF[1][indx] != 0)
1690 pstRDSData->AFON_Data.AF[1][indx] = pstRDSData->AFON_Data.AF[0][indx];
1693 //compare AF buff0 and buff1 data:end
1695 pstRDSData->AFON_Data.Addr_Cnt = 0xFF;
1696 pstRDSData->event_status |= RDS_EVENT_AFON_LIST;
1698 for (indx = 0; indx < num; indx++) {
1699 if ((pstRDSData->AFON_Data.AF[1][indx]) == 0) {
1700 pstRDSData->AFON_Data.Addr_Cnt = 0x0F;
1701 pstRDSData->event_status &= (~RDS_EVENT_AFON_LIST);
1705 pstRDSData->AFON_Data.Addr_Cnt = 0x0F;
1712 TA_ON = block_data[1] & 0x0008;
1713 WCN_DBG(FM_DBG | RDSC, "TA g14 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);
1715 if ((!pstRDSData->RDSFlag.TP) && (pstRDSData->RDSFlag.TA) && TP_ON && TA_ON) {
1718 for (num = 0; num < 25; num++) {
1719 if (pstRDSData->AFON_Data.AF[1][num] != 0) {
1726 WCN_DBG(FM_NTC | RDSC, "TA set RDS_EVENT_TAON");
1728 if (TA_num == pstRDSData->AFON_Data.AF_Num) {
1729 pstRDSData->event_status |= RDS_EVENT_TAON;
1739 * Block0: PI code(16bits)
1740 * Block1: Group type(4bits), B0=version code(1bit), TP=traffic program code(1bit),
1741 * PTY=program type code(5bits), other(5bits)
1744 * @rds_dst - target buffer that record RDS parsing result
1745 * @rds_raw - rds raw data
1746 * @rds_size - size of rds raw data
1747 * @getfreq - function pointer, AF need get current freq
1749 fm_s32 rds_parser(rds_t *rds_dst, struct rds_rx_t *rds_raw, fm_s32 rds_size, fm_u16(*getfreq)(void))
1752 //block_data[0] = blockA, block_data[1] = blockB, block_data[2] = blockC, block_data[3] = blockD,
1753 //block_data[4] = CRC, block_data[5] = CBC
1754 fm_u16 block_data[6];
1755 fm_u8 GroupType, SubType = 0;
1758 fm_bool dirty = fm_false;
1759 //target buf to fill the result in
1760 fm_u16 *event = &rds_dst->event_status;
1761 fm_u32 *flag = &rds_dst->RDSFlag.flag_status;
1763 FMR_ASSERT(getfreq);
1764 rds_get_freq = getfreq;
1766 ret = rds_cnt_get(rds_raw, rds_size, &rds_cnt);
1769 WCN_DBG(FM_WAR | RDSC, "get cnt err[ret=%d]\n", ret);
1773 while (rds_cnt > 0) {
1774 ret = rds_grp_get(&block_data[0], rds_raw, i);
1777 WCN_DBG(FM_WAR | RDSC, "get group err[ret=%d]\n", ret);
1781 ret = rds_grp_type_get(block_data[4], block_data[1], &GroupType, &SubType);
1784 WCN_DBG(FM_WAR | RDSC, "get group type err[ret=%d]\n", ret);
1788 ret = rds_grp_counter_add(GroupType, SubType, &rds_dst->gc);
1790 ret = rds_grp_pi_get(block_data[4], block_data[0], &rds_dst->PI, &dirty);
1793 WCN_DBG(FM_WAR | RDSC, "get group pi err[ret=%d]\n", ret);
1795 } else if (dirty == fm_true) {
1796 ret = rds_event_set(event, RDS_EVENT_PI_CODE); //yes, we got new PI code
1799 ret = rds_grp_pty_get(block_data[4], block_data[1], &rds_dst->PTY, &dirty);
1802 WCN_DBG(FM_WAR | RDSC, "get group pty err[ret=%d]\n", ret);
1804 } else if (dirty == fm_true) {
1805 ret = rds_event_set(event, RDS_EVENT_PTY_CODE); // yes, we got new PTY code
1808 ret = rds_grp_tp_get(block_data[4], block_data[1], &rds_dst->RDSFlag.TP, &dirty);
1811 WCN_DBG(FM_WAR | RDSC, "get group tp err[ret=%d]\n", ret);
1813 } else if (dirty == fm_true) {
1814 ret = rds_event_set(event, RDS_EVENT_FLAGS); // yes, we got new TP code
1815 ret = rds_flag_set(flag, RDS_FLAG_IS_TP);
1818 switch (GroupType) {
1821 if ((ret = rds_retrieve_g0(&block_data[0], SubType, rds_dst)))
1827 if ((ret = rds_retrieve_g1(&block_data[0], SubType, rds_dst)))
1833 if ((ret = rds_retrieve_g2(&block_data[0], SubType, rds_dst)))
1839 if ((ret = rds_retrieve_g4(&block_data[0], SubType, rds_dst)))
1845 if ((ret = rds_retrieve_g14(&block_data[0], SubType, rds_dst)))
1855 if (ret && (ret != -FM_ECRC)) {
1856 WCN_DBG(FM_ERR | RDSC, "parsing err[ret=%d]\n", ret);