webradio/webradio.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2007 by egnite Software GmbH. All rights reserved.
00003  * Copyright (C) 2008 by egnite GmbH. All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00022  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00024  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00025  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00026  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00028  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00029  * SUCH DAMAGE.
00030  *
00031  * For additional information see http://www.ethernut.de/
00032  */
00033 
00046 /*
00047  * Limited AT91SAM9260-EK MP3 player sample.
00048  *
00049  * Will sequentially play all MP3 files from an MMC's root directory.
00050  *
00051  * MultiMedia Cards only, no SD Cards (see arch/arm/dev/at91_mmc.c).
00052  * Root directory must contain MP3 files only.
00053  * Hardcoded for 180MHz CPU clock and 44.1kHz sampling rate (also see ./at73dac.c).
00054  */
00055 
00056 #include <cfg/os.h>
00057 #include <cfg/clock.h>
00058 #include <dev/board.h>
00059 #include <dev/st7036.h>
00060 
00061 #include <stdlib.h>
00062 #include <string.h>
00063 #include <stdio.h>
00064 #include <time.h>
00065 #include <fcntl.h>
00066 #include <io.h>
00067 
00068 #include <sys/version.h>
00069 #include <sys/confos.h>
00070 #include <sys/confnet.h>
00071 #include <sys/atom.h>
00072 #include <sys/heap.h>
00073 #include <sys/thread.h>
00074 #include <sys/timer.h>
00075 #include <sys/event.h>
00076 #include <sys/socket.h>
00077 
00078 #if defined(USE_SOFTWARE_CODEC)
00079 #include <hxmp3/mp3dec.h>
00080 #endif
00081 
00082 #include <netinet/tcp.h>
00083 #include <arpa/inet.h>
00084 #include <net/route.h>
00085 #include <netdb.h>
00086 
00087 #include <pro/dhcp.h>
00088 #include <pro/sntp.h>
00089 #include <pro/discover.h>
00090 
00091 #include <dev/vscodec.h>
00092 
00093 #include "config.h"
00094 #include "logmsg.h"
00095 #include "favlist.h"
00096 #include "shoutcast.h"
00097 #include "httpserv.h"
00098 #include "xmlserv.h"
00099 #include "userif.h"
00100 
00101 /*
00102  * Unique MAC address of the Ethernut Board.
00103  *
00104  * Ignored if EEPROM contains a valid configuration.
00105  */
00106 #define MY_MAC { 0x00, 0x06, 0x98, 0x30, 0x00, 0x39 }
00107 
00108 /*
00109  * Unique IP address of the Ethernut Board.
00110  *
00111  * Ignored if DHCP is used.
00112  */
00113 #define MY_IPADDR "192.168.192.39"
00114 
00115 /*
00116  * IP network mask of the Ethernut Board.
00117  *
00118  * Ignored if DHCP is used.
00119  */
00120 #define MY_IPMASK "255.255.255.0"
00121 
00122 /*
00123  * Gateway IP address for the Ethernut Board.
00124  *
00125  * Ignored if DHCP is used.
00126  */
00127 #define MY_IPGATE "192.168.192.1"
00128 
00129 /*
00130  * Wether we should run a discovery responder.
00131  */
00132 #if defined(AT91SAM9260_EK) || defined(ELEKTOR_IR1)
00133 #define USE_DISCOVERY
00134 #endif
00135 
00136 /*
00137  * IP address of the host running a time daemon. 
00138  */
00139 #if defined(AT91SAM9260_EK) || defined(ELEKTOR_IR1)
00140 //#define MY_TIMED "130.149.17.21"
00141 #endif
00142 
00143 /*
00144  * Local timezone, -1 for Central Europe. 
00145  */
00146 #ifndef MY_TZ
00147 #define MY_TZ    -1
00148 #endif
00149 
00150 
00151 WEBRADIO webradio;
00152 
00153 /*
00154  * Query a time server and optionally update the hardware clock.
00155  */
00156 static int QueryTimeServer(void)
00157 {
00158     int rc = -1;
00159 
00160 #ifdef MY_TIMED
00161     int retries = 5;
00162 
00163     _timezone = MY_TZ * 60L * 60L;
00164     while (retries--) {
00165         time_t now;
00166         u_long timeserver = inet_addr(MY_TIMED);
00167 
00168         /* Query network time service and set the system time. */
00169         LogMsg(LOG_STARTUP, "Query time from %s...", MY_TIMED);
00170         if(NutSNTPGetTime(&timeserver, &now) == 0) {
00171             LogMsg(LOG_STARTUP, "OK\n");
00172             rc = 0;
00173             stime(&now);
00174             break;
00175         }
00176         else {
00177             LogMsg(LOG_STARTUP, "failed\n");
00178         }
00179     }
00180 #endif
00181 
00182     return rc;
00183 }
00184 
00185 int InitEthernetDevice(void)
00186 {
00187     u_long ip_addr = inet_addr(MY_IPADDR);
00188     u_long ip_mask = inet_addr(MY_IPMASK);
00189     u_long ip_gate = inet_addr(MY_IPGATE);
00190     u_char mac[6] = MY_MAC;
00191 
00192     for (;;) {
00193         LogMsg(LOG_STARTUP, "Register %s...", DEV_ETHER_NAME);
00194         if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5) == 0) {
00195             LogMsg(LOG_STARTUP, "OK\n");
00196             break;
00197         }
00198         LogMsg(LOG_STARTUP, "No Ethernet, retry\n");
00199     }
00200 
00201     LogMsg(LOG_STARTUP, "Configure %s...", DEV_ETHER_NAME);
00202     if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000) == 0) {
00203         LogMsg(LOG_STARTUP, "OK\n");
00204         return 0;
00205     }
00206     LogMsg(LOG_STARTUP, "initial boot...");
00207     if (NutDhcpIfConfig(DEV_ETHER_NAME, mac, 60000) == 0) {
00208         LogMsg(LOG_STARTUP, "OK\n");
00209         return 0;
00210     }
00211     LogMsg(LOG_STARTUP, "No DHCP...");
00212     NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask);
00213     /* Without DHCP we had to set the default gateway manually.*/
00214     if(ip_gate) {
00215         LogMsg(LOG_STARTUP, "hard coded gate...");
00216         NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
00217     }
00218     LogMsg(LOG_STARTUP, "OK\n");
00219 
00220     return 0;
00221 }
00222 
00223 
00227 int main(void)
00228 {
00229     u_long baud = 115200;
00230     u_long ipgate;
00231     int stream_idx = 0;
00232     u_int rstat;
00233     u_int ostat = 0;
00234 
00235     /*
00236      * Register and open the DBGU device, which we will use for debug 
00237      * output via stdout.
00238      */
00239     NutRegisterDevice(&DEV_DEBUG, 0, 0);
00240     freopen(DEV_DEBUG_NAME, "w", stdout);
00241     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00242 
00243     /*
00244      * Display some general information.
00245      */
00246 #ifdef LOG_ENABLE
00247 #if LOG_ENABLE
00248     LogMsg((u_int)-1, "Internet Radio %s - Nut/OS %s\n", VERSION, NutVersionString());
00249 #endif
00250 #endif
00251     LogMsg(LOG_STARTUP, "%u bytes free\n", (u_int)NutHeapAvailable());
00252     LogMsg(LOG_STARTUP, "CPU Clock   : %lu\n", NutGetCpuClock());
00253     LogMsg(LOG_STARTUP, "Master Clock: %lu\n", At91GetMasterClock());
00254 
00255     if (NutLoadConfig() == 0) {
00256         LogMsg(LOG_STARTUP, "Hostname: %s\n", confos.hostname);
00257     }
00258 
00259     /*
00260      * Load configuration.
00261      */
00262     if (ConfigInit()) {
00263         /* No configuration memory, run with factory defaults. */
00264         ConfigResetFactory();
00265         FavListResetFactory();
00266     }
00267     else {
00268         if (ConfigLoad()) {
00269             /* No configuration info, use factory defaults. */
00270             ConfigResetFactory();
00271             ConfigSave();
00272         }
00273         if (FavListLoad()) {
00274             /* No favorites, use hard coded entries. */
00275             FavListResetFactory();
00276             FavListSave();
00277         }
00278     }
00279 
00280     /*
00281      * Register codec device.
00282      */
00283     if (NutRegisterDevice(&devVsCodec, 0, 0)) {
00284         LogMsg(LOG_ERROR, "No audio decoder\n");
00285         for(;;);
00286     }
00287 #if USE_DISPLAY
00288     /*
00289      * Initialize the user interface, LCD and 3 buttons.
00290      */
00291     if (NutRegisterDevice(&devSbiLcd, 0, 0)) {
00292         LogMsg(LOG_ERROR, "Failed to register LCD\n");
00293     }
00294 #endif
00295 
00296     if (UserIfInit("sbilcd")) {
00297         LogMsg(LOG_ERROR, "LCD init failure\n");
00298     }
00299 
00300     /* 
00301      * Initialize the Ethernet device and print our IP setting. 
00302      */
00303     InitEthernetDevice();
00304     NutIpRouteQuery(0, &ipgate);
00305     LogMsg(LOG_STARTUP, "IP Addr: %s\n", inet_ntoa(confnet.cdn_ip_addr));
00306     LogMsg(LOG_STARTUP, "IP Mask: %s\n", inet_ntoa(confnet.cdn_ip_mask));
00307     LogMsg(LOG_STARTUP, "IP Gate: %s\n", inet_ntoa(ipgate));
00308     LogMsg(LOG_STARTUP, "PrimDNS: %s\n", inet_ntoa(webradio.wr_pridns));
00309     LogMsg(LOG_STARTUP, "Sec DNS: %s\n", inet_ntoa(webradio.wr_secdns));
00310     if (confnet.cdn_cip_addr) {
00311         NutDnsConfig2(NULL, NULL, webradio.wr_pridns, webradio.wr_secdns);
00312     }
00313 
00314     /* 
00315      * Register a discovery responder. This optional feature
00316      * allows to discover all Nut/OS devices in a local network.
00317      */
00318 #ifdef USE_DISCOVERY
00319     LogMsg(LOG_STARTUP, "Start Responder...");
00320     if (NutRegisterDiscovery((u_long)-1, 0, DISF_INITAL_ANN)) {
00321         LogMsg(LOG_STARTUP, "failed\n");
00322     }
00323     else {
00324         LogMsg(LOG_STARTUP, "OK\n");
00325     }
00326 #endif
00327 
00328     /*
00329      * Try to get current date and time from an SNTP server.
00330      */
00331     if (QueryTimeServer() == 0) {
00332         time_t now = time(0);
00333         struct _tm *lot = localtime(&now);
00334         LogMsg(LOG_STARTUP, "Date: %02u.%02u.%u\n", lot->tm_mday, lot->tm_mon + 1, 1900 + lot->tm_year);
00335         LogMsg(LOG_STARTUP, "Time: %02u:%02u:%02u\n", lot->tm_hour, lot->tm_min, lot->tm_sec);
00336 #ifdef USE_HTTPSERVER
00337         h_timevalid = 1;
00338 #endif
00339     }
00340 
00341 #ifdef USE_HTTPSERVER
00342     HttpServerStart();
00343     XmlServerStart();
00344 #endif
00345 
00346     /*
00347      * Create all supported receiver instances.
00348      */
00349     webradio.wr_ritab[0] = ReceiverCreate(&rpiShoutcast);
00350 
00351     /*
00352      * Never ending station selection loop.
00353      */
00354     for (;;) {
00355         /*
00356          * Connect station.
00357          */
00358         UserIfShowStatus(DIST_CONNECTING);
00359         webradio.wr_sip = StationConnect(&favlist[1], stream_idx);
00360         if (webradio.wr_sip == NULL) {
00361             /* Connection failed. */
00362             UserIfShowStatus(DIST_DEAD);
00363             NutSleep(1000);
00364         } else {
00365             /* Station connected, start receiver. */
00366             webradio.wr_rip = ReceiverStart(webradio.wr_ritab, webradio.wr_sip);
00367             if (webradio.wr_rip == NULL) {
00368                 /* Receiver start failed. */
00369                 UserIfShowStatus(DIST_DEAD);
00370                 NutSleep(1000);
00371             } else {
00372                 /* Receiver running. */
00373                 UserIfShowStatus(DIST_CONNECTED);
00374                 /* Save the current station setting. */
00375                 webradio.wr_favupd = 10;
00376                 /* Monitor everything. */
00377                 for (;;) {
00378                     NutSleep(1000);
00379                     if (favlist[TOP_FAVORITE].rs_streams) {
00380                         break;
00381                     }
00382                     /* Delayed favorites list storage. */
00383                     if (webradio.wr_favupd && --webradio.wr_favupd == 0) {
00384                         FavListSave();
00385                     }
00386                     /* Reboot? */
00387                     if (webradio.wr_reboot) {
00388                         webradio.wr_reboot--;
00389                         if (webradio.wr_reboot == 0) {
00390                             outr(RSTC_CR, RSTC_KEY | RSTC_PROCRST);
00391                         }
00392                         LogMsg(LOG_WARN, "Reboot in %ds\n", webradio.wr_reboot);
00393                     }
00394                     /* Still playing? */
00395                     rstat = ReceiverStatus(webradio.wr_rip);
00396                     if (rstat != ostat) {
00397                         if (rstat & (RSTAT_IDLE | RSTAT_STOP)) {
00398                             break;
00399                         }
00400                         UserIfShowStatus(DIST_FORCE);
00401                         ostat = rstat;
00402                     }
00403                 }
00404                 UserIfShowStatus(DIST_NONE);
00405                 ReceiverStop(webradio.wr_rip);
00406             }
00407             StationDisconnect(webradio.wr_sip);
00408             webradio.wr_sip = NULL;
00409         }
00410         if (favlist[TOP_FAVORITE].rs_streams) {
00411             LogMsg(LOG_STATION, "Selected %s\n", favlist[TOP_FAVORITE].rs_name);
00412             FavListCopy(TOP_FAVORITE, LAST_FAVORITE);
00413             FavListSet(TOP_FAVORITE, NULL, NULL);
00414             stream_idx = 0;
00415         } else {
00416             if (++stream_idx >= favlist[LAST_FAVORITE].rs_streams) {
00417                 stream_idx = 0;
00418             }
00419         }
00420     }
00421 }

© 2008 by egnite GmbH - visit www.ethernut.de