Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

userif.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003-2007 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00045 #include <cfg/lcd.h>
00046 
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 #include <string.h>
00050 
00051 #include <dev/term.h>
00052 
00053 #include <sys/thread.h>
00054 #include <sys/timer.h>
00055 #include <sys/event.h>
00056 
00057 #include <arpa/inet.h>
00058 
00059 #include "config.h"
00060 #include "webradio.h"
00061 #include "shoutcast.h"
00062 #include "mp3player.h"
00063 #include "tlv320dac.h"
00064 #include "buttons.h"
00065 #include "userif.h"
00066 
00073 #ifndef LCD_VCOLS
00074 #ifdef AT91SAM7X_EK
00075 #define LCD_VCOLS    40
00076 #else
00077 #define LCD_VCOLS    80
00078 #endif
00079 #endif
00080 
00081 #ifndef LCD_SCROLL_GAP
00082 #define LCD_SCROLL_GAP  (LCD_COLS / 2)
00083 #endif
00084 
00085 #ifndef UI_REFRESH_RATE
00086 #define UI_REFRESH_RATE 300
00087 #endif
00088 
00089 #ifndef UI_THREAD_STACK
00090 #ifdef AT91SAM7X_EK
00091 #define UI_THREAD_STACK 512
00092 #else
00093 #define UI_THREAD_STACK 2048
00094 #endif
00095 #endif
00096 
00097 typedef struct {
00098     char dln_status[LCD_VCOLS + 1];
00099     char dln_msg[LCD_VCOLS + 1];
00100     u_int dln_step;
00101     u_int dln_len;
00102     u_int dln_msgticks;
00103 } DISPLAYLINE;
00104 
00105 typedef struct {
00106     FILE *dpi_stream;
00107     u_int dpi_scrolling;   
00108     char *dpi_sptr;
00109     char dpi_buff[LCD_COLS + 1];
00110     DISPLAYLINE dpi_line[LCD_ROWS];
00111 } DISPLAYINFO;
00112 
00113 static DISPLAYINFO display;
00114 
00118 static void DisplayRefresh(void)
00119 {
00120     u_int ln;
00121     u_int cn;
00122     DISPLAYLINE *dlp;
00123     char *line;
00124 
00125     for (ln = 0; ln < LCD_ROWS; ln++) {
00126         dlp = &display.dpi_line[ln];
00127 
00128         /*
00129          * Determine if we display a message or just the current status.
00130          */
00131         if (dlp->dln_msgticks) {
00132             /* Displaying a message. */
00133             line = dlp->dln_msg;
00134             dlp->dln_msgticks--;
00135         } else {
00136             /* Displaying the status. */
00137             line = dlp->dln_status;
00138         }
00139 
00140         /* 
00141          * Re-initialize scrolling, if the line length changed.
00142          */
00143         if (dlp->dln_len != strlen(line)) {
00144             dlp->dln_len = strlen(line);
00145             dlp->dln_step = 0;
00146         }
00147 
00148         /* Position the cursor. */
00149         fprintf(display.dpi_stream, ESC_POS "%c" "\x20", ln + 32);
00150 
00151         if (dlp->dln_len <= LCD_COLS) {
00152             /* No scrolling required. */
00153             fputs(line, display.dpi_stream);
00154             if (dlp->dln_len < LCD_COLS) {
00155                 fputs(ESC_CLREOL, display.dpi_stream);
00156             }
00157         }
00158         else {
00159             for (cn = 0; cn < LCD_COLS; cn++) {
00160                 if (dlp->dln_step + cn < dlp->dln_len) {
00161                     display.dpi_buff[cn] = line[dlp->dln_step + cn];
00162                 }
00163                 else if (dlp->dln_step + cn < dlp->dln_len + LCD_SCROLL_GAP) {
00164                     display.dpi_buff[cn] = ' ';
00165                 }
00166                 else {
00167                     display.dpi_buff[cn] = line[dlp->dln_step + cn - (dlp->dln_len + LCD_SCROLL_GAP)];
00168                 }
00169             }
00170             fputs(display.dpi_buff, display.dpi_stream);
00171 
00172             /* Update the scroll position counter. */
00173             dlp->dln_step++;
00174             if (dlp->dln_step >= dlp->dln_len + LCD_SCROLL_GAP) {
00175                 dlp->dln_step = 0;
00176             }
00177         }
00178     }
00179 }
00180 
00186 static void UserIfShowStationConf(STATIONCONF * scp)
00187 {
00188     if (scp->rs_port) {
00189         if (scp->rs_symbol && scp->rs_symbol[0]) {
00190             strncpy(display.dpi_line[0].dln_status, scp->rs_symbol, LCD_VCOLS);
00191         } else {
00192             strncpy(display.dpi_line[0].dln_status, inet_ntoa(scp->rs_ip), LCD_VCOLS);
00193         }
00194     } else {
00195         display.dpi_line[0].dln_status[0] = 0;
00196     }
00197 }
00198 
00206 static void UserIfShowStationInfo(STATIONINFO * sip)
00207 {
00208     if (sip) {
00209         if (sip->si_name && sip->si_name[0]) {
00210             strncpy(display.dpi_line[0].dln_status, sip->si_name, LCD_VCOLS);
00211         } else {
00212             UserIfShowStationConf(sip->si_scp);
00213         }
00214     } else {
00215         display.dpi_line[0].dln_status[0] = 0;
00216     }
00217 }
00218 
00223 void UserIfMainMenu(void)
00224 {
00225     char key;
00226     u_int tmocnt = 0;
00227     u_char want = radio.rc_cstation;
00228 
00229     for (;;) {
00230         UserIfShowStationConf(&station[want]);
00231         strcpy(display.dpi_line[1].dln_status, "Prev Select Next");
00232         DisplayRefresh();
00233 
00234         /* Read the next button key code. Timeout after 5 seconds. */
00235         if ((key = ButtonRead(UI_REFRESH_RATE)) == 0) {
00236             /* Button timeout. Keep the current station and return from 
00237                main menu. */
00238             if (++tmocnt > 20) {
00239                 want = radio.rc_cstation;
00240                 break;
00241             }
00242         }
00243         else {
00244             tmocnt = 0;
00245             if (key == KEYCODE_DOWN) {
00246                 /* User pressed the DOWN button. Show the preceding list item. */
00247                 want = StationSelect(want, -1);
00248             }
00249             else if (key == KEYCODE_UP) {
00250                 /* User pressed the UP button. Show the next list item. */
00251                 want = StationSelect(want, 1);
00252             }
00253             else if (key == KEYCODE_SELECT) {
00254                 /* User pressed the SELECT key. */
00255                 break;
00256             }
00257         }
00258     }
00259     if (want != radio.rc_cstation) {
00260         UserIfShowMessage(1, 5, "Please wait");
00261         radio.rc_rstation = want;
00262     }
00263 }
00264 
00270 THREAD(UserIfThread, arg)
00271 {
00272     char key;
00273 
00274     fputs(ESC_CURSOROFF, display.dpi_stream);
00275     NutThreadSetPriority(128);
00276     
00277     for (;;) {
00278         key = ButtonRead(UI_REFRESH_RATE);
00279         if (key == KEYCODE_SELECT) {
00280             UserIfMainMenu();
00281         }
00282         else {
00283             if (key) {
00284                 if (key == KEYCODE_DOWN) {
00285                     if (radio.rc_rvolume > DAC_MIN_VOLUME) {
00286                         radio.rc_rvolume--;
00287                     }
00288                 }
00289                 else if (key == KEYCODE_UP) {
00290                     if (radio.rc_rvolume < DAC_MAX_VOLUME) {
00291                         radio.rc_rvolume++;
00292                     }
00293                 }
00294                 UserIfShowMessage(1, 2, "Volume %d dB", radio.rc_rvolume);
00295             }
00296             DisplayRefresh();
00297         }
00298     }
00299 }
00300 
00309 void UserIfShowMessage(u_char row, u_char secs, CONST char *fmt, ...)
00310 {
00311     va_list ap;
00312 
00313     va_start(ap, fmt);
00314     if (secs) {
00315         vsprintf(display.dpi_line[row].dln_msg, fmt, ap);
00316         display.dpi_line[row].dln_msgticks = secs * (1000 / UI_REFRESH_RATE);
00317     } else
00318         vsprintf(display.dpi_line[row].dln_status, fmt, ap);
00319     va_end(ap);
00320 }
00321 
00327 void UserIfShowStatus(u_char status)
00328 {
00329     if (radio.rc_cstatus != status) {
00330         if (status == DIST_FORCE)
00331             status = radio.rc_cstatus;
00332         else
00333             radio.rc_cstatus = status;
00334 
00335         if (status == DIST_NONE) {
00336             strcpy(display.dpi_line[0].dln_status, "Internet Radio");
00337             strcpy(display.dpi_line[1].dln_status, "Version ");
00338             strcat(display.dpi_line[1].dln_status, VERSION);
00339         } else if (status == DIST_DEAD) {
00340             UserIfShowStationConf(&station[radio.rc_cstation]);
00341             UserIfShowMessage(1, 2, "not available");
00342         } else if (status == DIST_CONNECTING) {
00343             UserIfShowStationConf(&station[radio.rc_cstation]);
00344             strcpy(display.dpi_line[1].dln_status, "Connecting...");
00345         } else if (status == DIST_CONNECTED) {
00346             UserIfShowStationInfo(radio.rc_sip);
00347             if (radio.rc_rip) {
00348                 SHOUTCASTINFO *sci = (SHOUTCASTINFO *) radio.rc_rip->ri_bcast;
00349                 if (sci) {
00350                     if (sci->sci_metatitle && sci->sci_metatitle[0]) {
00351                         strncpy(display.dpi_line[1].dln_status, sci->sci_metatitle, LCD_VCOLS);
00352                     }
00353                     else if (radio.rc_sip && radio.rc_sip->si_genre && radio.rc_sip->si_genre[0]) {
00354                         strncpy(display.dpi_line[1].dln_status, radio.rc_sip->si_genre, LCD_VCOLS);
00355                     }
00356                 }
00357             }
00358         }
00359     }
00360 }
00361 
00369 int UserIfInit(char *name)
00370 {
00371     /* Initialize button interface. */
00372     ButtonInit();
00373 
00374     if ((display.dpi_stream = fopen(name, "w")) == 0) {
00375         return -1;
00376     }
00377     display.dpi_scrolling = LCD_ROWS;
00378 
00379     if (NutThreadCreate("displ", UserIfThread, 0, UI_THREAD_STACK) == 0) {
00380         fclose(display.dpi_stream);
00381         display.dpi_stream = NULL;
00382         return -1;
00383     }
00384     radio.rc_cstatus = DIST_NONE;
00385     UserIfShowStatus(DIST_FORCE);
00386 
00387     return 0;
00388 }

Generated on Fri Feb 23 17:28:49 2007 for SAM Internet Radio by  doxygen 1.4.4