⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 userif.c

📁 qt91上实现的mp3播放机,支持sam9260,参考用
💻 C
字号:
/*
 * Copyright (C) 2003-2007 by egnite Software 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 EGNITE SOFTWARE GMBH 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 EGNITE
 * SOFTWARE GMBH 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 config.c
 * \brief User interface.
 *
 * \verbatim
 *
 * $Log$
 *
 * \endverbatim
 */

#include <cfg/lcd.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <dev/term.h>

#include <sys/thread.h>
#include <sys/timer.h>
#include <sys/event.h>

#include <arpa/inet.h>

#include "config.h"
#include "webradio.h"
#include "shoutcast.h"
#include "mp3player.h"
#include "tlv320dac.h"
#include "buttons.h"
#include "userif.h"

/*!
 * \def LCD_VCOLS
 * \brief Number of virtual columns.
 *
 * Contents will be scrolled, if it doesn't fit on a single LCD line.
 */
#ifndef LCD_VCOLS
#ifdef AT91SAM7X_EK
#define LCD_VCOLS    40
#else
#define LCD_VCOLS    80
#endif
#endif

#ifndef LCD_SCROLL_GAP
#define LCD_SCROLL_GAP  (LCD_COLS / 2)
#endif

#ifndef UI_REFRESH_RATE
#define UI_REFRESH_RATE 300
#endif

#ifndef UI_THREAD_STACK
#ifdef AT91SAM7X_EK
#define UI_THREAD_STACK 512
#else
#define UI_THREAD_STACK 2048
#endif
#endif

typedef struct {
    char dln_status[LCD_VCOLS + 1];
    char dln_msg[LCD_VCOLS + 1];
    u_int dln_step;
    u_int dln_len;
    u_int dln_msgticks;
} DISPLAYLINE;

typedef struct {
    FILE *dpi_stream;
    u_int dpi_scrolling;   /*!< . */
    char *dpi_sptr;
    char dpi_buff[LCD_COLS + 1];
    DISPLAYLINE dpi_line[LCD_ROWS];
} DISPLAYINFO;

static DISPLAYINFO display;

/*!
 * \brief Refresh the LCD.
 */
static void DisplayRefresh(void)
{
    u_int ln;
    u_int cn;
    DISPLAYLINE *dlp;
    char *line;

    for (ln = 0; ln < LCD_ROWS; ln++) {
        dlp = &display.dpi_line[ln];

        /*
         * Determine if we display a message or just the current status.
         */
        if (dlp->dln_msgticks) {
            /* Displaying a message. */
            line = dlp->dln_msg;
            dlp->dln_msgticks--;
        } else {
            /* Displaying the status. */
            line = dlp->dln_status;
        }

        /* 
         * Re-initialize scrolling, if the line length changed.
         */
        if (dlp->dln_len != strlen(line)) {
            dlp->dln_len = strlen(line);
            dlp->dln_step = 0;
        }

        /* Position the cursor. */
        fprintf(display.dpi_stream, ESC_POS "%c" "\x20", ln + 32);

        if (dlp->dln_len <= LCD_COLS) {
            /* No scrolling required. */
            fputs(line, display.dpi_stream);
            if (dlp->dln_len < LCD_COLS) {
                fputs(ESC_CLREOL, display.dpi_stream);
            }
        }
        else {
            for (cn = 0; cn < LCD_COLS; cn++) {
                if (dlp->dln_step + cn < dlp->dln_len) {
                    display.dpi_buff[cn] = line[dlp->dln_step + cn];
                }
                else if (dlp->dln_step + cn < dlp->dln_len + LCD_SCROLL_GAP) {
                    display.dpi_buff[cn] = ' ';
                }
                else {
                    display.dpi_buff[cn] = line[dlp->dln_step + cn - (dlp->dln_len + LCD_SCROLL_GAP)];
                }
            }
            fputs(display.dpi_buff, display.dpi_stream);

            /* Update the scroll position counter. */
            dlp->dln_step++;
            if (dlp->dln_step >= dlp->dln_len + LCD_SCROLL_GAP) {
                dlp->dln_step = 0;
            }
        }
    }
}

/*!
 * \brief Displays configured information about a station.
 *
 * \param scp Pointer to the configuration table entry.
 */
static void UserIfShowStationConf(STATIONCONF * scp)
{
    if (scp->rs_port) {
        if (scp->rs_symbol && scp->rs_symbol[0]) {
            strncpy(display.dpi_line[0].dln_status, scp->rs_symbol, LCD_VCOLS);
        } else {
            strncpy(display.dpi_line[0].dln_status, inet_ntoa(scp->rs_ip), LCD_VCOLS);
        }
    } else {
        display.dpi_line[0].dln_status[0] = 0;
    }
}

/*!
 * \brief Displays station information.
 *
 * Called during connect.
 *
 * \param scp Pointer to the configuration table entry.
 */
static void UserIfShowStationInfo(STATIONINFO * sip)
{
    if (sip) {
        if (sip->si_name && sip->si_name[0]) {
            strncpy(display.dpi_line[0].dln_status, sip->si_name, LCD_VCOLS);
        } else {
            UserIfShowStationConf(sip->si_scp);
        }
    } else {
        display.dpi_line[0].dln_status[0] = 0;
    }
}

/*!
 * \brief Main menu processing.
 *
 */
void UserIfMainMenu(void)
{
    char key;
    u_int tmocnt = 0;
    u_char want = radio.rc_cstation;

    for (;;) {
        UserIfShowStationConf(&station[want]);
        strcpy(display.dpi_line[1].dln_status, "Prev Select Next");
        DisplayRefresh();

        /* Read the next button key code. Timeout after 5 seconds. */
        if ((key = ButtonRead(UI_REFRESH_RATE)) == 0) {
            /* Button timeout. Keep the current station and return from 
               main menu. */
            if (++tmocnt > 20) {
                want = radio.rc_cstation;
                break;
            }
        }
        else {
            tmocnt = 0;
            if (key == KEYCODE_DOWN) {
                /* User pressed the DOWN button. Show the preceding list item. */
                want = StationSelect(want, -1);
            }
            else if (key == KEYCODE_UP) {
                /* User pressed the UP button. Show the next list item. */
                want = StationSelect(want, 1);
            }
            else if (key == KEYCODE_SELECT) {
                /* User pressed the SELECT key. */
                break;
            }
        }
    }
    if (want != radio.rc_cstation) {
        UserIfShowMessage(1, 5, "Please wait");
        radio.rc_rstation = want;
    }
}

/*!
 * \brief Background thread for user interface.
 *
 * \param arg Unused. Should be NULL.
 */
THREAD(UserIfThread, arg)
{
    char key;

    fputs(ESC_CURSOROFF, display.dpi_stream);
    NutThreadSetPriority(128);
    
    for (;;) {
        key = ButtonRead(UI_REFRESH_RATE);
        if (key == KEYCODE_SELECT) {
            UserIfMainMenu();
        }
        else {
            if (key) {
                if (key == KEYCODE_DOWN) {
                    if (radio.rc_rvolume > DAC_MIN_VOLUME) {
                        radio.rc_rvolume--;
                    }
                }
                else if (key == KEYCODE_UP) {
                    if (radio.rc_rvolume < DAC_MAX_VOLUME) {
                        radio.rc_rvolume++;
                    }
                }
                UserIfShowMessage(1, 2, "Volume %d dB", radio.rc_rvolume);            }
            DisplayRefresh();
        }
    }
}

/*!
 * \brief Display a specified text.
 *
 * \param row  Row position of the message.
 * \param secs Number of seconds to display the message. Set to 0 for
 *             permanent display.
 * \param fmt  Format string containing conversion specifications.
 */
void UserIfShowMessage(u_char row, u_char secs, CONST char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    if (secs) {
        vsprintf(display.dpi_line[row].dln_msg, fmt, ap);
        display.dpi_line[row].dln_msgticks = secs * (1000 / UI_REFRESH_RATE);
    } else
        vsprintf(display.dpi_line[row].dln_status, fmt, ap);
    va_end(ap);
}

/*!
 * \brief Display a specified status.
 *
 * \param status Status to be displayed.
 */
void UserIfShowStatus(u_char status)
{
    if (radio.rc_cstatus != status) {
        if (status == DIST_FORCE)
            status = radio.rc_cstatus;
        else
            radio.rc_cstatus = status;

        if (status == DIST_NONE) {
            strcpy(display.dpi_line[0].dln_status, "Internet Radio");
            strcpy(display.dpi_line[1].dln_status, "Version ");
            strcat(display.dpi_line[1].dln_status, VERSION);
        } else if (status == DIST_DEAD) {
            UserIfShowStationConf(&station[radio.rc_cstation]);
            UserIfShowMessage(1, 2, "not available");
        } else if (status == DIST_CONNECTING) {
            UserIfShowStationConf(&station[radio.rc_cstation]);
            strcpy(display.dpi_line[1].dln_status, "Connecting...");
        } else if (status == DIST_CONNECTED) {
            UserIfShowStationInfo(radio.rc_sip);
            if (radio.rc_rip) {
                SHOUTCASTINFO *sci = (SHOUTCASTINFO *) radio.rc_rip->ri_bcast;
                if (sci) {
                    if (sci->sci_metatitle && sci->sci_metatitle[0]) {
                        strncpy(display.dpi_line[1].dln_status, sci->sci_metatitle, LCD_VCOLS);
                    }
                    else if (radio.rc_sip && radio.rc_sip->si_genre && radio.rc_sip->si_genre[0]) {
                        strncpy(display.dpi_line[1].dln_status, radio.rc_sip->si_genre, LCD_VCOLS);
                    }
                }
            }
        }
    }
}

/*!
 * \brief Start background thread for display updates.
 *
 * \param name Display device name.
 *
 * \return 0 on success or -1 in case of a failure.
 */
int UserIfInit(char *name)
{
    /* Initialize button interface. */
    ButtonInit();

    if ((display.dpi_stream = fopen(name, "w")) == 0) {
        return -1;
    }
    display.dpi_scrolling = LCD_ROWS;

    if (NutThreadCreate("displ", UserIfThread, 0, UI_THREAD_STACK) == 0) {
        fclose(display.dpi_stream);
        display.dpi_stream = NULL;
        return -1;
    }
    radio.rc_cstatus = DIST_NONE;
    UserIfShowStatus(DIST_FORCE);

    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -