/******************************************************************************* * File Name : UserMenu.c * Author : lxyppc * Version : V1.0 * Date : 10-03-05 * Description : User menu implemention *******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_lib.h" #include "menu.h" #include "SSD1303.h" #include "Graphics\Graphics.h" #include "time.h" #include "icon.h" #include "bsp.h" #include "ClockUI.h" #include "string.h" #include "StringResource.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ //#define OnMeasureBat DefaultMenuFunc //#define OnMeasureGravity DefaultMenuFunc //#define OnSetContrast DefaultMenuFunc //#define OnSetTime DefaultMenuFunc //#define OnLanguageSet DefaultMenuFunc /* Private variables ---------------------------------------------------------*/ extern const MenuItem MainMenu[]; extern const MenuItem SettingMenu[]; extern const MenuItem StatusMenu[]; extern const MenuItem LanguageMenu[]; const LPCSTR* curLang = StringTable_CHS; Device appDevice; extern ADResult_t ADCResult; #define LoadString(STR_ID) curLang[(STR_ID)] // January is 0 #define LoadStrMonth(Month) LoadString(STR_JAN + (Month)) // Sunday is 0 #define LoadStrWeek(WeekDay) LoadString(STR_SUNDAY + (WeekDay)) // Year is 0, then month,date,hour and minute #define LoadStrTimeDesc(index) LoadString(STR_YEAR + (index)) //LPCSTR* MonthText = MonthText_En; //LPCSTR* WeekText = WeekText_En; //LPCSTR * SetTimeDesc = SetTimeDesc_En; //LPCSTR* UserText = UserText_En; //#define UserText (curLang) //#define MonthText (curLang + STR_JAN) //#define WeekText (curLang + STR_SUNDAY) //#define SetTimeDesc (curLang + STR_YEAR) /* Private function prototypes -----------------------------------------------*/ MenuResult OnMenuAbout(void* p, Msg* msg); MenuResult OnMenuTest(void* p, Msg* msg); MenuResult DefaultMenuFunc(void* p, Msg* msg); MenuResult OnMenuRoot(void* param, Msg* msg); MenuResult OnSetContrast(void* param, Msg* msg); MenuResult OnSetTime(void* param, Msg* msg); MenuResult OnMeasureGravity(void* param, Msg* msg); MenuResult OnMeasureBat(void* param, Msg* msg); MenuResult OnLanguageSet(void* param, Msg* msg); /* Private functions ---------------------------------------------------------*/ /******************************************************************************/ /************************** Menu definitions begin ****************************/ /* Root main */ const MenuItem RootMenu = { /*Parent child/pfn index cnt resource type*/ 0, (void*)OnMenuRoot, 0, 1, STR_ROOT, MT_NULL }; /* Main menu */ const MenuItem MainMenu[] = { /*Parent child/pfn index cnt resource type*/ { 0, StatusMenu, 0, 4, STR_STATUS, MT_SUB}, { 0, (void*)OnMenuTest, 1, 4, STR_TEST, MT_NULL}, { 0, SettingMenu, 2, 4, STR_SETTING, MT_SUB}, { 0, (void*)OnMenuAbout, 3, 4, STR_ABOUT, MT_NULL}, }; /* Setting menu */ const MenuItem SettingMenu[] = { /*Parent child/pfn index cnt resource type*/ { MainMenu+2, (void*)OnSetContrast, 0, 3, STR_SETTING_CONTRAST, MT_NULL}, { MainMenu+2, (void*)OnSetTime, 1, 3, STR_SETTING_TIME, MT_NULL}, { MainMenu+2, LanguageMenu, 2, 3, STR_SETTING_LANGUAGE, MT_SUB}, }; /* Language menu*/ const MenuItem LanguageMenu[] = { /*Parent child/pfn index cnt resource type*/ {SettingMenu+2, (void*)OnLanguageSet, 0, 2, STR_LANG_ENG, MT_NULL}, {SettingMenu+2, (void*)OnLanguageSet, 1, 2, STR_LANG_CHS, MT_NULL}, }; /**/ const MenuItem StatusMenu[] = { /*Parent child/pfn index cnt resource type*/ { MainMenu+0, (void*)OnMeasureBat, 0, 2, STR_STATUS_BAT, MT_NULL}, { MainMenu+0, (void*)OnMeasureGravity, 1, 2, STR_STATUS_GRAVITY, MT_NULL}, }; /************************** Menu definitions end ****************************/ /******************************************************************************/ /******************************************************************************* * Function Name : OnMenuAbout * Description : Callback function for about menu * Input : void* pointer of the menu item when message is MSG_INIT * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ MenuResult OnMenuAbout(void* p, Msg* msg) { if(msg->message == MSG_INIT){ SetColor(BLACK); ClearDevice(); TextOut(&appDevice, 0, 5,LoadString(STR_ABOUT_0), 0xFF); TextOut(&appDevice, 0, 25,LoadString(STR_ABOUT_1), 0xFF); TextOut(&appDevice, 0, 45,LoadString(STR_ABOUT_2), 0xFF); return MR_Continue; }else if(msg->message == MSG_KEY_UP){ return MR_Finish; } return MR_Continue; } /******************************************************************************* * Function Name : OnMenuTest * Description : Callback function for test menu * Input : void* pointer of the menu item when message is MSG_INIT * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ MenuResult OnMenuTest(void* p, Msg* msg) { if(msg->message == MSG_INIT){ SetColor(BLACK); ClearDevice(); TextOut(&appDevice, 0, 0, "Scroll Test", 0xFF); return MR_Continue; }else if(msg->message == MSG_KEY_UP){ return MR_Finish; }else if(msg->message == MSG_SCROLL){ s32 res = (s32)msg->param; char buf[3] = "+"; if(res<0){ res = -res; buf[0] = '-'; } static Pos_t x = 0; static Pos_t y = 13; buf[1] = res%10+'0'; buf[2] = ','; x = TextOut(&appDevice, x, y, buf, 3); if(x > 110){ x = 0; y+=13; } if( y > 64-12){ y = 13; } } return MR_Continue; } /******************************************************************************* * Function Name : DefaultMenuFunc * Description : Default menu callback function * Input : void* pointer of the menu item when message is MSG_INIT * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ MenuResult DefaultMenuFunc(void* p, Msg* msg) { if(msg->message == MSG_INIT){ SetColor(BLACK); ClearDevice(); TextOut(&appDevice, 0, 25,curLang[STR_DEFAULT], 0xFF); return MR_Continue; }else if(msg->message == MSG_KEY_UP){ return MR_Finish; } return MR_Continue; } /******************************************************************************* * Function Name : GetBatCap * Description : Get battery capacity * Input : None * Output : Battary capacity percentage * Return : None * Details : Battary fully charge is 4.2V, and lower power is 3.3V Vref = 3.28V, resistive partial-pressure is 10K/13.6K In 12 bit ADC, 4.2*10/13.6/3.28*4096 = 3875 3.3*10/13.6/3.28*4096 = 3030 *******************************************************************************/ unsigned long GetBatCap() { u32 res = ADCResult.ADBat; if(res > 3835){ res = 800; }else if(res < 3030){ res = 0; }else{ res -= 3030; } return 100*res/800; } /******************************************************************************* * Function Name : UpdateBatIcon * Description : Update the battery icon * Input : Pos_t x position of the icon * Pos_t y position of the icon * u32 battery capacity, in percentage * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ void UpdateBatIcon(Pos_t x, Pos_t y,u32 cap) { if(IsCHG()){ DrawIcon(x,y,ICON_ID_CHARGE); }else if(IsPGOOD()){ DrawIcon(x,y,ICON_ID_POWER); }else{ DrawIcon(x,y,ICON_ID_BATTARY); SetColor(BLACK); SetLineThickness(NORMAL_LINE); u32 res = cap*16/100; res += 106; Bar(res,2,121,7); } } /******************************************************************************* * Function Name : OnMenuRoot * Description : Root menu callback function * Input : void* pointer of the menu item when message is MSG_INIT * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ MenuResult OnMenuRoot(void* param, Msg* msg) { static u8 deviceClose = 0; switch(msg->message){ case MSG_INIT: SetColor(BLACK); ClearDevice(); Clock_DrawFace(GetMaxY()>>1,GetMaxY()>>1,GetMaxY()>>1); deviceClose = 0; case MSG_SECOND: { Pos_t x = 70; Pos_t y = 35; time_t now = (time_t)RTC_GetCounter(); struct tm* curTm = localtime(&now); Clock_UpdateTime(curTm->tm_hour,curTm->tm_min,curTm->tm_sec); u32 year = curTm->tm_year + 1900; char tBuf[8] = {year/1000+'0',year/100%10+'0',year/10%10+'0',year%10+'0'}; x = TextOut(&appDevice,x,y,tBuf,4); x = TextOut(&appDevice,x,y," ",1); x = TextOut(&appDevice,x,y,LoadStrWeek(curTm->tm_wday),3); x = 70; y += 13; x = TextOut(&appDevice,x,y,LoadStrMonth(curTm->tm_mon),0xFF); x = TextOut(&appDevice,x,y," ",1); tBuf[0] = curTm->tm_mday/10+'0'; tBuf[1] = curTm->tm_mday%10+'0'; x = TextOut(&appDevice,x,y,tBuf,2); x = TextOut(&appDevice,x,y," ",1); x = TextOut(&appDevice,70,y-26,LoadString(curTm->tm_hour>12 ? STR_PM : STR_AM),2); #ifdef DEBUG_BOARD { DrawIcon(104,0,ICON_ID_BATTARY); static u32 res1 = 16; if(res1)res1--; else res1=16; u32 res = res1 + 106; SetColor(BLACK); SetLineThickness(NORMAL_LINE); Bar(res,2,121,7); } #else UpdateBatIcon(104,0,GetBatCap()); #endif } break; case MSG_KEY_UP: if((u32)msg->param > SSD1303_FPS*2){ deviceClose = 1; SSD1303_TurnOff(); MMA_SLEEP(); }else if(deviceClose){ deviceClose = 0; SSD1303_TurnOn(); MMA_WAKEUP(); }else{ PopupMenu(MainMenu); return MR_Finish; } } return MR_Continue; } /******************************************************************************* * Function Name : OnSetContrast * Description : Set contrast menu callback function * Input : void* pointer of the menu item when message is MSG_INIT * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ MenuResult OnSetContrast(void* param, Msg* msg) { if(msg->message == MSG_INIT){ SetColor(BLACK); ClearDevice(); TextOut(&appDevice,0,0,LoadString(STR_CHANGE_CONTRAST),0xFF); u32 con = SSD1303_GetContrast(); char buf[] = {con/100+'0',(con/10)%10+'0',con%10+'0'}; TextOut(&appDevice,45,18,buf,3); SetLineThickness(NORMAL_LINE); SetColor(WHITE); Rectangle(0,30,127,45); con = 123*con/256 + 2; Bar(2,32,con,43); }else if(msg->message == MSG_SCROLL){ s16 enc = (s16)((s32)msg->param); u32 con = SSD1303_GetContrast(); if(enc>0){ if(con<255)con++; }else if(con){ con--; } char buf[] = {con/100+'0',(con/10)%10+'0',con%10+'0'}; TextOut(&appDevice,45,18,buf,3); SSD1303_SetContrast(con); SetColor(BLACK); Bar(2,32,125,43); SetColor(WHITE); con = 123*con/256 + 2; Bar(2,32,con,43); }else if(msg->message == MSG_KEY_UP){ return MR_Finish; } return MR_Continue; } typedef unsigned long(*pfnTextOut)(Device*,Pos_t,Pos_t,const char*,Size_t); #define DrawOK() UpdateTimeText(TextOut,0, TI_OK) #define DrawCancel() UpdateTimeText(TextOut,0, TI_Cancel) #define HighLightOK() UpdateTimeText(TextOut_HighLight,0, TI_OK) #define HighLightCancel() UpdateTimeText(TextOut_HighLight,0, TI_Cancel) typedef enum{ TI_All = 0, TI_Year = 1, TI_First = 1, TI_Month = 2, TI_Date = 3, TI_Hour = 4, TI_Minute = 5, TI_OK = 6, TI_Cancel = 7, TI_Last = 8, TI_Unknown = 0xFF, }TimeIndex; /******************************************************************************* * Function Name : UpdateTimeText * Description : Update texts when set time * Input : pfnTextOut pointer of textOut Function * struct tm* time structure to display * TimeIndex time item index * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ void UpdateTimeText(pfnTextOut textOut,struct tm* pTM, TimeIndex timeIndex) { u8 wid = GetFontTextWidth(appDevice.pfnFont,' '); Pos_t yPos = 13; switch(timeIndex){ case TI_All:// Inital textOut(&appDevice,2+16*wid,yPos,":",1); case TI_Year:// year { u32 year = pTM->tm_year + 1900; char buf[] = {year/1000+'0',year/100%10+'0',year/10%10+'0',year%10+'0'}; textOut(&appDevice,2,yPos,buf,4); } if(timeIndex!=TI_All)break; case TI_Month:// Month textOut(&appDevice,2+5*wid,yPos,LoadStrMonth(pTM->tm_mon),3); if(timeIndex!=TI_All)break; case TI_Date:// Date { char buf[] = {pTM->tm_mday/10+'0',pTM->tm_mday%10+'0'}; textOut(&appDevice,2+10*wid,yPos,buf,2); } if(timeIndex!=TI_All)break; case TI_Hour:// Hour { char buf[] = {pTM->tm_hour/10+'0',pTM->tm_hour%10+'0'}; textOut(&appDevice,2+14*wid,yPos,buf,2); } if(timeIndex!=TI_All)break; case TI_Minute:// Minute { char buf[] = {pTM->tm_min/10+'0',pTM->tm_min%10+'0'}; textOut(&appDevice,2+17*wid,yPos,buf,2); } if(timeIndex!=TI_All)break; case TI_OK:// OK textOut(&appDevice,2+1*wid,52,LoadString(STR_OK),2); if(timeIndex!=TI_All)break; case TI_Cancel:// cancel textOut(&appDevice,126-7*wid,52,LoadString(STR_CANCEL),6); if(timeIndex!=TI_All)break; default: break; } } #define Round(param,low,high) \ if((param)<(low)){(param)=(high);}else if((param)>(high)){(param)=(low);} /******************************************************************************* * Function Name : ModifyTime * Description : Set contrast menu callback function * Input : int Current encoder roll dirction * struct tm* time structure to be modified * TimeIndex time item index * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ void ModifyTime(int enc, struct tm* pTM, TimeIndex timeIndex) { switch(timeIndex){ case TI_Year: pTM->tm_year += enc; Round(pTM->tm_year,-130,130); { u32 year = pTM->tm_year + 1900; char buf[] = {year/1000+'0',year/100%10+'0',year/10%10+'0',year%10+'0'}; TextOut_HighLight(&appDevice,64,30,buf,4); } break; case TI_Month: pTM->tm_mon += enc; Round(pTM->tm_mon,0,11); TextOut_HighLight(&appDevice,64,30,LoadStrMonth(pTM->tm_mon),3); break; case TI_Date: pTM->tm_mday += enc; Round(pTM->tm_mday,1,31); { char buf[] = {pTM->tm_mday/10+'0',pTM->tm_mday%10+'0'}; TextOut_HighLight(&appDevice,64,30,buf,2); } break; case TI_Hour: pTM->tm_hour += enc; Round(pTM->tm_hour,0,23); { char buf[] = {pTM->tm_hour/10+'0',pTM->tm_hour%10+'0'}; TextOut_HighLight(&appDevice,64,30,buf,2); } break; case TI_Minute: pTM->tm_min += enc; Round(pTM->tm_min,0,59); { char buf[] = {pTM->tm_min/10+'0',pTM->tm_min%10+'0'}; TextOut_HighLight(&appDevice,64,30,buf,2); } break; default: break; } } /******************************************************************************* * Function Name : OnSetTime * Description : Set time menu callback function * Input : void* pointer of the menu item when message is MSG_INIT * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ MenuResult OnSetTime(void* param, Msg* msg) { static struct tm oldTm; static TimeIndex position; static TimeIndex lastPosition; static u8 modifyMode; if(msg->message == MSG_INIT){ time_t now = (time_t)RTC_GetCounter(); struct tm* ptm = localtime(&now); memcpy(&oldTm,ptm,sizeof(oldTm)); lastPosition = TI_Unknown; position = TI_All; SetColor(BLACK); ClearDevice(); TextOut(&appDevice,0,0,LoadString(STR_SET_TIME),0xFF); UpdateTimeText(TextOut,&oldTm,position); position++; UpdateTimeText(TextOut_HighLight,&oldTm,position); lastPosition = position; modifyMode = 0; }else if(msg->message == MSG_KEY_UP){ if(position == TI_Cancel){ return MR_Finish; }else if(position == TI_OK){ oldTm.tm_sec = 0; RTC_SetCounter(mktime(&oldTm)); RTC_WaitForLastTask(); return MR_Finish; }else if(position<7 && position>0){ if(modifyMode){ modifyMode = 0; SetColor(BLACK); Bar(10,30,100,50); UpdateTimeText(TextOut_HighLight,&oldTm,position); }else{ modifyMode = 1; TextOut(&appDevice,20,30,LoadStrTimeDesc(position-1),0xFF); ModifyTime(0,&oldTm,position); } } }else if(msg->message == MSG_SCROLL){ int enc = (int)msg->param; if(enc>0)enc=1; else enc = -1; if(modifyMode){ ModifyTime(enc,&oldTm,position); }else{ position+=enc; if(position>=TI_Last){ position = TI_Year; }else if(positionmessage == MSG_INIT){ SetColor(BLACK); ClearDevice(); SetColor(WHITE); SetLineThickness(NORMAL_LINE); Rectangle(64,0,127,63); Line(0,63,63,63); Line(63,63,48,40); Line(16,40,48,40); Line(16,40,0,63); MMA_WAKEUP(); }else if(msg->message == MSG_KEY_UP){ MMA_SLEEP(); return MR_Finish; }else if(msg->message == MSG_GRAV_XY){ static u16 lastX = 64+64*2; static u16 lastY = 64/2; u16 gX = 4096-GetGravX(msg); u16 gY = 4096-GetGravY(msg); gX = gX*64 / 4096+64; gY = gY*64 / 4096; SetColor(BLACK); FillCircle(lastX,lastY,2); SetColor(WHITE); FillCircle(gX,gY,2); lastX = gX; lastY = gY; }else if(msg->message == MSG_GRAV_Z){ static u16 lastZ = 50/2; u16 gZ = GetGravZ(msg); gZ = gZ*50 / 4096; SetColor(BLACK); Circle(32,lastZ,2); SetColor(WHITE); Circle(32,gZ,2); lastZ = gZ; } return MR_Continue; } /******************************************************************************* * Function Name : OnMeasureBat * Description : Measure battery menu callback function * Input : void* pointer of the menu item when message is MSG_INIT * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ MenuResult OnMeasureBat(void* param, Msg* msg) { switch(msg->message){ case MSG_INIT: SetColor(BLACK); ClearDevice(); TextOut(&appDevice,0,0,LoadString(STR_VIEW_BATTARY),0xFF); case MSG_SECOND: if(IsCHG()){ TextOut(&appDevice,10,16,LoadString(STR_BAT_CHARGE),0xFF); }else if(IsPGOOD()){ TextOut(&appDevice,10,16,LoadString(STR_BAT_FULL),0xFF); }else{ TextOut(&appDevice,10,16,LoadString(STR_BAT_NORMAL),0xFF); //DrawIcon(104,0,ICON_ID_BATTARY); } { u32 res = GetBatCap(); UpdateBatIcon(104,0,res); char buf[4] = {res/100 + '0',res/10%10+'0',res%10+'0','%'}; Pos_t x = TextOut(&appDevice,10,32,LoadString(STR_BAT_CAPACITY),0xFF); x = TextOut(&appDevice,x,32,buf,4); res = ADCResult.ADBat; res = ((res*136*120) / ADCResult.ADRef) / 100; //res = res * 328 * 136 / (4096*100); char ADBuf[] = {(res/100)%10+'0', '.', (res/10)%10+'0', res%10+'0','V', 0}; x = TextOut(&appDevice,10,48,LoadString(STR_BAT_VOLTAGE),0xFF); TextOut(&appDevice,x,48,ADBuf,5); } break; case MSG_KEY_UP: return MR_Finish; default: break; } return MR_Continue; } /******************************************************************************* * Function Name : OnLanguageSet * Description : Set language menu callback function * Input : void* pointer of the menu item when message is MSG_INIT * Output : Msg* pointer of the msg structure * Return : None *******************************************************************************/ MenuResult OnLanguageSet(void* param, Msg* msg) { static const LPCSTR* preLang = NULL; static u8 curSel = 0; switch(msg->message){ case MSG_INIT: { SetColor(BLACK); ClearDevice(); switch(((const MenuItem*)param)->res){ case STR_LANG_ENG: preLang = StringTable_ENG; TextOut(&appDevice,30,20,preLang[STR_LANG_ENG],0xFF); break; case STR_LANG_CHS: default: preLang = StringTable_CHS; TextOut(&appDevice,30,20,preLang[STR_LANG_CHS],0xFF); break; } curSel = 1; } case MSG_SCROLL: { curSel = !curSel; const LPCSTR* tmp = curLang; curLang = preLang; if(curSel){ HighLightOK(); DrawCancel(); }else{ DrawOK(); HighLightCancel(); } curLang = tmp; } break; case MSG_KEY_UP: if(curSel){ curLang = preLang; } return MR_Finish; } return MR_Continue; }