📄 webradio.c
字号:
/*
* Copyright (C) 2006-2007 by egnite Software GmbH. All rights reserved.
* Copyright (C) 2008 by egnite GmbH. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* For additional information see http://www.ethernut.de/
*/
/*!
* \file webradio.c
* \brief Internet radio main file.
*
* \verbatim
*
* $Log$
*
* \endverbatim
*/
/*
* Limited AT91SAM9260-EK MP3 player sample.
*
* Will sequentially play all MP3 files from an MMC's root directory.
*
* MultiMedia Cards only, no SD Cards (see arch/arm/dev/at91_mmc.c).
* Root directory must contain MP3 files only.
* Hardcoded for 180MHz CPU clock and 44.1kHz sampling rate (also see ./at73dac.c).
*/
#include <cfg/os.h>
#include <cfg/clock.h>
#include <dev/board.h>
#include <dev/st7036.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <io.h>
#include <sys/version.h>
#include <sys/confos.h>
#include <sys/confnet.h>
#include <sys/atom.h>
#include <sys/heap.h>
#include <sys/thread.h>
#include <sys/timer.h>
#include <sys/event.h>
#include <sys/socket.h>
#if defined(USE_SOFTWARE_CODEC)
#include <hxmp3/mp3dec.h>
#endif
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <netdb.h>
#include <pro/dhcp.h>
#include <pro/sntp.h>
#include <pro/discover.h>
#include <dev/vscodec.h>
#include "config.h"
#include "logmsg.h"
#include "favlist.h"
#include "shoutcast.h"
#include "httpserv.h"
#include "xmlserv.h"
#include "userif.h"
/*
* Unique MAC address of the Ethernut Board.
*
* Ignored if EEPROM contains a valid configuration.
*/
#define MY_MAC { 0x00, 0x06, 0x98, 0x30, 0x00, 0x39 }
/*
* Unique IP address of the Ethernut Board.
*
* Ignored if DHCP is used.
*/
#define MY_IPADDR "192.168.192.39"
/*
* IP network mask of the Ethernut Board.
*
* Ignored if DHCP is used.
*/
#define MY_IPMASK "255.255.255.0"
/*
* Gateway IP address for the Ethernut Board.
*
* Ignored if DHCP is used.
*/
#define MY_IPGATE "192.168.192.1"
/*
* Wether we should run a discovery responder.
*/
#if defined(AT91SAM9260_EK) || defined(ELEKTOR_IR1)
#define USE_DISCOVERY
#endif
/*
* IP address of the host running a time daemon.
*/
#if defined(AT91SAM9260_EK) || defined(ELEKTOR_IR1)
//#define MY_TIMED "130.149.17.21"
#endif
/*
* Local timezone, -1 for Central Europe.
*/
#ifndef MY_TZ
#define MY_TZ -1
#endif
WEBRADIO webradio;
/*
* Query a time server and optionally update the hardware clock.
*/
static int QueryTimeServer(void)
{
int rc = -1;
#ifdef MY_TIMED
int retries = 5;
_timezone = MY_TZ * 60L * 60L;
while (retries--) {
time_t now;
u_long timeserver = inet_addr(MY_TIMED);
/* Query network time service and set the system time. */
LogMsg(LOG_STARTUP, "Query time from %s...", MY_TIMED);
if(NutSNTPGetTime(×erver, &now) == 0) {
LogMsg(LOG_STARTUP, "OK\n");
rc = 0;
stime(&now);
break;
}
else {
LogMsg(LOG_STARTUP, "failed\n");
}
}
#endif
return rc;
}
int InitEthernetDevice(void)
{
u_long ip_addr = inet_addr(MY_IPADDR);
u_long ip_mask = inet_addr(MY_IPMASK);
u_long ip_gate = inet_addr(MY_IPGATE);
u_char mac[6] = MY_MAC;
for (;;) {
LogMsg(LOG_STARTUP, "Register %s...", DEV_ETHER_NAME);
if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5) == 0) {
LogMsg(LOG_STARTUP, "OK\n");
break;
}
LogMsg(LOG_STARTUP, "No Ethernet, retry\n");
}
LogMsg(LOG_STARTUP, "Configure %s...", DEV_ETHER_NAME);
if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000) == 0) {
LogMsg(LOG_STARTUP, "OK\n");
return 0;
}
LogMsg(LOG_STARTUP, "initial boot...");
if (NutDhcpIfConfig(DEV_ETHER_NAME, mac, 60000) == 0) {
LogMsg(LOG_STARTUP, "OK\n");
return 0;
}
LogMsg(LOG_STARTUP, "No DHCP...");
NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask);
/* Without DHCP we had to set the default gateway manually.*/
if(ip_gate) {
LogMsg(LOG_STARTUP, "hard coded gate...");
NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
}
LogMsg(LOG_STARTUP, "OK\n");
return 0;
}
/*!
* \brief Main application routine.
*/
int main(void)
{
u_long baud = 115200;
u_long ipgate;
int stream_idx = 0;
u_int rstat;
u_int ostat = 0;
/*
* Register and open the DBGU device, which we will use for debug
* output via stdout.
*/
NutRegisterDevice(&DEV_DEBUG, 0, 0);
freopen(DEV_DEBUG_NAME, "w", stdout);
_ioctl(_fileno(stdout), UART_SETSPEED, &baud);
/*
* Display some general information.
*/
#ifdef LOG_ENABLE
#if LOG_ENABLE
LogMsg((u_int)-1, "Internet Radio %s - Nut/OS %s\n", VERSION, NutVersionString());
#endif
#endif
LogMsg(LOG_STARTUP, "%u bytes free\n", (u_int)NutHeapAvailable());
LogMsg(LOG_STARTUP, "CPU Clock : %lu\n", NutGetCpuClock());
LogMsg(LOG_STARTUP, "Master Clock: %lu\n", At91GetMasterClock());
if (NutLoadConfig() == 0) {
LogMsg(LOG_STARTUP, "Hostname: %s\n", confos.hostname);
}
/*
* Load configuration.
*/
if (ConfigInit()) {
/* No configuration memory, run with factory defaults. */
ConfigResetFactory();
FavListResetFactory();
}
else {
if (ConfigLoad()) {
/* No configuration info, use factory defaults. */
ConfigResetFactory();
ConfigSave();
}
if (FavListLoad()) {
/* No favorites, use hard coded entries. */
FavListResetFactory();
FavListSave();
}
}
/*
* Register codec device.
*/
if (NutRegisterDevice(&devVsCodec, 0, 0)) {
LogMsg(LOG_ERROR, "No audio decoder\n");
for(;;);
}
#if USE_DISPLAY
/*
* Initialize the user interface, LCD and 3 buttons.
*/
if (NutRegisterDevice(&devSbiLcd, 0, 0)) {
LogMsg(LOG_ERROR, "Failed to register LCD\n");
}
#endif
if (UserIfInit("sbilcd")) {
LogMsg(LOG_ERROR, "LCD init failure\n");
}
/*
* Initialize the Ethernet device and print our IP setting.
*/
InitEthernetDevice();
NutIpRouteQuery(0, &ipgate);
LogMsg(LOG_STARTUP, "IP Addr: %s\n", inet_ntoa(confnet.cdn_ip_addr));
LogMsg(LOG_STARTUP, "IP Mask: %s\n", inet_ntoa(confnet.cdn_ip_mask));
LogMsg(LOG_STARTUP, "IP Gate: %s\n", inet_ntoa(ipgate));
LogMsg(LOG_STARTUP, "PrimDNS: %s\n", inet_ntoa(webradio.wr_pridns));
LogMsg(LOG_STARTUP, "Sec DNS: %s\n", inet_ntoa(webradio.wr_secdns));
if (confnet.cdn_cip_addr) {
NutDnsConfig2(NULL, NULL, webradio.wr_pridns, webradio.wr_secdns);
}
/*
* Register a discovery responder. This optional feature
* allows to discover all Nut/OS devices in a local network.
*/
#ifdef USE_DISCOVERY
LogMsg(LOG_STARTUP, "Start Responder...");
if (NutRegisterDiscovery((u_long)-1, 0, DISF_INITAL_ANN)) {
LogMsg(LOG_STARTUP, "failed\n");
}
else {
LogMsg(LOG_STARTUP, "OK\n");
}
#endif
/*
* Try to get current date and time from an SNTP server.
*/
if (QueryTimeServer() == 0) {
time_t now = time(0);
struct _tm *lot = localtime(&now);
LogMsg(LOG_STARTUP, "Date: %02u.%02u.%u\n", lot->tm_mday, lot->tm_mon + 1, 1900 + lot->tm_year);
LogMsg(LOG_STARTUP, "Time: %02u:%02u:%02u\n", lot->tm_hour, lot->tm_min, lot->tm_sec);
#ifdef USE_HTTPSERVER
h_timevalid = 1;
#endif
}
#ifdef USE_HTTPSERVER
HttpServerStart();
XmlServerStart();
#endif
/*
* Create all supported receiver instances.
*/
webradio.wr_ritab[0] = ReceiverCreate(&rpiShoutcast);
/*
* Never ending station selection loop.
*/
for (;;) {
/*
* Connect station.
*/
UserIfShowStatus(DIST_CONNECTING);
webradio.wr_sip = StationConnect(&favlist[1], stream_idx);
if (webradio.wr_sip == NULL) {
/* Connection failed. */
UserIfShowStatus(DIST_DEAD);
NutSleep(1000);
} else {
/* Station connected, start receiver. */
webradio.wr_rip = ReceiverStart(webradio.wr_ritab, webradio.wr_sip);
if (webradio.wr_rip == NULL) {
/* Receiver start failed. */
UserIfShowStatus(DIST_DEAD);
NutSleep(1000);
} else {
/* Receiver running. */
UserIfShowStatus(DIST_CONNECTED);
/* Save the current station setting. */
webradio.wr_favupd = 10;
/* Monitor everything. */
for (;;) {
NutSleep(1000);
if (favlist[TOP_FAVORITE].rs_streams) {
break;
}
/* Delayed favorites list storage. */
if (webradio.wr_favupd && --webradio.wr_favupd == 0) {
FavListSave();
}
/* Reboot? */
if (webradio.wr_reboot) {
webradio.wr_reboot--;
if (webradio.wr_reboot == 0) {
outr(RSTC_CR, RSTC_KEY | RSTC_PROCRST);
}
LogMsg(LOG_WARN, "Reboot in %ds\n", webradio.wr_reboot);
}
/* Still playing? */
rstat = ReceiverStatus(webradio.wr_rip);
if (rstat != ostat) {
if (rstat & (RSTAT_IDLE | RSTAT_STOP)) {
break;
}
UserIfShowStatus(DIST_FORCE);
ostat = rstat;
}
}
UserIfShowStatus(DIST_NONE);
ReceiverStop(webradio.wr_rip);
}
StationDisconnect(webradio.wr_sip);
webradio.wr_sip = NULL;
}
if (favlist[TOP_FAVORITE].rs_streams) {
LogMsg(LOG_STATION, "Selected %s\n", favlist[TOP_FAVORITE].rs_name);
FavListCopy(TOP_FAVORITE, LAST_FAVORITE);
FavListSet(TOP_FAVORITE, NULL, NULL);
stream_idx = 0;
} else {
if (++stream_idx >= favlist[LAST_FAVORITE].rs_streams) {
stream_idx = 0;
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -