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

Dependencies:   DMBasicGUI DMSupport

This is the software that is flashed on the LPC4088 Display Modules before they are shipped from Embedded Artists.

Information

This project works on both the 4.3" and 5" display modules but requires different file systems to handle the different display resolutions.

For the 4.3" displays first drag-n-drop the media/fs_480_raw.fs5 (if you are using the new DAPLINK firmware use fs_480_raw.hex) file to the MBED drive and then drag-n-drop the demo itself. This way both the file system and software are up to date.

For the 5" displays first drag-n-drop the media/fs_800_raw.fsF (if you are using the new DAPLINK firmware use fs_800_raw.hex) file to the MBED drive and then drag-n-drop the demo itself. This way both the file system and software are up to date.

There is a prebuilt version of the demo binary here.

This is what it looks like on a 4.3" display:

/media/uploads/embeddedartists/demo480_cap_000.png /media/uploads/embeddedartists/demo480_cap_001.png /media/uploads/embeddedartists/demo480_cap_002.png /media/uploads/embeddedartists/demo480_cap_004.png /media/uploads/embeddedartists/demo480_cap_006.png /media/uploads/embeddedartists/demo480_cap_007.png /media/uploads/embeddedartists/demo480_cap_008.png
The first slide from the Slideshow:
/media/uploads/embeddedartists/demo480_cap_003.png
A couple of images from the Image Viewer
/media/uploads/embeddedartists/demo480_cap_009.png /media/uploads/embeddedartists/demo480_cap_010.png

Committer:
alindvall
Date:
Tue Apr 28 12:21:14 2015 +0000
Revision:
4:a7cbb22e4348
Parent:
0:b94e330c98ac
Child:
5:6ca8470ba8f8
Updated to latest version of the DMSupport and DMBasicGUI libraries

Who changed what in which revision?

UserRevisionLine numberNew contents of line
alindvall 0:b94e330c98ac 1 /*
alindvall 0:b94e330c98ac 2 * Copyright 2014 Embedded Artists AB
alindvall 0:b94e330c98ac 3 *
alindvall 0:b94e330c98ac 4 * Licensed under the Apache License, Version 2.0 (the "License");
alindvall 0:b94e330c98ac 5 * you may not use this file except in compliance with the License.
alindvall 0:b94e330c98ac 6 * You may obtain a copy of the License at
alindvall 0:b94e330c98ac 7 *
alindvall 0:b94e330c98ac 8 * http://www.apache.org/licenses/LICENSE-2.0
alindvall 0:b94e330c98ac 9 *
alindvall 0:b94e330c98ac 10 * Unless required by applicable law or agreed to in writing, software
alindvall 0:b94e330c98ac 11 * distributed under the License is distributed on an "AS IS" BASIS,
alindvall 0:b94e330c98ac 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
alindvall 0:b94e330c98ac 13 * See the License for the specific language governing permissions and
alindvall 0:b94e330c98ac 14 * limitations under the License.
alindvall 0:b94e330c98ac 15 */
alindvall 0:b94e330c98ac 16
alindvall 0:b94e330c98ac 17
alindvall 0:b94e330c98ac 18 #include "mbed.h"
alindvall 0:b94e330c98ac 19 #include "AppImageViewer.h"
alindvall 0:b94e330c98ac 20 #include "lpc_swim_font.h"
alindvall 0:b94e330c98ac 21 #include "lpc_swim_image.h"
alindvall 0:b94e330c98ac 22 #include "Image.h"
alindvall 0:b94e330c98ac 23
alindvall 0:b94e330c98ac 24 /******************************************************************************
alindvall 0:b94e330c98ac 25 * Defines and typedefs
alindvall 0:b94e330c98ac 26 *****************************************************************************/
alindvall 0:b94e330c98ac 27
alindvall 0:b94e330c98ac 28 #define BTN_OFF 20
alindvall 0:b94e330c98ac 29
alindvall 0:b94e330c98ac 30 /******************************************************************************
alindvall 0:b94e330c98ac 31 * Global variables
alindvall 0:b94e330c98ac 32 *****************************************************************************/
alindvall 0:b94e330c98ac 33
alindvall 0:b94e330c98ac 34 /******************************************************************************
alindvall 0:b94e330c98ac 35 * Private functions
alindvall 0:b94e330c98ac 36 *****************************************************************************/
alindvall 0:b94e330c98ac 37
alindvall 0:b94e330c98ac 38 static void buttonClicked(uint32_t x)
alindvall 0:b94e330c98ac 39 {
alindvall 0:b94e330c98ac 40 bool* done = (bool*)x;
alindvall 0:b94e330c98ac 41 *done = true;
alindvall 0:b94e330c98ac 42 }
alindvall 0:b94e330c98ac 43
alindvall 0:b94e330c98ac 44 void AppImageViewer::draw()
alindvall 0:b94e330c98ac 45 {
alindvall 0:b94e330c98ac 46 // Prepare fullscreen
alindvall 0:b94e330c98ac 47 swim_window_open(_win,
alindvall 0:b94e330c98ac 48 _disp->width(), _disp->height(), // full size
alindvall 0:b94e330c98ac 49 (COLOR_T*)_fb1,
alindvall 0:b94e330c98ac 50 0,0,_disp->width()-1, _disp->height()-1, // window position and size
alindvall 0:b94e330c98ac 51 0, // border
alindvall 0:b94e330c98ac 52 BLACK, BLACK, BLACK); // colors: pen, backgr, forgr
alindvall 0:b94e330c98ac 53
alindvall 0:b94e330c98ac 54 // Create (but don't show) the button
alindvall 0:b94e330c98ac 55 _btn = new ImageButton(_win->fb, _win->xpmax - BTN_OFF - _resOk->width(), _win->ypmax - BTN_OFF - _resOk->height(), _resOk->width(), _resOk->height());
alindvall 0:b94e330c98ac 56 _btn->loadImages(_resOk);
alindvall 0:b94e330c98ac 57 // Copy everything onto the back buffer
alindvall 0:b94e330c98ac 58 memcpy(_fb2, _fb1, _disp->fbSize());
alindvall 0:b94e330c98ac 59 }
alindvall 0:b94e330c98ac 60
alindvall 0:b94e330c98ac 61 void AppImageViewer::load(const char* file)
alindvall 0:b94e330c98ac 62 {
alindvall 0:b94e330c98ac 63 Image::ImageData_t pre = {0};
alindvall 0:b94e330c98ac 64
alindvall 0:b94e330c98ac 65 int res = Image::decode(file, Image::RES_16BIT, &pre);
alindvall 0:b94e330c98ac 66 if (res == 0) {
alindvall 0:b94e330c98ac 67 DMBoard::instance().logger()->printf("[ImageLoader] Preparing %s\n", file);
alindvall 0:b94e330c98ac 68 Image::ImageData_t* data = _mailbox.alloc(osWaitForever);
alindvall 0:b94e330c98ac 69 if (data != NULL) {
alindvall 0:b94e330c98ac 70 *data = pre;
alindvall 0:b94e330c98ac 71 _mailbox.put(data);
alindvall 0:b94e330c98ac 72 } else {
alindvall 0:b94e330c98ac 73 DMBoard::instance().logger()->printf("[ImageLoader] Failed to get memory to prepare %s\n", file);
alindvall 0:b94e330c98ac 74 }
alindvall 0:b94e330c98ac 75 }
alindvall 0:b94e330c98ac 76 }
alindvall 0:b94e330c98ac 77
alindvall 0:b94e330c98ac 78 static bool recursiveProcessFS(char* buff, const char* name, unsigned int maxLen, AppImageViewer* app, int depth, int maxDepth)
alindvall 0:b94e330c98ac 79 {
alindvall 0:b94e330c98ac 80 if (depth > maxDepth) {
alindvall 0:b94e330c98ac 81 return true;
alindvall 0:b94e330c98ac 82 }
alindvall 0:b94e330c98ac 83 uint32_t len = strlen(buff);
alindvall 0:b94e330c98ac 84 if (len > 0) {
alindvall 0:b94e330c98ac 85 if (buff[len - 1] != '/') {
alindvall 0:b94e330c98ac 86 buff[len++] = '/';
alindvall 0:b94e330c98ac 87 buff[len] = '\0';
alindvall 0:b94e330c98ac 88 }
alindvall 0:b94e330c98ac 89 }
alindvall 0:b94e330c98ac 90 if ((strlen(name) + len) >= maxLen) {
alindvall 0:b94e330c98ac 91 // avoid memory overwrite due to too long file path
alindvall 0:b94e330c98ac 92 return true;
alindvall 0:b94e330c98ac 93 }
alindvall 0:b94e330c98ac 94 strcat(buff, name);
alindvall 0:b94e330c98ac 95 len += strlen(name);
alindvall 0:b94e330c98ac 96
alindvall 0:b94e330c98ac 97 DIR *d = opendir(buff);
alindvall 0:b94e330c98ac 98 bool result = true; // success
alindvall 0:b94e330c98ac 99 if (d != NULL) {
alindvall 0:b94e330c98ac 100 struct dirent *p;
alindvall 0:b94e330c98ac 101 while (result && ((p = readdir(d)) != NULL)) {
alindvall 0:b94e330c98ac 102 result = recursiveProcessFS(buff, p->d_name, maxLen, app, depth+1, maxDepth);
alindvall 0:b94e330c98ac 103 buff[len] = '\0';
alindvall 0:b94e330c98ac 104 }
alindvall 0:b94e330c98ac 105 closedir(d);
alindvall 0:b94e330c98ac 106 } else {
alindvall 0:b94e330c98ac 107 // a file
alindvall 0:b94e330c98ac 108 if (len > 3) {
alindvall 0:b94e330c98ac 109 if ((strncasecmp(buff+len-4, ".bmp", 4)==0) ||
alindvall 0:b94e330c98ac 110 (strncasecmp(buff+len-4, ".png", 4)==0) ||
alindvall 0:b94e330c98ac 111 (strncasecmp(buff+len-4, ".raw", 4)==0)) {
alindvall 0:b94e330c98ac 112 DMBoard::instance().logger()->printf("[ImageLoader] found %s\n", buff);
alindvall 0:b94e330c98ac 113 app->load(buff);
alindvall 0:b94e330c98ac 114 }
alindvall 0:b94e330c98ac 115 }
alindvall 0:b94e330c98ac 116 }
alindvall 0:b94e330c98ac 117 return result;
alindvall 0:b94e330c98ac 118 }
alindvall 0:b94e330c98ac 119
alindvall 0:b94e330c98ac 120 static void loaderTask(void const* args)
alindvall 0:b94e330c98ac 121 {
alindvall 0:b94e330c98ac 122 char* buff = (char*)malloc(512);
alindvall 0:b94e330c98ac 123 if (buff != NULL)
alindvall 0:b94e330c98ac 124 {
alindvall 0:b94e330c98ac 125 DMBoard::instance().logger()->printf("Recursive list of file and folders in /mci/\n");
alindvall 0:b94e330c98ac 126 buff[0] = '\0';
alindvall 0:b94e330c98ac 127 recursiveProcessFS(buff, "/mci/", 512, (AppImageViewer*)args, 0, 2);
alindvall 0:b94e330c98ac 128 DMBoard::instance().logger()->printf("Recursive list of file and folders in /usb/\n");
alindvall 0:b94e330c98ac 129 buff[0] = '\0';
alindvall 0:b94e330c98ac 130 recursiveProcessFS(buff, "/usb/", 512, (AppImageViewer*)args, 0, 2);
alindvall 0:b94e330c98ac 131 if (DMBoard::instance().display()->width() == 480) {
alindvall 0:b94e330c98ac 132 DMBoard::instance().logger()->printf("Recursive list of file and folders in /qspi/480x272/\n");
alindvall 0:b94e330c98ac 133 buff[0] = '\0';
alindvall 0:b94e330c98ac 134 recursiveProcessFS(buff, "/qspi/480x272/", 512, (AppImageViewer*)args, 0, 1);
alindvall 0:b94e330c98ac 135 } else {
alindvall 0:b94e330c98ac 136 DMBoard::instance().logger()->printf("Recursive list of file and folders in /qspi/800x480/\n");
alindvall 0:b94e330c98ac 137 buff[0] = '\0';
alindvall 0:b94e330c98ac 138 recursiveProcessFS(buff, "/qspi/800x480/", 512, (AppImageViewer*)args, 0, 1);
alindvall 0:b94e330c98ac 139 }
alindvall 0:b94e330c98ac 140 free(buff);
alindvall 0:b94e330c98ac 141 }
alindvall 0:b94e330c98ac 142 DMBoard::instance().logger()->printf("loaderTask done\n");
alindvall 0:b94e330c98ac 143 }
alindvall 0:b94e330c98ac 144
alindvall 0:b94e330c98ac 145 /******************************************************************************
alindvall 0:b94e330c98ac 146 * Public functions
alindvall 0:b94e330c98ac 147 *****************************************************************************/
alindvall 0:b94e330c98ac 148
alindvall 0:b94e330c98ac 149 AppImageViewer::AppImageViewer() : _disp(NULL), _win(NULL),
alindvall 0:b94e330c98ac 150 _fb1(NULL), _fb2(NULL), _btn(NULL), _active(0), _resOk(NULL)
alindvall 0:b94e330c98ac 151 {
alindvall 0:b94e330c98ac 152 }
alindvall 0:b94e330c98ac 153
alindvall 0:b94e330c98ac 154 AppImageViewer::~AppImageViewer()
alindvall 0:b94e330c98ac 155 {
alindvall 0:b94e330c98ac 156 teardown();
alindvall 0:b94e330c98ac 157 }
alindvall 0:b94e330c98ac 158
alindvall 0:b94e330c98ac 159 bool AppImageViewer::setup()
alindvall 0:b94e330c98ac 160 {
alindvall 0:b94e330c98ac 161 _disp = DMBoard::instance().display();
alindvall 0:b94e330c98ac 162 _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
alindvall 0:b94e330c98ac 163 _fb1 = _disp->allocateFramebuffer();
alindvall 0:b94e330c98ac 164 _fb2 = _disp->allocateFramebuffer();
alindvall 0:b94e330c98ac 165
alindvall 0:b94e330c98ac 166 return (_win != NULL && _fb1 != NULL && _fb2 != NULL);
alindvall 0:b94e330c98ac 167 }
alindvall 0:b94e330c98ac 168
alindvall 0:b94e330c98ac 169 void AppImageViewer::runToCompletion()
alindvall 0:b94e330c98ac 170 {
alindvall 0:b94e330c98ac 171 // Alternative 1: use the calling thread's context to run in
alindvall 0:b94e330c98ac 172 bool done = false;
alindvall 0:b94e330c98ac 173 draw();
alindvall 0:b94e330c98ac 174 _btn->setAction(buttonClicked, (uint32_t)&done);
alindvall 0:b94e330c98ac 175 void* oldFB = _disp->swapFramebuffer(_fb1);
alindvall 0:b94e330c98ac 176
alindvall 0:b94e330c98ac 177 _active = 1;
alindvall 0:b94e330c98ac 178
alindvall 0:b94e330c98ac 179 Thread* tLoader = new Thread(loaderTask, this, osPriorityNormal, 8192);
alindvall 0:b94e330c98ac 180
alindvall 0:b94e330c98ac 181 bool first = true;
alindvall 0:b94e330c98ac 182 Timer t;
alindvall 0:b94e330c98ac 183 while(!done) {
alindvall 0:b94e330c98ac 184 osEvent evt = _mailbox.get(1000);
alindvall 0:b94e330c98ac 185 if (evt.status == osEventMail) {
alindvall 0:b94e330c98ac 186 COLOR_T* fb;
alindvall 0:b94e330c98ac 187 if (_active == 1) {
alindvall 0:b94e330c98ac 188 // render on the second frame buffer
alindvall 0:b94e330c98ac 189 fb = (COLOR_T*)_fb2;
alindvall 0:b94e330c98ac 190 } else {
alindvall 0:b94e330c98ac 191 // render on the first frame buffer
alindvall 0:b94e330c98ac 192 fb = (COLOR_T*)_fb1;
alindvall 0:b94e330c98ac 193 }
alindvall 0:b94e330c98ac 194 _win->fb = fb;
alindvall 0:b94e330c98ac 195 Image::ImageData_t* data = (Image::ImageData_t*)evt.value.p;
alindvall 4:a7cbb22e4348 196 if ((data->width < _disp->width()) || (data->height < _disp->height())) {
alindvall 4:a7cbb22e4348 197 // Clear background as the image is not full screen
alindvall 4:a7cbb22e4348 198 memset(fb, 0, _disp->fbSize());
alindvall 4:a7cbb22e4348 199 }
alindvall 0:b94e330c98ac 200 swim_put_image_xy(_win, (COLOR_T*)data->pixels, data->width, data->height, (_disp->width()-data->width)/2, (_disp->height()-data->height)/2);
alindvall 0:b94e330c98ac 201 free(data->pointerToFree);
alindvall 0:b94e330c98ac 202 _mailbox.free(data);
alindvall 0:b94e330c98ac 203 if (first) {
alindvall 0:b94e330c98ac 204 first = false;
alindvall 0:b94e330c98ac 205 t.start();
alindvall 0:b94e330c98ac 206 } else {
alindvall 0:b94e330c98ac 207 while (t.read_ms() < 2000) {
alindvall 0:b94e330c98ac 208 Thread::wait(100);
alindvall 0:b94e330c98ac 209 }
alindvall 0:b94e330c98ac 210 }
alindvall 0:b94e330c98ac 211 _disp->setFramebuffer(fb);
alindvall 0:b94e330c98ac 212 _active = (_active == 1 ? 2 : 1);
alindvall 0:b94e330c98ac 213 t.reset();
alindvall 0:b94e330c98ac 214 } else if (tLoader->get_state() == Thread::Inactive) {
alindvall 0:b94e330c98ac 215 // No more images in the queue and the loader thread
alindvall 0:b94e330c98ac 216 // has completed its search
alindvall 0:b94e330c98ac 217 break;
alindvall 0:b94e330c98ac 218 }
alindvall 0:b94e330c98ac 219 }
alindvall 0:b94e330c98ac 220
alindvall 0:b94e330c98ac 221 delete tLoader;
alindvall 0:b94e330c98ac 222
alindvall 0:b94e330c98ac 223 // The button must be drawn on the current framebuffer
alindvall 0:b94e330c98ac 224 _btn->draw(_win->fb);
alindvall 0:b94e330c98ac 225
alindvall 0:b94e330c98ac 226 // Wait for touches, but the AppLauncher is already listening
alindvall 0:b94e330c98ac 227 // for new touch event and sends a signal to its thread which
alindvall 0:b94e330c98ac 228 // is the same as runs this function so it is enough to wait
alindvall 0:b94e330c98ac 229 // for that signal.
alindvall 0:b94e330c98ac 230 TouchPanel* touch = DMBoard::instance().touchPanel();
alindvall 0:b94e330c98ac 231 touch_coordinate_t coord;
alindvall 0:b94e330c98ac 232 while(!done) {
alindvall 0:b94e330c98ac 233 Thread::signal_wait(0x1);
alindvall 0:b94e330c98ac 234 if (touch->read(coord) == TouchPanel::TouchError_Ok) {
alindvall 0:b94e330c98ac 235 if (_btn->handle(coord.x, coord.y, coord.z > 0)) {
alindvall 0:b94e330c98ac 236 _btn->draw();
alindvall 0:b94e330c98ac 237 }
alindvall 0:b94e330c98ac 238 }
alindvall 0:b94e330c98ac 239 }
alindvall 0:b94e330c98ac 240
alindvall 0:b94e330c98ac 241 // User has clicked the button, restore the original FB
alindvall 0:b94e330c98ac 242 _disp->swapFramebuffer(oldFB);
alindvall 0:b94e330c98ac 243 swim_window_close(_win);
alindvall 0:b94e330c98ac 244 }
alindvall 0:b94e330c98ac 245
alindvall 0:b94e330c98ac 246 bool AppImageViewer::teardown()
alindvall 0:b94e330c98ac 247 {
alindvall 0:b94e330c98ac 248 if (_win != NULL) {
alindvall 0:b94e330c98ac 249 free(_win);
alindvall 0:b94e330c98ac 250 _win = NULL;
alindvall 0:b94e330c98ac 251 }
alindvall 0:b94e330c98ac 252 if (_fb1 != NULL) {
alindvall 0:b94e330c98ac 253 free(_fb1);
alindvall 0:b94e330c98ac 254 _fb1 = NULL;
alindvall 0:b94e330c98ac 255 }
alindvall 0:b94e330c98ac 256 if (_fb2 != NULL) {
alindvall 0:b94e330c98ac 257 free(_fb2);
alindvall 0:b94e330c98ac 258 _fb2 = NULL;
alindvall 0:b94e330c98ac 259 }
alindvall 0:b94e330c98ac 260 if (_btn != NULL) {
alindvall 0:b94e330c98ac 261 delete _btn;
alindvall 0:b94e330c98ac 262 _btn = NULL;
alindvall 0:b94e330c98ac 263 }
alindvall 0:b94e330c98ac 264 return true;
alindvall 0:b94e330c98ac 265 }
alindvall 0:b94e330c98ac 266
alindvall 0:b94e330c98ac 267 void AppImageViewer::addResource(Resources id, Resource* res)
alindvall 0:b94e330c98ac 268 {
alindvall 0:b94e330c98ac 269 _resOk = res;
alindvall 0:b94e330c98ac 270 }