nutpiper/nutpiper.c

$Log$ Revision 1.7 2009/02/18 12:18:58 olereinhardt 2009-02-18 Ole Reinhardt <ole.reinhardt@thermotemp.de>

Fixed compilier warnings. Especialy signedness of char buffers as well as unused code on arm platform and main functions without return value

Revision 1.6 2006/08/31 19:14:44 haraldkipp Not all platforms do have devDebug0. Use board.h to determine the correct driver.

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 
00071 #include <stdlib.h>
00072 #include <string.h>
00073 #include <stdio.h>
00074 #include <io.h>
00075 
00076 #include <dev/board.h>
00077 #include <dev/debug.h>
00078 #include <dev/term.h>
00079 #include <dev/hd44780.h>
00080 #include <dev/vs1001k.h>
00081 #ifdef ETHERNUT2
00082 #include <dev/lanc111.h>
00083 #else
00084 #include <dev/nicrtl.h>
00085 #endif
00086 
00087 #include <sys/heap.h>
00088 #include <sys/thread.h>
00089 #include <sys/timer.h>
00090 
00091 #include <netinet/tcp.h>
00092 #include <arpa/inet.h>
00093 #include <net/route.h>
00094 
00095 #include <pro/dhcp.h>
00096 
00097 #include <sys/bankmem.h>
00098 #include <dev/irsony.h>
00099 
00100 #include "config.h"
00101 #include "display.h"
00102 #include "scanner.h"
00103 #include "player.h"
00104 
00105 #if defined(__AVR__)
00106 
00107 /*
00108  * TCP buffer size.
00109  */
00110 static u_short tcpbufsiz = 4288;
00111 
00112 /*
00113  * Maximum segment size, choose 536 up to 1460. Note, that segment 
00114  * sizes above 536 may result in fragmented packets. Remember, that 
00115  * Ethernut doesn't support TCP fragmentation.
00116  */
00117 static u_short mss = 536;
00118 
00119 /*
00120  * Socket receive timeout.
00121  */
00122 static u_long rx_to = 1000;
00123 
00124 /*
00125  * Connect to a radio station.
00126  */
00127 static TCPSOCKET *ConnectStation(RADIOSTATION * rsp)
00128 {
00129     TCPSOCKET *sock;
00130     int rc;
00131 
00132     /* Create a socket. TODO: A failure is fatal and should restart
00133        the system. */
00134     if ((sock = NutTcpCreateSocket()) == 0)
00135         return sock;
00136 
00137     /* Set socket options. Failures are ignored. */
00138     if (NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss)))
00139         printf("Sockopt MSS failed\n");
00140     if (NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to)))
00141         printf("Sockopt TO failed\n");
00142     if (NutTcpSetSockOpt(sock, SO_RCVBUF, &tcpbufsiz, sizeof(tcpbufsiz)))
00143         printf("Sockopt rxbuf failed\n");
00144 
00145     /* Connect the stream server. */
00146     printf("[CNCT %s:%u]", inet_ntoa(rsp->rs_ip), rsp->rs_port);
00147     if ((rc = NutTcpConnect(sock, rsp->rs_ip, rsp->rs_port)) == 0) {
00148         printf("[CNCTD]");
00149         /* Process header from server. */
00150         if (ScanStreamHeader(sock, rsp) == 0) {
00151             /* TODO: Failed to start the player is fatal. */
00152             if (PlayerStart(sock, rsp->rs_metaint, 30000)) {
00153                 NutTcpCloseSocket(sock);
00154                 sock = 0;
00155             }
00156         } else {
00157             NutTcpCloseSocket(sock);
00158             sock = 0;
00159         }
00160     } else {
00161         printf("[CERR=%d]\n", NutTcpError(sock));
00162         NutTcpCloseSocket(sock);
00163         sock = 0;
00164     }
00165     return sock;
00166 }
00167 
00168 /*
00169  * Disconnect from a radio station.
00170  */
00171 static void DisconnectStation(TCPSOCKET * sock)
00172 {
00173     if (PlayerStop(3000)) {
00174         printf("[PPFAIL]");
00175     }
00176     printf("Disconnecting\n");
00177     NutTcpCloseSocket(sock);
00178 }
00179 
00180 /*
00181  * Get next command from user interface.
00182  *
00183  * We are supporting the remote control only for now.
00184  */
00185 static u_short UserInput(void)
00186 {
00187     u_short rc;
00188     static u_short old = 0xFFFF;
00189 
00190     if ((rc = (u_short) NutIrGet(500)) == 0xFFFF)
00191         old = rc;
00192     else if (rc == old || (rc >> 7) != IR_DEVICE)
00193         rc = 0xFFFF;
00194     else {
00195         old = rc;
00196         rc &= 0x7F;
00197         if (rc == IRCMD_VOL_UP || rc == IRCMD_VOL_DN)
00198             old = 0xFFFF;
00199     }
00200     return rc;
00201 }
00202 
00203 /*
00204  * If we got a background scanner 
00205  */
00206 static void StationList(void)
00207 {
00208     u_char cf = 1;
00209     u_char rs = radio.rc_cstation;
00210     u_short ircode;
00211 
00212     DisplayMessage(0, 1, "Stations");
00213     DisplayEntry(rs);
00214     while (cf) {
00215         /*
00216          * Process user input.
00217          */
00218         if ((ircode = UserInput()) != 0xFFFF) {
00219             switch (ircode) {
00220             case IRCMD_CHAN_UP:
00221                 if (++rs >= MAXNUM_STATIONS)
00222                     rs = 0;
00223                 DisplayEntry(rs);
00224                 break;
00225             case IRCMD_CHAN_DN:
00226                 if (rs)
00227                     rs--;
00228                 else
00229                     rs = MAXNUM_STATIONS - 1;
00230                 DisplayEntry(rs);
00231                 break;
00232             case IRCMD_SELECT:
00233                 radio.rc_rstation = rs;
00234             default:
00235                 cf = 0;
00236                 break;
00237             }
00238         }
00239     }
00240     DisplayStatus(DIST_FORCE);
00241 }
00242 
00246 static void UserInterface(void)
00247 {
00248     u_char ief;
00249     u_short ircode;
00250     TCPSOCKET *sock = 0;
00251 
00252     for (;;) {
00253 
00254         /*
00255          * Process user input.
00256          */
00257         if ((ircode = UserInput()) != 0xFFFF) {
00258             radio.rc_off = 0;
00259             switch (ircode) {
00260             case IRCMD_CHAN_1:
00261                 radio.rc_rstation = 1;
00262                 break;
00263             case IRCMD_CHAN_2:
00264                 radio.rc_rstation = 2;
00265                 break;
00266             case IRCMD_CHAN_3:
00267                 radio.rc_rstation = 3;
00268                 break;
00269             case IRCMD_CHAN_4:
00270                 radio.rc_rstation = 4;
00271                 break;
00272             case IRCMD_CHAN_5:
00273                 radio.rc_rstation = 5;
00274                 break;
00275             case IRCMD_CHAN_6:
00276                 radio.rc_rstation = 6;
00277                 break;
00278             case IRCMD_CHAN_7:
00279                 radio.rc_rstation = 7;
00280                 break;
00281             case IRCMD_CHAN_8:
00282                 radio.rc_rstation = 8;
00283                 break;
00284             case IRCMD_CHAN_9:
00285                 radio.rc_rstation = 9;
00286                 break;
00287             case IRCMD_CHAN_UP:
00288                 radio.rc_rstation = NEXT_STATION;
00289                 break;
00290             case IRCMD_CHAN_DN:
00291                 radio.rc_rstation = PREV_STATION;
00292                 break;
00293             case IRCMD_VOL_UP:
00294                 player.psi_start = 1;
00295                 if (radio.rc_rvolume < 245)
00296                     radio.rc_rvolume += 10;
00297                 break;
00298             case IRCMD_VOL_DN:
00299                 player.psi_start = 1;
00300                 if (radio.rc_rvolume > 10)
00301                     radio.rc_rvolume -= 10;
00302                 break;
00303             case IRCMD_MUTE:
00304                 radio.rc_rmute = !radio.rc_rmute;
00305                 break;
00306             case IRCMD_OFF:
00307                 radio.rc_off = 1;
00308                 DisplayMessage(0, 0, "Shutdown...");
00309                 DisplayMessage(1, 0, "");
00310                 PlayerStop(1000);
00311                 ConfigSave();
00312                 radio.rc_cstation = PREV_STATION;
00313                 DisplayMessage(0, 0, "");
00314                 break;
00315             case IRCMD_VTEXT:
00316                 StationList();
00317                 break;
00318             default:
00319                 DisplayMessage(0, 1, "Code %u", ircode);
00320                 ief = VsPlayerInterrupts(0);
00321                 printf("%lu kBytes used, %lu kBytes free\n", NutSegBufUsed() / 1024UL, NutSegBufAvailable() / 1024UL);
00322                 VsPlayerInterrupts(ief);
00323                 break;
00324             }
00325         }
00326 
00327         if (radio.rc_off) {
00328             NutSleep(500);
00329             continue;
00330         }
00331 
00332         /*
00333          * Handle station changes.
00334          */
00335         if (radio.rc_rstation != radio.rc_cstation) {
00336             /* Disconnect current stream. */
00337             if (sock) {
00338                 DisconnectStation(sock);
00339                 sock = 0;
00340             }
00341 
00342             /* If scanning, move to the next/previous station. */
00343             if (radio.rc_rstation == NEXT_STATION) {
00344                 if (++radio.rc_cstation >= MAXNUM_STATIONS)
00345                     radio.rc_rstation = 0;
00346             } else if (radio.rc_rstation == PREV_STATION) {
00347                 if (radio.rc_cstation)
00348                     radio.rc_cstation--;
00349                 else
00350                     radio.rc_cstation = MAXNUM_STATIONS - 1;
00351             } else {
00352                 radio.rc_cstation = radio.rc_rstation;
00353             }
00354 
00355             DisplayMessage(0, 1, "Station %03u", radio.rc_cstation);
00356 
00357             /* Check for valid IP address and port. */
00358             if (station[radio.rc_cstation].rs_ip && station[radio.rc_cstation].rs_port) {
00359                 if (station[radio.rc_cstation].rs_scandead) {
00360                     DisplayStatus(DIST_DEAD);
00361                 } else {
00362                     DisplayStatus(DIST_CONNECTING);
00363                     if ((sock = ConnectStation(&station[radio.rc_cstation])) != 0) {
00364                         radio.rc_rstation = radio.rc_cstation;
00365                         DisplayStatus(DIST_CONNECTED);
00366                     } else {
00367                         DisplayStatus(DIST_DEAD);
00368                     }
00369                 }
00370             } else {
00371                 DisplayStatus(DIST_DEAD);
00372             }
00373         } else if (radio.rc_cmute != radio.rc_rmute) {
00374 
00375             radio.rc_cmute = radio.rc_rmute;
00376             if (radio.rc_cmute) {
00377                 DisplayMessage(0, 1, "Mute");
00378                 VsSetVolume(255, 255);
00379             } else {
00380                 DisplayMessage(0, 1, "Volume %u", radio.rc_cvolume);
00381                 VsSetVolume(255 - radio.rc_cvolume, 255 - radio.rc_cvolume);
00382             }
00383         } else if (radio.rc_cvolume != radio.rc_rvolume) {
00384             DisplayMessage(0, 1, "Volume %u", radio.rc_rvolume);
00385             VsSetVolume(255 - radio.rc_rvolume, 255 - radio.rc_rvolume);
00386             radio.rc_cvolume = radio.rc_rvolume;
00387             radio.rc_rmute = 0;
00388         } else if (player.psi_metaupdate) {
00389             DisplayStatus(DIST_FORCE);
00390             player.psi_metaupdate = 0;
00391         }
00392     }
00393 }
00394 
00395 #endif /* __AVR__ */
00396 
00397 /*
00398  * Main entry of the Internet Radio Application.
00399  */
00400 int main(void)
00401 {
00402 #if defined(__AVR__)
00403     /* Unique MAC address of the Ethernut Board. */
00404     u_char mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x00 };
00405     /* Unique IP address of the Ethernut Board. Ignored if DHCP is used. */
00406     u_long ip_addr = inet_addr("192.168.192.100");
00407     /* IP network mask of the Ethernut Board. Ignored if DHCP is used. */
00408     u_long ip_mask = inet_addr("255.255.255.0");
00409     /* Gateway IP address for the Ethernut Board. Ignored if DHCP is used. */
00410     u_long ip_gate = inet_addr("192.168.192.3");
00411     /* Baudrate for debug output. */
00412 #endif
00413     u_long baud = 115200;
00414 
00415     /*
00416      * Assign stdout to the debug device.
00417      */
00418     NutRegisterDevice(&DEV_DEBUG, 0, 0);
00419     freopen(DEV_DEBUG_NAME, "w", stdout);
00420     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00421 
00422     /*
00423      * Load configuration and display banner.
00424      */
00425     if (ConfigLoad())
00426         ConfigResetFactory();
00427 
00428 #if defined(__AVR__)
00429     /*
00430      * Initialize the MP3 device early to avoid noice, caused
00431      * by floating, tri-stated port lines.
00432      */
00433     if (NutSegBufInit(8192) == 0) {
00434         printf("Can't init segbuf\n");
00435         for (;;);
00436     }
00437     PlayerInit();
00438 
00439     /*
00440      * Initialize the LCD.
00441      */
00442     NutRegisterDevice(&devLcd, 0, 0);
00443     if (DisplayInit("lcd")) {
00444         printf("Display failure\n");
00445         for (;;);
00446     }
00447 
00448     /*
00449      * Initialize IR remote control.
00450      */
00451     NutIrInitSony();
00452 
00453     /*
00454      * LAN configuration using EEPROM values or DHCP/ARP method.
00455      * If it fails, use fixed values.
00456      */
00457     if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5))
00458         puts("Registering device failed");
00459     if (NutDhcpIfConfig("eth0", 0, 60000)) {
00460         puts("EEPROM/DHCP/ARP config failed");
00461         NutNetIfConfig("eth0", mac, ip_addr, ip_mask);
00462         NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
00463     }
00464     puts("ready\n");
00465 
00466     VsSetVolume(255 - radio.rc_rvolume, 255 - radio.rc_rvolume);
00467     VsBeep(2, 100);
00468 
00469     /*
00470      * Start the background scanner.
00471      */
00472     //ScannerInit();
00473 
00474     /*
00475      * Call the user interface..
00476      */
00477     for (;;) {
00478         UserInterface();
00479     }
00480 #endif /* __AVR__ */
00481 
00482     for (;;)
00483         NutSleep(1000);
00484 
00485     return 0;
00486 }

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/