📄 yampp3.c
字号:
/*
Copyright (C) 2001 Jesper Hansen <jesperh@telia.com>.
Rewritten by: Nikolai Vorontsov <nickviz@mail.be>
Rewritten by: Romuald Bialy (aka MIS) <romek_b@o2.pl>
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
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 <string.h>
#include "Constants.h"
#include "types.h"
#include "mem.h"
#include "delay.h"
#include "ata_if.h"
#include "fat.h"
#include "vs1001.h"
#include "remote.h"
#include "uart.h"
#include "lcd.h"
// Amount of small steps in LCD play position bar
#ifdef PROGRESBAR_II
#if (LCD_LINES == 2)
#define LCD_STEPS ((LCD_LINE_LENGTH - 7 - 2*(LCD_LINE_LENGTH != 16)) * 5)
#else
#define LCD_STEPS ((LCD_LINE_LENGTH - 6) * 5)
#endif
#else //PROGRESBAR_II
#if (LCD_LINES == 2)
#define LCD_STEPS ((LCD_LINE_LENGTH - 6) * 5)
#else
#define LCD_STEPS ((LCD_LINE_LENGTH - 5) * 5)
#endif
#endif //PROGRESBAR_II
// Amount of buffers writed before relinquish control
#define MAX_CONS_WRITES 100
#define EV_IDLE 0
#define EV_PLAY 1
#define EV_STOP 2
#define EV_NEXT 3
#define EV_PREV 4
#define EV_NEXT10 5
#define EV_PREV10 6
#define EV_VOLUP 7
#define EV_VOLDN 8
#define EV_NEXTD 9
#define EV_PREVD 10
#define EV_FFWD 11
#define EV_FREW 12
#define EV_LOUDNESS 13
#define EV_RANDOM 14
#define EV_REMAIN 15
#define EV_NEXTL 16
#define EV_PREVL 17
#define EV_NUMBER 18
#define EV_PAUSE 19
// Auxilliary functions declarations
void sectordump(u32 sector);
u08* unsigned2str(u16 track, u08 *str);
u08 get_char_event(void);
u08 ir_event(void);
u08 get_key_event(void);
void setvolume(u08 v);
void dispbar(void);
u16 Numb2Int(void);
void BadHeadStrip(void);
u08 get_char_event(void);
void send_sinewave_beeps(void);
#ifdef PROGRESBAR_II
void lcd_frame(void);
#else
#define lcd_frame()
#endif
// Global variables
u08 scroll_length;
u08 scroll_pos;
char *scroll_line;
u08 LastEvent = EV_IDLE;
#if (LCD_LINES == 4) && (defined DIR_SCROLL)
u08 dir_scroll_length;
u08 dir_scroll_pos;
char *dir_scroll_line;
#endif
bool bPlaying; // Current state - play/stop
u08 *pPlayData; // Pointer to current position in currently used buffer
u08 *pUpdBuf; // Pointer to buffer need updating
u32 dwPlayed; // Amount of already played blocks (32 bytes)
u16 wBackStepPos; // Actual position in backstep tabele
u16 wSongNum; // Current playing song
u16 wMaxSongs = 1; // Maximum available songs
#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 nKeyTime = 0; // Counter for keypress time check - Added by MIS
#ifdef OLD_VS1001
volatile u16 wPlayT = 0; // Play Time counter for older VS1001 chips
#endif
SIGNAL(SIG_OVERFLOW1) // Timer1 overflow every 100 mS
{
nDispUpd++;
nKeyTime++;
#ifdef OLD_VS1001
wPlayT++;
#endif
outp(TI1_H, TCNT1H); // Reload timer
outp(TI1_L, TCNT1L);
}
#ifndef SETUP_REMOTE_CODES
// Random stuff, maximum 65535 songs on the disk!
static u32 seed = 1;
static u16 wFirstInDir = 0;
// Init randomize table
void InitRnd(void)
{
u16 Temp;
for (Temp = 0; Temp < (wMaxSongs >> 3); Temp++)
RANDOM_TAB[Temp] = 0; // one bit in table represent one song
RANDOM_TAB[Temp] = (0xff << (wMaxSongs % 8)); // last byte.
}
u16 randcalc(u16 max) // assembler optimized randomizer function
{
// return ((seed = seed * 1103515245L + 12345) % max); // get new song number
asm volatile ("push r24");
asm volatile ("push r25");
asm volatile ("lds r22,seed");
asm volatile ("lds r23,(seed)+1");
asm volatile ("lds r24,(seed)+2");
asm volatile ("lds r25,(seed)+3");
asm volatile ("ldi r18,lo8(1103515245)");
asm volatile ("ldi r19,hi8(1103515245)");
asm volatile ("ldi r20,hlo8(1103515245)");
asm volatile ("ldi r21,hhi8(1103515245)");
#ifdef YAMPP3USB
asm volatile ("call __mulsi3");
#else
asm volatile ("rcall __mulsi3");
#endif
asm volatile ("subi r22,lo8(-(12345))");
asm volatile ("sbci r23,hi8(-(12345))");
asm volatile ("sbci r24,hlo8(-(12345))");
asm volatile ("sbci r25,hhi8(-(12345))");
asm volatile ("sts seed,r22");
asm volatile ("sts (seed)+1,r23");
asm volatile ("sts (seed)+2,r24");
asm volatile ("sts (seed)+3,r25");
asm volatile ("pop r19");
asm volatile ("pop r18");
asm volatile ("clr r20");
asm volatile ("clr r21");
#ifdef YAMPP3USB
asm volatile ("call __udivmodsi4");
#else
asm volatile ("rcall __udivmodsi4");
#endif
asm volatile ("mov r25,r23");
asm volatile ("mov r24,r22");
return max;
}
u08 tabval(u16 num, u08 fn) // check random tabele for song status
{ // and mark as played if necessary
u16 index = (num + wFirstInDir) >> 3;
u08 offset = 1 << ((num + wFirstInDir) % 8);
if(fn)
RANDOM_TAB[index] |= offset; // if fn=1 mark as played
return (RANDOM_TAB[index] & offset); // return status
}
// new random procedure
u16 do_rand(u16 max) // returned random value from 0 to max - 1
{
u16 num;
for(num = 0; num < max; num++)
if(tabval(num,0) == 0)
break;
if (num == max)
{
InitRnd();
num = -1;
}
else
{
do
{
WDR;
num = randcalc(max);
} while (tabval(num,0) != 0); // check this song not be played piervously
tabval(num,1); // mark as just played
}
return num;
}
// This function return number of songs in current direcrory and sets first song number variable
u16 checkdir(void)
{
register u16 Temp;
for (Temp = 0; Temp < nLastPosD; Temp++) // search dir tabele
{
if (DirsTable[Temp].song_num <= wSongNum)
wFirstInDir = DirsTable[Temp].song_num; // update first song number in current dir
else
break; // found end of current dir
}
if (Temp == nLastPosD) // if this is last dir on CD
return (wMaxSongs - wFirstInDir);
return (DirsTable[Temp].song_num - wFirstInDir);
}
#if (LCD_LINES == 4)
void printsp(void)
{
register u08 i = (LCD_LINE_LENGTH - 11);
while(i--) lcd_putchar(' ');
}
#endif
void load_buffers(void)
{
ReadBuffer(BUFFER1P); // Load buffer1
ReadBuffer(BUFFER2P); // Load buffer2
pUpdBuf = 0; // Mark as just loaded
pPlayData = BUFFER1P; // Start playing from buffer1
#ifdef OLD_VS1001
BadHeadStrip();
#endif
}
u08 *randstr = "Rand*";
u08 *loudstr = "Loud*";
u08 randmod[] = "-+*";
u08 trackstr[6], *pTrack, timestr[6], tot_sw = 0;
#ifdef ENABLE_NUMERIC
u08 number[6], *pNum = number;
#endif
#endif // #ifndef SETUP_REMOTE_CODES
//----------------------------------------------------------------------------
// Main part
//----------------------------------------------------------------------------
int main(void)
{
#ifndef SETUP_REMOTE_CODES
bool bRandom, bLoudness; // Modificators
bool bFfwdMute = false; // Search mute flag
u08 nVolume = 0; // Current volume level
u16 wPlayTime; // Current play time
#ifdef REMAIN_TIME
u16 wSongTime = 0; // Song time for remain calculation
u08 bTimeMode = 0; // Remain time modificator
#endif
u16 wAddTime = 0; // Fix play time for search
u08 nWrites, i; // Buffering variables
u08 event = EV_STOP; // Current event
u08 *src, *dst; // Temporary variables
u16 nTemp;
udiv_t divt;
#endif // #ifndef SETUP_REMOTE_CODES
//----------------------------------------------------------------------------
// B - Port
//----------------------------------------------------------------------------
outp(0x57, PORTB);
outp(0xBB, DDRB);
//----------------------------------------------------------------------------
// D - Port
//----------------------------------------------------------------------------
outp (0xDC ,PORTD);
#ifdef ENABLE_RST_OUT
outp (0xF0 ,DDRD);
#else
outp (0xE0 ,DDRD);
#endif
#ifdef YAMPP3USB
#define SRW SRW10
cbi(DDRD, PD5); // PD5 is input in yampp-3/USB
//----------------------------------------------------------------------------
// E - Port
//----------------------------------------------------------------------------
cbi(DDRE, PE0); // PE0 is IR input
sbi(PORTE, PE0); // activate pullup
sbi(DDRE, PE1); // set ALE pin as output
cbi(PORTE, PE1); // and set it low (inactive)
sbi(DDRE, PE2); // PE2 is LCD_ENABLE
cbi(PORTE, PE2); // and set it low (inactive)
#endif
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
outp((1<<SRE)|(1<<SRW), MCUCR); // enable external SRAM and wait states
delay10(1000);
lcd_init(0, LCD_FUNCTION_DEFAULT);
outp((1<<MSTR) | (1<<SPE), SPCR); // SPI 2 MHz clock
inp(SPSR); // clear SPI status
#if (LCD_LINE_LENGTH == 16)
lcd_puts_p(PSTR(" Hi, MP3 world!\n yampp-3 player"));
#endif
#if (LCD_LINE_LENGTH == 20)
lcd_puts_p(PSTR(" Hi, MP3 world!\nyampp-3 player Alive"));
#endif
#if (LCD_LINE_LENGTH == 24)
lcd_puts_p(PSTR(" Hi, MP3 world!\n yampp-3 player Alive !"));
#endif
UART_Init(); // Init RS-232 link
#ifdef ENABLE_RST_OUT
cbi(PORTD,PD4); // activate reset signal to VS1001 and CD-ROM
delay10(1000);
sbi(PORTD,PD4); // deactivate reset signal to VS1001 and CD-ROM
#endif
// Say hello to UART
PRINT_p(PSTR("\n\nyampp-3 "__DATE__" "__TIME__"\nATA checking..."));
#ifdef ENABLE_WATCHDOG
wdt_enable(0x07);
#endif
delay10(10000);
vs1001_setcomp(F_VS1001); // set frequency of vs1001 clock
vs1001_reset(false); // Init VS1001
#ifdef SETUP_REMOTE_CODES
setvolume(6);
send_sinewave_beeps(); // Send three sinewave beeps to indicate
remote_setup(); // Enter remote setup procedure
while(1) WDR;
#else // SETUP_REMOTE_CODES - for get full code space
ATA_Init(); // Init and wait for drive
ATA_SW_Reset(); // Reset drive
PRINT_p(PSTR("done.\n"));
if ((nTemp = init_fat())) // Read disk structure
{
lcd_clrscr();
lcd_puts_p(PSTR("Wrong cluster\nsize ")); // Error info, recompile code
lcd_puts(unsigned2str((nTemp>>1), trackstr)); // Show cluster size for this disk
lcd_putchar('k');
while (true) WDR; // Lock player
}
PRINT_p(PSTR("Scanning..."));
// wMaxSongs = dirlist(DIRLIST_VERBOSE);
wMaxSongs = dirlist(DIRLIST_SCAN);
PRINT(unsigned2str(wMaxSongs , trackstr)); // jman number of songs in decimal
PRINT_p(PSTR(" entries\n"));
seed = 1 + inp(TCNT1L); // Init randomizer from timer
// (ATA init gives us random delay)
InitRnd(); // Init randomizer tabele
if ((nVolume = eeprom_rb(EEPROM_VOLUME)) > MIN_VOLUME) // Load and set initial volume
nVolume = MIN_VOLUME / 2; // set volume to 1/2 scale after eeprom erase
setvolume(nVolume);
#ifdef PWR_BEEPS
send_sinewave_beeps(); // Send three sinewave beeps to indicate
#endif // we're starting up okay
// load bAutoPlay and position settings
bRandom = eeprom_rb(EEPROM_RANDOM) % 3; // Load random setting
wSongNum = eeprom_rw(EEPROM_SONGPOS); // Load position setting
bLoudness = eeprom_rb(EEPROM_LOUDNESS);
// set initial status in the strings
*(loudstr+4) = bLoudness ? '+' : '-';
*(randstr+4) = randmod[bRandom];
if (eeprom_rb(EEPROM_AUTOPLAY)) // Load autoplay status
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();
else
if (nKeyTime > 16)
LastEvent = EV_IDLE;
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;
case EV_PREVD: // Switch to previous start dir
checkdir();
wSongNum = ((wFirstInDir) ? wFirstInDir : wMaxSongs) -1;
checkdir();
wSongNum = wFirstInDir;
goto PLAY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -