nutpiper.c

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

© 2000-2010 by contributors - visit http://www.ethernut.de/