Revision 1.5 2006/07/21 09:06:36 haraldkipp Exclude AVR specific parts from building for other platforms. This does not imply, that all samples are working on all platforms.
Revision 1.4 2006/05/15 12:51:47 haraldkipp Player start timeout increased.
Revision 1.3 2004/05/11 17:22:12 drsung Deprecated header file removed.
Revision 1.2 2003/11/04 17:46:52 haraldkipp Adapted to Ethernut 2
Revision 1.1 2003/07/21 17:50:48 haraldkipp First check in
Shoutcast radio application..
00001 /* 00002 * Copyright (C) 2003-2006 by egnite Software GmbH. All rights reserved. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holders nor the names of 00014 * contributors may be used to endorse or promote products derived 00015 * from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS 00018 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00019 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00020 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE 00021 * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00022 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00023 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 00024 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 00025 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00026 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 00027 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00028 * SUCH DAMAGE. 00029 * 00030 * For additional information see http://www.ethernut.de/ 00031 * 00032 */ 00033 00064 #include <stdlib.h> 00065 #include <string.h> 00066 #include <stdio.h> 00067 #include <io.h> 00068 00069 #include <dev/board.h> 00070 #include <dev/debug.h> 00071 #include <dev/term.h> 00072 #include <dev/hd44780.h> 00073 #include <dev/vs1001k.h> 00074 #ifdef ETHERNUT2 00075 #include <dev/lanc111.h> 00076 #else 00077 #include <dev/nicrtl.h> 00078 #endif 00079 00080 #include <sys/heap.h> 00081 #include <sys/thread.h> 00082 #include <sys/timer.h> 00083 00084 #include <netinet/tcp.h> 00085 #include <arpa/inet.h> 00086 #include <net/route.h> 00087 00088 #include <pro/dhcp.h> 00089 00090 #include <sys/bankmem.h> 00091 #include <dev/irsony.h> 00092 00093 #include "config.h" 00094 #include "display.h" 00095 #include "scanner.h" 00096 #include "player.h" 00097 00098 #if defined(__AVR__) 00099 00100 /* 00101 * TCP buffer size. 00102 */ 00103 static u_short tcpbufsiz = 4288; 00104 00105 /* 00106 * Maximum segment size, choose 536 up to 1460. Note, that segment 00107 * sizes above 536 may result in fragmented packets. Remember, that 00108 * Ethernut doesn't support TCP fragmentation. 00109 */ 00110 static u_short mss = 536; 00111 00112 /* 00113 * Socket receive timeout. 00114 */ 00115 static u_long rx_to = 1000; 00116 00117 /* 00118 * Connect to a radio station. 00119 */ 00120 static TCPSOCKET *ConnectStation(RADIOSTATION * rsp) 00121 { 00122 TCPSOCKET *sock; 00123 int rc; 00124 00125 /* Create a socket. TODO: A failure is fatal and should restart 00126 the system. */ 00127 if ((sock = NutTcpCreateSocket()) == 0) 00128 return sock; 00129 00130 /* Set socket options. Failures are ignored. */ 00131 if (NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss))) 00132 printf("Sockopt MSS failed\n"); 00133 if (NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to))) 00134 printf("Sockopt TO failed\n"); 00135 if (NutTcpSetSockOpt(sock, SO_RCVBUF, &tcpbufsiz, sizeof(tcpbufsiz))) 00136 printf("Sockopt rxbuf failed\n"); 00137 00138 /* Connect the stream server. */ 00139 printf("[CNCT %s:%u]", inet_ntoa(rsp->rs_ip), rsp->rs_port); 00140 if ((rc = NutTcpConnect(sock, rsp->rs_ip, rsp->rs_port)) == 0) { 00141 printf("[CNCTD]"); 00142 /* Process header from server. */ 00143 if (ScanStreamHeader(sock, rsp) == 0) { 00144 /* TODO: Failed to start the player is fatal. */ 00145 if (PlayerStart(sock, rsp->rs_metaint, 30000)) { 00146 NutTcpCloseSocket(sock); 00147 sock = 0; 00148 } 00149 } else { 00150 NutTcpCloseSocket(sock); 00151 sock = 0; 00152 } 00153 } else { 00154 printf("[CERR=%d]\n", NutTcpError(sock)); 00155 NutTcpCloseSocket(sock); 00156 sock = 0; 00157 } 00158 return sock; 00159 } 00160 00161 /* 00162 * Disconnect from a radio station. 00163 */ 00164 static void DisconnectStation(TCPSOCKET * sock) 00165 { 00166 if (PlayerStop(3000)) { 00167 printf("[PPFAIL]"); 00168 } 00169 printf("Disconnecting\n"); 00170 NutTcpCloseSocket(sock); 00171 } 00172 00173 /* 00174 * Get next command from user interface. 00175 * 00176 * We are supporting the remote control only for now. 00177 */ 00178 static u_short UserInput(void) 00179 { 00180 u_short rc; 00181 static u_short old = 0xFFFF; 00182 00183 if ((rc = (u_short) NutIrGet(500)) == 0xFFFF) 00184 old = rc; 00185 else if (rc == old || (rc >> 7) != IR_DEVICE) 00186 rc = 0xFFFF; 00187 else { 00188 old = rc; 00189 rc &= 0x7F; 00190 if (rc == IRCMD_VOL_UP || rc == IRCMD_VOL_DN) 00191 old = 0xFFFF; 00192 } 00193 return rc; 00194 } 00195 00196 /* 00197 * If we got a background scanner 00198 */ 00199 static void StationList(void) 00200 { 00201 u_char cf = 1; 00202 u_char rs = radio.rc_cstation; 00203 u_short ircode; 00204 00205 DisplayMessage(0, 1, "Stations"); 00206 DisplayEntry(rs); 00207 while (cf) { 00208 /* 00209 * Process user input. 00210 */ 00211 if ((ircode = UserInput()) != 0xFFFF) { 00212 switch (ircode) { 00213 case IRCMD_CHAN_UP: 00214 if (++rs >= MAXNUM_STATIONS) 00215 rs = 0; 00216 DisplayEntry(rs); 00217 break; 00218 case IRCMD_CHAN_DN: 00219 if (rs) 00220 rs--; 00221 else 00222 rs = MAXNUM_STATIONS - 1; 00223 DisplayEntry(rs); 00224 break; 00225 case IRCMD_SELECT: 00226 radio.rc_rstation = rs; 00227 default: 00228 cf = 0; 00229 break; 00230 } 00231 } 00232 } 00233 DisplayStatus(DIST_FORCE); 00234 } 00235 00239 static void UserInterface(void) 00240 { 00241 u_char ief; 00242 u_short ircode; 00243 TCPSOCKET *sock = 0; 00244 00245 for (;;) { 00246 00247 /* 00248 * Process user input. 00249 */ 00250 if ((ircode = UserInput()) != 0xFFFF) { 00251 radio.rc_off = 0; 00252 switch (ircode) { 00253 case IRCMD_CHAN_1: 00254 radio.rc_rstation = 1; 00255 break; 00256 case IRCMD_CHAN_2: 00257 radio.rc_rstation = 2; 00258 break; 00259 case IRCMD_CHAN_3: 00260 radio.rc_rstation = 3; 00261 break; 00262 case IRCMD_CHAN_4: 00263 radio.rc_rstation = 4; 00264 break; 00265 case IRCMD_CHAN_5: 00266 radio.rc_rstation = 5; 00267 break; 00268 case IRCMD_CHAN_6: 00269 radio.rc_rstation = 6; 00270 break; 00271 case IRCMD_CHAN_7: 00272 radio.rc_rstation = 7; 00273 break; 00274 case IRCMD_CHAN_8: 00275 radio.rc_rstation = 8; 00276 break; 00277 case IRCMD_CHAN_9: 00278 radio.rc_rstation = 9; 00279 break; 00280 case IRCMD_CHAN_UP: 00281 radio.rc_rstation = NEXT_STATION; 00282 break; 00283 case IRCMD_CHAN_DN: 00284 radio.rc_rstation = PREV_STATION; 00285 break; 00286 case IRCMD_VOL_UP: 00287 player.psi_start = 1; 00288 if (radio.rc_rvolume < 245) 00289 radio.rc_rvolume += 10; 00290 break; 00291 case IRCMD_VOL_DN: 00292 player.psi_start = 1; 00293 if (radio.rc_rvolume > 10) 00294 radio.rc_rvolume -= 10; 00295 break; 00296 case IRCMD_MUTE: 00297 radio.rc_rmute = !radio.rc_rmute; 00298 break; 00299 case IRCMD_OFF: 00300 radio.rc_off = 1; 00301 DisplayMessage(0, 0, "Shutdown..."); 00302 DisplayMessage(1, 0, ""); 00303 PlayerStop(1000); 00304 ConfigSave(); 00305 radio.rc_cstation = PREV_STATION; 00306 DisplayMessage(0, 0, ""); 00307 break; 00308 case IRCMD_VTEXT: 00309 StationList(); 00310 break; 00311 default: 00312 DisplayMessage(0, 1, "Code %u", ircode); 00313 ief = VsPlayerInterrupts(0); 00314 printf("%lu kBytes used, %lu kBytes free\n", NutSegBufUsed() / 1024UL, NutSegBufAvailable() / 1024UL); 00315 VsPlayerInterrupts(ief); 00316 break; 00317 } 00318 } 00319 00320 if (radio.rc_off) { 00321 NutSleep(500); 00322 continue; 00323 } 00324 00325 /* 00326 * Handle station changes. 00327 */ 00328 if (radio.rc_rstation != radio.rc_cstation) { 00329 /* Disconnect current stream. */ 00330 if (sock) { 00331 DisconnectStation(sock); 00332 sock = 0; 00333 } 00334 00335 /* If scanning, move to the next/previous station. */ 00336 if (radio.rc_rstation == NEXT_STATION) { 00337 if (++radio.rc_cstation >= MAXNUM_STATIONS) 00338 radio.rc_rstation = 0; 00339 } else if (radio.rc_rstation == PREV_STATION) { 00340 if (radio.rc_cstation) 00341 radio.rc_cstation--; 00342 else 00343 radio.rc_cstation = MAXNUM_STATIONS - 1; 00344 } else { 00345 radio.rc_cstation = radio.rc_rstation; 00346 } 00347 00348 DisplayMessage(0, 1, "Station %03u", radio.rc_cstation); 00349 00350 /* Check for valid IP address and port. */ 00351 if (station[radio.rc_cstation].rs_ip && station[radio.rc_cstation].rs_port) { 00352 if (station[radio.rc_cstation].rs_scandead) { 00353 DisplayStatus(DIST_DEAD); 00354 } else { 00355 DisplayStatus(DIST_CONNECTING); 00356 if ((sock = ConnectStation(&station[radio.rc_cstation])) != 0) { 00357 radio.rc_rstation = radio.rc_cstation; 00358 DisplayStatus(DIST_CONNECTED); 00359 } else { 00360 DisplayStatus(DIST_DEAD); 00361 } 00362 } 00363 } else { 00364 DisplayStatus(DIST_DEAD); 00365 } 00366 } else if (radio.rc_cmute != radio.rc_rmute) { 00367 00368 radio.rc_cmute = radio.rc_rmute; 00369 if (radio.rc_cmute) { 00370 DisplayMessage(0, 1, "Mute"); 00371 VsSetVolume(255, 255); 00372 } else { 00373 DisplayMessage(0, 1, "Volume %u", radio.rc_cvolume); 00374 VsSetVolume(255 - radio.rc_cvolume, 255 - radio.rc_cvolume); 00375 } 00376 } else if (radio.rc_cvolume != radio.rc_rvolume) { 00377 DisplayMessage(0, 1, "Volume %u", radio.rc_rvolume); 00378 VsSetVolume(255 - radio.rc_rvolume, 255 - radio.rc_rvolume); 00379 radio.rc_cvolume = radio.rc_rvolume; 00380 radio.rc_rmute = 0; 00381 } else if (player.psi_metaupdate) { 00382 DisplayStatus(DIST_FORCE); 00383 player.psi_metaupdate = 0; 00384 } 00385 } 00386 } 00387 00388 #endif /* __AVR__ */ 00389 00390 /* 00391 * Main entry of the Internet Radio Application. 00392 */ 00393 int main(void) 00394 { 00395 /* Unique MAC address of the Ethernut Board. */ 00396 u_char mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x00 }; 00397 /* Unique IP address of the Ethernut Board. Ignored if DHCP is used. */ 00398 u_long ip_addr = inet_addr("192.168.192.100"); 00399 /* IP network mask of the Ethernut Board. Ignored if DHCP is used. */ 00400 u_long ip_mask = inet_addr("255.255.255.0"); 00401 /* Gateway IP address for the Ethernut Board. Ignored if DHCP is used. */ 00402 u_long ip_gate = inet_addr("192.168.192.3"); 00403 /* Baudrate for debug output. */ 00404 u_long baud = 115200; 00405 00406 /* 00407 * Assign stdout to the debug device. 00408 */ 00409 NutRegisterDevice(&DEV_DEBUG, 0, 0); 00410 freopen(DEV_DEBUG_NAME, "w", stdout); 00411 _ioctl(_fileno(stdout), UART_SETSPEED, &baud); 00412 00413 /* 00414 * Load configuration and display banner. 00415 */ 00416 if (ConfigLoad()) 00417 ConfigResetFactory(); 00418 00419 #if defined(__AVR__) 00420 /* 00421 * Initialize the MP3 device early to avoid noice, caused 00422 * by floating, tri-stated port lines. 00423 */ 00424 if (NutSegBufInit(8192) == 0) { 00425 printf("Can't init segbuf\n"); 00426 for (;;); 00427 } 00428 PlayerInit(); 00429 00430 /* 00431 * Initialize the LCD. 00432 */ 00433 NutRegisterDevice(&devLcd, 0, 0); 00434 if (DisplayInit("lcd")) { 00435 printf("Display failure\n"); 00436 for (;;); 00437 } 00438 00439 /* 00440 * Initialize IR remote control. 00441 */ 00442 NutIrInitSony(); 00443 00444 /* 00445 * LAN configuration using EEPROM values or DHCP/ARP method. 00446 * If it fails, use fixed values. 00447 */ 00448 if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5)) 00449 puts("Registering device failed"); 00450 if (NutDhcpIfConfig("eth0", 0, 60000)) { 00451 puts("EEPROM/DHCP/ARP config failed"); 00452 NutNetIfConfig("eth0", mac, ip_addr, ip_mask); 00453 NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER); 00454 } 00455 puts("ready\n"); 00456 00457 VsSetVolume(255 - radio.rc_rvolume, 255 - radio.rc_rvolume); 00458 VsBeep(2, 100); 00459 00460 /* 00461 * Start the background scanner. 00462 */ 00463 //ScannerInit(); 00464 00465 /* 00466 * Call the user interface.. 00467 */ 00468 for (;;) { 00469 UserInterface(); 00470 } 00471 #endif /* __AVR__ */ 00472 00473 for (;;) 00474 NutSleep(1000); 00475 00476 return 0; 00477 }