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 AppImageViewer.cpp Source File

AppImageViewer.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 "AppImageViewer.h"
00020 #include "lpc_swim_font.h"
00021 #include "lpc_swim_image.h"
00022 #include "Image.h"
00023 
00024 /******************************************************************************
00025  * Defines and typedefs
00026  *****************************************************************************/
00027  
00028 #define BTN_OFF    20
00029  
00030 /******************************************************************************
00031  * Global variables
00032  *****************************************************************************/
00033 
00034 /******************************************************************************
00035  * Private functions
00036  *****************************************************************************/
00037 
00038 static void buttonClicked(uint32_t x)
00039 {
00040   bool* done = (bool*)x;
00041   *done = true;
00042 }
00043 
00044 void AppImageViewer::draw()
00045 {
00046     // Prepare fullscreen
00047     swim_window_open(_win, 
00048                    _disp->width(), _disp->height(),         // full size
00049                    (COLOR_T*)_fb1,
00050                    0,0,_disp->width()-1, _disp->height()-1, // window position and size
00051                    0,                                       // border
00052                    BLACK, BLACK, BLACK);                    // colors: pen, backgr, forgr
00053 
00054     // Create (but don't show) the button
00055     _btn = new ImageButton(_win->fb, _win->xpmax - BTN_OFF - _resOk->width(), _win->ypmax - BTN_OFF - _resOk->height(), _resOk->width(), _resOk->height());
00056     _btn->loadImages(_resOk);
00057     // Copy everything onto the back buffer
00058     memcpy(_fb2, _fb1, _disp->fbSize());
00059 }
00060 
00061 void AppImageViewer::load(const char* file)
00062 {
00063     Image::ImageData_t pre = {0};
00064     
00065     int res = Image::decode(file, Image::RES_16BIT, &pre);
00066     if (res == 0) {
00067         DMBoard::instance().logger()->printf("[ImageLoader] Preparing %s\n", file);
00068         Image::ImageData_t* data = _mailbox.alloc(osWaitForever);        
00069         if (data != NULL) {
00070             *data = pre;
00071             _mailbox.put(data);
00072         } else {
00073             DMBoard::instance().logger()->printf("[ImageLoader] Failed to get memory to prepare %s\n", file);
00074         }
00075     }
00076 }
00077 
00078 static bool recursiveProcessFS(char* buff, const char* name, unsigned int maxLen, AppImageViewer* app, int depth, int maxDepth)
00079 {
00080   if (depth > maxDepth) {
00081     return true;
00082   }
00083   uint32_t len = strlen(buff);
00084   if (len > 0) {
00085     if (buff[len - 1] != '/') {
00086       buff[len++] = '/';
00087       buff[len] = '\0';
00088     }
00089   }
00090   if ((strlen(name) + len) >= maxLen) {
00091     // avoid memory overwrite due to too long file path
00092     return true;
00093   }
00094   strcat(buff, name);
00095   len += strlen(name);
00096 
00097   DIR *d = opendir(buff);
00098   bool result = true; // success
00099   if (d != NULL) {
00100     struct dirent *p;
00101     while (result && ((p = readdir(d)) != NULL)) {
00102       result = recursiveProcessFS(buff, p->d_name, maxLen, app, depth+1, maxDepth);
00103       buff[len] = '\0';
00104     }
00105     closedir(d);
00106   } else {
00107     // a file
00108     if (len > 3) {
00109       if ((strncasecmp(buff+len-4, ".bmp", 4)==0) ||
00110           (strncasecmp(buff+len-4, ".png", 4)==0) ||
00111           (strncasecmp(buff+len-4, ".raw", 4)==0)) {
00112         DMBoard::instance().logger()->printf("[ImageLoader] found %s\n", buff);
00113         app->load(buff);
00114       }
00115     }
00116   }
00117   return result;
00118 }
00119 
00120 static void loaderTask(void const* args)
00121 {
00122   char* buff = (char*)malloc(512);
00123   if (buff != NULL)
00124   {
00125     DMBoard::instance().logger()->printf("Recursive list of file and folders in /mci/\n");
00126     buff[0] = '\0';
00127     recursiveProcessFS(buff, "/mci/", 512, (AppImageViewer*)args, 0, 2);
00128     DMBoard::instance().logger()->printf("Recursive list of file and folders in /usb/\n");
00129     buff[0] = '\0';
00130     recursiveProcessFS(buff, "/usb/", 512, (AppImageViewer*)args, 0, 2);
00131     if (DMBoard::instance().display()->width() == 480) {
00132       DMBoard::instance().logger()->printf("Recursive list of file and folders in /qspi/480x272/\n");
00133       buff[0] = '\0';
00134       recursiveProcessFS(buff, "/qspi/480x272/", 512, (AppImageViewer*)args, 0, 1);
00135     } else {
00136       DMBoard::instance().logger()->printf("Recursive list of file and folders in /qspi/800x480/\n");
00137       buff[0] = '\0';
00138       recursiveProcessFS(buff, "/qspi/800x480/", 512, (AppImageViewer*)args, 0, 1);
00139     }
00140     free(buff);
00141   }
00142   DMBoard::instance().logger()->printf("loaderTask done\n");
00143 }
00144 
00145 /******************************************************************************
00146  * Public functions
00147  *****************************************************************************/
00148 
00149 AppImageViewer::AppImageViewer() : _disp(NULL), _win(NULL), 
00150    _fb1(NULL), _fb2(NULL), _btn(NULL), _active(0), _resOk(NULL)
00151 {
00152 }
00153 
00154 AppImageViewer::~AppImageViewer()
00155 {
00156     teardown();
00157 }
00158 
00159 bool AppImageViewer::setup()
00160 {
00161     _disp = DMBoard::instance().display();
00162     _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
00163     _fb1 = _disp->allocateFramebuffer();
00164     _fb2 = _disp->allocateFramebuffer();
00165 
00166     return (_win != NULL && _fb1 != NULL && _fb2 != NULL);
00167 }
00168 
00169 void AppImageViewer::runToCompletion()
00170 {
00171     // Alternative 1: use the calling thread's context to run in
00172     bool done = false;
00173     draw();
00174     _btn->setAction(buttonClicked, (uint32_t)&done);
00175     void* oldFB = _disp->swapFramebuffer(_fb1);
00176 
00177     _active = 1;
00178     
00179     Thread* tLoader = new Thread(osPriorityNormal, 8192);
00180     tLoader->start(callback(loaderTask, this));
00181     
00182     bool first = true;
00183     Timer t;
00184     while(!done) {
00185       osEvent evt = _mailbox.get(1000);
00186       if (evt.status == osEventMail) {
00187         COLOR_T* fb;
00188         if (_active == 1) {
00189           // render on the second frame buffer
00190           fb = (COLOR_T*)_fb2;
00191         } else {
00192           // render on the first frame buffer
00193           fb = (COLOR_T*)_fb1;
00194         }
00195         _win->fb = fb;
00196         Image::ImageData_t* data = (Image::ImageData_t*)evt.value.p;
00197         if ((data->width < _disp->width()) || (data->height < _disp->height())) {
00198           // Clear background as the image is not full screen
00199           memset(fb, 0, _disp->fbSize());
00200         }
00201         swim_put_image_xy(_win, (COLOR_T*)data->pixels, data->width, data->height, (_disp->width()-data->width)/2, (_disp->height()-data->height)/2);
00202         free(data->pointerToFree);
00203         _mailbox.free(data);
00204         if (first) {
00205           first = false;
00206           t.start();
00207         } else {
00208           while (t.read_ms() < 2000) {
00209             ThisThread::sleep_for(100);
00210           }
00211         }
00212         _disp->setFramebuffer(fb);
00213         _active = (_active == 1 ? 2 : 1);
00214         t.reset();
00215       } else if (tLoader->get_state() == Thread::Inactive) {
00216         // No more images in the queue and the loader thread 
00217         // has completed its search
00218         break;
00219       }
00220     }
00221     
00222     delete tLoader;
00223     
00224     // The button must be drawn on the current framebuffer
00225     _btn->draw(_win->fb);
00226 
00227     // Wait for touches, but the AppLauncher is already listening
00228     // for new touch event and sends a signal to its thread which
00229     // is the same as runs this function so it is enough to wait
00230     // for that signal.
00231     TouchPanel* touch = DMBoard::instance().touchPanel();
00232     touch_coordinate_t coord;
00233     while(!done) {
00234       ThisThread::flags_wait_all(0x1);
00235       if (touch->read(coord) == TouchPanel::TouchError_Ok) {
00236         if (_btn->handle(coord.x, coord.y, coord.z > 0)) {
00237             _btn->draw();
00238         }
00239       }
00240     }
00241     
00242     // User has clicked the button, restore the original FB
00243     _disp->swapFramebuffer(oldFB);
00244     swim_window_close(_win);
00245 }
00246 
00247 bool AppImageViewer::teardown()
00248 {
00249     if (_win != NULL) {
00250         free(_win);
00251         _win = NULL;
00252     }
00253     if (_fb1 != NULL) {
00254         free(_fb1);
00255         _fb1 = NULL;
00256     }
00257     if (_fb2 != NULL) {
00258         free(_fb2);
00259         _fb2 = NULL;
00260     }
00261     if (_btn != NULL) {
00262         delete _btn;
00263         _btn = NULL;
00264     }
00265     return true;
00266 }
00267 
00268 void AppImageViewer::addResource(Resources id, Resource* res)
00269 {
00270     _resOk = res;
00271 }