Demo for Embedded World 2015.
Dependencies: DMBasicGUI DMSupport
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
Generated on Wed Jul 13 2022 18:24:58 by 1.7.2