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:
Fri Mar 20 13:36:44 2015 +0000
Revision:
0:b94e330c98ac
Child:
4:a7cbb22e4348
First version

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 0:b94e330c98ac 196 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 197 free(data->pointerToFree);
alindvall 0:b94e330c98ac 198 _mailbox.free(data);
alindvall 0:b94e330c98ac 199 if (first) {
alindvall 0:b94e330c98ac 200 first = false;
alindvall 0:b94e330c98ac 201 t.start();
alindvall 0:b94e330c98ac 202 } else {
alindvall 0:b94e330c98ac 203 while (t.read_ms() < 2000) {
alindvall 0:b94e330c98ac 204 Thread::wait(100);
alindvall 0:b94e330c98ac 205 }
alindvall 0:b94e330c98ac 206 }
alindvall 0:b94e330c98ac 207 _disp->setFramebuffer(fb);
alindvall 0:b94e330c98ac 208 _active = (_active == 1 ? 2 : 1);
alindvall 0:b94e330c98ac 209 t.reset();
alindvall 0:b94e330c98ac 210 } else if (tLoader->get_state() == Thread::Inactive) {
alindvall 0:b94e330c98ac 211 // No more images in the queue and the loader thread
alindvall 0:b94e330c98ac 212 // has completed its search
alindvall 0:b94e330c98ac 213 break;
alindvall 0:b94e330c98ac 214 }
alindvall 0:b94e330c98ac 215 }
alindvall 0:b94e330c98ac 216
alindvall 0:b94e330c98ac 217 delete tLoader;
alindvall 0:b94e330c98ac 218
alindvall 0:b94e330c98ac 219 // The button must be drawn on the current framebuffer
alindvall 0:b94e330c98ac 220 _btn->draw(_win->fb);
alindvall 0:b94e330c98ac 221
alindvall 0:b94e330c98ac 222 // Wait for touches, but the AppLauncher is already listening
alindvall 0:b94e330c98ac 223 // for new touch event and sends a signal to its thread which
alindvall 0:b94e330c98ac 224 // is the same as runs this function so it is enough to wait
alindvall 0:b94e330c98ac 225 // for that signal.
alindvall 0:b94e330c98ac 226 TouchPanel* touch = DMBoard::instance().touchPanel();
alindvall 0:b94e330c98ac 227 touch_coordinate_t coord;
alindvall 0:b94e330c98ac 228 while(!done) {
alindvall 0:b94e330c98ac 229 Thread::signal_wait(0x1);
alindvall 0:b94e330c98ac 230 if (touch->read(coord) == TouchPanel::TouchError_Ok) {
alindvall 0:b94e330c98ac 231 if (_btn->handle(coord.x, coord.y, coord.z > 0)) {
alindvall 0:b94e330c98ac 232 _btn->draw();
alindvall 0:b94e330c98ac 233 }
alindvall 0:b94e330c98ac 234 }
alindvall 0:b94e330c98ac 235 }
alindvall 0:b94e330c98ac 236
alindvall 0:b94e330c98ac 237 // User has clicked the button, restore the original FB
alindvall 0:b94e330c98ac 238 _disp->swapFramebuffer(oldFB);
alindvall 0:b94e330c98ac 239 swim_window_close(_win);
alindvall 0:b94e330c98ac 240 }
alindvall 0:b94e330c98ac 241
alindvall 0:b94e330c98ac 242 bool AppImageViewer::teardown()
alindvall 0:b94e330c98ac 243 {
alindvall 0:b94e330c98ac 244 if (_win != NULL) {
alindvall 0:b94e330c98ac 245 free(_win);
alindvall 0:b94e330c98ac 246 _win = NULL;
alindvall 0:b94e330c98ac 247 }
alindvall 0:b94e330c98ac 248 if (_fb1 != NULL) {
alindvall 0:b94e330c98ac 249 free(_fb1);
alindvall 0:b94e330c98ac 250 _fb1 = NULL;
alindvall 0:b94e330c98ac 251 }
alindvall 0:b94e330c98ac 252 if (_fb2 != NULL) {
alindvall 0:b94e330c98ac 253 free(_fb2);
alindvall 0:b94e330c98ac 254 _fb2 = NULL;
alindvall 0:b94e330c98ac 255 }
alindvall 0:b94e330c98ac 256 if (_btn != NULL) {
alindvall 0:b94e330c98ac 257 delete _btn;
alindvall 0:b94e330c98ac 258 _btn = NULL;
alindvall 0:b94e330c98ac 259 }
alindvall 0:b94e330c98ac 260 return true;
alindvall 0:b94e330c98ac 261 }
alindvall 0:b94e330c98ac 262
alindvall 0:b94e330c98ac 263 void AppImageViewer::addResource(Resources id, Resource* res)
alindvall 0:b94e330c98ac 264 {
alindvall 0:b94e330c98ac 265 _resOk = res;
alindvall 0:b94e330c98ac 266 }
alindvall 0:b94e330c98ac 267