webradio/userif.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003-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  */
00034 
00046 #include <cfg/lcd.h>
00047 
00048 #include <stdio.h>
00049 #include <io.h>
00050 #include <stdlib.h>
00051 #include <string.h>
00052 
00053 #include <dev/term.h>
00054 #include <dev/vscodec.h>
00055 
00056 #include <sys/thread.h>
00057 #include <sys/timer.h>
00058 #include <sys/event.h>
00059 
00060 #include <arpa/inet.h>
00061 
00062 #include "config.h"
00063 #include "logmsg.h"
00064 #include "favlist.h"
00065 #include "webradio.h"
00066 #include "shoutcast.h"
00067 #include "xmlserv.h"
00068 #include "buttons.h"
00069 #include "userif.h"
00070 
00071 #ifndef UI_THREAD_STACK
00072 #ifdef AT91SAM7X_EK
00073 #define UI_THREAD_STACK 512
00074 #else
00075 #define UI_THREAD_STACK 2048
00076 #endif
00077 #endif
00078 
00079 #ifndef UI_REFRESH_RATE
00080 #define UI_REFRESH_RATE 300
00081 #endif
00082 
00089 #ifndef LCD_VCOLS
00090 #ifdef AT91SAM7X_EK
00091 #define LCD_VCOLS    40
00092 #else
00093 #define LCD_VCOLS    160
00094 #endif
00095 #endif
00096 
00097 typedef struct {
00099     char dln_status[LCD_VCOLS + 1];
00101     char dln_msg[LCD_VCOLS + 1];
00102 #if USE_DISPLAY || USE_TERM
00103     u_int dln_step;
00104     u_int dln_len;
00105 #endif
00106     u_int dln_msgticks;
00107 } DISPLAYLINE;
00108 
00109 typedef struct {
00110 #if USE_DISPLAY || USE_TERM
00111 
00112     FILE *dpi_stream;
00114     char dpi_buff[LCD_COLS + 1];
00115 #endif
00116     DISPLAYLINE dpi_line[LCD_ROWS];
00117 } DISPLAYINFO;
00118 
00119 static DISPLAYINFO display;
00120 
00121 
00122 #if USE_DISPLAY || USE_TERM
00123 #ifndef LCD_SCROLL_GAP
00124 #define LCD_SCROLL_GAP  (LCD_COLS / 2)
00125 #endif
00126 #endif
00127 
00131 static void DisplayRefresh(void)
00132 {
00133 #if USE_DISPLAY || USE_TERM
00134     u_int ln;
00135     u_int cn;
00136     DISPLAYLINE *dlp;
00137     char *line;
00138 
00139     for (ln = 0; ln < LCD_ROWS; ln++) {
00140         dlp = &display.dpi_line[ln];
00141 
00142         /*
00143          * Determine if we display a message or just the current status.
00144          */
00145         if (dlp->dln_msgticks) {
00146             /* Displaying a message. */
00147             line = dlp->dln_msg;
00148             dlp->dln_msgticks--;
00149         } else {
00150             /* Displaying the status. */
00151             line = dlp->dln_status;
00152         }
00153 
00154         /* 
00155          * Re-initialize scrolling, if the line length changed.
00156          */
00157         if (dlp->dln_len != strlen(line)) {
00158             dlp->dln_len = strlen(line);
00159             dlp->dln_step = 0;
00160         }
00161 
00162         /* Position the cursor. */
00163         fprintf(display.dpi_stream, ESC_POS "%c" "\x20", ln + 32);
00164 
00165         if (dlp->dln_len <= LCD_COLS) {
00166             /* No scrolling required. */
00167             fputs(line, display.dpi_stream);
00168             if (dlp->dln_len < LCD_COLS) {
00169                 fputs(ESC_CLREOL, display.dpi_stream);
00170             }
00171         }
00172         else {
00173             for (cn = 0; cn < LCD_COLS; cn++) {
00174                 if (dlp->dln_step + cn < dlp->dln_len) {
00175                     display.dpi_buff[cn] = line[dlp->dln_step + cn];
00176                 }
00177                 else if (dlp->dln_step + cn < dlp->dln_len + LCD_SCROLL_GAP) {
00178                     display.dpi_buff[cn] = ' ';
00179                 }
00180                 else {
00181                     display.dpi_buff[cn] = line[dlp->dln_step + cn - (dlp->dln_len + LCD_SCROLL_GAP)];
00182                 }
00183             }
00184             fputs(display.dpi_buff, display.dpi_stream);
00185 
00186             /* Update the scroll position counter. */
00187             dlp->dln_step++;
00188             if (dlp->dln_step >= dlp->dln_len + LCD_SCROLL_GAP) {
00189                 dlp->dln_step = 0;
00190             }
00191         }
00192     }
00193 #endif /* USE_DISPLAY */
00194 }
00195 
00201 static void UserIfShowStationConf(RADIOSTATION * scp)
00202 {
00203     display.dpi_line[0].dln_status[0] = 0;
00204     if (scp && scp->rs_name && scp->rs_name[0]) {
00205         strncpy(display.dpi_line[0].dln_status, scp->rs_name, LCD_VCOLS);
00206     }
00207 }
00208 
00216 static void UserIfShowStationInfo(STATIONINFO * sip)
00217 {
00218     display.dpi_line[0].dln_status[0] = 0;
00219     if (sip) {
00220         if (sip->si_name && sip->si_name[0]) {
00221             strncpy(display.dpi_line[0].dln_status, sip->si_name, LCD_VCOLS);
00222         } else {
00223             UserIfShowStationConf(sip->si_scp);
00224         }
00225     }
00226 }
00227 
00228 #if USE_DISPLAY || USE_TERM
00229 
00233 static void UserIfMainMenu(void)
00234 {
00235     char key;
00236     u_int tmocnt = 0;
00237     int want = 0;
00238 
00239     for (;;) {
00240         UserIfShowStationConf(&favlist[want]);
00241         strcpy(display.dpi_line[1].dln_status, "Prev Select Next");
00242         DisplayRefresh();
00243 
00244         /* Read the next button key code. Timeout after 5 seconds. */
00245         if ((key = ButtonRead(UI_REFRESH_RATE)) == 0) {
00246             /* Button timeout. Keep the current station and return from 
00247                main menu. */
00248             if (++tmocnt > 20) {
00249                 want = -1;
00250             }
00251         }
00252         else {
00253             tmocnt = 0;
00254             if (key == KEYCODE_DOWN) {
00255                 /* User pressed the DOWN button. Show the preceding list item. */
00256                 want = FavListSearch(want, -1);
00257             }
00258             else if (key == KEYCODE_UP) {
00259                 /* User pressed the UP button. Show the next list item. */
00260                 want = FavListSearch(want, 1);
00261             }
00262             else if (key == KEYCODE_SELECT) {
00263                 /* User pressed the SELECT key. */
00264                 break;
00265             }
00266         }
00267     }
00268     if (want > 0) {
00269         if (FavListCopy(want, TOP_FAVORITE) == 0) {
00270             UserIfShowMessage(1, 5, "Please wait");
00271         }
00272     }
00273 }
00274 #endif
00275 
00281 THREAD(UserIfThread, arg)
00282 {
00283     char key;
00284 
00285 #if USE_DISPLAY || USE_TERM
00286     fputs(ESC_CURSOROFF, display.dpi_stream);
00287 #endif
00288     NutThreadSetPriority(128);
00289     
00290     for (;;) {
00291         key = ButtonRead(UI_REFRESH_RATE);
00292         if (key == KEYCODE_SELECT) {
00293 #if USE_DISPLAY || USE_TERM
00294             UserIfMainMenu();
00295 #endif
00296         }
00297         else {
00298             if (key) {
00299                 if (key == KEYCODE_DOWN) {
00300                     if (webradio.wr_gain > AUDIO_DAC_MIN_GAIN) {
00301                         webradio.wr_gain--;
00302                     }
00303                 }
00304                 else if (key == KEYCODE_UP) {
00305                     if (webradio.wr_gain < AUDIO_DAC_MAX_GAIN) {
00306                         webradio.wr_gain++;
00307                     }
00308                 }
00309                 UserIfShowMessage(1, 2, "Volume %d dB", webradio.wr_gain);
00310                 webradio.wr_cfgupd = 10;
00311                 if (webradio.wr_rip == NULL || /* */
00312                     webradio.wr_rip->ri_decoder == -1 || /* */
00313                     _ioctl(webradio.wr_rip->ri_decoder, AUDIO_SET_PLAYGAIN, &webradio.wr_gain) != 0) {
00314                         LogMsg(LOG_ERROR, "No volume control\n");
00315                 }
00316                 XmlRefresh();
00317             }
00318             DisplayRefresh();
00319         }
00320     }
00321 }
00322 
00331 void UserIfShowMessage(u_char row, u_char secs, CONST char *fmt, ...)
00332 {
00333     va_list ap;
00334 
00335     va_start(ap, fmt);
00336     if (secs) {
00337         vsprintf(display.dpi_line[row].dln_msg, fmt, ap);
00338         display.dpi_line[row].dln_msgticks = secs * (1000 / UI_REFRESH_RATE);
00339     } else
00340         vsprintf(display.dpi_line[row].dln_status, fmt, ap);
00341     va_end(ap);
00342 }
00343 
00349 void UserIfShowStatus(u_char status)
00350 {
00351     if (webradio.wr_status != status) {
00352         if (status == DIST_FORCE)
00353             status = webradio.wr_status;
00354         else
00355             webradio.wr_status = status;
00356 
00357         if (status == DIST_NONE) {
00358             strcpy(display.dpi_line[0].dln_status, "Internet Radio");
00359             strcpy(display.dpi_line[1].dln_status, "Version ");
00360             strcat(display.dpi_line[1].dln_status, VERSION);
00361         } else if (status == DIST_DEAD) {
00362             UserIfShowStationConf(&favlist[LAST_FAVORITE]);
00363             UserIfShowMessage(1, 2, "Not available");
00364         } else if (status == DIST_CONNECTING) {
00365             UserIfShowStationConf(&favlist[LAST_FAVORITE]);
00366             strcpy(display.dpi_line[1].dln_status, "Connecting...");
00367         } else if (status == DIST_CONNECTED) {
00368             UserIfShowStationInfo(webradio.wr_sip);
00369             display.dpi_line[1].dln_status[0] = '\0';
00370             if (webradio.wr_rip) {
00371                 SHOUTCASTINFO *sci = (SHOUTCASTINFO *) webradio.wr_rip->ri_bcast;
00372                 if (sci) {
00373                     if (sci->sci_metatitle && sci->sci_metatitle[0]) {
00374                         strncpy(display.dpi_line[1].dln_status, sci->sci_metatitle, LCD_VCOLS);
00375                     }
00376                     else if (webradio.wr_sip && webradio.wr_sip->si_genre) {
00377                         strncpy(display.dpi_line[1].dln_status, webradio.wr_sip->si_genre, LCD_VCOLS);
00378                     }
00379                 }
00380             }
00381         }
00382         LogMsg(LOG_USERIF, "Display %d.0 '%s'\n", status, display.dpi_line[0].dln_status);
00383         LogMsg(LOG_USERIF, "Display %d.1 '%s'\n", status, display.dpi_line[1].dln_status);
00384         XmlRefresh();
00385     }
00386 }
00387 
00396 char * UserIfGetDisplayText(char *buff, size_t siz)
00397 {
00398     if (siz) {
00399         siz--;
00400         buff[siz] = '\0';
00401         if (siz) {
00402             if (display.dpi_line[1].dln_msgticks) {
00403 #if (USE_DISPLAY == 0) && (USE_TERM == 0)
00404                 display.dpi_line[1].dln_msgticks = 0;
00405 #endif
00406                 strncpy(buff, display.dpi_line[1].dln_msg, siz);
00407             } else {
00408                 strncpy(buff, display.dpi_line[1].dln_status, siz);
00409                 siz -= strlen(buff);
00410                 if (siz > 4 && display.dpi_line[0].dln_status[0]) {
00411                     strcat(buff, "    ");
00412                     strncpy(buff + strlen(buff), display.dpi_line[0].dln_status, siz - 4);
00413                 }
00414             }
00415         }
00416     }
00417     return buff;
00418 }
00419 
00427 int UserIfInit(char *name)
00428 {
00429     /* Initialize button interface. */
00430     ButtonInit();
00431 
00432 #if USE_DISPLAY
00433     if ((display.dpi_stream = fopen(name, "w")) == 0) {
00434         return -1;
00435     }
00436 #elif USE_TERM
00437     display.dpi_stream = stdout;
00438 #endif
00439 
00440     if (NutThreadCreate("displ", UserIfThread, 0, UI_THREAD_STACK) == 0) {
00441 #if USE_DISPLAY
00442         fclose(display.dpi_stream);
00443 #endif
00444 #if USE_DISPLAY || USE_TERM
00445         display.dpi_stream = NULL;
00446 #endif
00447         return -1;
00448     }
00449     webradio.wr_status = DIST_NONE;
00450     UserIfShowStatus(DIST_FORCE);
00451 
00452     return 0;
00453 }

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