📄 yampp7_usb.c
字号:
//
// return the next FAT in a chain
//
u32 next_fat(void)
{
u32 fat_sector = fat_start + MyCluster / (SECTORSIZE / sizeof(CLUSTER));
u16 fat_offset = MyCluster % (SECTORSIZE / sizeof(CLUSTER));
while (CARD_Read(fat_sector))
CARD_SW_Reset2();
ClusterCount++; // counter for F.Forward file sizing
return ((CLUSTER*)SectorBuffer)[fat_offset];
}
void init_load_sectors(u32 cluster)
{
MyCluster = cluster;
MySector = sector_cluster_offset + YADL_SECTORS_PER_CLUSTER * MyCluster;
while(CARD_Read(MySector))
CARD_SW_Reset2();
SectorsLd = 1;
}
//
// load a bufferfull of data
//
void load_sector(void)
{
if (SectorsLd == YADL_SECTORS_PER_CLUSTER)
init_load_sectors(next_fat());
else
{
MySector++;
while(CARD_Read(MySector))
CARD_SW_Reset2();
SectorsLd++;
}
}
/****************************************************************************************/
void init_stuff(void)
{
u08 i,update = 0;
YADL_ROOT_SECTOR *pRoot; // Boot Sector struct
pRoot = (YADL_ROOT_SECTOR *) SectorBuffer; // Allocate room from the temp buffer
while (CARD_Read(YADL_SEC_ROOT)) // read root sector
CARD_SW_Reset2();
if ( *(u32*)pRoot->id != 0x4C444159) // "YADL" signature not found
{
lcd_clrscr();
_p_puts(Format_txt);
static u08 tones[]= {SINE_300,SINE_500,SINE_800,SINE_1000};
for (i=0; i<4; i++)
{
beep(tones[i],200);
delayms(10);
}
do{
get_key();
i = check_event();
wdt_reset();
}while(i != EV_STOP);
if(format_new_disk() == 0) // format Card with YADL f.s.
{
_p_puts(FormOK_txt);
beep(SINE_1500,100);
}
else
{
_p_puts(FormER_txt);
beep(SINE_500,200);
}
wdt_enable(6); // time for text displaying
while(1); // reset player by watchdog
}
if(pRoot->firmware_version_major != YAMPP_FIRMWARE_VERSION_MAJOR)
{
pRoot->firmware_version_major = YAMPP_FIRMWARE_VERSION_MAJOR;
update = 1;
}
if(pRoot->firmware_version_minor != YAMPP_FIRMWARE_VERSION_MINOR)
{
pRoot->firmware_version_minor = YAMPP_FIRMWARE_VERSION_MINOR;
update = 1;
}
if(strcmp_P(pRoot->build_timestamp, date_txt))
{
strcpy_P(pRoot->build_timestamp, date_txt);
update = 1;
}
if (update)
{
while(CARD_Write(YADL_SEC_ROOT))
CARD_SW_Reset2();
lcd_clrscr();
_p_puts(FirmUpd_txt);
beep(SINE_1500,80);
beep(SINE_2000,80);
delayms(1000);
}
sector_cluster_offset = pRoot->sector_cluster_offset;
songbase_start = pRoot->songbase_start; // SECTOR !!
songbase_qty = pRoot->songbase_qty;
playlist_start = sector_cluster_offset + YADL_SECTORS_PER_CLUSTER * pRoot->playlist_start; // SECTOR !!!
playlist_qty = pRoot->playlist_qty;
fat_start = pRoot->fat_start;
//
// VS1001 User Software Loader
//
u32 app_start = pRoot->wasteland_start;
lcd_data_start = pRoot->wasteland_start + 10;
vs1001_fw = 0;
if (app_start != 0)
{
u16 *pData;
pData = (u16*) SectorBuffer;
CARD_Read(app_start); // read first free sector
if(*pData++ != 0x4679 || *pData++ != 0x776D) // Firmware signature ('yFmw') not found
return; // exit
u16 DataLen = *pData++; // length of firmware in words (firmware only)
vs1001_fw = *pData++; // address to enter into VS1001 register A1ADDR
// for application running.
vs1001_write(7,vs1001_fw + 0x4000); // write to VS1001 register WRAMADDR
while(DataLen--) // data length in words
{
if (pData == (u16*)(SectorBuffer+512))
{
app_start++;
CARD_Read(app_start); // read next sector with application datas
pData = (u16*) SectorBuffer; // new start address
}
vs1001_write(6,*pData++); // write firmware word to vs1001
}
}
}
/****************************************************************************************/
YADL_PLAY_LIST_ENTRY *get_pl_entry(u16 index)
{
u32 nCurSector;
//
// find (and load) correct playlist sector
//
nCurSector = playlist_start + (index >> 3); // 64 bytes per one playlist entry
while(CARD_Read(nCurSector))
CARD_SW_Reset2();
return &((YADL_PLAY_LIST_ENTRY *)SectorBuffer)[index % 8];
}
YADL_SONG_BASE_ENTRY *get_song_entry(u16 index)
{
u32 nCurSector;
nCurSector = songbase_start + (index >> 2);
while(CARD_Read(nCurSector))
CARD_SW_Reset2();
return &((YADL_SONG_BASE_ENTRY *)SectorBuffer)[index % 4];
}
// Nilrog: Rewrote this function since it couldn't properly handle
// the fact that a playlist can begin in one sector and the
// index pointed to a position which was located in the next
// sector.
u16 get_offset_entry(u16 index)
{
YADL_PLAY_LIST_ENTRY *pListEntry = get_pl_entry(curPlaylist);
FOFFSET offset = pListEntry->offset;
/* calculate absolute position from start of playlistfile */
u16 pos = offset + index * sizeof(u16);
/* calculate if the current playlist position wraps into another sector */
u08 wraps = pos / SECTORSIZE;
/* calculate which sector to read */
u32 nCurSector = playlist_start + wraps;
/* if playlist wraps we need to re-calculate index and offset */
if (wraps)
{
index = (pos - wraps * SECTORSIZE) / sizeof(u16);
offset = 0;
}
/* if no wrap ocurred 'index' and 'offset' are clear to use as is */
while(CARD_Read(nCurSector))
CARD_SW_Reset2();
u16 *pList = (u16*) ( (u08*)SectorBuffer + offset);
return pList[index];
}
//********************************************************************************
char index_fmt[] __attribute__ ((progmem)) = "%3u/%u";
void Playlist_name(void)
{
u08 *src;
udiv_t divt;
lcd_image(1); // Playing background image
pump_audio();
YADL_PLAY_LIST_ENTRY *pListEntry = get_pl_entry(curPlaylist);
u16 tmp = (pListEntry->entry_qty);
lcd_color(colors[PLAYLIST_NAME], colors[PLAYLIST_NAME+16]);
#ifdef PLAYLIST_NAME_CENTERED
u08 j = strlen(pListEntry->name);
if(j<15)
lcd_gotoxy((15-j)*4 + 4, PLAYLIST_NAME_YPOS);
else
#endif
lcd_gotoxy(4, PLAYLIST_NAME_YPOS);
lcd_puts(pListEntry->name); // playlist name
YADL_SONG_BASE_ENTRY *pEntry = get_song_entry(get_offset_entry(curIndex));
strcpy(titlename, pEntry->title);
src = titlename + strlen(titlename);
*src++ = ' ';
*src++ = '(';
songtime = pEntry->play_time;
divt = udiv(songtime, 600);
u08 s = (u08)divt.quot % 10;
if (s)
*src++ = '0' + s; // song time up to 99 min
divt = udiv(divt.rem, 60);
*src++ = '0' + (u08)divt.quot;
*src++ = ':';
divt = udiv(divt.rem, 10);
*src++ = '0' + (u08)divt.quot;
*src++ = '0' + (u08)divt.rem;
*src++ = ')';
#ifndef ALTERNATE_SCROLL
if (src-titlename > 14)
*((u32*)src)++ = 0x203E3E20L; // adding " >> " sign
#else
scroll_dir = scroll_dir_2 = 0;
#endif
*src = 0;
scroll_length_2 = src-titlename;
scroll_pos = scroll_pos_2 = 0;
lcd_color(colors[ARTIST_NAME], colors[ARTIST_NAME+16]);
lcd_gotoxy(4, ARTIST_NAME_YPOS);
lcd_puts(pEntry->artist); // artist name
lcd_color(colors[SONG_NAME], colors[SONG_NAME+16]);
lcd_gotoxy(4, SONG_NAME_YPOS);
lcd_puts(titlename); // title name
lcd_color(colors[PL_SO_NUMBERS], colors[PL_SO_NUMBERS+16]);
lcd_gotoxy(PLIST_NUMBER_XPOS, PLIST_NUMBER_YPOS);
_p_printf(index_fmt, curPlaylist+1, playlist_qty);
lcd_gotoxy(SONG_NUMBER_XPOS, SONG_NUMBER_YPOS);
_p_printf(index_fmt, curIndex+1, tmp);
pump_audio();
status_display();
time_flag = 5;
scroll_flag = 2;
}
// ******************************************************************************
// this is in assembler procedure because c not propper handle
// pointers array located in program memory (in this case)
u08* PRG_RDW(u08* addr)
{
asm volatile ("movw r30,r24");
asm volatile ("LPM r24,Z+");
asm volatile ("LPM r25,Z");
return addr;
}
#define SONGS_D 0
#define MENU_D 1
u16 browse_list(u16 index, u16 min, u16 max, u08 func)
{
u08 i,j = 0;
event_e event;
while (1)
{
for (i=0; i < 3 + 3*func; i++)
{
#if (CLKDIV > 0)
set_cpu_speed(CLKDIV>>1); // CPU clock * 2
#endif
if (func)
{
lcd_clrline(14*i + MENUITEMS_YOFFSET);
if (index+i < max)
{
lcd_putchar((i==j) ? 30 : ' ');
lcd_progputs(PRG_RDW((u08*)&function_name[index+i])); // menu print on LCD
}
if(isPlaying)
feed_audio_data();
}
else
{
lcd_clrline(28*i + (MENUITEMS_YOFFSET+14));
lcd_clrline(28*i + MENUITEMS_YOFFSET);
if (index+i < max)
{
YADL_SONG_BASE_ENTRY *pEntry = get_song_entry(get_offset_entry(index+i));
lcd_putchar((i==j) ? 30 : ' ');
lcd_puts(pEntry->artist); // print artist
lcd_gotoxy(4, 28*i + (MENUITEMS_YOFFSET+14));
lcd_putchar((i==j) ? 30 : ' ');
lcd_puts(pEntry->title); // print title
}
pump_audio();
}
}
do
{
time_flag = 0;
sleepcount = 0; // power off blocking
event = get_event();
switch (event)
{
case EV_NEXT:
case EV_UP:
if ( index+j > min )
{
if(j)
j--;
else
index--;
}
break;
case EV_PREV:
case EV_DOWN:
if ( index+j+1 < max )
{
if(j < 3*func + 2)
j++;
else
index++;
}
break;
case EV_PLAY:
return index+j;
case EV_STOP:
return -1;
}
}
while (event == EV_IDLE);
}
}
// ***************************************************************************************
u16 browse_songs(void)
{
lcd_image(3);
status_display();
lcd_color(colors[BROWSE_WINDOW], colors[BROWSE_WINDOW+16]);
YADL_PLAY_LIST_ENTRY *pListEntry = get_pl_entry(curPlaylist);
return (browse_list(curIndex, 0, pListEntry->entry_qty, SONGS_D));
}
/***********************************************************************************/
u16 browse_menu(void)
{
lcd_image(2);
status_display();
lcd_color(colors[MENU_WINDOW], colors[MENU_WINDOW+16]);
return (browse_list(menu_event ? menu_event-1 : 0, 0, 11, MENU_D));
}
/***********************************************************************************/
#ifdef PCB_REV_D
u08 IsCharging(void)
{
u08 b = 0;
u08 c = MCUCR;
MCUCR = 0; // disable external memory interface
cbi(CHARGE_DDR,CHARGE_PIN); // set pin as input
sbi(CHARGE_PORT,CHARGE_PIN); // activate pullup
delay10();
if (bit_is_clear(CHARGE_INP,CHARGE_PIN)) // if charging
b = 1;
MCUCR = c ; // restore control register setting
return b;
}
#else // PCB older than D
u08 IsCharging(void)
{
return (bit_is_clear(CHARGE_INP,CHARGE_PIN));
}
#endif // PCB_REV_D
void BatteryMeasure(void)
{
if (!IsCharging()) // no charging in progress
{
cbi(PORTB, PB3); // PB3 as analog comparator input
cbi(DDRB, PB3); // for battery level measure
delay100();
if (bit_is_set(ACSR,ACO)) // low battery
{
if (!lobatt)
{
lobatt = 1;
lobatt_time = 0;
}
else
lobatt = 2;
}
sbi(PORTB, PB3);
sbi(DDRB, PB3);
}
}
void feed_audio_data(void)
{
set_cpu_speed(CLKDIV); // CPU clock = XTAL / M162CLKDIV
wdt_reset(); // reset the watchdog
u08 ContWrites = 0; // counter for prevent infinite vs1001 writing
// pump some data to the decoder
while (bit_is_set(PIND, DREQ_PIN)) // while DREQ is hi
{
vs1001_send32(outptr); // send data on SPI bus
outptr += 32; // advance data pointer
fileplayed++;
// check for buffer wrap
if ( outptr == (SectorBuffer+512) ) // buffer empty
{
outptr = SectorBuffer; // data pointer at begin of sector buffer
load_sector(); // will load into SectorBuffer on YAMPP7
}
// check if we're done
if (fileplayed >= filesize)
{
isPlaying = 0; // the end is near
next_song(0);
return;
}
if (--ContWrites == 0) // if vs1001 needs to more data
{
wdt_reset(); // reset the watchdog
cbi(PORTB, RESET_PIN); // VS1001 hardware reset
delayms(1);
sbi(PORTB, RESET_PIN); // VS1001 reset
delayms(10);
vs1001_reset();
LoudSet();
ContWrites = 0;
}
}
}
//********************************************************************************
//
// Run this as often as possible
// preferably every time around the main loop
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -