Demo for Embedded World 2015.

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