diff --git a/C-RK/C-RK-Week2/C-RK-Week2.vcxproj b/C-RK/C-RK-Week2/C-RK-Week2.vcxproj index 950e1d2..4c3492a 100644 --- a/C-RK/C-RK-Week2/C-RK-Week2.vcxproj +++ b/C-RK/C-RK-Week2/C-RK-Week2.vcxproj @@ -142,12 +142,12 @@ - + - + diff --git a/C-RK/C-RK-Week2/C-RK-Week2.vcxproj.filters b/C-RK/C-RK-Week2/C-RK-Week2.vcxproj.filters index 880eb05..6b7f960 100644 --- a/C-RK/C-RK-Week2/C-RK-Week2.vcxproj.filters +++ b/C-RK/C-RK-Week2/C-RK-Week2.vcxproj.filters @@ -3,10 +3,10 @@ - + - + \ No newline at end of file diff --git a/C-RK/C-RK-Week3/display.c b/C-RK/C-RK-Week3/display.c new file mode 100644 index 0000000..5572f21 --- /dev/null +++ b/C-RK/C-RK-Week3/display.c @@ -0,0 +1,162 @@ + +char customCharArray[64] = { + 0b00000,0b01000,0b11111,0b01000,0b00010,0b11111,0b00010,0b00000, //Web sync true + 0b00000,0b00100,0b01110,0b00000,0b00000,0b01110,0b00100,0b00000, //Up Down + 0b00100,0b01110,0b01110,0b01110,0b11111,0b00000,0b00100,0b00000, //Alarm Clock + 0b00000,0b00100,0b01101,0b11101,0b01101,0b00100,0b00000,0b00000, //Volume ON + 0b00000,0b00100,0b01100,0b11100,0b01100,0b00100,0b00000,0b00000, //Volume OFF + 0b00000,0b00001,0b00011,0b00111,0b01111,0b11111,0b00000,0b00000, //Network TRUE + 0b00000,0b01000,0b01100,0b01110,0b01100,0b01000,0b00000,0b00000, //PLAY + 0b00000,0b01110,0b10101,0b10111,0b10001,0b01110,0b00000,0b00000 //Time Sync TRUE +}; + + +void LcdClear() +{ + LcdWriteByte(WRITE_COMMAND, 0x01); // display clear + NutDelay(5); + LcdWriteByte(WRITE_COMMAND, 0x80); // DD-RAM address counter (cursor pos) to '0' +} + +void LcdLine(u_char line, char text[]) +{ + int i; + + if(line == 0) //Top line + { + LcdWriteByte(WRITE_COMMAND, 0x80); // command to write to line 1 + for(i = 0; i< 16; i++) + { + LcdChar(32); //Clear the line + } + LcdWriteByte(WRITE_COMMAND, 0x80); // command to write to line 1 + } + else if(line == 1) //Bottom line + { + LcdWriteByte(WRITE_COMMAND, 0xC0); // command to write to line 2 + for(i = 0; i< 16; i++) + { + LcdChar(32); //Clear the line + } + LcdWriteByte(WRITE_COMMAND, 0xC0); // command to write to line 1 + } + else + { + return; + } + + int count = 0; + + while(text[count] != '\0') + { + //Replace ~n with the decimal n + //This displays the custom character + if(text[count] == '~') + { + count++; + char num = text[count]; + + int number = num - '0'; + + LcdWriteByte(WRITE_DATA, number); + } + else + { + //Write char to display + LcdChar(text[count]); + } + + count++; + + if(count > 24) + break; + + NutSleep(1); + } +} + +void LcdScrollLine(u_char line, int pos, char text[]) +{ + int i; + + if(line == 0) + { + LcdWriteByte(WRITE_COMMAND, 0x80); // command to write to line 1 + for(i = 0; i< 16; i++) + { + LcdChar(32); + } + LcdWriteByte(WRITE_COMMAND, 0x80); // command to write to line 1 + } + else if(line == 1) + { + LcdWriteByte(WRITE_COMMAND, 0xC0); // command to write to line 2 + for(i = 0; i< 16; i++) + { + LcdChar(32); + } + LcdWriteByte(WRITE_COMMAND, 0xC0); // command to write to line 1 + } + else + { + return; + } + + //Start at scroll location + int count = pos; + + while(text[count] != '\0') + { + if(text[count] == '~') + { + count++; + char num = text[count]; + + int number = num - '0'; + + LcdWriteByte(WRITE_DATA, number); + } + else + { + LcdChar(text[count]); + } + + count++; + + if(count > 24 + pos) + break; + + NutSleep(1); + } +} + +//Write data to the Custom Character RAM +void LcdCGRAM(char *icon, int length) +{ + //SELECT CGRAM + LcdWriteByte(WRITE_COMMAND, 0x40); + + int count; + + //Write the array with custom icons + for(count = 0; count < length; count++) + { + LcdChar(icon[count]); + NutSleep(1); + } + + //Select the display RAM + LcdWriteByte(WRITE_COMMAND, 0x80); +} + +void LcdSetPosition(int line) +{ + if(line) + { + LcdWriteByte(WRITE_COMMAND, 0xC0); + } + else + { + LcdWriteByte(WRITE_COMMAND, 0x80); + } +} diff --git a/C-RK/C-RK-Week3/display.h b/C-RK/C-RK-Week3/display.h new file mode 100644 index 0000000..03393e8 --- /dev/null +++ b/C-RK/C-RK-Week3/display.h @@ -0,0 +1,10 @@ + +#ifndef _Display_H +#define _Display_H + +extern void LcdSetPosition(int); +extern void LcdLine(u_char line, char text[]); +extern void LcdScrollLine(u_char line, int pos, char text[]); +extern void LcdClear(void); + +#endif diff --git a/C-RK/C-RK-Week3/menu.c b/C-RK/C-RK-Week3/menu.c new file mode 100644 index 0000000..7623d26 --- /dev/null +++ b/C-RK/C-RK-Week3/menu.c @@ -0,0 +1,2522 @@ +#include +#include "keyboard.h" +#include "display.h" +#include "settings.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "web.h" +#include "vs10xx.h" +#include "rtc.h" +#include "menu.h" +#include "player.h" +#include "streamer.h" +#include "alarm.h" +#include "network.h" +#include "scheduler.h" + +#define HOME 8 +#define MENU 10 +#define STREAMING 10 +#define SCHEDULER 11 +#define ALARMS 12 +#define SETTINGS 13 +#define DEVICE 14 + +int CurrentTimeZone = 11; +int CurrentStream = 0; +int CurrentAlarm = 0; +int CurrentSchedule = 0; +int CurrentScrollPos = 0; +int CurrentAlarmDisplay = 0; +char buf[24] = {0}; +char str[30] = {0}; +char icon[8] = {0}; + +/* + First Time Setup +*/ +void SyncTimeEntry(void) +{ + if(SyncTime()) //If sync succeeded + navigateToMenu(4); + else //if sync failed + navigateToMenu(5); +} + +void CheckFirstTimeSetup(void) +{ + //Check if FTS is set in eeprom, skip FTS + if(GetFirstTimeSetup()) + { + navigateToMenu(HOME); + return; + } +} + +//Mark FTS as done in eeprom +void FirstTimeSetupComplete(void) +{ + SetFirstTimeSetup(1); +} + + +/* + TIMEZONES +*/ + +void DisplayTimeZone(void) +{ + GetTimeZoneName(CurrentTimeZone, str); + + sprintf(buf, "~1 %s", str); + + LcdLine(1, buf); +} + +//Automatically find the timezone using the curent IP address +void FindTimeZone(void) +{ + getTimezoneOffset(&CurrentTimeZone); + DisplayTimeZone(); +} + +void ChooseTimeZoneUp(void) +{ + CurrentTimeZone--; + + if(CurrentTimeZone < 0) + CurrentTimeZone = 24; + + DisplayTimeZone(); +} + +void ChooseTimeZoneDown(void) +{ + CurrentTimeZone++; + + if(CurrentTimeZone > 24) + CurrentTimeZone = 0; + + DisplayTimeZone(); +} + +//Sync using the selected timezone +void ChooseTimeZone(void) +{ + SetTimeZone(GetTimeZoneValue(CurrentTimeZone)); +} + +//Display the time and date in the RTC chip +void DisplayDateTime(void) +{ + GetDateTimeString(str); + + LcdLine(0, str); +} + + +/* + MAIN DISPLAYS +*/ + +//Create the icons at the top +void CreateIconsString(char* str, int * len) +{ + int length = 0; + + strcpy(str, ""); + + length++; + if(GetVolume() == 0) //Volume on or muted + { + strcat(str, "~4"); //muted + } + else + { + strcat(str, "~3"); //on + } + + if(GetSync() > 0) //Display checkmark if sync with server is on + { + strcat(str, "~0"); + length++; + } + + if(GetTimeSynced()) //Display checkmark if time is in sync with server + { + strcat(str, "~7"); + length++; + } + + if(AlarmsOn() || SchedulesOn()) //Display alarm icon if a schedule or alarm is going off + { + strcat(str, "~2"); + length++; + } + + *len = length; +} + +//Show current stream MetaData and scroll +void DisplayMetaData(void) +{ + if(isStreaming()) + { + CurrentScrollPos++; + if(CurrentScrollPos > strlen(GetMetaData()) - 16) + CurrentScrollPos = 0; + + LcdScrollLine(1, CurrentScrollPos, GetMetaData()); + } + else + { + LcdLine(1, " "); + CurrentScrollPos = 0; + } +} + +//Display the current timestamp followed by the icons +void UpdateTimeDisplay( void ) +{ + GetTimeString(str); + int l; + CreateIconsString(icon, &l); + + int i; + for(i=0; i<8-l; i++) + strcat(str, " "); + + strcat(str, icon); + + LcdLine(0, str); + + DisplayMetaData(); +} + +//Display the current date followed by the icons +void UpdateDateDisplay( void ) +{ + GetDateString(str); + + int l; + CreateIconsString(icon, &l); + + int i; + for(i=0; i<6-l; i++) + strcat(str, " "); + + strcat(str, icon); + + LcdLine(0, str); + + DisplayMetaData(); +} + + +/* + RESET +*/ +void FactoryResetOk(void) +{ + stop(); //Stop any audio + resetServer(); //Remove any data on the server + + NutSleep(10); + + FactoryReset(); //Reset the eeprom memory + + NutSleep(20); + + Reboot(); //Automatically reboot the device +} + + +/* + VOLUME/BASS/TREBLE SETTINGS +*/ +void VolumeDisplay(void) +{ + int volume = GetVolume() / 16; + + sprintf(buf, "Volume: %d", volume); + LcdLine(0, buf); + + strcpy(str, ""); + int i; + for(i = 0; i GetNumStreams() - 1) + CurrentStream = 0; + + DisplayStream(); +} + +void SelectStream(void) +{ + PlayStream(CurrentStream); +} + +void StopStream(void) +{ + stop(); //Stop any stream +} + +//Shortcuts to streams in memory +void PlayStream1(void) +{ + PlayStream(0); +} +void PlayStream2(void) +{ + PlayStream(1); +} +void PlayStream3(void) +{ + PlayStream(2); +} +void PlayStream4(void) +{ + PlayStream(3); +} +void PlayStream5(void) +{ + PlayStream(4); +} + + +/* + SCHEDULER +*/ +void DisplaySchedule(void) +{ + if(GetNumSchedules() == 0) + { + LcdLine(1, "No schedules"); + return; + } + + GetScheduleName(CurrentSchedule, str); + + sprintf(buf, "~1 %s", str); + + LcdLine(1, buf); +} + +void ScheduleUp(void) +{ + CurrentSchedule--; + + if(CurrentSchedule < 0) + CurrentSchedule = GetNumSchedules() - 1; + + DisplaySchedule(); +} + +void ScheduleDown(void) +{ + CurrentSchedule++; + + if(CurrentSchedule > GetNumSchedules() - 1) + CurrentSchedule = 0; + + DisplaySchedule(); +} + +void DisplaySelectedSchedule(void) +{ + GetScheduleName(CurrentSchedule, str); + LcdLine(0, str); + + GetScheduleTime(CurrentSchedule, str); + LcdLine(1, str); + + GetScheduleTime(CurrentSchedule, buf); + sprintf(str, "%s%s", buf, (GetScheduleOn(CurrentSchedule) == 1 ? " ON" : " OFF") ); + + LcdLine(1, str); +} + +void ToggleSelectedSchedule(void) +{ + ToggleScheduleOn(CurrentSchedule); + DisplaySelectedSchedule(); +} + + +/* + ALARMS +*/ +void DisplayAlarm(void) +{ + if(GetNumAlarms() == 0) + { + LcdLine(1, "No alarms"); + return; + } + + GetAlarmName(CurrentAlarm, str); + + sprintf(buf, "~1 %s", str); + + LcdLine(1, buf); +} + +void AlarmUp(void) +{ + CurrentAlarm--; + + if(CurrentAlarm < 0) + CurrentAlarm = GetNumAlarms() - 1; + + DisplayAlarm(); +} + +void AlarmDown(void) +{ + CurrentAlarm++; + + if(CurrentAlarm > GetNumAlarms() - 1) + CurrentAlarm = 0; + + DisplayAlarm(); +} + +void DisplaySelectedAlarm(void) +{ + GetAlarmName(CurrentAlarm, str); + LcdLine(0, str); + + GetAlarmTime(CurrentAlarm, buf); + sprintf(str, "%s%s", buf, (GetAlarmOn(CurrentAlarm) == 1 ? " ON" : " OFF") ); + + LcdLine(1, str); +} + +void ToggleSelectedAlarm(void) +{ + ToggleAlarmOn(CurrentAlarm); + DisplaySelectedAlarm(); +} + + +//Keep backlight on or off +void DisplayLightOFF(void) +{ + SetBacklight(0); +} + +void DisplayLightON(void) +{ + SetBacklight(1); +} + + + +//Save all the settings to eeprom when exiting the settings menu +void ExitSettings(void) +{ + SaveSettings(); +} + +/* + Alarm Management +*/ +void AlarmStartedRinging(void) +{ + navigateToMenu(100); //Navigate to the alarm menu when an alarm started ringing +} +void AlarmStoppedRinging(void) +{ + navigateToMenu(HOME); //Navigate back home when an alarm times out +} + + +void UpdateCurrentAlarm(void) +{ + if(CurrentAlarmDisplay < 3) + strcpy(str, "[OK] to snooze"); + else + strcpy(str, "[ESC] to stop"); + + LcdLine(1, str); + CurrentAlarmDisplay++; + + if(CurrentAlarmDisplay > 5) + CurrentAlarmDisplay = 0; +} +void DisplayCurrentAlarm(void) +{ + GetCurrentAlarmName(buf); + sprintf(str, "~2%s", buf); + + LcdLine(0, str); + + UpdateCurrentAlarm(); +} + +/* + Snooze settings +*/ +void DisplaySnooze(void) +{ + sprintf(buf, "~1 %d Min", GetSnooze()); + + LcdLine(1, buf); +} +void SnoozeUp(void) +{ + int i = GetSnooze(); + + i++; + + if(i >= 30) + i = 30; + + SetSnooze(i); + DisplaySnooze(); +} +void SnoozeDown(void) +{ + int i = GetSnooze(); + + i--; + + if(i <= 1) + i = 1; + + SetSnooze(i); + DisplaySnooze(); +} + +/* + Sync settings +*/ +void DisplaySync(void) +{ + if(GetSync() == 0) + sprintf(buf, "~1 Off"); + else + sprintf(buf, "~1 %d Min", GetSync()); + + LcdLine(1, buf); +} +void SyncUp(void) +{ + int i = GetSync(); + + i++; + + if(i >= 60) + i = 60; + + SetSync(i); + DisplaySync(); +} +void SyncDown(void) +{ + int i = GetSync(); + + i--; + + if(i <= 0) + i = 0; + + SetSync(i); + DisplaySync(); +} + +const MENU_ITEM_STRUCT menu[] = { + + /* + * FIRST TIME SETUP + * ITEMS: 1-7 + */ + // Start setup + { + 1, //ID + + &CheckFirstTimeSetup, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 0, //ESC + 0, //UP + 0, //DOWN + 2 //OK + }, + + //Text op het schermpje + { + "Start Setup", + "Press OK" + } + }, + + // Set Timezone + { + 2, //ID + + &FindTimeZone, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &ChooseTimeZoneUp, //UP + &ChooseTimeZoneDown, //DOWN + 0L, //LEFT + 0L, //RIGHT + &ChooseTimeZone, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 0, //ESC + 0, //UP + 0, //DOWN + 3 //OK + }, + + //Text op het schermpje + { + "Timezone", + "Loading...." + } + }, + + // Synchronizing + { + 3, //ID + + &SyncTimeEntry, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 0, //ESC + 0, //UP + 0, //DOWN + 0 //OK + }, + + //Text op het schermpje + { + "Synchronizing", + " " + } + }, + + // Sync Succesfull + { + 4, //ID + + &DisplayDateTime, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 0, //ESC + 0, //UP + 0, //DOWN + 7 //OK + }, + + //Text op het schermpje + { + "HH:MM DD/MM/YYYY", + "Sync succesfull" + } + }, + + // Sync Failed + { + 5, //ID + + &DisplayDateTime, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 0, //ESC + 0, //UP + 0, //DOWN + 7 //OK + }, + + //Text op het schermpje + { + "HH:MM DD/MM/YYYY", + "Sync Failed" + } + }, + + // Setup Complete + { + 7, //ID + + 0L, //onEntry Pointer + 0L, //onActive + &FirstTimeSetupComplete, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 0, //ESC + 0, //UP + 0, //DOWN + HOME //OK + }, + + //Text op het schermpje + { + "Setup Complete", + "Press OK" + } + }, + + /* + * MAIN SCREEN + * ITEMS: 8-9 + */ + + // Main Screen (time) + { + HOME, //ID + + 0L, //onEntry Pointer + &UpdateTimeDisplay, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + &VolumeDown, //LEFT + &VolumeUp, //RIGHT + 0L, //OK + &PlayStream1, //ONE + &PlayStream2, //TWO + &PlayStream3, //THREE + &PlayStream4, //FOUR + &PlayStream5, //FIVE + &StopStream, //ALT + + //Navigating, ID's of menu on button press + { + 0, //ESC + 9, //UP + 9, //DOWN + 10 //OK + }, + + //Text op het schermpje + { + "HH:MM:SS", + "" + } + }, + // Main Screen (date) + { + 9, //ID + + 0L, //onEntry Pointer + &UpdateDateDisplay, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + &VolumeDown, //LEFT + &VolumeUp, //RIGHT + 0L, //OK + &PlayStream1, //ONE + &PlayStream2, //TWO + &PlayStream3, //THREE + &PlayStream4, //FOUR + &PlayStream5, //FIVE + &StopStream, //ALT + + //Navigating, ID's of menu on button press + { + 0, //ESC + 8, //UP + 8, //DOWN + 10 //OK + }, + + //Text op het schermpje + { + "DD/MM/YYYY", + "" + } + }, + +/* + * MAIN MENU + * ITEMS: 10-14 + */ + // Main Menu (Music) + { + STREAMING, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + HOME, //ESC + DEVICE, //UP + SCHEDULER, //DOWN + 15 //OK + }, + + //Text op het schermpje + { + "Menu", + "~1 1.Streaming" + } + }, + // Main Menu (Scheduler) + { + SCHEDULER, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + HOME, //ESC + STREAMING, //UP + ALARMS, //DOWN + 20 //OK + }, + + //Text op het schermpje + { + "Menu", + "~1 2.Scheduler" + } + }, + + // Main Menu (Alarm) + { + ALARMS, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + HOME, //ESC + SCHEDULER, //UP + SETTINGS, //DOWN + 25 //OK + }, + + //Text op het schermpje + { + "Menu", + "~1 3.Alarms" + } + }, + + // Main Menu (Settings) + { + SETTINGS, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + HOME, //ESC + ALARMS, //UP + DEVICE, //DOWN + 50 //OK + }, + + //Text op het schermpje + { + "Menu", + "~1 4.Settings" + } + }, +// Main Menu (Device) + { + DEVICE, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + HOME, //ESC + SETTINGS, //UP + STREAMING, //DOWN + 80 //OK + }, + + //Text op het schermpje + { + "Menu", + "~1 5.Device" + } + }, + /* + * MUSIC SOURCE + * 15-24 + */ + { + 15, //ID + + &DisplayStream, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &StreamUp, //UP + &StreamDown, //DOWN + 0L, //LEFT + 0L, //RIGHT + &SelectStream, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + STREAMING, //ESC + 0, //UP + 0, //DOWN + HOME //OK + }, + + //Text op het schermpje + { + "Menu/Streaming", + "~1 Loading" + } + }, + { + 20, //ID + + &DisplaySchedule, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &ScheduleUp, //UP + &ScheduleDown, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + SCHEDULER, //ESC + 0, //UP + 0, //DOWN + 21 //OK + }, + + //Text op het schermpje + { + "Menu/Scheduler", + "~1 Loading" + } + }, + { + 21, //ID + + &DisplaySelectedSchedule, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &ToggleSelectedSchedule, //UP + &ToggleSelectedSchedule, //DOWN + &ToggleSelectedSchedule, //LEFT + &ToggleSelectedSchedule, //RIGHT + &ToggleSelectedSchedule, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 20, //ESC + 0, //UP + 0, //DOWN + 0 //OK + }, + + //Text op het schermpje + { + "Loading", + "" + } + }, + { + 25, //ID + + &DisplayAlarm, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &AlarmUp, //UP + &AlarmDown, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + ALARMS, //ESC + 0, //UP + 0, //DOWN + 26 //OK + }, + + //Text op het schermpje + { + "Menu/Alarms", + "~1 Loading" + } + }, + { + 26, //ID + + &DisplaySelectedAlarm, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &ToggleSelectedAlarm, //UP + &ToggleSelectedAlarm, //DOWN + &ToggleSelectedAlarm, //LEFT + &ToggleSelectedAlarm, //RIGHT + &ToggleSelectedAlarm, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 25, //ESC + 0, //UP + 0, //DOWN + 0 //OK + }, + + //Text op het schermpje + { + "Loading", + "" + } + }, + /* + * SETTINGS + * 50-74 + */ + { + 50, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + &ExitSettings, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + SETTINGS, //ESC + 90, //UP + 51, //DOWN + 55 //OK + }, + + //Text op het schermpje + { + "Menu/Settings", + "~1 1.Sound" + } + }, + { + 51, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + &ExitSettings, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + SETTINGS, //ESC + 50, //UP + 52, //DOWN + 61 //OK + }, + + //Text op het schermpje + { + "Menu/Settings", + "~1 2.Display" + } + }, + { + 52, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + &ExitSettings, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + SETTINGS, //ESC + 51, //UP + 53, //DOWN + 65 //OK + }, + + //Text op het schermpje + { + "Menu/Settings", + "~1 3.Time/Date" + } + }, + { + 53, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + &ExitSettings, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + SETTINGS, //ESC + 52, //UP + 54, //DOWN + 70 //OK + }, + + //Text op het schermpje + { + "Menu/Settings", + "~1 4.Snooze" + } + }, + { + 54, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + &ExitSettings, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + SETTINGS, //ESC + 53, //UP + 84, //DOWN + 75 //OK + }, + + //Text op het schermpje + { + "Menu/Settings", + "~1 5.Reset Device" + } + }, + /* + * SETTINGS / SOUND + */ + { + 55, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 50, //ESC + 57, //UP + 56, //DOWN + 58 //OK + }, + + //Text op het schermpje + { + "Settings/Sound", + "~1 1.Volume" + } + }, + { + 56, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 50, //ESC + 55, //UP + 57, //DOWN + 59 //OK + }, + + //Text op het schermpje + { + "Settings/Sound", + "~1 2.Bass" + } + }, + { + 57, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 50, //ESC + 56, //UP + 55, //DOWN + 60 //OK + }, + + //Text op het schermpje + { + "Settings/Sound", + "~1 3.Treble" + } + }, + { + 58, //ID + + &VolumeDisplay, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &VolumeUp, //UP + &VolumeDown, //DOWN + &VolumeDown, //LEFT + &VolumeUp, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 55, //ESC + 0, //UP + 0, //DOWN + 55 //OK + }, + + //Text op het schermpje + { + " Volume: ", + "" + } + }, + { + 59, //ID + + &BassDisplay, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &BassUp, //UP + &BassDown, //DOWN + &BassDown, //LEFT + &BassUp, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 56, //ESC + 0, //UP + 0, //DOWN + 56 //OK + }, + + //Text op het schermpje + { + " Bass: ", + "", + } + }, + { + 60, //ID + + &TrebleDisplay, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &TrebleUp, //UP + &TrebleDown, //DOWN + &TrebleDown, //LEFT + &TrebleUp, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 57, //ESC + 0, //UP + 0, //DOWN + 57 //OK + }, + + //Text op het schermpje + { + " Treble:", + "", + } + }, + /* + * SETTINGS DISPLAY + */ + { + 61, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 51, //ESC + 0, //UP + 0, //DOWN + 62 //OK + }, + + //Text op het schermpje + { + "Settings/Display", + "~1 1.Backlight" + } + }, + { + 62, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + &DisplayLightOFF, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 61, //ESC + 63, //UP + 63, //DOWN + 61 //OK + }, + + //Text op het schermpje + { + "Light always on", + "~1 1.NO" + } + }, + { + 63, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + &DisplayLightON, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 61, //ESC + 62, //UP + 62, //DOWN + 61 //OK + }, + + //Text op het schermpje + { + "Light always on", + "~1 2.YES" + } + }, + /* + * SNOOZE TIME + */ + { + 65, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 53, //ESC + 0, //UP + 0, //DOWN + 70 //OK + }, + + //Text op het schermpje + { + "Settings/Snooze", + "~1 1.Snooze Time" + } + }, + { + 70, //ID + + &DisplaySnooze, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &SnoozeUp, //UP + &SnoozeDown, //DOWN + &SnoozeDown, //LEFT + &SnoozeUp, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 65, //ESC + 0, //UP + 0, //DOWN + 65 //OK + }, + + //Text op het schermpje + { + "Snooze/Time", + "~1 ? Min" + } + }, + /* + * FACTORY RESET + */ + { + 75, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 54, //ESC + 76, //UP + 76, //DOWN + 54 //OK + }, + + //Text op het schermpje + { + "Reset device", + "~1 1.NO" + } + }, + { + 76, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 54, //ESC + 75, //UP + 75, //DOWN + 77 //OK + }, + + //Text op het schermpje + { + "Reset device", + "~1 2.YES" + } + }, + { + 77, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 54, //ESC + 78, //UP + 78, //DOWN + 54 //OK + }, + + //Text op het schermpje + { + "Are you sure?", + "~1 1.NO" + } + }, + { + 78, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + &FactoryResetOk, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 54, //ESC + 77, //UP + 77, //DOWN + 0 //OK + }, + + //Text op het schermpje + { + "Are you sure?", + "~1 2.YES" + } + }, + /* + * Device + */ + { + 80, //ID + + &DisplayDeviceID, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + DEVICE, //ESC + 0, //UP + 0, //DOWN + DEVICE //OK + }, + + //Text op het schermpje + { + "Menu/Device", + "ID: " + } + }, + /* + * REBOOT DEVICE + */ + { + 84, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + &ExitSettings, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + SETTINGS, //ESC + 54, //UP + 90, //DOWN + 85 //OK + }, + + //Text op het schermpje + { + "Menu/Settings", + "~1 6.Reboot device" + } + }, + { + 85, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 84, //ESC + 86, //UP + 86, //DOWN + 84 //OK + }, + + //Text op het schermpje + { + "Reboot device", + "~1 1.NO" + } + }, + { + 86, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + &Reboot, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 84, //ESC + 85, //UP + 85, //DOWN + 0 //OK + }, + + //Text op het schermpje + { + "Reboot device", + "~1 2.YES" + } + }, + + //SYNC SETTINGS + + { + 90, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + &ExitSettings, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + SETTINGS, //ESC + 84, //UP + 50, //DOWN + 91 //OK + }, + + //Text op het schermpje + { + "Menu/Settings", + "~1 7.Web Sync" + } + }, + { + 91, //ID + + 0L, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 90, //ESC + 0, //UP + 0, //DOWN + 92 //OK + }, + + //Text op het schermpje + { + "Settings/Sync", + "~1 1.Sync time" + } + }, + { + 92, //ID + + &DisplaySync, //onEntry Pointer + 0L, //onActive + 0L, //onExit + + 0L, //ESC + &SyncUp, //UP + &SyncDown, //DOWN + &SyncDown, //LEFT + &SyncUp, //RIGHT + 0L, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + 91, //ESC + 0, //UP + 0, //DOWN + 91 //OK + }, + + //Text op het schermpje + { + "Sync/Time", + "~1 ? Min" + } + }, + { + 100, //ID + + &DisplayCurrentAlarm, //onEntry Pointer + &UpdateCurrentAlarm, //onActive + 0L, //onExit + + &StopAlarm, //ESC + 0L, //UP + 0L, //DOWN + 0L, //LEFT + 0L, //RIGHT + &SnoozeAlarm, //OK + 0L, //ONE + 0L, //TWO + 0L, //THREE + 0L, //FOUR + 0L, //FIVE + 0L, //ALT + + //Navigating, ID's of menu on button press + { + HOME, //ESC + 0, //UP + 0, //DOWN + HOME //OK + }, + + //Text op het schermpje + { + "Alarm Ringing", + "" + } + } +}; + +unsigned int curMenuId; +unsigned int keyloop_done; +unsigned int activeCount; + +// Let op: confict met display.h ??? +typedef enum { LINE1, LINE2 } LCD_LINE_ENUM; + + +THREAD(MenuThread, arg) +{ + NutThreadSetPriority(64); // high prio + + handleMenu(); + + printf("[MENU] End of menu thread\n"); + + NutThreadExit(); + + for(;;) { + NutThreadYield(); + } +} + +void InitMenu() //Start the menu thread +{ + NutThreadCreate("Menu", MenuThread, NULL, 256); + //handleMenu(); +} + +//Navigate to a menu item from outsite of the menu +void navigateToMenu(unsigned int menuID) +{ + printf("[MENU] Navigating from %d to %d\n", curMenuId, menuID); + + curMenuId = menuID; + NutSleep(10); + keyloop_done = 1; + NutSleep(10); +} + +//Main menu handler +void handleMenu(void) +{ + unsigned int idx = 0; //menu item position in struct array + unsigned int menuloop_done = 0; //if menu should end + unsigned int powerPressed = 0; //Power button timeout + keyloop_done = 0; //if key has been pressed + unsigned int bl_delay = 0; //backlight timeout + curMenuId = 1; //current menu ID + activeCount = 0; //counter to activate the onActive function pointer + while( !menuloop_done ) + { + + /* Clear display */ + LcdClear(); + + idx = 0; + /* Lookup current menuID in the static array of menu items */ + while( menu[idx].menuID != curMenuId ) idx++; + + /* Write the text to the display */ + LcdLine(0, menu[idx].txt[0]); + LcdLine(1, menu[idx].txt[1]); + + /* Call the onEntry function */ + if( *menu[idx].fp_onEntry ) + (*menu[idx].fp_onEntry)(); + + /* Loop for key events and act according */ + while( keyloop_done == 0 ) + { + /* Call the onActive function */ + if(activeCount > 10) + { + activeCount = 0; + + if( *menu[idx].fp_onActive ) + (*menu[idx].fp_onActive)(); + } + + activeCount++; + + u_char key = KbGetKey(); + + switch( key ) + { + case KEY_ESC: + if( *menu[idx].fp_onKeyESC ) + (*menu[idx].fp_onKeyESC)(); + + + if(menu[idx].newMenuIdKey[0]) + { + keyloop_done = 1; + curMenuId = menu[idx].newMenuIdKey[0]; + } + + bl_delay = 0; + break; + + case KEY_UP: + if( *menu[idx].fp_onKeyUP ) + (*menu[idx].fp_onKeyUP)(); + + if(menu[idx].newMenuIdKey[1]) + { + keyloop_done = 1; + curMenuId = menu[idx].newMenuIdKey[1]; + } + + bl_delay = 0; + break; + + case KEY_DOWN: + if( *menu[idx].fp_onKeyDOWN ) + (*menu[idx].fp_onKeyDOWN)(); + + if(menu[idx].newMenuIdKey[2]) + { + keyloop_done = 1; + curMenuId = menu[idx].newMenuIdKey[2]; + } + + bl_delay = 0; + break; + + case KEY_OK: + if( *menu[idx].fp_onKeyOK ) + (*menu[idx].fp_onKeyOK)(); + + if(menu[idx].newMenuIdKey[3]) + { + keyloop_done = 1; + curMenuId = menu[idx].newMenuIdKey[3]; + } + + bl_delay = 0; + break; + + case KEY_LEFT: + if( *menu[idx].fp_onKeyLEFT ) + (*menu[idx].fp_onKeyLEFT)(); + + bl_delay = 0; + break; + + case KEY_RIGHT: + if( *menu[idx].fp_onKeyRIGHT) + (*menu[idx].fp_onKeyRIGHT)(); + + bl_delay = 0; + break; + + case KEY_ALT: + if( *menu[idx].fp_onKeyALT) + (*menu[idx].fp_onKeyALT)(); + + bl_delay = 0; + break; + + case KEY_01: + if( *menu[idx].fp_onKeyONE) + (*menu[idx].fp_onKeyONE)(); + + bl_delay = 0; + break; + + case KEY_02: + if( *menu[idx].fp_onKeyTWO) + (*menu[idx].fp_onKeyTWO)(); + + bl_delay = 0; + break; + + case KEY_03: + if( *menu[idx].fp_onKeyTHREE) + (*menu[idx].fp_onKeyTHREE)(); + + bl_delay = 0; + break; + + case KEY_04: + if( *menu[idx].fp_onKeyFOUR) + (*menu[idx].fp_onKeyFOUR)(); + + bl_delay = 0; + break; + + case KEY_05: + if( *menu[idx].fp_onKeyFIVE) + (*menu[idx].fp_onKeyFIVE)(); + + bl_delay = 0; + break; + + case KEY_POWER: + //Reboot if the power button is pressed + powerPressed++; + if(powerPressed > 5) //0.5 seconds + Reboot(); + break; + + default: + //No key pressed + break; + } + + /* Idle loop function */ + + /* Backlight switch off */ + if(bl_delay >= BL_SWITCH_OFF_DELAY ) + { + LcdBackLight(LCD_BACKLIGHT_OFF); + } + else + { + LcdBackLight(LCD_BACKLIGHT_ON); + bl_delay++; + } + + if(GetBacklight() == 1) + bl_delay = 0; + + /* Loop delay */ + NutSleep(100); + } + + powerPressed = 0; + activeCount = 10; + keyloop_done = 0; + + /* Keypress is handled, call the menu's exit function. */ + if( *menu[idx].fp_onExit ) + (*menu[idx].fp_onExit)(); + + + NutSleep(250); + } +} + diff --git a/C-RK/C-RK-Week3/menu.h b/C-RK/C-RK-Week3/menu.h new file mode 100644 index 0000000..3ef3fa0 --- /dev/null +++ b/C-RK/C-RK-Week3/menu.h @@ -0,0 +1,48 @@ +#ifndef MENU_INCLUDE +#define MENU_INCLUDE + +/* Defines */ +#define BL_SWITCH_OFF_DELAY 100 // lcd back-light switches of 10 sec after idle +#define MAX_MENU_KEY 4 +#define LCD_MAX_LINES 2 +/* Exported functions */ +void handleMenu(void); +void InitMenu(void); +void navigateToMenu(unsigned int); + +void AlarmStartedRinging(void); +void AlarmStoppedRinging(void); + +typedef struct +{ + unsigned int menuID; /* (Uniek) MenuID */ + + //Navigating + void (*fp_onEntry)(void); /* On entry function call */ + void (*fp_onActive)(void); //On active function call + void (*fp_onExit)(void); /* On exit function call */ + + //Key events + void (*fp_onKeyESC)(void); /* function call for key's */ + void (*fp_onKeyUP)(void); + void (*fp_onKeyDOWN)(void); + void (*fp_onKeyLEFT)(void); + void (*fp_onKeyRIGHT)(void); + void (*fp_onKeyOK)(void); + void (*fp_onKeyONE)(void); + void (*fp_onKeyTWO)(void); + void (*fp_onKeyTHREE)(void); + void (*fp_onKeyFOUR)(void); + void (*fp_onKeyFIVE)(void); + void (*fp_onKeyALT)(void); + + //Quick navigating + unsigned int newMenuIdKey[MAX_MENU_KEY]; /* New menuId when key pressed */ + + //Text and other data + char *txt[LCD_MAX_LINES]; /* LCD_MAX_LINES lines of LCD text (or NULL) */ + +} MENU_ITEM_STRUCT; + +#endif + diff --git a/C-RK/C-RK-Week3/player.c b/C-RK/C-RK-Week3/player.c new file mode 100644 index 0000000..b0fe21a --- /dev/null +++ b/C-RK/C-RK-Week3/player.c @@ -0,0 +1,344 @@ + +#define LOG_MODULE LOG_PLAYER_MODULE + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "player.h" +#include "vs10xx.h" +#include "streamer.h" +#include "settings.h" +#include + +#define OK 1 +#define NOK 0 + +int stopped = 1; +int stopstream = 0; + +char* MetaData; + +int initPlayer(void) +{ + MetaData = (char *) calloc(128, sizeof(char)); + + SetBass(GetBass()); + SetTreble(GetTreble()); + SetVolume(GetVolume()); + return OK; +} + +char* GetMetaData(void) +{ + return MetaData; +} + +int isStreaming() +{ + return !stopped; +} + +int ProcessMetaData(FILE *stream) +{ + u_char blks = 0; + u_short cnt; + int got; + int rc = 0; + u_char *mbuf; + + /* + * Wait for the lenght byte. + */ + got = fread(&blks, 1, 1, stream); + if(got != 1) { + return -1; + } + if (blks) { + if (blks > 32) { + printf("[PLAYER] Error: Metadata too large, %u blocks\n", blks); + return -1; + } + + cnt = blks * 16; + if ((mbuf = malloc(cnt + 1)) == 0) { + return -1; + } + + /* + * Receive the metadata block. + */ + for (;;) { + if ((got = fread(mbuf + rc, 1, cnt, stream)) <= 0) { + return -1; + } + if ((cnt -= got) == 0) { + break; + } + rc += got; + mbuf[rc] = 0; + } + + memset(&MetaData[0], 0, sizeof(MetaData)); + + int count = 0; + int copy = 0; + + int startval = 0; + int stopval = 0; + + for(;;) + { + + if(mbuf[count] == '\'' && copy == 1) + { + copy = 0; + stopval = count-1; + break; + } + + if(mbuf[count] == '\'' && copy == 0) + { + startval = count+1; + copy = 1; + } + + count++; + } + + int len = stopval - startval; + len = len > 127 ? 127 : len; + + strncpy(MetaData, (char*) &mbuf[startval], len); + + free(mbuf); + } + return 0; +} + +int stop(void) +{ + if(stopped == 1) + return 0; + + printf("[PLAYER] Stopping other stream\n"); + + stopstream = 1; + + while(!stopped) { NutSleep(5); }; + printf("[PLAYER] Stream stopped\n"); + + //Give thread time to clean up + NutSleep(100); + + strcpy(MetaData, ""); + + return 1; +} + +int play(u_long ip, u_short port, u_char *path) +{ + stop(); //Stop any old threads + + FILE *stream; + TCPSOCKET *sock = 0; + u_long metaint; + + stream = ConnectStation(sock, ip, port, path, &metaint); //Connect to a stream + + if(!stream) + { + printf("[PLAYER] Not stream\n"); + return NOK; + } + + //Package 3 variables in a struct to pass them to the thread. + StreamData *arguments = malloc(sizeof(StreamData)); + arguments->stream = stream; + arguments->sock = sock; + arguments->metaint = metaint; + + //Start thread with packaged arguments + NutThreadCreate("Streamer", StreamPlayer, arguments, 512); + + //Await thread start + NutSleep(20); + + //Clear the packege + free(arguments); + + return OK; +} + +THREAD(StreamPlayer, arg) +{ + + NutThreadSetPriority(1); // high prio + + printf("[PLAYER] Play thread created. Device is playing stream now !\n"); + + StreamData* f = (StreamData *) arg; + + FILE* stream = f->stream; + TCPSOCKET* sock = f->sock; + u_long metaint = f->metaint; + + size_t rbytes; + u_char *mp3buf; + u_char ief; + int got = 0; + u_long last; + u_long mp3left = metaint; + int endstream = 0; + + /* + * Initialize the MP3 buffer. The NutSegBuf routines provide a global + * system buffer, which works with banked and non-banked systems. + */ + if (NutSegBufInit(8192) == 0) { + printf("[PLAYER] Error: MP3 buffer init failed\n"); + NutThreadExit(); + } + + /* + * Initialize the MP3 decoder hardware. + */ + if (VsPlayerReset(0)) { + printf("[PLAYER] Error: MP3 hardware init failed\n"); + NutThreadExit(); + } + + stopped = 0; + + /* + * Reset the MP3 buffer. + */ + ief = VsPlayerInterrupts(0); + NutSegBufReset(); + VsPlayerInterrupts(ief); + last = NutGetSeconds(); + + for (;;) { + + if(stopstream) + { + break; + } + + /* + * Query number of byte available in MP3 buffer. + */ + ief = VsPlayerInterrupts(0); + mp3buf = (u_char*) NutSegBufWriteRequest(&rbytes); + VsPlayerInterrupts(ief); + + /* + * If the player is not running, kick it. + */ + if (VsGetStatus() != VS_STATUS_RUNNING) { + printf("[PLAYER] Not running\n"); + if(rbytes < 1024 || NutGetSeconds() - last > 4UL) { + last = NutGetSeconds(); + printf("[PLAYER] Kick player\n"); + VsPlayerKick(); + } + } + /* + * Do not read pass metadata. + */ + if (metaint && rbytes > mp3left) { + rbytes = mp3left; + } + + /* + * Read data directly into the MP3 buffer. + */ + while (rbytes) { + + if ((got = fread(mp3buf, 1, rbytes, stream)) > 0) { + ief = VsPlayerInterrupts(0); + mp3buf = (u_char *) NutSegBufWriteCommit(got); + VsPlayerInterrupts(ief); + + if (metaint) { + mp3left -= got; + if (mp3left == 0) { + ProcessMetaData(stream); + mp3left = metaint; + } + } + + if(got < rbytes && got < 512) { + //printf("%lu buffered\n", NutSegBufUsed()); + NutSleep(250); + } + else { + NutThreadYield(); + } + } else { + printf("[PLAYER] Failed to read from stream, closing\n"); + break; + } + rbytes -= got; + } + + if(got <= 0) { + endstream++; + + printf("[PLAYER] Stream ending, %d tries left\n", 3 - endstream); + + if(endstream >= 3) + { + printf("[PLAYER] End of stream, closing\n"); + break; + } + } + else + endstream = 0; + } + + VsPlayerStop(); //Stop the audio + + while (VsGetStatus() == VS_STATUS_RUNNING) { + NutSleep(50); //Wait until player has really stopped + } + + fclose(stream); //Close stream + NutTcpCloseSocket(sock); //Close socket + + strcpy(MetaData, ""); //Clear meta data + + stopstream = 0; //Clear stop flag + stopped = 1; //Mark thread as stopped + + printf("[PLAYER] End of play thread\n"); + + NutThreadExit(); //Clean up thread and exit + + for(;;) + { + printf("[PLAYER] PLAY THREAD NOT STOPPED\n"); + NutThreadYield(); + } +} + + + diff --git a/C-RK/C-RK-Week3/player.h b/C-RK/C-RK-Week3/player.h new file mode 100644 index 0000000..0c3a025 --- /dev/null +++ b/C-RK/C-RK-Week3/player.h @@ -0,0 +1,28 @@ +#ifndef PLAYER_INC +#define PLAYER_INC + +#include +#include + +//#include +//#include +#include +#include + +//Struct to package arguments to array +typedef struct +{ + FILE* stream; + TCPSOCKET* sock; + u_long metaint; +} StreamData; + +THREAD(StreamPlayer, arg); + +extern int initPlayer(void); +extern char * GetMetaData(void); +extern int play(u_long ip, u_short port, u_char *path); +extern int stop(void); +extern int isStreaming(void); + +#endif diff --git a/C-RK/C-RK-Week3/rtc.c b/C-RK/C-RK-Week3/rtc.c new file mode 100644 index 0000000..0604d1e --- /dev/null +++ b/C-RK/C-RK-Week3/rtc.c @@ -0,0 +1,155 @@ +/* ======================================================================== + * [PROJECT] SIR + * [MODULE] Real Time Clock + * [TITLE] High- and low level Routines for INtersil X1205 RTC chip + * [FILE] rtc.c + * [VSN] 1.0 + * [CREATED] 13042007 + * [LASTCHNGD] 131042007 + * [COPYRIGHT] Copyright (C) STREAMIT BV 2010 + * [PURPOSE] contains all interface- and low-level routines to + * read/write date/time/status strings from the X1205 + * ======================================================================== */ + +#define LOG_MODULE LOG_RTC_MODULE + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "rtc.h" +#include "portio.h" + +//Timezones with offset value and name +const int tz[25] = { -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, +13}; +const char tzName[25][30] = { "Midway", "Honolulu", "Anchorage", "Los Angeles", "Phoenix", "Chicago", "New York", "Santiago", "Buenos Aires", "South-Georgia", "Azores", "London", "Amsterdam", "Athens", "Moscow", "Dubai", "Pakistan", "Bangladesh", "Bangkok", "Bejing", "Tokyo", "Sydney", "Solomon", "Auckland", "Samoa" }; + + +//Sync the RTC with NTP server and apply timezone offset +int X12RTCSyncClock(void) +{ + time_t cur_time = 0; + tm *cur_dt = malloc(sizeof(tm)); + + uint32_t timeserver = 0; + + timeserver = inet_addr("85.254.217.3"); + + int i; + //3 attempts are allowed before giving up + for (i = 0; i < 3; i++) { + + //Try to get the NTP time + if (NutSNTPGetTime(×erver, &cur_time) == 0) { + synced = 1; //Mark time as synced + + printf("[RTC] Sync Succesfull\n"); + + //TimeZone + _timezone = 0; + stime(&cur_time); + + _timezone = -GetTimeZone() * 60 * 60; //Apply timezone offset + _daylight = 1; + time(&cur_time); + cur_dt = localtime(&cur_time); //Calculate timezone offset + + X12RtcSetClock(cur_dt); //Set the new time in the RTC + break; + } else { + synced = 0; //Mark time as out of sync + NutSleep(500); + printf("[RTC] Sync Failed, retrying\n"); + } + } + + free(cur_dt); + + SetConnected(synced); //Mark network connections the same as synced value + + return 1; +} + +//Format the RTC value to a Time string +void GetTimeString(char * str) +{ + if (X12RtcGetClock(&gmt) == 0) + { + gmt.tm_year = gmt.tm_year + 1900; + sprintf(str, "%02d:%02d:%02d", gmt.tm_hour, gmt.tm_min, gmt.tm_sec); + } +} + +//Format the RTC value to a Date string +void GetDateString(char * str) +{ + if (X12RtcGetClock(&gmt) == 0) + { + gmt.tm_year = gmt.tm_year + 1900; + sprintf(str, "%02d-%02d-%04d", gmt.tm_mday, gmt.tm_mon+1, gmt.tm_year ); + } +} + +//Format the RTC value to a DateTime string +void GetDateTimeString(char * str) +{ + if (X12RtcGetClock(&gmt) == 0) + { + gmt.tm_year = gmt.tm_year + 1900; + sprintf(str, "%02d:%02d %02d-%02d-%04d", gmt.tm_hour, gmt.tm_min, gmt.tm_mday, gmt.tm_mon+1, gmt.tm_year ); + } +} + +//Get the time struct which is synced using the RTC and NTP +tm* GetTimeStruct(void) +{ + if (X12RtcGetClock(&gmt) == 0) + { + gmt.tm_year = gmt.tm_year + 1900; + } + + return &gmt; +} + +//Sync time with the NTP server +int SyncTime( void ) +{ + X12RTCSyncClock(); + + if (X12RtcGetClock(&gmt) == 0) + { + //X12RtcGetClockTimezone(&gmt, GetTimeZone()); + gmt.tm_year = gmt.tm_year + 1900; + printf("[RTC] Time [%02d:%02d:%02d / %02d-%02d-%04d]\n", gmt.tm_hour, gmt.tm_min, gmt.tm_sec, gmt.tm_mday, gmt.tm_mon+1, gmt.tm_year ); + } + + return synced; +} + +int GetTimeSynced(void) +{ + return synced; +} + +int GetTimeZoneValue(int i) +{ + return tz[i]; +} + +void GetTimeZoneName(int i, char * string) +{ + strcpy(string, tzName[i]); +} diff --git a/C-RK/C-RK-Week3/rtc.h b/C-RK/C-RK-Week3/rtc.h new file mode 100644 index 0000000..8a78b61 --- /dev/null +++ b/C-RK/C-RK-Week3/rtc.h @@ -0,0 +1,28 @@ +#ifndef _RTC_H_ +#define _RTC_H_ + +#include // for tm-struct + +tm gmt; +int synced; + +extern void GetDateString(char*); +extern void GetDateTimeString(char*); +extern void GetTimeString(char*); +extern tm* GetTimeStruct(void); +extern int SyncTime( void ); +extern int GetTimeSynced( void ); + +extern int GetTimeZoneValue(int); +extern void GetTimeZoneName(int, char *); + +/* Prototypes */ +extern int X12Init(void); + +extern int X12RtcGetClock(tm *tm); +extern int X12RtcSetClock(CONST tm *tm); +extern int X12RtcSyncClock(void); +extern int X12RtcWrite(int nv, CONST u_char *buff, size_t len); + +/* End of prototypes */ +#endif diff --git a/C-RK/C-RK-Week3/streamer.c b/C-RK/C-RK-Week3/streamer.c new file mode 100644 index 0000000..77f56d6 --- /dev/null +++ b/C-RK/C-RK-Week3/streamer.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "streamer.h" +#include "player.h" +#include "web.h" + +#define OK 1 +#define NOK 0 +/*! + * \brief Connect to a radio station. + * + * \param sock TCP socket for this connection. + * \param ip IP address of the server to connect. + * \param port Port number of the server to connect. + * + * \return Stream pointer of the established connection on success. + * Otherwise 0 is returned. + */ +FILE *ConnectStation(TCPSOCKET *sock, u_long ip, u_short port, u_char *path, u_long *metaint){ + FILE *stream; + u_char *line; + u_char *cp; + + stream = getStream(sock, ip,port); + + /* + * Send the HTTP request. + */ + printf("[STREAMER] GET %s HTTP/1.0\n\n", path); + fprintf(stream, "GET %s HTTP/1.0\r\n", path); + fprintf(stream, "Host: %s\r\n", inet_ntoa(ip)); + fprintf(stream, "User-Agent: Ethernut\r\n"); + fprintf(stream, "Accept: */*\r\n"); + fprintf(stream, "Icy-MetaData: 1\r\n"); + fprintf(stream, "Connection: close\r\n"); + fputs("\r\n", stream); + fflush(stream); + + /* + * Receive the HTTP header. + */ + line = malloc(MAX_HEADERLINE); + while(fgets((char*) line, MAX_HEADERLINE, stream)) { + + /* + * Chop off the carriage return at the end of the line. If none + * was found, then this line was probably too large for our buffer. + */ + cp = (u_char *) strchr((char*) line, '\r'); + if(cp == 0) { + printf("[STREAMER] Warning: Input buffer overflow\n"); + continue; + } + *cp = 0; + + /* + * The header is terminated by an empty line. + */ + if(*line == 0) { + break; + } + if(strncmp((char*) line, "icy-metaint:", 12) == 0) { + *metaint = atol( (char*) (line + 12)); + } + printf("[STREAMER] line of metaint: %s\n", line); + } + putchar('\n'); + + free(line); + + return stream; +} diff --git a/C-RK/C-RK-Week3/streamer.h b/C-RK/C-RK-Week3/streamer.h new file mode 100644 index 0000000..97e1264 --- /dev/null +++ b/C-RK/C-RK-Week3/streamer.h @@ -0,0 +1,9 @@ +#ifndef STREAMER_INC +#define STREAMER_INC + +#define MAX_HEADERLINE 512 + +extern FILE *ConnectStation(TCPSOCKET *sock, u_long ip, u_short port, u_char *path, u_long *metaint); + + +#endif