nutpiper.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*
  2. * Copyright (C) 2003-2006 by egnite Software GmbH
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. */
  34. /*!
  35. * $Id: nutpiper.c 4640 2012-09-24 12:05:56Z u_bonnes $
  36. */
  37. /*!
  38. * \example nutpiper/nutpiper.c
  39. *
  40. * Shoutcast radio application..
  41. */
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <stdio.h>
  45. #include <io.h>
  46. #include <dev/board.h>
  47. #include <dev/debug.h>
  48. #include <dev/term.h>
  49. #include <dev/hd44780.h>
  50. #include <dev/vs1001k.h>
  51. #ifdef ETHERNUT2
  52. #include <dev/lanc111.h>
  53. #else
  54. #include <dev/nicrtl.h>
  55. #endif
  56. #include <sys/heap.h>
  57. #include <sys/thread.h>
  58. #include <sys/timer.h>
  59. #include <netinet/tcp.h>
  60. #include <arpa/inet.h>
  61. #include <net/route.h>
  62. #include <pro/dhcp.h>
  63. #include <sys/bankmem.h>
  64. #include <dev/irsony.h>
  65. #include "config.h"
  66. #include "display.h"
  67. #include "scanner.h"
  68. #include "player.h"
  69. #if defined(__AVR__)
  70. /*
  71. * TCP buffer size.
  72. */
  73. static uint16_t tcpbufsiz = 4288;
  74. /*
  75. * Maximum segment size, choose 536 up to 1460. Note, that segment
  76. * sizes above 536 may result in fragmented packets. Remember, that
  77. * Ethernut doesn't support TCP fragmentation.
  78. */
  79. static uint16_t mss = 536;
  80. /*
  81. * Socket receive timeout.
  82. */
  83. static uint32_t rx_to = 1000;
  84. /*
  85. * Connect to a radio station.
  86. */
  87. static TCPSOCKET *ConnectStation(RADIOSTATION * rsp)
  88. {
  89. TCPSOCKET *sock;
  90. int rc;
  91. /* Create a socket. TODO: A failure is fatal and should restart
  92. the system. */
  93. if ((sock = NutTcpCreateSocket()) == 0)
  94. return sock;
  95. /* Set socket options. Failures are ignored. */
  96. if (NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss)))
  97. printf("Sockopt MSS failed\n");
  98. if (NutTcpSetSockOpt(sock, SO_RCVTIMEO, &rx_to, sizeof(rx_to)))
  99. printf("Sockopt TO failed\n");
  100. if (NutTcpSetSockOpt(sock, SO_RCVBUF, &tcpbufsiz, sizeof(tcpbufsiz)))
  101. printf("Sockopt rxbuf failed\n");
  102. /* Connect the stream server. */
  103. printf("[CNCT %s:%u]", inet_ntoa(rsp->rs_ip), rsp->rs_port);
  104. if ((rc = NutTcpConnect(sock, rsp->rs_ip, rsp->rs_port)) == 0) {
  105. printf("[CNCTD]");
  106. /* Process header from server. */
  107. if (ScanStreamHeader(sock, rsp) == 0) {
  108. /* TODO: Failed to start the player is fatal. */
  109. if (PlayerStart(sock, rsp->rs_metaint, 30000)) {
  110. NutTcpCloseSocket(sock);
  111. sock = 0;
  112. }
  113. } else {
  114. NutTcpCloseSocket(sock);
  115. sock = 0;
  116. }
  117. } else {
  118. printf("[CERR=%d]\n", NutTcpError(sock));
  119. NutTcpCloseSocket(sock);
  120. sock = 0;
  121. }
  122. return sock;
  123. }
  124. /*
  125. * Disconnect from a radio station.
  126. */
  127. static void DisconnectStation(TCPSOCKET * sock)
  128. {
  129. if (PlayerStop(3000)) {
  130. printf("[PPFAIL]");
  131. }
  132. printf("Disconnecting\n");
  133. NutTcpCloseSocket(sock);
  134. }
  135. /*
  136. * Get next command from user interface.
  137. *
  138. * We are supporting the remote control only for now.
  139. */
  140. #ifdef ARTHERNET1
  141. static uint16_t UserInput(void)
  142. {
  143. /* IR will not work on Arthernet, because interrupt 5
  144. is in use and can't be re-configured in the IR driver. */
  145. return 0xFFFF;
  146. }
  147. #else /* ARTHERNET1 */
  148. static uint16_t UserInput(void)
  149. {
  150. uint16_t rc;
  151. static uint16_t old = 0xFFFF;
  152. if ((rc = (uint16_t) NutIrGet(500)) == 0xFFFF)
  153. old = rc;
  154. else if (rc == old || (rc >> 7) != IR_DEVICE)
  155. rc = 0xFFFF;
  156. else {
  157. old = rc;
  158. rc &= 0x7F;
  159. if (rc == IRCMD_VOL_UP || rc == IRCMD_VOL_DN)
  160. old = 0xFFFF;
  161. }
  162. return rc;
  163. }
  164. #endif /* ARTHERNET1 */
  165. /*
  166. * If we got a background scanner
  167. */
  168. static void StationList(void)
  169. {
  170. uint8_t cf = 1;
  171. uint8_t rs = radio.rc_cstation;
  172. uint16_t ircode;
  173. DisplayMessage(0, 1, "Stations");
  174. DisplayEntry(rs);
  175. while (cf) {
  176. /*
  177. * Process user input.
  178. */
  179. if ((ircode = UserInput()) != 0xFFFF) {
  180. switch (ircode) {
  181. case IRCMD_CHAN_UP:
  182. if (++rs >= MAXNUM_STATIONS)
  183. rs = 0;
  184. DisplayEntry(rs);
  185. break;
  186. case IRCMD_CHAN_DN:
  187. if (rs)
  188. rs--;
  189. else
  190. rs = MAXNUM_STATIONS - 1;
  191. DisplayEntry(rs);
  192. break;
  193. case IRCMD_SELECT:
  194. radio.rc_rstation = rs;
  195. default:
  196. cf = 0;
  197. break;
  198. }
  199. }
  200. }
  201. DisplayStatus(DIST_FORCE);
  202. }
  203. /*!
  204. * \brief Loop for user input and update display.
  205. */
  206. static void UserInterface(void)
  207. {
  208. uint8_t ief;
  209. uint16_t ircode;
  210. TCPSOCKET *sock = 0;
  211. for (;;) {
  212. /*
  213. * Process user input.
  214. */
  215. if ((ircode = UserInput()) != 0xFFFF) {
  216. radio.rc_off = 0;
  217. switch (ircode) {
  218. case IRCMD_CHAN_1:
  219. radio.rc_rstation = 1;
  220. break;
  221. case IRCMD_CHAN_2:
  222. radio.rc_rstation = 2;
  223. break;
  224. case IRCMD_CHAN_3:
  225. radio.rc_rstation = 3;
  226. break;
  227. case IRCMD_CHAN_4:
  228. radio.rc_rstation = 4;
  229. break;
  230. case IRCMD_CHAN_5:
  231. radio.rc_rstation = 5;
  232. break;
  233. case IRCMD_CHAN_6:
  234. radio.rc_rstation = 6;
  235. break;
  236. case IRCMD_CHAN_7:
  237. radio.rc_rstation = 7;
  238. break;
  239. case IRCMD_CHAN_8:
  240. radio.rc_rstation = 8;
  241. break;
  242. case IRCMD_CHAN_9:
  243. radio.rc_rstation = 9;
  244. break;
  245. case IRCMD_CHAN_UP:
  246. radio.rc_rstation = NEXT_STATION;
  247. break;
  248. case IRCMD_CHAN_DN:
  249. radio.rc_rstation = PREV_STATION;
  250. break;
  251. case IRCMD_VOL_UP:
  252. player.psi_start = 1;
  253. if (radio.rc_rvolume < 245)
  254. radio.rc_rvolume += 10;
  255. break;
  256. case IRCMD_VOL_DN:
  257. player.psi_start = 1;
  258. if (radio.rc_rvolume > 10)
  259. radio.rc_rvolume -= 10;
  260. break;
  261. case IRCMD_MUTE:
  262. radio.rc_rmute = !radio.rc_rmute;
  263. break;
  264. case IRCMD_OFF:
  265. radio.rc_off = 1;
  266. DisplayMessage(0, 0, "Shutdown...");
  267. DisplayMessage(1, 0, "");
  268. PlayerStop(1000);
  269. ConfigSave();
  270. radio.rc_cstation = PREV_STATION;
  271. DisplayMessage(0, 0, "");
  272. break;
  273. case IRCMD_VTEXT:
  274. StationList();
  275. break;
  276. default:
  277. DisplayMessage(0, 1, "Code %u", ircode);
  278. ief = VsPlayerInterrupts(0);
  279. printf("%lu kBytes used, %lu kBytes free\n", NutSegBufUsed() / 1024UL, NutSegBufAvailable() / 1024UL);
  280. VsPlayerInterrupts(ief);
  281. break;
  282. }
  283. }
  284. if (radio.rc_off) {
  285. NutSleep(500);
  286. continue;
  287. }
  288. /*
  289. * Handle station changes.
  290. */
  291. if (radio.rc_rstation != radio.rc_cstation) {
  292. /* Disconnect current stream. */
  293. if (sock) {
  294. DisconnectStation(sock);
  295. sock = 0;
  296. }
  297. /* If scanning, move to the next/previous station. */
  298. if (radio.rc_rstation == NEXT_STATION) {
  299. if (++radio.rc_cstation >= MAXNUM_STATIONS)
  300. radio.rc_rstation = 0;
  301. } else if (radio.rc_rstation == PREV_STATION) {
  302. if (radio.rc_cstation)
  303. radio.rc_cstation--;
  304. else
  305. radio.rc_cstation = MAXNUM_STATIONS - 1;
  306. } else {
  307. radio.rc_cstation = radio.rc_rstation;
  308. }
  309. DisplayMessage(0, 1, "Station %03u", radio.rc_cstation);
  310. /* Check for valid IP address and port. */
  311. if (station[radio.rc_cstation].rs_ip && station[radio.rc_cstation].rs_port) {
  312. if (station[radio.rc_cstation].rs_scandead) {
  313. DisplayStatus(DIST_DEAD);
  314. } else {
  315. DisplayStatus(DIST_CONNECTING);
  316. if ((sock = ConnectStation(&station[radio.rc_cstation])) != 0) {
  317. radio.rc_rstation = radio.rc_cstation;
  318. DisplayStatus(DIST_CONNECTED);
  319. } else {
  320. DisplayStatus(DIST_DEAD);
  321. }
  322. }
  323. } else {
  324. DisplayStatus(DIST_DEAD);
  325. }
  326. } else if (radio.rc_cmute != radio.rc_rmute) {
  327. radio.rc_cmute = radio.rc_rmute;
  328. if (radio.rc_cmute) {
  329. DisplayMessage(0, 1, "Mute");
  330. VsSetVolume(255, 255);
  331. } else {
  332. DisplayMessage(0, 1, "Volume %u", radio.rc_cvolume);
  333. VsSetVolume(255 - radio.rc_cvolume, 255 - radio.rc_cvolume);
  334. }
  335. } else if (radio.rc_cvolume != radio.rc_rvolume) {
  336. DisplayMessage(0, 1, "Volume %u", radio.rc_rvolume);
  337. VsSetVolume(255 - radio.rc_rvolume, 255 - radio.rc_rvolume);
  338. radio.rc_cvolume = radio.rc_rvolume;
  339. radio.rc_rmute = 0;
  340. } else if (player.psi_metaupdate) {
  341. DisplayStatus(DIST_FORCE);
  342. player.psi_metaupdate = 0;
  343. }
  344. }
  345. }
  346. #endif /* __AVR__ */
  347. /*
  348. * Main entry of the Internet Radio Application.
  349. */
  350. int main(void)
  351. {
  352. #if defined(__AVR__)
  353. /* Unique MAC address of the Ethernut Board. */
  354. uint8_t mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x00 };
  355. /* Unique IP address of the Ethernut Board. Ignored if DHCP is used. */
  356. uint32_t ip_addr = inet_addr("192.168.192.100");
  357. /* IP network mask of the Ethernut Board. Ignored if DHCP is used. */
  358. uint32_t ip_mask = inet_addr("255.255.255.0");
  359. /* Gateway IP address for the Ethernut Board. Ignored if DHCP is used. */
  360. uint32_t ip_gate = inet_addr("192.168.192.3");
  361. /* Baudrate for debug output. */
  362. #endif
  363. uint32_t baud = 115200;
  364. /*
  365. * Assign stdout to the debug device.
  366. */
  367. NutRegisterDevice(&DEV_CONSOLE, 0, 0);
  368. freopen(DEV_CONSOLE.dev_name, "w", stdout);
  369. _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
  370. /*
  371. * Load configuration and display banner.
  372. */
  373. if (ConfigLoad())
  374. ConfigResetFactory();
  375. #if defined(__AVR__)
  376. /*
  377. * Initialize the MP3 device early to avoid noice, caused
  378. * by floating, tri-stated port lines.
  379. */
  380. if (NutSegBufInit(8192) == 0) {
  381. printf("Can't init segbuf\n");
  382. for (;;);
  383. }
  384. PlayerInit();
  385. /*
  386. * Initialize the LCD.
  387. */
  388. NutRegisterDevice(&devLcd, 0, 0);
  389. if (DisplayInit("lcd")) {
  390. printf("Display failure\n");
  391. for (;;);
  392. }
  393. #ifndef ARTHERNET1
  394. /*
  395. * Initialize IR remote control.
  396. * This will not work on Arthernet, because interrupt 5
  397. * is in use and can't be re-configured in the IR driver.
  398. */
  399. NutIrInitSony();
  400. #endif
  401. /*
  402. * LAN configuration using EEPROM values or DHCP/ARP method.
  403. * If it fails, use fixed values.
  404. */
  405. if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5))
  406. puts("Registering device failed");
  407. if (NutDhcpIfConfig("eth0", 0, 60000)) {
  408. puts("EEPROM/DHCP/ARP config failed");
  409. NutNetIfConfig("eth0", mac, ip_addr, ip_mask);
  410. NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER);
  411. }
  412. puts("ready\n");
  413. VsSetVolume(255 - radio.rc_rvolume, 255 - radio.rc_rvolume);
  414. VsBeep(2, 100);
  415. /*
  416. * Start the background scanner.
  417. */
  418. //ScannerInit();
  419. /*
  420. * Call the user interface..
  421. */
  422. for (;;) {
  423. UserInterface();
  424. }
  425. #endif /* __AVR__ */
  426. for (;;)
  427. NutSleep(1000);
  428. return 0;
  429. }