RDS 工作笔记

话说西元一千九百七十四年,欧洲有一帮不安分份子开始密谋策划,妄想利用有限的无线电频谱资源,去传送更多的资信讯息。六年后的1980年,他们在瑞士的伯尔尼进行了第一次的实用性试验。之后82年和83年又分别进行了各一次试验。至84年,首份正式的RDS技术规范EBU 3244横空出世----历经10年,RDS胚胎总算孕育成形;同年,美国福特公司开始汽车RDS收音机的研发工作。

85年,大规模的预运作试验在德国进行;同年,EUB(European Broadcast Union,欧洲广播联盟)确定了第一部实用RDS接收机面世的时间----1987年。

米国佬眼看欧洲在按部就班的进行着RDS的推广活动,再也坐不住了。1986年,他们在达拉斯向全国广播工作者协会推广介绍RDS系统。同年,国际无线电咨询委员会的RDS推荐文件正式发行。

好了,终于等到87年。在柏林IFA大展览会上,人们终于见到RDS接收机的倩影。德国VOLVO上市全球第一部RDS汽车收音机。88年,根德和菲力浦亦开始量产RDS汽车收音机。

再说回米国,直至89年,还在华盛顿D.C和拉斯维加斯向全国广播工作者协会介绍RDS系统----咳,由此可见,一项新鲜事物的接受程度哪怕是在科技发达的米帝国亦是步步唯艰。(哈哈,89年,诸位都干了些啥呢?)来到92年,米国的RDS国家标准----RBDS(Radio Broadcast Data System)技术规范才正式出炉。同年,RDS欧洲标准CENELEC EN 50067:1992出版发行。(注:CENELEC=欧洲电工技术标准化委员会)

RDS硬件规范
1)副载波导频:57KHz +/- 6Hz,对主载波标称频偏+/-1.0KHz 至 +/-7.5KHz;
2)调制方法:PSK(相移键控)
3)数据传输比特率:1187.5bit/s

进一步调查,知道的都说RDS家教甚好!举止文雅、谈吐不俗自不需多说,另外18般武艺也样样精通。都有些啥子本事?嘿嘿......
1。PI----节目识别。能使接收机依据节目身份代码正确切换。
2。PS----节目业务名称。使接收机能显示正在收听的电台节目业务名。
3。PTY----节目类型。随节目同时发出,共分31类,如音乐、体育、新闻等。
4。TP----交通节目识别。是一个开关信号,指明正在收听的节目业务是否播送交通公告的节目。
5。TA----交通公告识别。是一个切换信号,指明是否正在播送交通公告。
6。AF----替换频率表。此表给出在同一或相邻区域内播送同一节目的各发射机的频率信息。
7。DI----解码器识别。是一个切换信号,指明广播节目使用的16种工作模式的哪一种(或其合成)。
8。RT----广播文本。播音同时可在接收机显示屏显示的文本信息。
9。EON----增强的其他网络信息。有此功能的接收机既可收听调谐节目,又可通过EON功能收听相互参照的其他节目的交通公告。
10。CT----时间和日期。广播节目和日期码,使用UTC制式,并又接收机自动转为当地时。
11。EWS----紧急报警系统。紧急情况下使用的,接收机可自动调谐且识别此信息。
12。LN----定位和导航。给出发射台的位置信息,为导航和定位提供数据。
13。M/S----音乐/语言切换。听众可根据此信号调整接收机的音量和音调以达到最佳效果。
14。TMC----交通信息通道。用于传送交通编码信息,格式待定。
15。RP----广播寻呼。功能类似寻呼机。
16。IH----内部应用。由各个广播机构自行决定。
17。PIN----节目栏目号。广播电台所公布的预定的节目开始日期和时间,接收机用此设置预收听节目。
18。TDC----透明数据信道。用以传送图形数据的信道,有32个子信道。



检查揭示:RDS共有16组编码),每条上有四个块,每块里又各有26个bit。其中16bit是信息字,10bit是校验字。
首先,要将RDS信号运送出来

(RDS编码发送过程)

再看接应一方的手段

(RDS接收解码过程)

说到这里,该是进入实用话题的时候了。

话题一:关于RDS广播特点及RDS广播接收机

RDS系统除了传送实用的信息数据外,同时也传送开关信号。人们利用这套编码系统,从而实现FM频段的一台多频点的发射方案----方法是:一个电台,利用小功率的多个频点完成对某一区域的覆盖,从而替代单频点大功率的发射模式;优点是:节省发射功率,减少电磁污染,可以使覆盖范围信号强度均匀,避免强的过载,弱的收不到的烦恼。(手机移动通讯系统应该从这里偷了师)

RDS系统一开始开发,就有一个很特定目标:满足汽车收音的移动特性,使之能有满意的移动接收效果。所以,PI、TP、TA、AF、EON等编码都是为满足这个目的而设计的。至于家用收音机的RDS功能,只不过是拾人家一点牙惠而已。最近亦有便携式收音机做些汽车机的功能,呵呵,它也有移动特性啊。

问题:移动接收的效果是如何满足的?首先,每个RDS电台都有自己的身份证---PI码,然后AF码里面又包含有本台的各发射频率列表,利用这两个编码,接收机便能比较出哪一个频率的信号最强,使之始终接收最强的那个频点,并实现无缝切换。

另外,TA是一个强制执行代码。只要你在汽车里开着音响,哪怕是在听CD或播放磁带,只要有交通消息播报,接收机自动切回收音状态收听。播完后又自动回到原先的工作状态,想干啥继续干啥。
总之,RDS系统在交通管制上可以实现:
一、交通信息广播。
二、交通诱导(交通流量控制)。
三、紧急通告(强迫接收)。
四、单呼(BP机功能)。
五、群呼。
六、报失车辆的锁定与报警。



特别提示:不要指望你能买到一部收音机,它能具有RDS的所有功能。原因之一是RDS本身还在完善之中,之二就是制造商总是针对自己的目标市场选择性的做一些RDS功能。

花絮:曾经参与开发一款RDS汽车机,历时近两年(是干活的时间而不是抄作时间)。光是路试就在欧洲做了一次,香港做了三次,深圳做了两次。。。。。亦苦亦乐


(RDS汽车机)




(NEWS)




(CLASSIC MUSIC)




(SPORTS)






话题二:RDS在中国
1991年RDS首次在中国推介,至1995年,中华人民共和国国家标准《广播数据系统技术规范》出台(GB/T 15770-1995),也就是说RDS在中国的准生证有了。下面呢,我们化整为零说说RDS在中国的情况。

1。大陆

因Car—radio手头资料有限,真的部知道大陆甚麽地方在试播RDS信号,还望各位兄弟告知。
猜想没能迅速推广的原因:1)市场因数。需投入大量人力物力进行设备更新,需进行大量市场宣传。另外,设备不能自己生产亦是重要因数之一。2)技术因数。RDS技术引入中国时,DAB(数码音频广播)技术已经成熟。本着宁超前不滞后的原则,于是先行选择了DAB试播。


顺便贴一贴广东佛山电台数码广播在珠三角地区信号强度实测数据对应图



回澜33dB    罗源24dB  江谷30dB  广利32dB   
炭步35dB  钟落潭33dB  广州45dB  佛山85dB
黄埔39dB    石碣31dB  番愚34dB  厚街33dB
鹤山52dB    长安28dB  新垦28dB  宝安27dB
中山46dB    三江31dB  斗门32dB



下面是中国各省区RDS的识别码对应图,各位可对一下自己所在地是甚麽编码




2。香港
因收大英帝国长期殖民统治,香港的工业体制甚至生活习惯都深受英国影响。目前香港共16个广播频道。其中7个FM频道,除两个没有RDS功能外,剩下的都有。


有RDS功能之五个FM电台之频率和发射基站对应表(频率:MHz)

      电台名      商业电台1  商业电台2  香港电台4  劲歌    金曲
                    CR1        CR2        RTHK4    HIT    FM-S
发射基站

太平山              88.1      90.6      97.6      99.7    104.6 
飞鹅山              89.5      92.1      98.9      101.8    106.3     
青山                88.6      91.2      98.7      100.4    102.5
金山                88.9      90.9      98.4      101.6    105.5
笔架山              89.2      91.1      98.1      100.5    102.4
南丫岛              89.1      91.6      98.2      102.1    104.5
大雾山              88.3      90.7      97.8      100.0    104.7


以上列表还要港人及在香港的朋友收听验证。(深圳不能收到全部频点)


3。澳门

澳门虽曾是葡萄牙的殖民地,但因地域太小,估计未必采用RDS制式。这一点请珠海、中山、澳门和香港的朋友验证。


4。台湾

台湾一直跟在米国和***屁股后面,整天嗅些尾气。但米国的RBDS推广并不普及(***那边也不见啥动静),猜想台湾这方面还在按兵不动。这里烦请米乐.刘以及其他方便出入台湾的朋友来补充。

 

rds源代码解码:

View Code
   1 /*
   2 
   3 Copyright (C) 2006 Marc Ketel
   4 
   5 This program is free software; you can redistribute it and/or
   6 modify it under the terms of the GNU General Public License
   7 as published by the Free Software Foundation; either version 2
   8 of the License, or (at your option) any later version.
   9 
  10 This program is distributed in the hope that it will be useful,
  11 but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 GNU General Public License for more details.
  14 
  15 You should have received a copy of the GNU General Public License
  16 along with this program; if not, write to the Free Software
  17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  18 
  19 */
  20 
  21 #define INFO "20060629-1 RDS Decoder by Marc Ketel alias DiNo, marc@atoomnet.net."
  22 /*
  23 
  24 Works with RDS clock signal and RDS data signal. During design a TDA7300B rds demodulator was used.
  25 
  26 This source compiles correctly with WinAVR 20060421.
  27 
  28 Use a Atmega168 to flash program into. low fuse: 0xF0, high fuse: 0xDD
  29 
  30 Versions:
  31   20060629-1  Initial version
  32 
  33 */
  34 
  35 /*
  36 
  37 general word on ISR: it does not seem that ISR has global interrupts disabled.
  38 
  39 */
  40 
  41 #include <avr/io.h>
  42 #include <avr/interrupt.h>
  43 #include <avr/pgmspace.h>
  44 #include <avr/wdt.h>
  45 #include <stdio.h>
  46 #include <math.h>
  47 
  48 #define RDS_PORT PIND
  49 #define RDS_PIN  PD4
  50 
  51 FILE* Uart;
  52 
  53 //used for stdout
  54 int uartSend(char data, FILE* stream) {
  55   //wait for completion of previous send
  56   loop_until_bit_is_set(UCSR0A, UDRE0);
  57 
  58   //send the data
  59   UDR0 = data;
  60   return 0;
  61 }
  62 
  63 //used for stdin
  64 int uartRecv(FILE* stream) {
  65   loop_until_bit_is_set(UCSR0A, RXC0);
  66   return UDR0;
  67 }
  68 
  69 volatile unsigned char event = 0;
  70 #define eventTimerOverflow      _BV(0)
  71 #define eventUsart0RxDInterrupt _BV(1)
  72 #define eventGroupComplete      _BV(2)
  73 #define eventBitstreamSnapshot  _BV(3)
  74 #define eventSyncLost           _BV(4)
  75 
  76 volatile unsigned char timerOverflowCount = 0;
  77 volatile unsigned char usart0RxDByte = 0;
  78 volatile unsigned char bitCounter = 0;
  79 volatile unsigned char bitCounterSnapshot = 0;
  80 
  81 volatile unsigned char synchronized = 0;
  82 volatile unsigned char syncQuality = 0; //0-31, 0=no useable signal, 15=medium quality, 31=perfect!
  83 volatile unsigned char syncCounter = 0;
  84 
  85 volatile unsigned char block = 0;
  86 volatile unsigned long bitstream = 0;
  87 volatile unsigned long bitstreamData = 0;
  88 volatile unsigned int block1 = 0;
  89 volatile unsigned int block2 = 0;
  90 volatile unsigned int block3 = 0;
  91 volatile unsigned int block4 = 0;
  92 
  93 //ISR is executed when there is a new rds bit to read
  94 ISR(INT0_vect) {
  95   cli();
  96   unsigned int syndrome = 0;
  97   
  98   //Copy global vars to local vars for performance
  99   unsigned long bitstreamLocal = bitstream;
 100   unsigned char blockLocal = block;
 101   
 102   //shift rds bit in on right side
 103   bitstreamLocal *= 2; 
 104   if (RDS_PORT & _BV(RDS_PIN))
 105     bitstreamLocal++;
 106     
 107   bitCounter++;
 108   
 109   //collect data for raw bitstream snapshots
 110   bitCounterSnapshot++;
 111   if (bitCounterSnapshot == 26) {
 112     bitstreamData = (bitstreamLocal & 0x3FFFFFF);
 113     bitCounterSnapshot = 0;
 114     
 115     event |= eventBitstreamSnapshot;
 116   }
 117   
 118   //when we have 26 bits or are not synchronized to the stream
 119   //check the CRC and maybe store a rds block
 120   if (bitCounter == 26 || !synchronized) {
 121   
 122     bitstreamLocal &= 0x3FFFFFF; //we only need 26 bits
 123   
 124     syndrome = (bitstreamLocal / 0x10000); //bits 16-31 (2^16)
 125   
 126     if (bitstreamLocal & _BV(0))
 127       syndrome ^= 0x031b;
 128     
 129     if (bitstreamLocal & _BV(1))
 130       syndrome ^= 0x038f;
 131     
 132     if (bitstreamLocal & _BV(2))
 133       syndrome ^= 0x02a7;
 134       
 135     if (bitstreamLocal & _BV(3))
 136       syndrome ^= 0x00f7;
 137     
 138     if (bitstreamLocal & _BV(4))
 139       syndrome ^= 0x01ee;
 140     
 141     if (bitstreamLocal & _BV(5))
 142       syndrome ^= 0x03dc;
 143     
 144     if (bitstreamLocal & _BV(6))
 145       syndrome ^= 0x0201;
 146     
 147     if (bitstreamLocal & _BV(7))
 148       syndrome ^= 0x01bb;
 149     
 150     if (bitstreamLocal & _BV(8))
 151       syndrome ^= 0x0376;
 152     
 153     if (bitstreamLocal & _BV(9))
 154       syndrome ^= 0x0355;
 155   
 156     if (bitstreamLocal & _BV(10))
 157       syndrome ^= 0x0313;
 158     
 159     if (bitstreamLocal & _BV(11))
 160       syndrome ^= 0x039f;
 161   
 162     if (bitstreamLocal & _BV(12))
 163       syndrome ^= 0x0287;
 164       
 165     if (bitstreamLocal & _BV(13))
 166       syndrome ^= 0x00b7;
 167     
 168     if (bitstreamLocal & _BV(14))
 169       syndrome ^= 0x016e;
 170 
 171     if (bitstreamLocal & 0b1000000000000000) // _BV(15) does not work!!!
 172       syndrome ^= 0x02dc;
 173 
 174     //Block A?
 175     if (blockLocal == 0 && syndrome == 0x03d8) {
 176       block1 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
 177       synchronized = 1;
 178       blockLocal++;
 179     } else 
 180     //Block B?
 181     if (blockLocal == 1 && syndrome == 0x03d4) {
 182       block2 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
 183       synchronized = 1;
 184       blockLocal++;
 185     } else  
 186     //Block C type A?
 187     if (blockLocal == 2 && !(block2 & _BV(11)) && syndrome == 0x025c) {
 188       block3 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
 189       synchronized = 1;
 190       blockLocal++;
 191     } else
 192     //Block C type B?
 193     if (blockLocal == 2 && (block2 & _BV(11)) && syndrome == 0x03cc) {
 194       block3 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
 195       synchronized = 1;
 196       blockLocal++;
 197     } else
 198     //Block D?
 199     if (blockLocal == 3 && syndrome == 0x0258) {
 200       block4 = bitstreamLocal / 0x400; //bits 10-25 (2^10)
 201       synchronized = 1;
 202       blockLocal = 0;
 203       //we have a complete group!
 204       event |= eventGroupComplete;
 205     } else {
 206       //sync lost..
 207       synchronized = 0;
 208       blockLocal = 0;
 209       event |= eventSyncLost;
 210     }
 211     
 212     bitCounter = 0; 
 213   }
 214   
 215   if (event & eventGroupComplete) {
 216     PORTC |= _BV(PC1);
 217     
 218     if (syncQuality < 31)
 219       syncQuality++;
 220     
 221   } else if (!synchronized) {
 222     PORTC &= ~_BV(PC1);
 223     
 224     syncCounter++;
 225     if (syncQuality > 0 && syncCounter == 26) {
 226       syncQuality--;
 227       syncCounter = 0;
 228     }
 229       
 230   }
 231   
 232   if (syncQuality >= 15)
 233     PORTC |= _BV(PC2);
 234   else
 235     PORTC &= ~_BV(PC2);
 236   
 237   //Store local vars into global vars to remember state
 238   bitstream = bitstreamLocal;
 239   block = blockLocal;
 240   sei();
 241 }
 242 
 243 //timer0 overflowed
 244 ISR(TIMER0_OVF_vect) {
 245   cli();
 246   timerOverflowCount++;
 247   if (timerOverflowCount > 4) {
 248     event |= eventTimerOverflow;
 249     timerOverflowCount = 0;
 250   }
 251   sei();
 252 }
 253 
 254 ISR(USART_RX_vect) {
 255   cli();
 256   usart0RxDByte = UDR0;
 257   event |= eventUsart0RxDInterrupt;
 258   sei();
 259 }
 260 
 261 void displayInfo(void) {
 262   printf_P(PSTR("INFO: 0x01, "));
 263   printf_P(PSTR(INFO));
 264   printf_P(PSTR("\r\n"));
 265 }
 266 
 267 int main(void) {
 268 
 269   wdt_reset(); //reset inmediately in case of a previous system reset
 270   //lets enable watchdog with 1 second timeout
 271   wdt_enable(WDTO_1S);
 272 
 273   unsigned int  programmeIdentificationCode = 0;
 274   unsigned char groupType = 0;
 275   unsigned char groupVersion = 0;
 276   unsigned char trafficProgrammeIdentificationCode = 0;
 277   unsigned char programmeTypeCode = 0;
 278   unsigned char trafficAnnouncementCode = 0;
 279   unsigned char musicSpeechSwitchScode = 0;
 280   unsigned char group0CodeBits = 0;
 281   unsigned char group0CodeBitsSteadyCount = 0;
 282   unsigned char programmeServiceName[8];
 283   unsigned char programmeServiceNameNew[8];
 284   unsigned char decoderIdentificationControlCode = 0;
 285   unsigned char decoderIdentificationControlCodeNew = 0;
 286   unsigned char alternativeFrequencyCodes[27];
 287   unsigned char syncMessage = 0;
 288   unsigned char displayRaw = 0;
 289   unsigned char displayBitstream = 0;
 290   unsigned char linkageActuator = 0;
 291   unsigned char extendedCountryCode = 0;
 292   unsigned char textSegmentAddress = 0;
 293   unsigned char textSegmentAddressPrevious = 0;
 294   unsigned char textVersion = 0;
 295   unsigned char textVersionPrevious = 0; 
 296   unsigned char radioText[64];
 297   unsigned char radioTextPrevious[64];
 298   unsigned char textSegmentAddress0Seen = 0;
 299   unsigned int  modifiedJulianDay = 0;
 300   unsigned int  utcYear = 0;
 301   unsigned char utcMonth = 0;
 302   unsigned char utcDay = 0;
 303   signed   char localHours = 0;
 304   unsigned char utcHours = 0;
 305   signed   char localMinutes = 0;
 306   unsigned char utcMinutes = 0;
 307   unsigned char utcMinutesPrevious = 0xFF;
 308   unsigned char localSign = 0;
 309   unsigned int  localTimeOffset = 0;
 310   
 311   //general purpose vars
 312   unsigned int  m;
 313   unsigned char h;
 314   unsigned char i;
 315   unsigned char j;
 316   
 317   //1.8mhz crystal
 318   //baudrate 115.2K
 319   //UBRR0 = 0;
 320   //baudrate 9600
 321   //UBRR0 = 11;
 322   
 323   //16mhz crystal
 324   //38.4k
 325   //UBRR0 = 25;
 326   
 327   //4.332Mhz crystal
 328   //baudrate 38K4
 329   UBRR0 = 6;
 330   
 331   //enable RxD interrupt, RxD, TxD
 332   UCSR0B |= _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
 333   
 334   //8 bit
 335   //UCSR0C |= _BV(UCSZ00) | _BV(UCSZ01);
 336   
 337   //UART is stdout and stdin;
 338   Uart = fdevopen(uartSend, uartRecv);
 339 
 340   //enable int0
 341   EIMSK = _BV(INT0);
 342   
 343   //INT0 raising edge
 344   EICRA |= _BV(ISC01) | _BV(ISC00);
 345   
 346   //PC0, PC1, PC2 are outputs;
 347   DDRC |= _BV(PC0) | _BV(PC1) | _BV(PC2);
 348 
 349   //timer0 prescaler clk/1024
 350   TCCR0B |= _BV(CS02) | _BV(CS00);
 351   //enable overflow interrupt
 352   TIMSK0 |= _BV(TOIE0);
 353   
 354   displayInfo();
 355   
 356   sei(); //enable interrupts;
 357   
 358   for (;;) {
 359     
 360     do {} while (!event);
 361     wdt_reset(); //reset watchdog, we are still alive!
 362     
 363     cli();
 364     if (event & eventUsart0RxDInterrupt) {
 365       event &= ~eventUsart0RxDInterrupt;
 366       sei();
 367       
 368       //collect the command
 369       
 370       //switch group display on (G) or off (g)
 371       if (usart0RxDByte == 'G')
 372         displayRaw = 0;
 373       else if (usart0RxDByte == 'g')
 374         displayRaw = 1;
 375         
 376       //reset decoder
 377       if (usart0RxDByte == 'r') {
 378         wdt_enable(WDTO_15MS);
 379         for(;;) {};
 380       }
 381         
 382       //switch group display on (B) or off (b)
 383       if (usart0RxDByte == 'B')
 384         displayBitstream = 0;
 385       else if (usart0RxDByte == 'b')
 386         displayBitstream = 1;
 387         
 388     } else {
 389       sei();
 390     }
 391     
 392     //we have got 26 bits raw rds data
 393     cli();
 394     if (event & eventBitstreamSnapshot) {
 395       event &= ~eventBitstreamSnapshot;
 396       sei();
 397       
 398       if (displayBitstream) {
 399         printf_P(PSTR("B: 0x%07lX\r\n"), bitstreamData);
 400       }
 401     } else {
 402       sei();
 403     }
 404     
 405     cli();
 406     if (event & eventTimerOverflow) {
 407       event &= ~eventTimerOverflow;
 408       sei();
 409       
 410       /* no rds signal message */
 411       if (syncQuality == 0 && syncMessage < 12) {
 412         syncMessage++;
 413         if (syncMessage == 12) {
 414           printf_P(PSTR("INFO: 0x02, No RDS signal.\r\n"));
 415           programmeIdentificationCode = 0;
 416         }
 417       }
 418           
 419       if (syncQuality > 0)
 420           syncMessage = 0;
 421           
 422       if (PORTC & _BV(PC0))
 423         PORTC &= ~_BV(PC0); //heartbeat led off
 424       else
 425         PORTC |= _BV(PC0); //heartbeat led on
 426       
 427     } else {
 428       sei();
 429     }
 430     
 431     //reset vars when sync lost. Warning, sync lost happens 26 times as many as groupcomlete, do not do anything lenghty here
 432     cli();
 433     if (event & eventSyncLost) {
 434       event &= ~eventSyncLost;
 435       sei();
 436       group0CodeBitsSteadyCount = 5;
 437     } else {
 438       sei();
 439     }
 440     
 441     cli();
 442     if (event & eventGroupComplete) {
 443         event &= ~eventGroupComplete;
 444         sei();
 445         
 446       //Group type code
 447       groupType = block2 / 0x1000; //bits 12-15 (2^12)
 448       
 449       //Group version code
 450       if (block2 & _BV(11))
 451         groupVersion = 'B';
 452       else
 453         groupVersion = 'A';
 454       
 455       if (displayRaw)
 456         printf_P(PSTR("GROUP%02u%c: 0x%04X 0x%04X 0x%04X 0x%04X\r\n"), groupType, groupVersion, block1, block2, block3, block4);
 457       
 458       //PI Codes of block 3 B-version groups are not decoded.
 459       
 460       //Programme Identification code
 461       if (programmeIdentificationCode != block1) {
 462         displayInfo();
 463         programmeIdentificationCode = block1;
 464         printf_P(PSTR("PI: 0x%04X, Detected new station.\r\n"), programmeIdentificationCode);
 465         
 466         /* reset variables because PI code changed */
 467         trafficProgrammeIdentificationCode = 0xFF;
 468         programmeTypeCode = 0xFF;
 469         trafficAnnouncementCode = 0xFF;
 470         musicSpeechSwitchScode = 0xFF;
 471   
 472         group0CodeBitsSteadyCount = 0;
 473         for(i = 0; i < sizeof(programmeServiceName); i++)
 474           programmeServiceName[i] = 0xFF;
 475           
 476         decoderIdentificationControlCode = 0xFF;
 477         
 478         for(i = 0; i < sizeof(alternativeFrequencyCodes); i++)
 479           alternativeFrequencyCodes[i] = 0;
 480           
 481         linkageActuator = 0xFF;
 482         
 483         extendedCountryCode = 0;
 484         
 485         for(i = 0; i < sizeof(radioText); i++) {
 486           radioText[i] = 0;
 487           radioTextPrevious[i] = 0;
 488         }
 489         
 490         textSegmentAddress0Seen = 0;
 491           
 492         textVersionPrevious = 0;
 493         textSegmentAddressPrevious = 0;
 494         
 495         utcMinutesPrevious = 0xFF;
 496         
 497       }
 498   
 499       //Programme Type code
 500       if (programmeTypeCode != ((block2 / 0x20) & 0x1F)) {
 501         programmeTypeCode = ((block2 / 0x20) & 0x1F); //bits 5-9 (2^5)
 502         printf_P(PSTR("PTY: 0x%02X, "), programmeTypeCode);
 503         switch(programmeTypeCode) {
 504           case 0:
 505             printf_P(PSTR("None."));
 506             break;
 507           case 1:
 508             printf_P(PSTR("News."));
 509             break;
 510           case 2:
 511             printf_P(PSTR("Current Affairs."));
 512             break;
 513           case 3:
 514             printf_P(PSTR("Information."));
 515             break;
 516           case 4:
 517             printf_P(PSTR("Sport."));
 518             break;
 519           case 5:
 520             printf_P(PSTR("Education."));
 521             break;
 522           case 6:
 523             printf_P(PSTR("Drama."));
 524             break;
 525           case 7:
 526             printf_P(PSTR("Cultures."));
 527             break;
 528           case 8:
 529             printf_P(PSTR("Science."));
 530             break;
 531           case 9:
 532             printf_P(PSTR("Varied Speech."));
 533             break;
 534           case 10:
 535             printf_P(PSTR("Pop Music."));
 536             break;
 537           case 11:
 538             printf_P(PSTR("Rock Music."));
 539             break;
 540           case 12:
 541             printf_P(PSTR("Easy Listening."));
 542             break;
 543           case 13:
 544             printf_P(PSTR("Light Classics."));
 545             break;
 546           case 14:
 547             printf_P(PSTR("Serious Classics."));
 548             break;
 549           case 15:
 550             printf_P(PSTR("Other Music."));
 551             break;
 552           case 16:
 553             printf_P(PSTR("Weather."));
 554             break;
 555           case 17:
 556             printf_P(PSTR("Finance."));
 557             break;
 558           case 18:
 559             printf_P(PSTR("Children."));
 560             break;
 561           case 19:
 562             printf_P(PSTR("Social Affairs."));
 563             break;
 564           case 20:
 565             printf_P(PSTR("Religion."));
 566             break;
 567           case 21:
 568             printf_P(PSTR("Phone In."));
 569             break;
 570           case 22:
 571             printf_P(PSTR("Travel & Touring."));
 572             break;
 573           case 23:
 574             printf_P(PSTR("Leisure & Hobby."));
 575             break;
 576           case 24:
 577             printf_P(PSTR("Jazz Music."));
 578             break;
 579           case 25:
 580             printf_P(PSTR("Country Music."));
 581             break;
 582           case 26:
 583             printf_P(PSTR("National Music."));
 584             break;
 585           case 27:
 586             printf_P(PSTR("Oldies Music."));
 587             break;
 588           case 28:
 589             printf_P(PSTR("Folk Music."));
 590             break;
 591           case 29:
 592             printf_P(PSTR("Documentary."));
 593             break;
 594           case 30:
 595             printf_P(PSTR("Alarm Test."));
 596             break;
 597           case 31:
 598             printf_P(PSTR("Alarm - Alarm !"));
 599             break;
 600           default:
 601             printf_P(PSTR("Unknown."));
 602             break;
 603         }
 604         printf_P(PSTR("\r\n"));
 605       }
 606   
 607       //Type 0 groups: Basic tuning and switching information
 608       if (groupType == 0) {
 609       
 610         //Traffic Programme Identification code
 611         //Traffic announcement code
 612         if (trafficAnnouncementCode != ((block2 / 0x10) & 0x01) ||
 613             trafficProgrammeIdentificationCode != (block2 & _BV(10)) / 0x400) {
 614           
 615           trafficAnnouncementCode = (block2 / 0x10) & 0x01; //bit 4 (2^4)
 616           trafficProgrammeIdentificationCode = (block2 & _BV(10)) / 0x400; //bit 10
 617           
 618           printf_P(PSTR("TP&TA: 0x%02X 0x%02X, "), trafficProgrammeIdentificationCode, trafficAnnouncementCode);
 619 
 620           if (trafficProgrammeIdentificationCode == 0) {
 621           
 622             if (trafficAnnouncementCode == 0) {
 623               printf_P(PSTR("No traffic announcements available."));
 624             } else {
 625               printf_P(PSTR("Traffic announcements available via EON on another station."));
 626             }
 627           
 628           } else {
 629           
 630             if (trafficAnnouncementCode == 0) {
 631               printf_P(PSTR("Traffic announcements available on this station and maybe via EON on another station."));
 632             } else {
 633               printf_P(PSTR("Traffic announcement in progress."));
 634             }
 635             
 636           }
 637           
 638           printf_P(PSTR("\r\n"));
 639           
 640         }
 641       
 642         //Music Speech switch code
 643         if (musicSpeechSwitchScode != ((block2 / 0x08) & 0x01)) {
 644           musicSpeechSwitchScode = (block2 / 0x08) & 0x01;  //bit 3 (2^3)
 645           printf_P(PSTR("MS: 0x%02X, "), musicSpeechSwitchScode);
 646 
 647           if (musicSpeechSwitchScode) 
 648             printf_P(PSTR("Music is being broadcasted or station does not use MS flag."));
 649           else
 650             printf_P(PSTR("Speech is being broadcasted."));
 651           printf_P(PSTR("\r\n"));
 652         }
 653         
 654         //Decode program service name and decoder identification control code
 655         group0CodeBits = block2 & 0x03; //0, 1, 2, 3;
 656         
 657         
 658         //TODO: improve decoderIdentificationControlCode detection, decouple from PS name
 659         //Decoder-identification control code-bit is bit 3 in block2
 660         if (group0CodeBits == 0) {
 661           if (block2 & 0x04)
 662             decoderIdentificationControlCodeNew |= _BV(3);
 663           else 
 664             decoderIdentificationControlCodeNew &= ~_BV(3);
 665         }
 666         if (group0CodeBits == 1) {
 667           if (block2 & 0x04)
 668             decoderIdentificationControlCodeNew |= _BV(2);
 669           else 
 670             decoderIdentificationControlCodeNew &= ~_BV(2);
 671         }
 672         if (group0CodeBits == 2) {
 673           if (block2 & 0x04)
 674             decoderIdentificationControlCodeNew |= _BV(1);
 675           else 
 676             decoderIdentificationControlCodeNew &= ~_BV(1);
 677         }
 678         if (group0CodeBits == 3) {
 679           if (block2 & 0x04)
 680             decoderIdentificationControlCodeNew |= _BV(0);
 681           else 
 682             decoderIdentificationControlCodeNew &= ~_BV(0);
 683         }
 684   
 685         //fill in information
 686         i = group0CodeBits * 2;
 687         programmeServiceNameNew[i] = block4 / 0xFF; //bits 8-16 (2^8)
 688         programmeServiceNameNew[i + 1] = block4; //bit 0-8
 689         
 690         if (programmeServiceNameNew[i] != programmeServiceName[i] ||
 691             programmeServiceNameNew[i + 1] != programmeServiceName[i + 1]) {
 692           //detected change, reset counter if not already counting
 693           if (group0CodeBitsSteadyCount > 4)
 694                 group0CodeBitsSteadyCount = 0;
 695         }
 696         
 697         //increase counter only when there are less then 4 received words
 698         if (group0CodeBitsSteadyCount < 4)
 699           group0CodeBitsSteadyCount++;
 700         
 701         programmeServiceName[i] = programmeServiceNameNew[i];
 702         programmeServiceName[i + 1] = programmeServiceNameNew[i + 1];
 703         
 704         //when we detected 4 new PS words then display it
 705         if (group0CodeBitsSteadyCount == 4) {
 706           printf_P(PSTR("PS: "));
 707           for(i = 0; i < sizeof(programmeServiceName); i++) {
 708             printf_P(PSTR("%c"), programmeServiceName[i]);
 709           }
 710           printf_P(PSTR("\r\n"));
 711           //prevent redisplay
 712           group0CodeBitsSteadyCount++;
 713           
 714           if (decoderIdentificationControlCode != decoderIdentificationControlCodeNew) {
 715             decoderIdentificationControlCode = decoderIdentificationControlCodeNew;
 716             printf_P(PSTR("DI: 0x%02X"), decoderIdentificationControlCode);
 717             
 718             if (decoderIdentificationControlCode & 0b0001)
 719               printf_P(PSTR(", Stereo"));
 720             else
 721               printf_P(PSTR(", Mono"));
 722               
 723             if (decoderIdentificationControlCode & 0b0010)
 724               printf_P(PSTR(", Artificial Head"));
 725               
 726             if (decoderIdentificationControlCode & 0b0100)
 727               printf_P(PSTR(", Compressed"));
 728               
 729             if (decoderIdentificationControlCode & 0b1000)
 730               printf_P(PSTR(", Static PTY"));
 731             else
 732               printf_P(PSTR(", Dynamic PTY"));
 733               
 734             printf_P(PSTR(".\r\n"));
 735           }
 736         }
 737         
 738   
 739         if (groupVersion == 'A') {
 740         
 741           //Alternative frequency codes
 742           for (h = 0; h < 2; h++) {
 743             if (h == 0)
 744               j = block3; //first AF is in bits 0-7 of block3
 745             else
 746               j = block3 / 256; //second bits 8-15
 747               
 748             //only frequencies we want, no control codes
 749             if (j >= 1 && j <= 204) {
 750               for(i = 0; i < sizeof(alternativeFrequencyCodes); i++) {
 751                 if (alternativeFrequencyCodes[i] == j) {
 752                   break;
 753                 } 
 754                 if (alternativeFrequencyCodes[i] == 0) {
 755                   alternativeFrequencyCodes[i] = j;
 756                   printf_P(PSTR("AF: 0x%02X, "), alternativeFrequencyCodes[i]);
 757                   
 758                   m = 875 + j;
 759                   printf_P(PSTR("%u.%uMHz.\r\n"), m / 10, m % 10);
 760                   break;
 761                 }
 762               }
 763             }
 764             
 765             if (j == 224 && alternativeFrequencyCodes[25] != j) {
 766               alternativeFrequencyCodes[25] = 224;
 767               printf_P(PSTR("AF: 0x%02X, This station has no alternate frequenties.\r\n"), j);
 768             }
 769           }
 770           
 771           //TODO: LF/MF untested because lack of LM/MF station
 772           //Station transmits on LF/MF
 773           if (block3 == 250 && alternativeFrequencyCodes[26] != block3) {
 774             alternativeFrequencyCodes[26] = block3;
 775             j = block3 / 256;
 776             
 777             printf_P(PSTR("AF: 0x%02X 0x%02X, "), block3, j);
 778             
 779             //LF 153kHz-279kHz in 9 KHz steps
 780             if (j >= 1 && j <= 15) {
 781               m = 144 + (j * 9);
 782               printf_P(PSTR("%uKHz.\r\n"), m);
 783             } else
 784             //MF 531KHz-1602kHz in 9 KHz steps
 785             if (j >= 16 && j <= 135) {
 786               m = 387 + (j * 9);
 787               printf_P(PSTR("%uKHz.\r\n"), m);
 788             }
 789           }
 790         }
 791         //version B contains PI code in block3
 792   
 793       } else
 794       //Type 1 groups: Programme Item Number and slow labelling codes
 795       if (groupType == 1) {
 796       
 797         if (groupVersion == 'A') {
 798           //TODO: 5 bit Radio Paging Codes, bits 0-4 block2
 799           
 800           //TODO: Add textual description of LA
 801           //Linkage Actuator
 802           if (linkageActuator != (block3 & _BV(15))) {
 803             linkageActuator = (block3 & _BV(15));
 804             printf_P(PSTR("LA: 0x%02X\r\n"), linkageActuator);
 805           }
 806           
 807           //store variant code, bits 13-15
 808           i = (block3 / 0x2000) & 0x07;
 809           
 810           //TODO: Paging
 811           if (i == 0) {
 812             
 813             //TODO: Add textual description of ECC code
 814             //Extended Country Code, bits 0-7 block3
 815             if (extendedCountryCode != (block3 & 0xFF)) {
 816               extendedCountryCode = (block3 & 0xFF);
 817               printf_P(PSTR("ECC: 0x%02X\r\n"), extendedCountryCode);
 818             }
 819             
 820           
 821           } else 
 822           //TODO: TMC identification
 823           if (i == 1) {
 824           
 825           } else
 826           //TODO: Paging identification
 827           if (i == 2) {
 828           
 829           } else
 830           //TODO: Language codes
 831           if (i == 3) {
 832           
 833           } else
 834           //TODO: not assigned
 835           if (i == 4) {
 836           
 837           } else
 838           //TODO: not assigned
 839           if (i == 5) {
 840           
 841           } else
 842           //TODO: For use by broadcasters
 843           if (i == 6) {
 844           
 845           } else
 846           //TODO: Identification of EWS channel
 847           if (i == 7) {
 848           
 849           }
 850         }
 851         
 852         //TODO: Programme Item Number, block 4
 853       
 854       } else 
 855       //Type 2 groups: RadioText
 856       if (groupType == 2) {
 857       
 858         //text version A or B, bit 5 block 2
 859         if (block2 & 0x10) 
 860           textVersion = 'B';
 861         else
 862           textVersion = 'A';
 863         
 864         //block2 bit 0-3
 865         textSegmentAddress = (block2 & 0x0F);
 866         
 867         //clean radioText when version changes
 868         if (textVersionPrevious != 0 &&
 869             textVersionPrevious != textVersion) {
 870             
 871           for(i = 0; i < sizeof(radioText); i++) {
 872             radioText[i] = 0;
 873            }
 874            
 875           textSegmentAddressPrevious = 0;
 876           textSegmentAddress0Seen = 0;
 877         }
 878         
 879         //detected new start of text segment, normally address 0x00
 880         if (textSegmentAddressPrevious > textSegmentAddress) {
 881             
 882           if (groupVersion == 'A')
 883             h = 64;
 884           else
 885             h = 32;
 886           
 887           //detect new radioText
 888           j = 0;
 889           for (i = 0; i < h; i++) {
 890             if (radioText[i] != 0 && radioText[i] != ' ') {
 891               if (radioText[i] != radioTextPrevious[i]) {
 892                 j = 1;
 893                 break;
 894               }
 895             }
 896           }
 897           
 898           //only print when we have received address 0 once.
 899           if (textSegmentAddress0Seen == 0)
 900             j = 0;
 901            
 902           if (j) {
 903             printf_P(PSTR("RT%c: "), textVersion);
 904 
 905             for (i = 0; i < h; i++) {
 906             
 907               if (radioText[i] == 0) 
 908                 break;
 909               else if (!(radioText[i] == '\r' || radioText[i] == '\n'))
 910                 printf_P(PSTR("%c"), radioText[i]);
 911 
 912                 
 913               radioTextPrevious[i] = radioText[i];
 914             }
 915             printf_P(PSTR("\r\n"));
 916           }
 917           
 918           
 919         }
 920         
 921         //64 bit messages in block 3 & 4
 922         if (groupVersion == 'A') {
 923           
 924           radioText[(textSegmentAddress * 4)] = block3 / 256;
 925           radioText[(textSegmentAddress * 4) + 1] = block3;
 926           radioText[(textSegmentAddress * 4) + 2] = block4 / 256;
 927           radioText[(textSegmentAddress * 4) + 3] = block4;
 928           
 929           //fill bytes smaller then textSegmentAddress with spaces when they are '0'
 930           if (textSegmentAddress > 0) {
 931             for (i = 0; i < (textSegmentAddress - 1) * 4; i++) {
 932               if (radioText[i] == 0)
 933                 radioText[i] = ' ';
 934             }
 935           }
 936           
 937         }
 938         //TODO: 32 bit messages not tested because of lack station transmitting it.
 939         //32 bit messages in block 4
 940         else {
 941           radioText[(textSegmentAddress * 2)] = block4 / 256;
 942           radioText[(textSegmentAddress * 2) + 1] = block4;
 943           
 944           //fill bytes smaller then textSegmentAddress with spaces when they are '0'
 945           if (textSegmentAddress > 0) {
 946             for (i = 0; i < (textSegmentAddress - 1) * 2; i++) {
 947               if (radioText[i] == 0)
 948                 radioText[i] = ' ';
 949             }
 950           }
 951           
 952         }
 953         
 954         if (textSegmentAddress == 0)
 955           textSegmentAddress0Seen = 1;
 956         
 957         
 958         textVersionPrevious = textVersion;
 959         textSegmentAddressPrevious = textSegmentAddress;
 960         
 961       } else
 962       //Type 3A groups: Application identification for Open data
 963       if (groupType == 3 && groupVersion == 'A') {
 964       
 965       } else
 966       //Type 3B groups: Open Data Application
 967       if (groupType == 3 && groupVersion == 'B') {
 968       
 969       } else
 970       //Type 4A groups : Clock-time and date
 971       if (groupType == 4 && groupVersion == 'A') {
 972       
 973         //bits 0-5 are in block4 as bits 6-11
 974         utcMinutes = (block4  / 64) & 0x3F;
 975       
 976         if (utcMinutesPrevious != utcMinutes) {
 977         
 978           utcMinutesPrevious = utcMinutes;
 979         
 980           //bits 0-14 are in block3 as bits 1-15
 981           //bits 15-16 are in block2 as bits 0-1
 982           modifiedJulianDay = (block3 / 2) + (block2 & 0x03) * 32768;
 983           
 984           //bits 0-3 are in block4 as bits 12-15
 985           //bit 4 is in block3 as bit 1
 986           utcHours = (block4 / 4096) + (block3 & 0x01) * 16;
 987           
 988           //local time offset are bits 0-4 in block 4
 989           localTimeOffset = block4 & 0x1F;
 990           //sign is in bit 5 of block4, 0=+ 1=-
 991           if (block4 & 0x20) 
 992             localSign = '-';
 993           else
 994             localSign = '+';
 995           
 996           //multiply by 30 so that we have offset in minutes (offset is in multiples of .5 hours)
 997           localTimeOffset *= 30;
 998   
 999           printf_P(PSTR("CT: 0x%01X%04X%04X, "), (block2 & 0x03), block3, block4);
1000           
1001           //Modified Julian date to year-month-day conversion
1002           utcYear = floor((modifiedJulianDay - 15078.2) / 365.25);
1003           utcMonth = floor((modifiedJulianDay - 14956.1 - floor(utcYear * 365.25)) / 30.6001);
1004           utcDay = modifiedJulianDay - 14956 - floor(utcYear * 365.25) - floor(utcMonth * 30.6001);
1005         
1006           if (utcMonth == 14 || utcMonth == 15)
1007             i = 1; 
1008           else 
1009             i = 0;
1010         
1011           utcYear = utcYear + i + 1900;
1012           utcMonth = utcMonth - 1 - (i * 12);
1013   
1014           printf_P(PSTR("UTC %04u-%02u-%02u (MJD %u) %02u:%02u:00 %c%02u:%02u, "),
1015                    utcYear, utcMonth, utcDay,
1016                    modifiedJulianDay,
1017                    utcHours, utcMinutes, localSign,
1018                    localTimeOffset / 60, localTimeOffset % 60);
1019           
1020           //TODO: half hour timezones and negative timezones not tested because lack of station transmitting it.
1021           //lets calulate local time
1022           if (localSign == '-') {
1023             localHours = utcHours - (localTimeOffset / 60);
1024             localMinutes = utcMinutes - (localTimeOffset % 60);
1025           } else {
1026             localHours = utcHours + (localTimeOffset / 60);
1027             localMinutes = utcMinutes + (localTimeOffset % 60);
1028           }
1029           
1030           if (localMinutes < 0) {
1031             localMinutes += 60;
1032             localHours--;
1033           }
1034             
1035           if (localMinutes > 59) {
1036             localMinutes -= 60;
1037             localHours++;
1038           }
1039           
1040           if (localHours < 0)
1041             localHours += 24;
1042   
1043           if (localHours > 23)
1044             localHours -= 24;
1045             
1046           printf_P(PSTR("TIME %02u:%02u:00\r\n"), localHours, localMinutes);
1047         }
1048 
1049       } else
1050       //Type 4B groups: Open data application
1051       if (groupType == 4 && groupVersion == 'B') {
1052         
1053       } else
1054       //Type 5 groups: Transparent data channels or ODA
1055       if (groupType == 5) {
1056       
1057       } else
1058       //Type 6 groups: In-house applications or ODA
1059       if (groupType == 6) {
1060       
1061       } else 
1062       //Type 7A groups: Radio Paging or ODA
1063       if (groupType == 7 && groupVersion == 'A') {
1064       
1065       } else 
1066       //Type 7B groups: Open data application
1067       if (groupType == 7 && groupVersion == 'B') {
1068       
1069       } else 
1070       //Type 8 groups: Traffic Message Channel or ODA
1071       if (groupType == 8) {
1072       
1073       } else 
1074       //Type 9 groups: Emergency warning systems or ODA
1075       if (groupType == 9) {
1076       
1077       } else 
1078       //Type 10A groups: Programme Type Name
1079       if (groupType == 10 && groupVersion == 'A') {
1080       
1081       } else
1082       //Type 10B groups: Open data
1083       if (groupType == 10 && groupVersion == 'A') {
1084       
1085       } else
1086       //Type 11 groups: Open Data Application
1087       if (groupType == 11) {
1088       
1089       } else 
1090       //Type 12 groups: Open Data Application
1091       if (groupType == 12) {
1092       
1093       } else 
1094       //Type 13A groups: Enhanced Radio Paging or ODA
1095       if (groupType == 13 && groupVersion == 'A') {
1096       
1097       } else
1098       //Type 13B groups: Open Data Application
1099       if (groupType == 13 && groupVersion == 'B') {
1100       
1101       } else
1102       //Type 14 groups: Enhanced Other Networks information
1103       if (groupType == 14) {
1104       
1105       } else
1106       //Type 15A groups: 'currently unavailable'
1107       if (groupType == 15 && groupVersion == 'A') {
1108       
1109       } else
1110       //Type 15B groups: Fast basic tuning and switching information
1111       if (groupType == 15 && groupVersion == 'B') {
1112       
1113       }
1114     } else {
1115       sei();
1116     }
1117     
1118     
1119   }
1120 }

 

 

posted @ 2012-06-12 17:12  莫回头  阅读(1151)  评论(0编辑  收藏  举报