Embedded Artists


We are the leading providers of products and services around prototyping, evaluation and OEM platforms using NXP's ARM-based microcontrollers.

LPC4088DM Using the SlideShow Engine

The DMBasicGUI library comes with, among other things, a slideshow engine supporting:

  • Continuous or one time slideshows
  • Script controlled slideshow so it can be changed without recompiling the program
  • Several different transitions to choose between
  • Slideshow can be full screen or in part of the screen
  • Nested slideshows
  • Pre-loading of images while waiting for the next slide
  • "Video" support

Add the slideshow engine by importing the DMBasicGUI library:

Import libraryDMBasicGUI

A basic graphics package for the LPC4088 Display Module.

Example

There is an AppSlideShow.cpp in DMBasicGUI showing how to use the SlideShow class, but this is basically what is needed:

#include "mbed.h"
#include "SlideShow.h"
#include "Renderer.h"

static void tRender(void const *args)
{
  Renderer* s = (Renderer*)args;
  s->render();
}

int main(void) {
   // initialize the display
   ...

   // create the renderer that will handle the display
   Renderer r;

   // create the slideshow
   SlideShow s(&r);
   
   // parse and validate the script
   SlideShow::SlideShowError err = s.prepare("/mci/myscript.txt");
   if (err != SlideShow::Ok) {
       // handle error here
   }

   // Create the thread to handle the display
   Thread tr(tRender, &r, osPriorityHigh);

   // Run the slideshow
   s.run();
}


Place two images called img1.png and img2.png in the root of the uSD card together with this file:

myscript.txt

load /mci/img1.png  1
show 1 none
load /mci/img2.png  2
wait 1500
show 2 none

Classes

The engine consists of one Renderer serving one or more SlideShows.

The Renderer is responsible for putting together the result and showing it on the display. It handles the different layers and possibly different concurrent slideshows. The user code only have to create the Renderer, no further interaction is needed.

Import library

Public Member Functions

uint32_t  registerUser (int layer, int xoff, int yoff, int width, int height)
  Registers a part of the screen on a specific layer to be in use.
uint32_t  registerFullscreenUser (int layer)
  Registers the entire screen on a specific layer to be in use.
void  unregisterUser (uint32_t handle)
  Removes a previously registered user.
void  setFramebuffer (uint32_t handle, const uint16_t *data)
  Informs the renderer that there is new data to render.
void  render ()
  Run the renderer.

The SlideShow class parses and executes slideshow scripts, handling delays and transitions.

Import library

Public Types

typedef SlideShowError(*  calloutFunc )(int calloutId, SlideShow *ss, int identifier)
  A function that the script can call during execution.

Public Member Functions

  SlideShow ( Renderer *r, const char *pathPrefix=NULL, int xoff=0, int yoff=0, int layer=0, Mutex *fileMutex=NULL)
  Create a new slideshow.
SlideShowError  prepare (const char *scriptFile)
  Parses the script file and prepares internal structures.
SlideShowError  run ()
  Run the slideshow.
void  setCalloutHandler ( calloutFunc func, int calloutId)
  Register a function that the script can call.
void  releaseScreen (void)
  Decouples this SlideShow from the Renderer .
void  stop ()
  Stops the SlideShow .

Scripting

At the heart of the SlideShow engine is the script specifying what to do and it which order. An example of a script:

load /slides/img1.png  1
show 1 none
load /slides/img2.png  2
wait 1500
show 2 none

The script above loads and shows the first image and then loads image two. After 1.5 seconds the second image is displayed. There are no transitions used, the new image replaces the old immediately. The script will execute once.

File Format

The script files:

  • Ignores leading whitespace
  • Uses \n and/or \r as line termination
  • Treats lines starting with # as comments
  • All commands must be in lowercase

Supported commands:

CommandDescription
# somethingLines starting with # are treated as comments and are ignored
clear
clear <color>
clear <color> <trans>
Clears the slideshow area.
<color> is a hex value of the color to clear with, default is white
<trans> the transition to use, default is none
show <slot> <trans>Shows image in the specified slot with the specified transition
wait <ms>Waits up to ms milliseconds (explained below)
callout <id>Calls a user function passing along the specified id
label <string>Defines a position in the slideshow sequence that can be referenced by a goto command. Labels must be given unique names within the script
goto <label>Sets the next command in the script to be the command after the specified label
load <file> <slot>Loads the specified image file into the specified slot, overwriting old content if any

Loading Images

Images are loaded from files into slots using the load command. Slots can be reused by loading a new image into an existing slot. If there is enough memory, it could be a good idea to preload all images before the slideshow start:

load /mci/img1 1
load /mci/img2 2
...
label start
show 1 none
wait 1000
show 2 none
...
goto start

The paths of the images in the script above are both hardcoded to be loaded from an uSD card (the /mci/ part of the path). Sometime it is better to keep the exact location of the images out of the script and that is what the pathPrefix parameter in the SlideShow constructor is for:

load /slides/img1 1
load /slides/img2 2
...
label start
show 1 none
wait 1000
show 2 none
...
goto start

...
Renderer r;
SlideShow s(&r, "/mci/demo");
...


The result of the SlideShow constructor above is that the images in the script will be loaded from "/mci/demo/slides/img1.png" and "/mci/demo/slides/img2.png".

Transitions

The slideshow engine supports the following transitions:

noneThe new image will immediately replace the old one
left-rightThe new image is rolled in from the left, gradually covering more and more of the old image
down-upThe old image is gradually shifted upwards as the new image is shifted in
top-downThe old image is gradually shifted downwards as the new image is shifted in
blindsA curtain is pulled down over the old image and as it is rolled up again the new image appears
fadeThe old image gradually fades into the new image

All transitions have predefined execution times, see the SlideShow.h file for exact times.

Which transition to use is specified in the script's show and clear commands:

show 1 top-down
clear 001f fade
show 2 none
show 3 blinds

Delays

It is essential to be able to specify how long a slide show be shown before switching to the next one. This is controlled in the script file with the wait command.

The current time is stored each time an image is show (show), the screen is cleared (clear) or a delay (wait) has finished executing. The delay is then counted from the stored value and not from the current time.

In this example img2 will be show 2 seconds after img1 is shown

load /img1.png 1
load /img2.png 2
show 1 none
wait 2000
show 2 none

In this example img2 will be show 2 seconds after img1 is shown. Note that the time it takes to load img2 does not effect the time when img2 is shown (of course assuming that it is less than 2 seconds).

load /img1.png 1
show 1 none
load /img2.png 2
wait 2000
show 2 none

If the images are quick to load then this can be used to load images while showing the first few slides without the user noticing:

load /img1.png 1
show 1 none
load /img2.png 2
load /img3.png 3
load /img4.png 4
load /img5.png 5
load /img6.png 6
wait 4000
show 2 none
load /img7.png 7
load /img8.png 8
load /img9.png 9
load /img10.png 10
load /img11.png 11
wait 4000
show 3 none
...

Advanced

The SlideShow engine supports multiple slideshows running at the same time on the same display. An example could be to have a background slideshow running and when it comes to slide 3 it pauses and executes another slideshow perhaps showing a video on part of the screen. When the video has completed the main slideshow continues.

To handle nesting of slideshows in that way there must be a way for them to interact. This is handled with the callout command in the script and the setCalloutHandler() function in the code.

A simple example letting the slideshow print a counter on each loop of the presentation:

load /slides/img1.png 1
load /slides/img2.png 2
label start
  show 1 fade
  wait 1000
  show 2 blinds
  callout 100
  wait 2000
goto start

#include "SlideShow.h"
#include "DMBoard.h"

static SlideShow::SlideShowError handler(int calloutId, SlideShow* ss, int identifier) {
  static int counter = 0;
  DMBoard::instance().logger()->printf("counter = %d\n", counter++);
}

void main() {
 ...
 SlideShow s(...);
 s.setCalloutHandler(&handler, 42);
 ...
}


The example above would result in the following printouts (roughly 3 seconds apart):

counter = 0
counter = 1
...

The callout function is very versatile and can be used to delay execution or pass different sorts of messages:

static SlideShow::SlideShowError handler(int calloutId, SlideShow* ss, int identifier) {
  switch (calloutid) {
    case 42:
      switch (identifier) {
        case 1:
          // Slideshow has finished preloading of images
        break;
        case 2:
          // Slideshow has completed yet another loop
        break;
        case 3:
          // allow the delay to be controlled from code instead of from script
          wait_ms(1000);
        break;
      break;
    case ...
}


The callout can also be used to synchronize two or more presentations: The first "master" script shows slides 1 and 2 and then lets the other script run before continuing.

...
label a
  show 1 fade
  wait 1000
  show 2 fade
  callout 50
  show 3 fade
  wait 2000
goto a

The "video" script asks for permission to start (callout 0) and notifies when done (callout 100).

...
label start
  callout 0
  show 1 none
  show 2 none
  show 3 none
  show 4 none
  show 5 none
  callout 100
goto start

The corresponding code could be:

#include "SlideShow.h"
#include "DMBoard.h"

#define ID_MAIN   10
#define ID_VIDEO  20 

// This is just for the example, a better way is to use signalling or a Mutex
static bool volatile allowedToStartVideo = false;
static bool volatile videoFinished = true;

static SlideShow::SlideShowError handler(int calloutId, SlideShow* ss, int identifier) {
  if (calloutid == ID_MAIN) {
    if (identifier == 50) {
      // main slideshow wants to start video slideshow
      videoFinished = false;
      allowedToStartVideo = true;

      // wait for it to complete
      while (!videoFinished) {
        // only as example, should use signalling instead
      }
    }
  } else if (calloutid == ID_VIDEO) {
    if (identifier == 0) {
      // wait for permission to start
      while (!allowedToStartVideo) {
        // only as example, should use signalling instead
      }
      allowedToStartVideo = false;
    } else if (identifier == 100) {
      // let the main slideshow know that the video is done
      videoFinished = true;
    }
  }
}

static void slideTask(const void* args) {
  SlideShow* ss = (SlideShow*)args;
  ss->run();
}

void main() {
  ...
  SlideShow sMain(...);
  sMain.setCalloutHandler(&handler, ID_MAIN);
  sMain.prepare("/mci/main.txt");
  Thread tMain(slideTask, &sMain);

  SlideShow sVideo(...);
  sVideo.setCalloutHandler(&handler, ID_VIDEO);
  sVideo.prepare("/mci/video.txt");
  Thread tVideo(slideTask, &sVideo);
 ...
}



All wikipages