Si4735 Library with RDS/RBDS control functions
Embed:
(wiki syntax)
Show/hide line numbers
Si4735.cpp
00001 /* mbed Si4735 Library 00002 * Brett Wilson and Brett Berry 00003 * Georgia Tech ECE 4180 00004 * Note: this code has only been tested for FM. 00005 * Ported from ... 00006 00007 * Arduino Si4735 Library 00008 * Written by Ryan Owens for SparkFun Electronics 00009 * 5/17/11 00010 * 00011 * This library is for use with the SparkFun Si4735 Shield 00012 * Released under the 'Buy Me a Beer' license 00013 * (If we ever meet, you buy me a beer) 00014 * 00015 * See the header file for better function documentation. 00016 * 00017 * See the example sketches to learn how to use the library in your code. 00018 */ 00019 00020 #include "Si4735.h" 00021 #include "mbed.h" 00022 00023 //This is just a constructor. 00024 Si4735::Si4735(PinName sda, PinName scl, PinName RST_, Serial *pc) : 00025 _RST_(RST_) 00026 { 00027 i2c_ = new I2C(sda, scl); 00028 i2c_->frequency(100000); 00029 this->pc = pc; 00030 00031 strcpy(pty_prev, " "); 00032 _locale = NA; 00033 _ab = 0; 00034 _year = 0; 00035 _month = 0; 00036 _day = 0; 00037 _hour = 0; 00038 _minute = 0; 00039 _newRadioText = 0; 00040 clearRDS(); 00041 00042 } 00043 00044 00045 void Si4735::begin(char mode) 00046 { 00047 _mode = mode; 00048 //Set the initial volume level. 00049 _currentVolume=63; 00050 00051 // Reset the Si4735 00052 _RST_ = 0; 00053 wait(.2); 00054 _RST_ = 1; 00055 wait(.2); 00056 00057 00058 //Send the POWER_UP command 00059 switch(_mode) { 00060 case FM: 00061 sprintf(command, "%c%c%c", 0x01, 0x10, 0x05); 00062 break; 00063 case AM: 00064 case SW: 00065 case LW: 00066 sprintf(command, "%c%c%c", 0x01, 0x11, 0x05); 00067 break; 00068 default: 00069 return; 00070 } 00071 sendCommand(command, 3); 00072 wait(.2); 00073 00074 // Set the RCLK to 32768Hz 00075 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x02, 0x01, 0x80, 0x00); 00076 sendCommand(command, 6); 00077 wait(.2); 00078 00079 // Set default frequency to 99.7 MHz FM 00080 sprintf(command, "%c%c%c%c", 0x20, 0x00, 0x26, 0xF2); 00081 sendCommand(command, 4); 00082 wait(.2); 00083 00084 //Set the volume to the current value. 00085 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x00, 0x00, _currentVolume); 00086 sendCommand(command, 6); 00087 wait(.2); 00088 00089 //Disable Mute 00090 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x01, 0x00, 0x00); 00091 sendCommand(command, 6); 00092 wait(.2); 00093 00094 setProperty(0x1502, 0xAA01); 00095 00096 //Set the seek band for the desired mode (AM and FM can use default values) 00097 switch(_mode) { 00098 case SW: 00099 //Set the lower band limit for Short Wave Radio to 2300 kHz 00100 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x34, 0x00, 0x08, 0xFC); 00101 sendCommand(command, 6); 00102 wait(.001); 00103 //Set the upper band limit for Short Wave Radio to 23000kHz 00104 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x34, 0x01, 0x59, 0xD8); 00105 sendCommand(command, 6); 00106 wait(.001); 00107 break; 00108 case LW: 00109 //Set the lower band limit for Long Wave Radio to 152 kHz 00110 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x34, 0x00, 0x00, 0x99); 00111 sendCommand(command, 6); 00112 wait(.001); 00113 //Set the upper band limit for Long Wave Radio to 279 kHz 00114 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x34, 0x01, 0x01, 0x17); 00115 sendCommand(command, 6); 00116 wait(.001); 00117 break; 00118 default: 00119 break; 00120 } 00121 00122 } 00123 00124 /* 00125 * Description: Tunes the Si4735 to a frequency 00126 * 00127 * Params: int frequency - The desired frequency in kHz 00128 * 00129 * Returns: True if tune was successful 00130 * False if tune was unsuccessful 00131 */ 00132 bool Si4735::tuneFrequency(int frequency) 00133 { 00134 //Split the desired frequency into two character for use in the 00135 //set frequency command. 00136 char highByte = frequency >> 8; 00137 char lowByte = frequency & 0x00FF; 00138 00139 //Depending on the current mode, set the new frequency. 00140 switch(_mode) { 00141 case FM: 00142 sprintf(command, "%c%c%c%c", 0x20, 0x00, highByte, lowByte); 00143 break; 00144 case AM: 00145 case SW: 00146 case LW: 00147 sprintf(command, "%c%c%c%c", 0x40, 0x00, highByte, lowByte); 00148 break; 00149 default: 00150 break; 00151 } 00152 sendCommand(command, 4); 00153 wait(.1); 00154 clearRDS(); 00155 return true; 00156 } 00157 00158 //This function does not work unless you bypass the buffer chip! 00159 int Si4735::getFrequency(void) 00160 { 00161 char data[8]; 00162 int freq = 0; 00163 // FM only 00164 i2c_->start(); 00165 i2c_->write(address_write); 00166 i2c_->write(0x22); 00167 i2c_->write(0x02); 00168 i2c_->stop(); 00169 i2c_->start(); 00170 i2c_->write(address_read); 00171 for (int i=0; i<8; i++) 00172 data[i] = i2c_->read(1); 00173 //i2c_->read(address_read, data, 8, false); 00174 i2c_->stop(); 00175 freq = data[2]; 00176 freq = (freq << 8) | data[3]; 00177 return freq; 00178 } 00179 00180 bool Si4735::seekUp(void) 00181 { 00182 //Use the current mode selection to seek up. 00183 switch(_mode) { 00184 case FM: 00185 sprintf(command, "%c%c", 0x21, 0x0C); 00186 sendCommand(command, 2); 00187 break; 00188 case AM: 00189 case SW: 00190 case LW: 00191 sprintf(command, "%c%c%c%c%c%c", 0x41, 0x0C, 0x00, 0x00, 0x00, 0x00); 00192 sendCommand(command, 6); 00193 break; 00194 default: 00195 break; 00196 } 00197 wait(.001); 00198 clearRDS(); 00199 return true; 00200 } 00201 00202 bool Si4735::seekDown(void) 00203 { 00204 //Use the current mode selection to seek down. 00205 switch(_mode) { 00206 case FM: 00207 sprintf(command, "%c%c", 0x21, 0x04); 00208 sendCommand(command, 2); 00209 break; 00210 case AM: 00211 case SW: 00212 case LW: 00213 sprintf(command, "%c%c%c%c%c%c", 0x41, 0x04, 0x00, 0x00, 0x00, 0x00); 00214 sendCommand(command, 6); 00215 break; 00216 default: 00217 break; 00218 } 00219 wait(.001); 00220 clearRDS(); 00221 return true; 00222 } 00223 00224 void Si4735::volumeUp(void) 00225 { 00226 //If we're not at the maximum volume yet, increase the volume 00227 if(_currentVolume < 63) { 00228 _currentVolume+=1; 00229 //Set the volume to the current value. 00230 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x00, 0x00, _currentVolume); 00231 sendCommand(command, 6); 00232 wait(.01); 00233 } 00234 } 00235 00236 void Si4735::volumeDown(void) 00237 { 00238 //If we're not at the maximum volume yet, increase the volume 00239 if(_currentVolume > 0) { 00240 _currentVolume-=1; 00241 //Set the volume to the current value. 00242 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x00, 0x00, _currentVolume); 00243 sendCommand(command, 6); 00244 wait(.01); 00245 } 00246 } 00247 00248 void Si4735::mute(void) 00249 { 00250 //Disable Mute 00251 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x01, 0x00, 0x03); 00252 sendCommand(command, 6); 00253 wait(.001); 00254 } 00255 00256 void Si4735::unmute(void) 00257 { 00258 //Disable Mute 00259 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, 0x40, 0x01, 0x00, 0x00); 00260 sendCommand(command, 6); 00261 wait(.001); 00262 } 00263 00264 void Si4735::end(void) 00265 { 00266 sprintf(command, "%c", 0x11); 00267 sendCommand(command, 1); 00268 wait(.001); 00269 } 00270 00271 00272 void Si4735::setProperty(int address, int value) 00273 { 00274 sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, (address>>8)&255, address&255, (value>>8)&255, value&255); 00275 sendCommand(command, 6); 00276 wait(0.01); 00277 } 00278 00279 bool Si4735::readRDS() 00280 { 00281 char R[16]; 00282 sprintf(command, "%c%c", 0x24, 0x00); 00283 sendCommand(command, 2); 00284 i2c_->start(); 00285 i2c_->write(address_read); 00286 for (int i=0; i<16; i++) 00287 R[i] = i2c_->read(1); 00288 i2c_->stop(); 00289 00290 bool ps_rdy = false; 00291 char pty = ((R[6]&3) << 3) | ((R[7] >> 5)&7); 00292 ptystr(pty); 00293 char type = (R[6]>>4) & 15; 00294 bool version = bitRead(R[6], 4); 00295 bool tp = bitRead(R[5], 4); 00296 int pi; 00297 if (version == 0) { 00298 pi = R[4]; 00299 pi = (pi << 8) | R[5]; 00300 } else { 00301 pi = R[8]; 00302 pi = (pi << 8) | R[9]; 00303 } 00304 if(pi>=21672) { 00305 _csign[0]='W'; 00306 pi-=21672; 00307 } else if(pi<21672 && pi>=4096) { 00308 _csign[0]='K'; 00309 pi-=4096; 00310 } else { 00311 pi=-1; 00312 } 00313 if(pi>=0) { 00314 _csign[1]=char(pi/676+65);//char(pi/676); 00315 _csign[2]=char((pi - 676*int(pi/676))/26+65);//char((pi-676*(_csign[1]))/26+65); 00316 _csign[3]=char(((pi - 676*int(pi/676))%26)+65);//char((pi-676*(_csign[1]))%26+65); 00317 //_csign[1]+=65; 00318 _csign[4]='\0'; 00319 } else { 00320 _csign[0]='U'; 00321 _csign[1]='N'; 00322 _csign[2]='K'; 00323 _csign[3]='N'; 00324 _csign[4]='\0'; 00325 } 00326 if (type == 0) { 00327 bool ta = bitRead(R[7], 4); 00328 bool ms = bitRead(R[7], 3); 00329 char addr = R[7] & 3; 00330 bool diInfo = bitRead(R[7], 2); 00331 00332 // Groups 0A & 0B: to extract PS segment we need blocks 1 and 3 00333 if (addr >= 0 && addr<= 3) { 00334 if (R[10] != '\0') 00335 _ps[addr*2] = R[10]; 00336 if (R[11] != '\0') 00337 _ps[addr*2+1] = R[11]; 00338 ps_rdy=(addr==3); 00339 } 00340 printable_str(_ps, 8); 00341 } 00342 00343 else if (type == 2) { 00344 int addressRT = R[7] & 0xf; // Get rightmost 4 bits 00345 bool ab = bitRead(R[7], 4); 00346 bool cr = 0; //indicates that a carriage return was received 00347 char len = 64; 00348 if (version == 0) { 00349 if (addressRT >= 0 && addressRT <= 15) { 00350 if (R[8] != 0x0D ) 00351 _disp[addressRT*4] = R[8]; 00352 else { 00353 len=addressRT*4; 00354 cr=1; 00355 } 00356 if (R[9] != 0x0D) 00357 _disp[addressRT*4+1] = R[9]; 00358 else { 00359 len=addressRT*4+1; 00360 cr=1; 00361 } 00362 if (R[10] != 0x0D) 00363 _disp[addressRT*4+2] = R[10]; 00364 else { 00365 len=addressRT*4+2; 00366 cr=1; 00367 } 00368 if (R[11] != 0x0D) 00369 _disp[addressRT*4+3] = R[11]; 00370 else { 00371 len=addressRT*4+3; 00372 cr=1; 00373 } 00374 } 00375 } else { 00376 if (addressRT >= 0 && addressRT <= 7) { 00377 if (R[10] != '\0') 00378 _disp[addressRT*2] = R[10]; 00379 if (R[11] != '\0') 00380 _disp[addressRT*2+1] = R[11]; 00381 } 00382 } 00383 if(cr) { 00384 for (char i=len; i<64; i++) _disp[i] = ' '; 00385 } 00386 if (ab != _ab) { 00387 for (char i=0; i<64; i++) _disp[i] = ' '; 00388 _disp[64] = '\0'; 00389 _newRadioText=1; 00390 } else { 00391 _newRadioText=0; 00392 } 00393 _ab = ab; 00394 printable_str(_disp, 64); 00395 } 00396 00397 else if (type == 4 && version == 0) { 00398 unsigned long MJD = (R[7]&3<<15 | (unsigned int)(R[8])<<7 | (R[9]>>1)&127)&0x01FFFF; 00399 unsigned int Y=(MJD-15078.2)/365.25; 00400 unsigned int M=(MJD-14956.1-(unsigned int)(Y*365.25))/30.6001; 00401 char K; 00402 if(M==14||M==15) 00403 K=1; 00404 else 00405 K=0; 00406 _year=(Y+K)%100; 00407 _month=M-1-K*12; 00408 _day=MJD-14956-(unsigned int)(Y*365.25)-(unsigned int)(M*30.6001); 00409 00410 char sign=(((R[11]>>5)&1)/(-1)); 00411 if(sign==0)sign=1; //Make sign a bipolar variable 00412 char offset=sign*(R[11]&31); 00413 00414 _hour=((R[9]&1)<<4) | ((R[10]>>4)&15); 00415 _minute=((R[10]&15)<<2 | (R[11]>>6)&3); 00416 _hour= (_hour + (offset/2) + 24)%24; 00417 _minute=(_minute + (offset)%2*30 + 60)%60; 00418 } 00419 wait(0.04); 00420 return ps_rdy; 00421 } 00422 00423 void Si4735::getRDS() 00424 { 00425 strcpy(tuned.programService, _ps); 00426 strcpy(tuned.radioText, _disp); 00427 strcpy(tuned.programType, _pty); 00428 strcpy(tuned.callSign, _csign); 00429 tuned.newRadioText=_newRadioText; 00430 } 00431 00432 void Si4735::getTime() 00433 { 00434 date.year=_year; 00435 date.month=_month; 00436 date.day=_day; 00437 date.hour=_hour; 00438 date.minute=_minute; 00439 } 00440 00441 bool Si4735::getIntStatus(void) 00442 { 00443 char response; 00444 i2c_->start(); 00445 i2c_->write(address_write); 00446 i2c_->write(0x14); 00447 i2c_->stop(); 00448 00449 i2c_->start(); 00450 i2c_->write(address_read); 00451 response = i2c_->read(1); 00452 i2c_->stop(); 00453 (*pc).printf("Int Status Response: %c\n", response); 00454 00455 if(response == NULL) { 00456 return false; 00457 } 00458 return true; 00459 } 00460 00461 void Si4735::clearRDS(void) 00462 { 00463 char i; 00464 for(i=0; i<64; i++) _disp[i] ='\0'; 00465 for(i=0; i<8; i++) _ps[i] ='\0'; 00466 for(i=0; i<16; i++) _pty[i] ='\0'; 00467 for(i=0; i<4; i++) _csign[i]='\0'; 00468 } 00469 00470 void Si4735::setLocale(char locale) 00471 { 00472 _locale=locale; 00473 //Set the deemphasis to match the locale 00474 switch(_locale) { 00475 case NA: 00476 setProperty(0x1100, 0x0002); 00477 break; 00478 case EU: 00479 setProperty(0x1100, 0x0001); 00480 break; 00481 default: 00482 break; 00483 } 00484 } 00485 00486 char Si4735::getLocale(void) 00487 { 00488 return _locale; 00489 } 00490 00491 void Si4735::ptystr(char pty) 00492 { 00493 // Translate the Program Type bits to the RBDS 16-character fields 00494 if(pty>=0 && pty<32) { 00495 char* pty_LUT[51] = { 00496 " None ", 00497 " News ", 00498 " Information ", 00499 " Sports ", 00500 " Talk ", 00501 " Rock ", 00502 " Classic Rock ", 00503 " Adult Hits ", 00504 " Soft Rock ", 00505 " Top 40 ", 00506 " Country ", 00507 " Oldies ", 00508 " Soft ", 00509 " Nostalgia ", 00510 " Jazz ", 00511 " Classical ", 00512 "Rhythm and Blues", 00513 " Soft R & B ", 00514 "Foreign Language", 00515 "Religious Music ", 00516 " Religious Talk ", 00517 " Personality ", 00518 " Public ", 00519 " College ", 00520 " Reserved -24- ", 00521 " Reserved -25- ", 00522 " Reserved -26- ", 00523 " Reserved -27- ", 00524 " Reserved -28- ", 00525 " Weather ", 00526 " Emergency Test ", 00527 " !!!ALERT!!! ", 00528 "Current Affairs ", 00529 " Education ", 00530 " Drama ", 00531 " Cultures ", 00532 " Science ", 00533 " Varied Speech ", 00534 " Easy Listening ", 00535 " Light Classics ", 00536 "Serious Classics", 00537 " Other Music ", 00538 " Finance ", 00539 "Children's Progs", 00540 " Social Affairs ", 00541 " Phone In ", 00542 "Travel & Touring", 00543 "Leisure & Hobby ", 00544 " National Music ", 00545 " Folk Music ", 00546 " Documentary " 00547 }; 00548 if(_locale==NA) { 00549 strcpy(_pty, pty_LUT[pty]); 00550 } else if(_locale==EU) { 00551 char LUT[32] = {0, 1, 32, 2, 00552 3, 33, 34, 35, 00553 36, 37, 9, 5, 00554 38, 39, 40, 41, 00555 29, 42, 43, 44, 00556 20, 45, 46, 47, 00557 14, 10, 48, 11, 00558 49, 50, 30, 31 00559 }; 00560 strcpy(_pty, pty_LUT[LUT[pty]]); 00561 } else { 00562 strcpy(_pty, " LOCALE UNKN0WN "); 00563 } 00564 } else { 00565 strcpy(_pty, " PTY ERROR "); 00566 } 00567 } 00568 00569 void Si4735::refreshDisplay(int next_stn) 00570 { 00571 bool ps_rdy = readRDS(); 00572 if(!ps_rdy) 00573 return; 00574 getRDS(); 00575 //getTime(); 00576 bool refresh = false; 00577 if(strcmp(tuned.programType,pty_prev)) { 00578 //refresh = true; 00579 strcpy(pty_prev,tuned.programType); 00580 } 00581 if (strlen(tuned.programService) == 8) { 00582 if(ps_rdy) { 00583 if(strcmp(tuned.programService,ps_prev)) { 00584 refresh = true; 00585 strcpy(ps_prev,tuned.programService); 00586 } 00587 } 00588 } else if(strcmp(tuned.programType," None ")) { 00589 if(!strcmp("01234567",ps_prev)) { 00590 strcpy(tuned.programService, "mBed-Rdo"); 00591 strcpy(ps_prev,"01234567"); 00592 //refresh = true; 00593 } 00594 } 00595 if(!tuned.newRadioText) { 00596 strcpy(RadioText, tuned.radioText); 00597 } 00598 00599 if(refresh) { 00600 (*pc).printf("\x1B[2J"); 00601 (*pc).printf("\x1B[H"); 00602 (*pc).printf("Current Station: %3.2f MHz FM\n", float(getFrequency())/100.0); 00603 (*pc).printf("Program Type = %s\n", tuned.programType); 00604 (*pc).printf("Program Service = %s\n", tuned.programService); 00605 (*pc).printf("Radio Text = %s\n", RadioText); 00606 (*pc).printf("Call Sign = %s\n", tuned.callSign); 00607 //(*pc).printf("Time = %2d:%2d\n", date.hour, date.minute); 00608 } 00609 } 00610 00611 00612 /******************************************* 00613 * 00614 * Private Functions 00615 * 00616 *******************************************/ 00617 00618 void Si4735::sendCommand(char * command, int length) 00619 { 00620 //ack = i2c_->write(address_write, command, length, false); 00621 i2c_->start(); 00622 bool ack = i2c_->write(address_write); 00623 for(int i=0; i<length; i++) 00624 ack = i2c_->write(command[i]); 00625 char CTS = i2c_->read(1); 00626 i2c_->stop(); 00627 } 00628 00629 00630 bool Si4735::bitRead(char value, int index) 00631 { 00632 return ((value >> index) & 1) == 1; 00633 } 00634 void Si4735::printable_str(char * str, int length) 00635 { 00636 for(int i=0; i<length; i++) { 00637 if( (str[i]!=0 && str[i]<32) || str[i]>126 ) str[i]=' '; 00638 } 00639 }
Generated on Fri Jul 15 2022 01:59:08 by 1.7.2