?? yampp3.c
字號(hào):
/*
Copyright (C) 2001 Jesper Hansen <jesperh@telia.com>.
Rewritten by: Nikolai Vorontsov <nickviz@mail.be>
This file is part of the yampp system.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
PIN assignements on test board
PA0-PA7 data bus 0..7 + Address 0..7
PC0-PC7 address 8..15
PB0 T0 DIOW ATA out
PB1 T1 DIOR ATA out
PB2 AIN0 DREQ VS1001 in
PB3 AIN1 BSYNC VS1001 out
PB4 SS MP3 VS1001 out
PB5 MOSI SO VS1001 out
PB6 MISO SI VS1001 in
PB7 SCK SCK VS1001 out
PD0 RxD RS-232 UART in
PD1 TxD RS-232 UART out
PD2 INT0 IR_INPUT IR in
PD3 INT1 KEY_INPUT KEY in
PD4 T0
PD5 T1 LCD_ENABLE LCD out
PD6 WR WR RAM out
PD7 RD RD RAM out
*/
#include <stdlib.h>
#include <io.h>
#include <progmem.h>
#include <eeprom.h>
#include <sig-avr.h>
#include <interrupt.h>
#include <wdt.h>
#include "Constants.h"
#include "types.h"
#include "mem.h"
#include "delay.h"
#include "ata_if.h"
#include "fat.h"
#include "vs1001.h"
#include "rec80.h"
#include "uart.h"
#include "lcd.h"
// Amount of small steps in LCD play position bar
#define LCD_STEPS 50
// Amount of buffers writed before relinquish control
#define MAX_CONS_WRITES 128
typedef enum
{
EV_IDLE,
EV_PLAY,
EV_STOP,
EV_PAUSE,
EV_NEXT,
EV_PREV,
EV_NEXT10,
EV_PREV10,
EV_VOLUP,
EV_VOLDN,
EV_NEUTRAL,
EV_MUTE,
EV_RANDOM,
EV_NEXTL,
EV_PREVL,
EV_LOUDNESS,
EV_LASTEVENT
} event_e;
// Auxilliary functions declarations
void sectordump(u32 sector);
u08* unsigned2str(u16 track, u08 *str);
event_e get_char_event(void);
event_e ir_event(void);
event_e get_key_event(void);
void send_sinewave_beeps(void);
void userchars(void);
void setvolume(u08 v);
void dispbar(void);
bool RetrieveMP3Data(void);
// Global variables
u08 scroll_length = 0;
u08 scroll_pos = 0;
char *scroll_line = 0;
bool bPlaying = false; // Current state - play/stop
u08 *pPlayData = 0; // Pointer to current position in currently
// used buffer
u08 *pPlayBufStart = 0; // Pointer to currenly used buffer
u32 dwPlayed = 0; // Amount of already played bytes
// timer 1 routines
//
// At 8MHz clock : 100 mS divisor 8bit overflow
// tClk = 125 nS 200000 32 uS (31250 Hz)
// tClk/8 = 1 uS 50000 128 uS (7812.5 Hz)
// tClk/64 = 8 uS 12500 512 us (1953.125 Hz)
// tClk/256 = 32 uS 3125 2048 uS
// tClk/1024 = 128 uS 781.25 8192 uS
//
// prescaler set to 32 uS
// 3125 ticks = 100 mS (for 8MHz!)
#define TI1_H (((u16)-(F_CPU / 2560)) >> 8)
#define TI1_L (((u16)-(F_CPU / 2560)) & 0xff )
volatile u08 nDispUpd = 0; // Counter for display update loop
volatile u08 nScrollUpd = 0; // Counter for name scroll loop
volatile u08 nKeyTime = 0; // Counter for keypress time check - Added by MIS
SIGNAL(SIG_OVERFLOW1) // Timer1 overflow every 100 mS
{
nDispUpd++;
nScrollUpd++;
nKeyTime++;
outp(TI1_H, TCNT1H); // Reload timer
outp(TI1_L, TCNT1L);
}
// Random stuff, maximum 65535 songs on the disk!
#define MY_RAND_MAX 65535
static u32 seed = 1;
u16 do_rand(u16 max) // returned random value from 0 to max - 1
{
return ((seed = seed * 1103515245L + 12345) % max);
}
u08 *randstr = "Rand*";
u08 *loudstr = "Loud*";
u08 trackstr[6], *pTrack, timestr[6], tot_sw = 0;
//----------------------------------------------------------------------------
// Main part
//----------------------------------------------------------------------------
int main(void)
{
bool bAutoPlay = true, bRandom = true; // Modificators
bool bLoudness = true; // Modificators
u08 nVolume = 0; // Current volume level
u16 wSongNum = 0; // Current playing song
u16 wPlayTime; // Current play time
u16 wMaxSongs = 1; // Maximum available songs
u08 nWrites, nBursts; // Buffering variables
event_e event = EV_IDLE; // Current event
u08 nTemp, *src, *dst, *pTemp; // Temporary variables
u16 i;
udiv_t divt;
//----------------------------------------------------------------------------
// B - Port
//----------------------------------------------------------------------------
sbi(PORTB, 0); // DIOW- hi
sbi(DDRB, 0); // Pin PB0 is output, DIOW-
sbi(PORTB, 1); // DIOR- hi
sbi(DDRB, 1); // Pin PB1 is output, DIOR-
cbi(DDRB, 2); // Pin PB2 is input, DEMAND
sbi(PORTB, 2); // Activate pullup
// PB3 and PB4 is used for BSYNC and MP3 signals to VS1001
// PB5 (MOSI) is used for SPI
// PB6 (MISO) is used for SPI
// PB7 (SCK) is used for SPI
//----------------------------------------------------------------------------
// D - Port
//----------------------------------------------------------------------------
// PD0 and PD1 are TX and RX signals
// PD2 is used for the IR receiver
cbi(DDRD, 3); // Pin PD3 is keyboard input
// PD4 is available, but activate pullup to aviod noice problem
sbi(PORTD, 4);
// PD5 is LCD_ENABLE used by LCD module
// PD6 and PD7 are RD and WR signals
// but we need to set their default states used
// when the external memory interface is disabled
// they should then both be high to avoid disturbing
// RAM contents
sbi(DDRD, 6); // As outputs
sbi(DDRD, 7);
sbi(PORTD, 6); // And both hi
sbi(PORTD, 7);
//----------------------------------------------------------------------------
// Timer 1
//----------------------------------------------------------------------------
// setup timer1 for a 100mS periodic interrupt
outp(0, TCCR1A);
outp(4, TCCR1B); // Prescaler /256 tPeriod = 32 uS
outp(TI1_H, TCNT1H); // Load counter value hi
outp(TI1_L, TCNT1L); // Load counter value lo
//----------------------------------------------------------------------------
// Initialization
//----------------------------------------------------------------------------
lcd_init(0, LCD_FUNCTION_DEFAULT);
userchars(); // Construct some user definable characters
lcd_clrscr();
lcd_puts(" Hi, MP3 world!\n yampp-3 player");
UART_Init(); // Init RS-232 link
vs1001_init_io(); // Init IO interface for VS1001
vs1001_reset(false); // Init VS1001
init_rec80(); // Set up IR receiver interface
// Say hello to UART
PRINT("\n\nyampp-3 "__DATE__" "__TIME__"\nATA checking...");
ATA_Init(); // Init and wait for drive
ATA_SW_Reset(); // Reset drive
PRINT("done.\n");
#ifdef ENABLE_WATCHDOG // Enable watchdog (enabled by linker option)
wdt_enable(0x07);
#endif
seed = 1 + inp(TCNT1L); // Init randomizer from timer
// (ATA init gives us random delay)
if (!init_fat(DRIVE0)) // Read disk structure
{
lcd_clrscr();
lcd_puts("Wrong disk!");
while (true) WDR; // Lock player
}
PRINT("Scanning...");
// wMaxSongs = dirlist(DIRLIST_VERBOSE);
wMaxSongs = dirlist(DIRLIST_SCAN);
PRINT(unsigned2str(wMaxSongs , trackstr)); // jman number of songs in decimal
PRINT(" entries\n");
nVolume = eeprom_rb(EEPROM_VOLUME); // Load and set initial volume
if (nVolume > MIN_VOLUME)
nVolume = MIN_VOLUME;
setvolume(nVolume);
send_sinewave_beeps(); // Send three sinewave beeps to indicate
// we're starting up okay
// load bAutoPlay and position settings
bAutoPlay = eeprom_rb(EEPROM_AUTOPLAY); // Load autoplay and
bRandom = eeprom_rb(EEPROM_RANDOM); // position settings
wSongNum = eeprom_rw(EEPROM_SONGPOS);
bLoudness = eeprom_rb(EEPROM_LOUDNESS);
// set initial status in the strings
*(randstr+4) = bRandom ? '+' : '-';
*(loudstr+4) = bLoudness ? '+' : '-';
if (bAutoPlay)
event = EV_PLAY;
//----------------------------------------------------------------------------
// start things rolling
//----------------------------------------------------------------------------
sbi(TIMSK, TOIE1); // Enable timer1 interrupt
while (true) // Main loop
{
WDR; // Give watchdog full time
if (UART_HasChar()) // Check all input controls
event = get_char_event();
if (rec80_active())
event = ir_event();
if (event == EV_IDLE)
event = get_key_event();
if (bPlaying && event == EV_PLAY) // second play press does pause
event = EV_PAUSE;
switch (event) // According input control
{
case EV_IDLE:
break;
#ifdef ENABLE_NAV
case EV_PREVL: // Switch to previous start letter
nTemp = nLastPos - 1;
while (nTemp < nLastPos)
if (LetterTable[nTemp].letter < *LONG_NAME)
break;
else
nTemp--;
if (nTemp >= nLastPos)
nTemp = nLastPos - 1;
wSongNum = LetterTable[nTemp].song_num;
goto PLAY;
case EV_NEXTL: // Switch to next start letter
for (nTemp = 1; nTemp < nLastPos; nTemp++)
if (LetterTable[nTemp].letter > *LONG_NAME)
break;
if (nTemp >= nLastPos)
nTemp = 0;
wSongNum = LetterTable[nTemp].song_num;
goto PLAY;
#endif
case EV_PREV10: wSongNum -= 10; goto PLAY;
case EV_NEXT10: wSongNum += 10; goto PLAY;
case EV_PREV:
if (wSongNum == 0)
wSongNum = wMaxSongs - 1;
else
wSongNum--;
goto PLAY;
case EV_NEXT: wSongNum++;
// fall through
case EV_PLAY:
PLAY: lcd_clrscr();
lcd_puts("Loading...");
vs1001_reset(bLoudness); // Mandatory!
if (wSongNum >= wMaxSongs) // Protect for another disk
wSongNum = 0;
eeprom_ww(EEPROM_SONGPOS, wSongNum);
if (!get_dir_entry(wSongNum)) // Setup buffer for play
{
wSongNum = 0; // Something wrong
continue;
}
PRINT("\nPlaying #");
PRINT(pTrack = unsigned2str(wSongNum + 1, trackstr));
UART_SendByte(' '); PRINT(LONG_NAME);
scroll_line = src = LONG_NAME;
scroll_pos = 0;
scroll_length = 4; // To add ' >> ' sign
while (*src++)
scroll_length++;
src--;
// *((u32*)p)++ = 0x207E7F20L;
*((u32*)src)++ = 0x203E3E20L;
*src = 0;
dwPlayed = 0;
nScrollUpd = 0;
nDispUpd = 5;
tot_sw = 10;
ReadBuffer(BUF1); // Preload buffers
if (CheckAndAdvanceCluster()) // Long enough file
ReadBuffer(BUF2);
pPlayData = pPlayBufStart = BUFFER1P;
bPlaying = true;
// Special MP3 header patch to strip all invalid headers
// not needed for VS1001K chip
/* for (i = 0; i < BUFFER_SIZE - 1; i++)
if ((*(u16*)&BUFFER1P[i] & 0xfeff) != 0xfaff)
BUFFER1P[i] = 0;
else
break;
// End of special header patch
*/
break;
case EV_STOP:
bPlaying = false;
lcd_clrscr();
lcd_puts("yampp-3");
break;
case EV_VOLDN:
if (nVolume <= MIN_VOLUME-VOL_STEP)
{
nVolume += VOL_STEP;
setvolume(nVolume);
}
else
setvolume(0xfe);
break;
case EV_VOLUP:
if (nVolume >= VOL_STEP)
nVolume -= VOL_STEP;
setvolume(nVolume);
break;
case EV_NEUTRAL:
nVolume = 12; // -6 dB
setvolume(nVolume);
break;
// case EV_MUTE:
// mute = 1-mute;
// break;
case EV_LOUDNESS:
bLoudness = !bLoudness;
*(loudstr+4) = bLoudness ? '+' : '-';
vs1001_write(VS1001_MODE, 0x0080 * (bLoudness == true)); // write bit SM_BASS to VS1001K
eeprom_wb(EEPROM_LOUDNESS, bLoudness);
nDispUpd = 5;
tot_sw = 14;
break;
case EV_RANDOM:
bRandom = !bRandom;
*(randstr+4) = bRandom ? '+' : '-';
eeprom_wb(EEPROM_RANDOM, bRandom);
nDispUpd = 5;
tot_sw = 12;
break;
//jesper 011207 start
case EV_PAUSE:
event = EV_IDLE;
lcd_gotoxy(10,1);
lcd_puts("Paused");
while (rec80_active()) ; // wait for key release
do
{
WDR; // Give watchdog full time
if (UART_HasChar()) // Check all input controls
event = get_char_event();
if (rec80_active())
event = ir_event();
if (event == EV_IDLE)
event = get_key_event();
} while (event == EV_IDLE);
break;
//jesper 011207 end
default:
break;
} // switch (event)
event = EV_IDLE; // We always go back to IDLE when
// exiting switch
if (bPlaying)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -