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:
embeddedartists
Date:
Tue Nov 05 09:11:36 2019 +0000
Revision:
5:6ca8470ba8f8
Parent:
4:a7cbb22e4348
Updates related to mbed OS 5

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
embeddedartists 5:6ca8470ba8f8 179 Thread* tLoader = new Thread(osPriorityNormal, 8192);
embeddedartists 5:6ca8470ba8f8 180 tLoader->start(callback(loaderTask, this));
alindvall 0:b94e330c98ac 181
alindvall 0:b94e330c98ac 182 bool first = true;
alindvall 0:b94e330c98ac 183 Timer t;
alindvall 0:b94e330c98ac 184 while(!done) {
alindvall 0:b94e330c98ac 185 osEvent evt = _mailbox.get(1000);
alindvall 0:b94e330c98ac 186 if (evt.status == osEventMail) {
alindvall 0:b94e330c98ac 187 COLOR_T* fb;
alindvall 0:b94e330c98ac 188 if (_active == 1) {
alindvall 0:b94e330c98ac 189 // render on the second frame buffer
alindvall 0:b94e330c98ac 190 fb = (COLOR_T*)_fb2;
alindvall 0:b94e330c98ac 191 } else {
alindvall 0:b94e330c98ac 192 // render on the first frame buffer
alindvall 0:b94e330c98ac 193 fb = (COLOR_T*)_fb1;
alindvall 0:b94e330c98ac 194 }
alindvall 0:b94e330c98ac 195 _win->fb = fb;
alindvall 0:b94e330c98ac 196 Image::ImageData_t* data = (Image::ImageData_t*)evt.value.p;
alindvall 4:a7cbb22e4348 197 if ((data->width < _disp->width()) || (data->height < _disp->height())) {
alindvall 4:a7cbb22e4348 198 // Clear background as the image is not full screen
alindvall 4:a7cbb22e4348 199 memset(fb, 0, _disp->fbSize());
alindvall 4:a7cbb22e4348 200 }
alindvall 0:b94e330c98ac 201 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 202 free(data->pointerToFree);
alindvall 0:b94e330c98ac 203 _mailbox.free(data);
alindvall 0:b94e330c98ac 204 if (first) {
alindvall 0:b94e330c98ac 205 first = false;
alindvall 0:b94e330c98ac 206 t.start();
alindvall 0:b94e330c98ac 207 } else {
alindvall 0:b94e330c98ac 208 while (t.read_ms() < 2000) {
embeddedartists 5:6ca8470ba8f8 209 ThisThread::sleep_for(100);
alindvall 0:b94e330c98ac 210 }
alindvall 0:b94e330c98ac 211 }
alindvall 0:b94e330c98ac 212 _disp->setFramebuffer(fb);
alindvall 0:b94e330c98ac 213 _active = (_active == 1 ? 2 : 1);
alindvall 0:b94e330c98ac 214 t.reset();
alindvall 0:b94e330c98ac 215 } else if (tLoader->get_state() == Thread::Inactive) {
alindvall 0:b94e330c98ac 216 // No more images in the queue and the loader thread
alindvall 0:b94e330c98ac 217 // has completed its search
alindvall 0:b94e330c98ac 218 break;
alindvall 0:b94e330c98ac 219 }
alindvall 0:b94e330c98ac 220 }
alindvall 0:b94e330c98ac 221
alindvall 0:b94e330c98ac 222 delete tLoader;
alindvall 0:b94e330c98ac 223
alindvall 0:b94e330c98ac 224 // The button must be drawn on the current framebuffer
alindvall 0:b94e330c98ac 225 _btn->draw(_win->fb);
alindvall 0:b94e330c98ac 226
alindvall 0:b94e330c98ac 227 // Wait for touches, but the AppLauncher is already listening
alindvall 0:b94e330c98ac 228 // for new touch event and sends a signal to its thread which
alindvall 0:b94e330c98ac 229 // is the same as runs this function so it is enough to wait
alindvall 0:b94e330c98ac 230 // for that signal.
alindvall 0:b94e330c98ac 231 TouchPanel* touch = DMBoard::instance().touchPanel();
alindvall 0:b94e330c98ac 232 touch_coordinate_t coord;
alindvall 0:b94e330c98ac 233 while(!done) {
embeddedartists 5:6ca8470ba8f8 234 ThisThread::flags_wait_all(0x1);
alindvall 0:b94e330c98ac 235 if (touch->read(coord) == TouchPanel::TouchError_Ok) {
alindvall 0:b94e330c98ac 236 if (_btn->handle(coord.x, coord.y, coord.z > 0)) {
alindvall 0:b94e330c98ac 237 _btn->draw();
alindvall 0:b94e330c98ac 238 }
alindvall 0:b94e330c98ac 239 }
alindvall 0:b94e330c98ac 240 }
alindvall 0:b94e330c98ac 241
alindvall 0:b94e330c98ac 242 // User has clicked the button, restore the original FB
alindvall 0:b94e330c98ac 243 _disp->swapFramebuffer(oldFB);
alindvall 0:b94e330c98ac 244 swim_window_close(_win);
alindvall 0:b94e330c98ac 245 }
alindvall 0:b94e330c98ac 246
alindvall 0:b94e330c98ac 247 bool AppImageViewer::teardown()
alindvall 0:b94e330c98ac 248 {
alindvall 0:b94e330c98ac 249 if (_win != NULL) {
alindvall 0:b94e330c98ac 250 free(_win);
alindvall 0:b94e330c98ac 251 _win = NULL;
alindvall 0:b94e330c98ac 252 }
alindvall 0:b94e330c98ac 253 if (_fb1 != NULL) {
alindvall 0:b94e330c98ac 254 free(_fb1);
alindvall 0:b94e330c98ac 255 _fb1 = NULL;
alindvall 0:b94e330c98ac 256 }
alindvall 0:b94e330c98ac 257 if (_fb2 != NULL) {
alindvall 0:b94e330c98ac 258 free(_fb2);
alindvall 0:b94e330c98ac 259 _fb2 = NULL;
alindvall 0:b94e330c98ac 260 }
alindvall 0:b94e330c98ac 261 if (_btn != NULL) {
alindvall 0:b94e330c98ac 262 delete _btn;
alindvall 0:b94e330c98ac 263 _btn = NULL;
alindvall 0:b94e330c98ac 264 }
alindvall 0:b94e330c98ac 265 return true;
alindvall 0:b94e330c98ac 266 }
alindvall 0:b94e330c98ac 267
alindvall 0:b94e330c98ac 268 void AppImageViewer::addResource(Resources id, Resource* res)
alindvall 0:b94e330c98ac 269 {
alindvall 0:b94e330c98ac 270 _resOk = res;
alindvall 0:b94e330c98ac 271 }