The out-of-the-box demo application flashed on all display modules before they are shipped.

Dependencies:   DMBasicGUI DMSupport

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AppRTCSettings.cpp Source File

AppRTCSettings.cpp

00001 /*
00002  *  Copyright 2014 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016 
00017 
00018 #include "mbed.h"
00019 #include "AppRTCSettings.h"
00020 #include "lpc_swim_font.h"
00021 
00022 /******************************************************************************
00023  * Defines and typedefs
00024  *****************************************************************************/
00025  
00026 #define BTN_OFF    20
00027  
00028 /******************************************************************************
00029  * Private variables
00030  *****************************************************************************/
00031 
00032 // Ugly but needed for callbacks
00033 static AppRTCSettings* theApp = NULL;
00034 
00035 /******************************************************************************
00036  * Private functions
00037  *****************************************************************************/
00038 
00039 static void buttonClicked(uint32_t x)
00040 {
00041   bool* done = (bool*)x;
00042   *done = true;
00043 }
00044 
00045 static void fieldClicked(uint32_t x)
00046 {
00047   if (theApp != NULL) {
00048     theApp->setActiveField(x);
00049   }
00050 }
00051 
00052 static void increaseValue(uint32_t x)
00053 {
00054   AppRTCSettings* app = (AppRTCSettings*)x;
00055   app->modifyValue(1);
00056 }
00057 
00058 static void decreaseValue(uint32_t x)
00059 {
00060   AppRTCSettings* app = (AppRTCSettings*)x;
00061   app->modifyValue(-1);
00062 }
00063 
00064 static void nextField(uint32_t x)
00065 {
00066   AppRTCSettings* app = (AppRTCSettings*)x;
00067   app->changeActiveField(true);
00068 }
00069 
00070 static void prevField(uint32_t x)
00071 {
00072   AppRTCSettings* app = (AppRTCSettings*)x;
00073   app->changeActiveField(false);
00074 }
00075 
00076 void AppRTCSettings::draw()
00077 {
00078     // Prepare fullscreen
00079     swim_window_open(_win, 
00080                    _disp->width(), _disp->height(),         // full size
00081                    (COLOR_T*)_fb,
00082                    0,0,_disp->width()-1, _disp->height()-1, // window position and size
00083                    1,                                       // border
00084                    GREEN,WHITE,BLACK);/*WHITE, RED,  BLACK);*/                     // colors: pen, backgr, forgr
00085     swim_set_pen_color(_win, BLACK);
00086     swim_set_title(_win, "Real Time Clock Settings", GREEN);
00087     swim_set_pen_color(_win, BLACK);
00088 
00089     ImageButton* ib;
00090     
00091     Resource* rOk = _res[Resource_Ok_button];
00092     Resource* rCancel = _res[Resource_Cancel_button];
00093     ib =  new ImageButton(_win->fb, _win->xpmax - 2*BTN_OFF - rCancel->width() -rOk->width(), _win->ypmax - BTN_OFF - rOk->height(), rOk->width(), rOk->height());
00094     ib->loadImages(rOk);
00095     ib->draw();
00096     _buttons[ButtonOk] = ib;    
00097     ib =  new ImageButton(_win->fb, _win->xpmax - BTN_OFF - rCancel->width(), _win->ypmax - BTN_OFF - rCancel->height(), rCancel->width(), rCancel->height());
00098     ib->loadImages(rCancel);
00099     ib->draw();
00100     _buttons[ButtonCancel] = ib;    
00101 
00102     int arrowW = _res[Resource_ArrowUp_button]->width();
00103     int arrowH = _res[Resource_ArrowUp_button]->height();
00104     ib =  new ImageButton(_win->fb, 300, 40, arrowW, arrowH);
00105     ib->loadImages( _res[Resource_ArrowUp_button]);
00106     ib->setAction(increaseValue, (uint32_t)this);
00107     ib->draw();
00108     _buttons[ButtonUp] = ib;    
00109     ib =  new ImageButton(_win->fb, 300, 40+arrowH+arrowH, arrowW, arrowH);
00110     ib->loadImages( _res[Resource_ArrowDown_button]);
00111     ib->setAction(decreaseValue, (uint32_t)this);
00112     ib->draw();
00113     _buttons[ButtonDown] = ib;
00114     ib =  new ImageButton(_win->fb, 300-arrowW/2-10, 40+arrowH, arrowW, arrowH);
00115     ib->loadImages(_res[Resource_ArrowLeft_button]);
00116     ib->setAction(prevField, (uint32_t)this);
00117     ib->draw();
00118     _buttons[ButtonLeft] = ib;
00119     ib =  new ImageButton(_win->fb, 300+arrowW/2+10, 40+arrowH, arrowW, arrowH);
00120     ib->loadImages(_res[Resource_ArrowRight_button]);
00121     ib->setAction(nextField, (uint32_t)this);
00122     ib->draw();
00123     _buttons[ButtonRight] = ib;
00124     
00125     // To avoid having each DigitButton deallocate the shared image
00126     void* pointerToFree = _digitImage.pointerToFree;
00127     _digitImage.pointerToFree = NULL;
00128 
00129     addDateFields(0, 20);
00130     addTimeFields(0, 20+65);
00131     
00132     // Restore shared image so that it will be deallocated during teardown
00133     _digitImage.pointerToFree = pointerToFree;    
00134     
00135   for (int i = 0; i < NumButtons; i++) {
00136     _buttons[i]->draw();
00137   }
00138   
00139   markField(_activeField, true);
00140 }
00141 
00142 void AppRTCSettings::addDateFields(int xoff, int yoff)
00143 {
00144     DigitButton* db;
00145     
00146     int fontY = yoff;
00147     int y = fontY + swim_get_font_height(_win) + 2;
00148     int btny = y-7;
00149     y += _win->ypvmin; // compensate for title bar 
00150     int x = xoff+20;
00151     int idx = ButtonYear;
00152     int btnw;
00153     
00154     swim_put_text_xy(_win, "Year", x, fontY);
00155     btnw = 65;
00156     db =  new DigitButton(_win->fb, x, y, btnw, 34);
00157     db->loadImages(&_digitImage);
00158     db->setNumDigits(4);
00159     db->setValue(_values[idx]);
00160     db->setAction(fieldClicked, idx);
00161     _buttons[idx++] = db;
00162     
00163     x += btnw + 20;
00164     btnw = 45;
00165     swim_put_text_xy(_win, "Month", x, fontY);
00166     db =  new DigitButton(_win->fb, x, y, btnw, 34);
00167     db->loadImages(&_digitImage);
00168     db->setNumDigits(2);
00169     db->setValue(_values[idx]);
00170     db->setAction(fieldClicked, idx);
00171     _buttons[idx++] = db;
00172     swim_put_box(_win, x-13, btny+20, x-2, btny+23);
00173     
00174     x += btnw + 10;    
00175     swim_put_text_xy(_win, "Day", x, fontY);
00176     db =  new DigitButton(_win->fb, x, y, btnw, 34);
00177     db->loadImages(&_digitImage);
00178     db->setNumDigits(2);
00179     db->setValue(_values[idx]);
00180     db->setAction(fieldClicked, idx);
00181     _buttons[idx++] = db;
00182     swim_put_box(_win, x-13, btny+20, x-2, btny+23);
00183 }
00184 
00185 void AppRTCSettings::addTimeFields(int xoff, int yoff)
00186 {
00187     DigitButton* db;
00188     
00189     int fontY = yoff;
00190     int y = fontY + swim_get_font_height(_win) + 2;
00191     int btny = y-7;
00192     y += _win->ypvmin; // compensate for title bar 
00193     int x = xoff+20;
00194     int idx = ButtonHour;
00195     int btnw = 45;
00196     
00197     swim_put_text_xy(_win, "Hour", x, fontY);
00198     db =  new DigitButton(_win->fb, x, y, btnw, 34);
00199     db->loadImages(&_digitImage);
00200     db->setNumDigits(2);
00201     db->setValue(_values[idx]);
00202     db->setAction(fieldClicked, idx);
00203     _buttons[idx++] = db;
00204     
00205     x += btnw + 10;    
00206     swim_put_text_xy(_win, "Minutes", x, fontY);
00207     db =  new DigitButton(_win->fb, x, y, btnw, 34);
00208     db->loadImages(&_digitImage);
00209     db->setNumDigits(2);
00210     db->setValue(_values[idx]);
00211     db->setAction(fieldClicked, idx);
00212     _buttons[idx++] = db;
00213     swim_put_box(_win, x-13, btny+22, x-2, btny+25);
00214     
00215     x += btnw + 10;    
00216     swim_put_text_xy(_win, "Seconds", x, fontY);
00217     db =  new DigitButton(_win->fb, x, y, btnw, 34);
00218     db->loadImages(&_digitImage);
00219     db->setNumDigits(2);
00220     db->setValue(_values[idx]);
00221     db->setAction(fieldClicked, idx);
00222     _buttons[idx++] = db;
00223     swim_put_box(_win, x-13, btny+22, x-2, btny+25);
00224 }
00225 
00226 void AppRTCSettings::markField(int field, bool active)
00227 {
00228   COLOR_T oldPen = _win->pen;
00229   COLOR_T oldFill = _win->fill;
00230   _win->fill = active ? BLACK : _win->bkg;
00231   _win->pen = active ? BLACK : _win->bkg;
00232   if (field >= 0 && field < NumFields) {
00233     int x0, y0, x1, y1;
00234     _buttons[field]->bounds(x0,y0,x1,y1);
00235     y1 -= _win->ypvmin+1;
00236     x0--;
00237     swim_put_box(_win, x0, y1, x1, y1+3);
00238   }
00239   _win->fill = oldFill;
00240   _win->pen = oldPen;
00241 }
00242 
00243 /******************************************************************************
00244  * Public functions
00245  *****************************************************************************/
00246 
00247 AppRTCSettings::AppRTCSettings() : _disp(NULL), _win(NULL), _fb(NULL), _activeField(0)
00248 {
00249   for (int i = 0; i < NumButtons; i++) {
00250     _buttons[i] = NULL;
00251   }
00252   for (int i = 0; i < NumResources; i++) {
00253     _res[i] = NULL;
00254   }
00255   time_t rawtime;
00256   struct tm * timeinfo;
00257 
00258   time (&rawtime);
00259   timeinfo = localtime (&rawtime);
00260   
00261   _values[ButtonYear] = timeinfo->tm_year + 1900;
00262   _values[ButtonMonth] = timeinfo->tm_mon + 1;
00263   _values[ButtonDay] = timeinfo->tm_mday;
00264   _values[ButtonHour] = timeinfo->tm_hour;
00265   _values[ButtonMinute] = timeinfo->tm_min;
00266   _values[ButtonSecond] = timeinfo->tm_sec;
00267   
00268   _digitImage.pointerToFree = NULL;
00269   
00270   theApp = this;
00271 }
00272 
00273 AppRTCSettings::~AppRTCSettings()
00274 {
00275     theApp = NULL;
00276     teardown();
00277 }
00278 
00279 bool AppRTCSettings::setup()
00280 {
00281     _disp = DMBoard::instance().display();
00282     _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
00283     _fb = _disp->allocateFramebuffer();
00284     int res = Image::decode(_res[Resource_Digits], Image::RES_16BIT, &_digitImage);
00285 
00286     return (_win != NULL && _fb != NULL && res == 0);
00287 }
00288 
00289 void AppRTCSettings::runToCompletion()
00290 {
00291     // Alternative 1: use the calling thread's context to run in
00292     bool done = false;
00293     bool abort = false;
00294     draw();
00295     _buttons[ButtonOk]->setAction(buttonClicked, (uint32_t)&done);
00296     _buttons[ButtonCancel]->setAction(buttonClicked, (uint32_t)&abort);
00297     void* oldFB = _disp->swapFramebuffer(_fb);
00298     
00299     // Wait for touches
00300     TouchPanel* touch = DMBoard::instance().touchPanel();
00301     touch_coordinate_t coord;
00302 
00303     int lastPressed = NumButtons;
00304     Timer t;
00305     t.start();
00306     int repeatAt = 0;
00307 
00308     uint32_t maxDelay = osWaitForever; 
00309     while(!done && !abort) {
00310       ThisThread::flags_wait_all_for(0x1, maxDelay);
00311       if (touch->read(coord) == TouchPanel::TouchError_Ok) {
00312         for (int i = 0; i < NumButtons; i++) {
00313           if (_buttons[i]->handle(coord.x, coord.y, coord.z > 0)) {
00314             _buttons[i]->draw();
00315             if (_buttons[i]->pressed()) {
00316               lastPressed = i; // new button pressed
00317               t.reset();
00318               repeatAt = 1000;
00319             }
00320           }
00321         }
00322         if (lastPressed == ButtonUp || lastPressed == ButtonDown) {
00323           maxDelay = 10;
00324           if (_buttons[lastPressed]->pressed() && t.read_ms() > repeatAt) {
00325             modifyValue((lastPressed == ButtonUp) ? 1 : -1);
00326             repeatAt = t.read_ms()+(200/(t.read_ms()/1000));
00327           }
00328         } else {
00329           maxDelay = osWaitForever;
00330         }
00331       }
00332     }
00333 
00334     if (!abort) {
00335       RtosLog* log = DMBoard::instance().logger();
00336       log->printf("New time: %04d-%02d-%02d  %02d:%02d:%02d\n", _values[0], _values[1],
00337           _values[2], _values[3], _values[4], _values[5]);
00338         tm t;
00339         t.tm_year = _values[ButtonYear] - 1900;  // years since 1900
00340         t.tm_mon = _values[ButtonMonth] - 1;      // month is 0..11
00341         t.tm_mday = _values[ButtonDay];
00342         t.tm_hour = _values[ButtonHour];
00343         t.tm_min = _values[ButtonMinute];
00344         t.tm_sec = _values[ButtonSecond];
00345         set_time(mktime(&t));
00346     }
00347     
00348     // User has clicked the button, restore the original FB
00349     _disp->swapFramebuffer(oldFB);
00350     swim_window_close(_win);
00351 }
00352 
00353 bool AppRTCSettings::teardown()
00354 {
00355     if (_win != NULL) {
00356         free(_win);
00357         _win = NULL;
00358     }
00359     if (_fb != NULL) {
00360         free(_fb);
00361         _fb = NULL;
00362     }
00363     for (int i = 0; i < NumButtons; i++) {
00364         if (_buttons[i] != NULL) {
00365             delete _buttons[i];
00366             _buttons[i] = NULL;
00367         }
00368     }
00369     if (_digitImage.pointerToFree != NULL) {
00370         free(_digitImage.pointerToFree);
00371         _digitImage.pointerToFree = NULL;
00372     }
00373     return true;
00374 }
00375 
00376 void AppRTCSettings::modifyValue(int mod)
00377 {
00378   uint32_t v = _values[_activeField];
00379   switch (_activeField) {
00380       case ButtonYear:
00381           // 1970..2100
00382           _values[_activeField] = (((v - 1970 + (2100-1970)) + mod) % (2100-1970)) + 1970;
00383           break;
00384       case ButtonMonth:
00385           // 1..12
00386           _values[_activeField] = (((v - 1 + 12) + mod) % 12) + 1;
00387           break;
00388       case ButtonDay:
00389           // 1..31
00390           _values[_activeField] = (((v - 1 + 31) + mod) % 31) + 1;
00391           break;
00392       case ButtonHour:
00393           // 0..23
00394           _values[_activeField] = (v + 24 + mod) % 24;
00395           break;
00396       case ButtonMinute:
00397       case ButtonSecond:
00398           // 0..59
00399           _values[_activeField] = (v + 60 + mod) % 60;
00400           break;
00401   }
00402   ((DigitButton*)_buttons[_activeField])->setValue(_values[_activeField]);
00403 }
00404 
00405 void AppRTCSettings::changeActiveField(bool next)
00406 {
00407   markField(_activeField, false);
00408   if (next) {
00409     _activeField = (_activeField+1) % NumFields;
00410   } else {
00411     _activeField = (_activeField+NumFields-1) % NumFields;
00412   }
00413   markField(_activeField, true);
00414 }
00415 
00416 void AppRTCSettings::setActiveField(uint32_t newField)
00417 {
00418   if (_activeField != newField && newField < NumFields) {
00419     markField(_activeField, false);
00420     _activeField = newField;
00421     markField(_activeField, true);
00422   }
00423 }
00424 
00425 void AppRTCSettings::addResource(Resources id, Resource* res)
00426 {
00427     _res[id] = res;
00428 }
00429 
00430