A basic graphics package for the LPC4088 Display Module.

Dependents:   lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI lpc4088_displaymodule_fs_aid ... more

Fork of DMBasicGUI by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SlideShow.cpp Source File

SlideShow.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 #include "SlideShow.h"
00018 #include "Image.h"
00019 #include "mbed_debug.h"
00020 #include "DMBoard.h"
00021 
00022 /******************************************************************************
00023  * Defines and typedefs
00024  *****************************************************************************/
00025 
00026 #define SLIDESHOW_DBG             0
00027 
00028 #define NO_SLOT   -12   /* Some constant to indicate that no slot is in use */
00029 
00030 /* Helper macros for the Fade transition */
00031 #define FADE_XRED(__in)   (((__in)>>11)&0x1f)
00032 #define FADE_XGREEN(__in) (((__in)>>5)&0x3f)
00033 #define FADE_XBLUE(__in)  ((__in)&0x1f)
00034 #define FADE_COMBINE(__old, __new, __mul) \
00035         ( ((((FADE_XRED(__old)*(8-(__mul)))+(FADE_XRED(__new)*(__mul)))>>3)<<11) \
00036         | ((((FADE_XGREEN(__old)*(8-(__mul)))+(FADE_XGREEN(__new)*(__mul)))>>3)<<5) \
00037         | (((FADE_XBLUE(__old)*(8-(__mul)))+(FADE_XBLUE(__new)*(__mul)))>>3) )
00038 
00039 
00040 /******************************************************************************
00041  * Global variables
00042  *****************************************************************************/
00043 
00044 extern volatile uint32_t msTicks;
00045 
00046 /******************************************************************************
00047  * Private Functions
00048  *****************************************************************************/
00049 
00050 void SlideShow::Command::print()
00051 {
00052     switch(type)
00053     {
00054         case Clear:
00055             printf("CMD: Clear screen\n");
00056             break;
00057         case Goto:
00058             printf("CMD: Goto command %d\n", information);
00059             break;
00060         case LoadImage:
00061             printf("CMD: Load file %s into [%d]\n", fname, information);
00062             break;
00063         case Show:
00064             printf("CMD: Show image [%d] with %s transition\n", information, transition->typeString());
00065             break;
00066         case Wait:
00067             printf("CMD: Wait %d ms\n", information);
00068             break;
00069         case Callout:
00070             printf("CMD: Callout %d\n", information);
00071             break;
00072         default:
00073             printf("Unknown command\n");
00074     }
00075 }
00076 
00077 SlideShow::SlideShowError SlideShow::Command::handle(SlideShow* ss, int* seqIdx, int* lastTime)
00078 {
00079     SlideShowError result = Ok;
00080 
00081     //printf("[%03d] ", *seqIdx); print();
00082     switch (type)
00083     {
00084         case Clear:
00085             // Use the 3rd back buffer as a fake image for the transition
00086             Image::ImageData_t d;
00087             d.height = ss->screenHeight;
00088             d.width = ss->screenWidth;
00089             d.pixels = &ss->ImageBackBuffer[ss->screenPixels*2];
00090             d.pointerToFree = NULL;
00091             memset(d.pixels, information, ss->screenBytes);
00092             if (ss->CurrentSlot == NO_SLOT) {
00093                 result = transition->execute(ss, NULL, &d);
00094             } else {
00095                 result = transition->execute(ss, &(ss->PreparedImages[ss->CurrentSlot]), &d);
00096             }
00097             *lastTime = msTicks;
00098             *seqIdx+=1;
00099             break;
00100 
00101         case Goto:
00102             *seqIdx = information;
00103             break;
00104 
00105         case LoadImage:
00106             if ((result = ss->loadImage(fname, information)) != Ok)
00107             {
00108                 printf("Failed to load image. Aborting...\n");
00109                 break;
00110             }
00111             *seqIdx+=1;
00112             break;
00113 
00114         case Show:
00115             if (ss->CurrentSlot == NO_SLOT) {
00116                 result = transition->execute(ss, NULL, &(ss->PreparedImages[information]));
00117             } else {
00118                 result = transition->execute(ss, &(ss->PreparedImages[ss->CurrentSlot]), &(ss->PreparedImages[information]));
00119             }
00120             if (result != Ok) {
00121                 printf("Failed to show image. Aborting...\n");
00122                 break;
00123             }
00124             ss->CurrentSlot = information;
00125             *lastTime = msTicks;
00126             *seqIdx+=1;
00127             break;
00128 
00129         case Wait:
00130             ss->delay(*lastTime, information);
00131             *lastTime = msTicks;
00132             *seqIdx+=1;
00133             break;
00134 
00135         case Callout:
00136             if (ss->callout != NULL) {
00137                 result = ss->callout(ss->calloutId, ss, information);
00138             } else {
00139                 // Silently accept that no callout listener is registered
00140             }
00141             *seqIdx+=1;
00142             break;
00143 
00144         default:
00145             printf("Found unknown command at index %d\n", *seqIdx);
00146             result = InvalidScript;
00147     }
00148     return result;
00149 }
00150 
00151 SlideShow::SlideShowError SlideShow::Transition::execute(SlideShow* ss, Image::ImageData_t* CurrentImage, Image::ImageData_t* NewImage)
00152 {
00153   SlideShowError result = Ok;
00154 
00155   do {
00156 
00157     // TODO: This would be a good place to handle rendering of differently sized images,
00158     //       could unregister+register if NewImage is different from CurrentImage
00159 
00160     // Register with the Renderer if needed.
00161     if (ss->rendHnd == 0) {
00162       if (ss->rend == NULL) {
00163         printf("No registered renderer\n");
00164         result = RuntimeError;
00165         break;
00166       }
00167 
00168       // time to register with the renderer
00169       ss->rendHnd = ss->rend->registerUser(ss->layer, ss->drawXoff, ss->drawYoff,
00170                                            NewImage->width, NewImage->height);
00171       if (ss->rendHnd == 0) {
00172         printf("Failed to register with renderer\n");
00173         result = RuntimeError;
00174         break;
00175       }
00176     }
00177 
00178     switch (t) {
00179       case None:
00180       {
00181         ss->rend->setFramebuffer(ss->rendHnd, NewImage->pixels);
00182       }
00183       break;
00184 
00185       case LeftRight:  // TODO: Note that this transition is only implemented for fullscreen mode
00186       {
00187         // Create a buffer with the old image
00188         if (CurrentImage == NULL) {
00189           memset(ss->ImageBackBuffer, 0, ss->screenBytes);
00190         } else {
00191           memcpy(ss->ImageBackBuffer, CurrentImage->pixels, ss->screenBytes);
00192         }
00193         int end = ss->screenWidth - LeftRight_PixelsToSkip;
00194         for (int x = 0; x < end; x += LeftRight_PixelsToSkip)
00195         {
00196           int off = 0;
00197           for (int y = 0; y < ss->screenHeight; y++)
00198           {
00199             memcpy(ss->ImageBackBuffer + (off+x), NewImage->pixels + (off+x),
00200                    LeftRight_PixelsToSkip*sizeof(uint16_t));
00201             off += ss->screenWidth;
00202           }
00203 
00204           // Show the updated image
00205           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
00206 
00207           // Sleep and do over again
00208           ThisThread::sleep_for(LeftRight_DelayMs);
00209         }
00210 
00211         // Show final image
00212         ss->rend->setFramebuffer(ss->rendHnd, NewImage->pixels);
00213       }
00214       break;
00215 
00216       case DownUp:
00217       {
00218         int imgNumPixels = NewImage->width * NewImage->height;
00219 
00220         // Create a buffer with the two images after each other, NewImage below
00221         if (CurrentImage == NULL) {
00222           memset(ss->ImageBackBuffer, 0, imgNumPixels*2);
00223         } else {
00224           memcpy(ss->ImageBackBuffer, CurrentImage->pixels, imgNumPixels*2);
00225         }
00226         memcpy(ss->ImageBackBuffer + imgNumPixels, NewImage->pixels, imgNumPixels*2);
00227 
00228         // We will be using a back buffer
00229         for (int i = DownUp_LineSkip/2; i < (NewImage->height - 1); i+=DownUp_LineSkip)
00230         {
00231           // Show image by advancing what is shown one line at a time
00232           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer + i * NewImage->width);
00233 
00234           // Sleep and do over again
00235           ThisThread::sleep_for(DownUp_DelayMs);
00236         }
00237 
00238         // show final image
00239         ss->rend->setFramebuffer(ss->rendHnd, NewImage->pixels);
00240       }
00241       break;
00242 
00243       case TopDown:
00244       {
00245         int imgNumPixels = NewImage->width * NewImage->height;
00246 
00247         // Create a buffer with the two images after each other, NewImage above
00248         if (CurrentImage == NULL) {
00249           memset(ss->ImageBackBuffer + imgNumPixels, 0, imgNumPixels*2);
00250         } else {
00251           memcpy(ss->ImageBackBuffer + imgNumPixels, CurrentImage->pixels, imgNumPixels*2);
00252         }
00253         memcpy(ss->ImageBackBuffer, NewImage->pixels, imgNumPixels*2);
00254 
00255         // We will be using a back buffer
00256         for (int i = NewImage->height - TopDown_LineSkip/2; i > 0; i-=TopDown_LineSkip)
00257         {
00258           // Show image by advancing what is shown one line at a time
00259           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer + i*NewImage->width);
00260 
00261           // Sleep and do over again
00262           ThisThread::sleep_for(TopDown_DelayMs);
00263         }
00264 
00265         // show final image
00266         ss->rend->setFramebuffer(ss->rendHnd, NewImage->pixels);
00267       }
00268       break;
00269 
00270       case Blinds:
00271       {
00272         int i;
00273         int blockNumPixels = Blinds_LinesPerBlock * ss->screenWidth;
00274         int blockNumBytes = blockNumPixels * sizeof(uint16_t);
00275         image_t beamBlock = ss->ImageBackBuffer + ss->screenPixels;
00276         image_t bkgBlock = beamBlock + blockNumPixels;
00277 
00278         // Create a buffer with the old image
00279         if (CurrentImage == NULL) {
00280           memset(ss->ImageBackBuffer, 0, ss->screenBytes);
00281         } else {
00282           memcpy(ss->ImageBackBuffer, CurrentImage->pixels, ss->screenBytes);
00283         }
00284 
00285         // Create the two coloured blocks
00286         memset(beamBlock, Blinds_BeamColor, blockNumBytes);
00287         memset(bkgBlock, Blinds_BackColor, blockNumBytes);
00288 
00289         for (i = 0; i < ss->screenPixels; i += blockNumPixels)
00290         {
00291           // Draw the moving beam, erasing the old image
00292           memcpy(ss->ImageBackBuffer+i, beamBlock, blockNumBytes);
00293 
00294           // Fill upp behind the beam with background color
00295           if (i > 0) {
00296             memcpy(ss->ImageBackBuffer+i-blockNumPixels, bkgBlock, blockNumBytes);
00297           }
00298 
00299           // Show the updated image
00300           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
00301 
00302           // Sleep and do over again
00303           ThisThread::sleep_for(Blinds_DelayMs);
00304         }
00305         memcpy(ss->ImageBackBuffer+i-blockNumPixels, bkgBlock, blockNumBytes);
00306         ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
00307         ThisThread::sleep_for(Blinds_DelayMs);
00308 
00309         for (i = 0; i < ss->screenPixels; i += blockNumPixels)
00310         {
00311           // Draw the moving beam, erasing the old image
00312           memcpy(ss->ImageBackBuffer+i, beamBlock, blockNumBytes);
00313 
00314           // Fill upp behind the beam with the new image
00315           if (i > 0) {
00316             memcpy(ss->ImageBackBuffer+i-blockNumPixels, NewImage->pixels+i-blockNumPixels, blockNumBytes);
00317           }
00318 
00319           // Show image by advancing what is shown one line at a time
00320           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
00321 
00322           // Sleep and do over again
00323           ThisThread::sleep_for(Blinds_DelayMs);
00324         }
00325 
00326         // show final image
00327         ss->rend->setFramebuffer(ss->rendHnd, NewImage->pixels);
00328       }
00329       break;
00330 
00331       case Fade:
00332       {
00333         // Create a buffer with the old image
00334         if (CurrentImage == NULL) {
00335           memset(ss->ImageBackBuffer, 0, ss->screenBytes * 2); // use an extra backbuffer
00336         } else {
00337           memcpy(ss->ImageBackBuffer, CurrentImage->pixels, ss->screenBytes);
00338         }
00339 
00340         uint32_t firstY = 0;
00341         uint32_t lastY = NewImage->height;
00342         for (uint32_t y = 0, off=0; y < NewImage->height; y++) {
00343           for (uint32_t x = 0; x < NewImage->width; x++) {
00344             off++;
00345             if (NewImage->pixels[off] != ss->ImageBackBuffer[off]) {
00346               firstY = y;
00347               y = NewImage->height;
00348               break;
00349             }
00350           }
00351         }
00352         for (uint32_t y = NewImage->height-1, off=NewImage->height*NewImage->width-1; y > firstY; y--) {
00353           for (uint32_t x = 0; x < NewImage->width; x++) {
00354             off--;
00355             if (NewImage->pixels[off] != ss->ImageBackBuffer[off]) {
00356               lastY = y;
00357               y = firstY; // to break the outer loop as well
00358               break;
00359             }
00360           }
00361         }
00362 
00363         // Gradually fade between the old and new images
00364         for (int pass = 1; pass < 8; pass++)
00365         {
00366           uint16_t* oldImg = CurrentImage==NULL ? &ss->ImageBackBuffer[ss->screenPixels] : &CurrentImage->pixels[firstY*NewImage->width];
00367           uint16_t* newImg = &NewImage->pixels[firstY*NewImage->width];
00368           uint16_t* dstImg = &ss->ImageBackBuffer[firstY*NewImage->width];
00369           for (uint32_t y = firstY; y <= lastY; y++)
00370           {
00371             for (uint32_t x = 0; x < NewImage->width; x++)
00372             {
00373               if (*oldImg != *newImg) {
00374                 *dstImg = FADE_COMBINE(*oldImg, *newImg, pass);
00375               }
00376               oldImg++;
00377               newImg++;
00378               dstImg++;
00379             }
00380           }
00381           // Show the updated image
00382           ss->rend->setFramebuffer(ss->rendHnd, ss->ImageBackBuffer);
00383 
00384           // Sleep and do over again
00385           ThisThread::sleep_for(Fade_DelayMs);
00386         }
00387 
00388         // show final image
00389         ss->rend->setFramebuffer(ss->rendHnd, NewImage->pixels);
00390       }
00391       break;
00392 
00393       case Unknown:
00394       default:
00395         result = RuntimeError;
00396     }
00397   } while(0);
00398 
00399   return result;
00400 }
00401 
00402 SlideShow::SlideShowError SlideShow::loadFile(const char* path, uint8_t** pData, uint32_t* pSize)
00403 {
00404     FILE* f = NULL;
00405     uint32_t pos, size, num;
00406     SlideShowError result = Ok;
00407 
00408     *pData = NULL;
00409     *pSize = 0;
00410 
00411     if (fileMutex != NULL) {
00412         fileMutex->lock();
00413     }
00414     do
00415     {
00416         f = fopen(path, "r");
00417         if (f == NULL) {
00418             printf("Failed to open file %s for reading\n", path);
00419             result = FileError;
00420             break;
00421         }
00422 
00423         // Determine file size
00424         pos = ftell(f);
00425         fseek(f, 0, SEEK_END);
00426         size = ftell(f);
00427         fseek(f, pos, SEEK_SET);
00428 
00429         // Allocate memory to read into
00430         *pData = (unsigned char*)malloc(size);
00431         if (*pData == NULL) {
00432             printf("Failed to allocate %u bytes to load %s into\n", size, path);
00433             result = OutOfMemory;
00434             break;
00435         }
00436 
00437         // Read entire file
00438         *pSize = size;
00439         pos = 0;
00440         do {
00441             num = fread(*pData + pos, 1, size, f);
00442             if (num > 0) {
00443                 size -= num;
00444                 pos += num;
00445             }
00446         } while ((num > 0) && (size > 0));
00447 
00448         if (size != 0) {
00449             printf("Failed to read entire %s, got %u of %u\n", path, pos, *pSize);
00450             result = FileError;
00451             break;
00452         }
00453 
00454         // All OK
00455 
00456     } while(0);
00457 
00458     if (f != NULL) {
00459         fclose(f);
00460     }
00461     if (result != Ok) {
00462         if (*pData != NULL) {
00463             free(*pData);
00464             *pData = NULL;
00465             *pSize = 0;
00466         }
00467     }
00468 
00469     if (fileMutex != NULL) {
00470         fileMutex->unlock();
00471     }
00472 
00473     return result;
00474 }
00475 
00476 
00477 // pBuf in, pOffset in/out, pLine out
00478 // returns 0 as long as a token is found
00479 int SlideShow::getNextLine(char* pBuf, int* pOffset, char** ppLine)
00480 {
00481     int pos = *pOffset;
00482     int result = -1;
00483 
00484     // trim whitespace from start of line
00485     while ((pBuf[pos] == ' ') || (pBuf[pos] == '\t'))
00486     {
00487         pos++;
00488     }
00489     *ppLine = &(pBuf[pos]);
00490 
00491     while (pBuf[pos] != '\0')
00492     {
00493         if ((pBuf[pos] == '\r') || (pBuf[pos] == '\n'))
00494         {
00495             // found the next end of line
00496             pBuf[pos++] = '\0';
00497             result = 0;
00498 
00499             // move past all end-of-line characters
00500             while ((pBuf[pos] == '\r') || (pBuf[pos] == '\n'))
00501             {
00502                 pos++;
00503             }
00504             break;
00505         }
00506         pos++;
00507     }
00508 
00509     *pOffset = pos;
00510     return result;
00511 }
00512 
00513 // pLine in, ppPart1 out, ppPart2 out, ppPart3 out
00514 // returns number of found parts
00515 int SlideShow::splitLine(char* pLine, char** ppPart1, char** ppPart2, char** ppPart3)
00516 {
00517     int pos = 0;
00518     int found = 0;
00519 
00520     *ppPart1 = NULL;
00521     *ppPart2 = NULL;
00522     *ppPart3 = NULL;
00523 
00524     if (*pLine != '\0')
00525     {
00526         *ppPart1 = &(pLine[0]);
00527         found++;
00528 
00529         while (pLine[pos] != '\0')
00530         {
00531             if (pLine[pos] == ' ')
00532             {
00533                 // found the next token separator
00534                 pLine[pos++] = '\0';
00535                 found++;
00536 
00537                 // move past all token separator characters
00538                 while (pLine[pos] == ' ')
00539                 {
00540                     pos++;
00541                 }
00542 
00543                 // start looking for end of next token
00544                 if (found == 2)
00545                 {
00546                     *ppPart2 = &(pLine[pos]);
00547                 }
00548                 else if (found == 3)
00549                 {
00550                     *ppPart3 = &(pLine[pos]);
00551                 }
00552             }
00553             pos++;
00554         }
00555     }
00556 
00557     return found;
00558 }
00559 
00560 // returns index of pLabel or -1 if it doesn't exist
00561 int SlideShow::findLabel(LabelInfo* pLabels, int numLabels, const char* pLabel)
00562 {
00563     int i;
00564     for (i = 0; i < numLabels; i++)
00565     {
00566         if (strcmp(pLabels[i].pLabel, pLabel) == 0)
00567         {
00568             return pLabels[i].index;
00569         }
00570     }
00571     return -1;
00572 }
00573 
00574 void SlideShow::freeSequence(void)
00575 {
00576     if (allocatedSequenceItems > 0) {
00577         for (int i = 0; i < usedSequenceItems; i++) {
00578             delete Sequence[i];
00579         }
00580         free(Sequence);
00581         Sequence = NULL;
00582         allocatedSequenceItems = 0;
00583         usedSequenceItems = 0;
00584     }
00585 }
00586 
00587 SlideShow::SlideShowError SlideShow::expandSequence()
00588 {
00589     int newSize = allocatedSequenceItems + 20;
00590     Command** newPtr = (Command**)realloc(Sequence, newSize * sizeof(Command*));
00591     if (newPtr != NULL) {
00592         Sequence = newPtr;
00593         allocatedSequenceItems = newSize;
00594         return Ok;
00595     } else {
00596         return OutOfMemory;
00597     }
00598 }
00599 
00600 SlideShow::SlideShowError SlideShow::parseScript(char* pBuf)
00601 {
00602     char* pLine = NULL;
00603     int offset = 0;
00604     LabelInfo Labels[10] = {0};
00605     int numLabels = 0;
00606     LabelInfo UnresolvedGotos[10] = {0};
00607     int numUnresolvedGotos = 0;
00608     int i;
00609     SlideShowError result;
00610 
00611     // cleanup old sequences
00612     freeSequence();
00613 
00614     // prepare the new one
00615     result = expandSequence();
00616     if (result != Ok) {
00617         return result;
00618     }
00619 
00620     // start parsing the new sequence
00621     while (getNextLine(pBuf, &offset, &pLine) == 0)
00622     {
00623         if (*pLine == '#')
00624         {
00625             // found a comment line
00626         }
00627         else
00628         {
00629             char* pCommand;
00630             char* pArg1;
00631             char* pArg2;
00632             int num = splitLine(pLine, &pCommand, &pArg1, &pArg2);
00633 
00634             if ((num >= 1) && (num <= 3) && (strcmp(pCommand, "clear") == 0))
00635             {
00636                 if (num == 1) {
00637                     Sequence[usedSequenceItems] = new Command(Command::Clear, 0xff, new Transition("none"));
00638                 } else if (num == 2) {
00639                     Sequence[usedSequenceItems] = new Command(Command::Clear, strtol(pArg1, NULL, 16), new Transition("none"));
00640                 } else {
00641                     Transition* t = new Transition(pArg2);
00642                     if (t->type() == Transition::Unknown) {
00643                         printf("Found invalid transition '%s'. Aborting...\n", pArg2);
00644                         result = InvalidScript;
00645                         break;
00646                     }
00647                     Sequence[usedSequenceItems] = new Command(Command::Clear, strtol(pArg1, NULL, 16), t);
00648                 }
00649             }
00650             else if ((num == 3) && (strcmp(pCommand, "show") == 0))
00651             {
00652                 Transition* t = new Transition(pArg2);
00653                 if (t->type() == Transition::Unknown) {
00654                     printf("Found invalid transition '%s'. Aborting...\n", pArg2);
00655                     result = InvalidScript;
00656                     break;
00657                 }
00658                 Sequence[usedSequenceItems] = new Command(Command::Show, atoi(pArg1), t);
00659             }
00660             else if ((num == 2) && (strcmp(pCommand, "wait") == 0))
00661             {
00662                 Sequence[usedSequenceItems] = new Command(Command::Wait, atoi(pArg1));
00663             }
00664             else if ((num == 2) && (strcmp(pCommand, "callout") == 0))
00665             {
00666                 Sequence[usedSequenceItems] = new Command(Command::Callout, atoi(pArg1));
00667             }
00668             else if ((num == 2) && (strcmp(pCommand, "label") == 0))
00669             {
00670                 int index = findLabel(&(Labels[0]), numLabels, pArg1);
00671                 if (index == -1)
00672                 {
00673                     // found a new label
00674                     Labels[numLabels].index = usedSequenceItems;
00675                     Labels[numLabels].pLabel = pArg1;
00676                     numLabels++;
00677 
00678                     // A label doesn't occupy a slot in the sequence
00679                     usedSequenceItems--;
00680                 }
00681                 else
00682                 {
00683                     // label already declared
00684                     printf("Found a second declaration of label '%s'. Aborting...\n", pArg1);
00685                     result = InvalidScript;
00686                     break;
00687                 }
00688             }
00689             else if ((num == 2) && (strcmp(pCommand, "goto") == 0))
00690             {
00691                 int index = findLabel(&(Labels[0]), numLabels, pArg1);
00692                 if (index == -1)
00693                 {
00694                     // couldn't find the label we are looking for so we
00695                     // wait for now
00696                     UnresolvedGotos[numUnresolvedGotos].index = usedSequenceItems;
00697                     UnresolvedGotos[numUnresolvedGotos].pLabel = pArg1;
00698                     numUnresolvedGotos++;
00699                 }
00700 
00701                 // Create the command
00702                 Sequence[usedSequenceItems] = new Command(Command::Goto, index);
00703             }
00704             else if ((num == 3) && (strcmp(pCommand, "load") == 0))
00705             {
00706                 Sequence[usedSequenceItems] = new Command(Command::LoadImage, atoi(pArg2), NULL, pArg1, pathPrefix);
00707                 if (Sequence[usedSequenceItems]->info() >= MaxNumPreparedImages) {
00708                     printf("Attempting to load into invalid slot %d, have 0..%d. Aborting...\n", Sequence[usedSequenceItems]->info(), MaxNumPreparedImages);
00709                     result = InvalidScript;
00710                     break;
00711                 }
00712             }
00713             else
00714             {
00715                 // unknown command
00716                 printf("Found unknown command '%s'. Aborting...\n", pCommand);
00717                 result = InvalidScript;
00718                 break;
00719             }
00720 
00721             // start looking for next part in the sequence
00722             usedSequenceItems++;
00723 
00724             // assure we don't pass memory limit
00725             if (usedSequenceItems >= allocatedSequenceItems)
00726             {
00727                 result = expandSequence();
00728                 if (result != Ok) {
00729                     printf("Failed to allocate memory to hold sequence. Aborting...\n");
00730                     break;
00731                 }
00732             }
00733         }
00734     }
00735 
00736     // Resolve any unresolved gotos. Happens when the label is on
00737     // a line with a higher line number than the goto statement.
00738     for (i = 0; i < numUnresolvedGotos && result==Ok; i++)
00739     {
00740         int index = findLabel(&(Labels[0]), numLabels, UnresolvedGotos[i].pLabel);
00741         if (index == -1)
00742         {
00743             printf("Unable to find label '%s' used in goto statement. Aborting...\n", UnresolvedGotos[i].pLabel);
00744             result = InvalidScript;
00745         }
00746         else
00747         {
00748             // Update the goto element with the correct index of the label
00749             Sequence[UnresolvedGotos[i].index]->updateInfo(index);
00750         }
00751     }
00752 
00753     if (result==Ok && usedSequenceItems == 0)
00754     {
00755         printf("Found no sequence. Aborting...\n");
00756         result = InvalidScript;
00757     }
00758     return result;
00759 }
00760 
00761 SlideShow::SlideShowError SlideShow::loadImage(const char* pFileName, int slot)
00762 {
00763     SlideShowError result = Ok;
00764 
00765     if (PreparedImages[slot].pointerToFree != NULL) {
00766         free(PreparedImages[slot].pointerToFree);
00767         PreparedImages[slot].pointerToFree = NULL;
00768     }
00769 
00770     if (Image::decode(pFileName, Image::RES_16BIT, &(PreparedImages[slot]), fileMutex) != 0) {
00771         printf("Failed to decode file %s as image\n", pFileName);
00772         result = FileError;
00773     }
00774 
00775     return result;
00776 }
00777 void SlideShow::delay(int lastTime, int millis)
00778 {
00779     int timeToWait = (lastTime + millis) - msTicks;
00780     if (timeToWait > 0) {
00781         ThisThread::sleep_for(timeToWait);
00782     }
00783 }
00784 
00785 SlideShow::SlideShowError SlideShow::runScript()
00786 {
00787     SlideShowError result = Ok;
00788     int seqIndex = 0;
00789     int lastTime = 0;
00790 
00791     while ((result == Ok) && (seqIndex < this->usedSequenceItems))
00792     {
00793         result = Sequence[seqIndex]->handle(this, &seqIndex, &lastTime);
00794 
00795         if (abortBeforeNextStep) {
00796             break;
00797         }
00798     }
00799 
00800 //    if (*pAbort)
00801 //    {
00802 //    return SLIDE_USER_ABORT;
00803 //    }
00804 //    else
00805 //    {
00806 //    return SLIDE_SCRIPT_END;
00807 //    }
00808     return Ok;
00809 }
00810 
00811 
00812 /******************************************************************************
00813  * Public Functions
00814  *****************************************************************************/
00815 
00816 SlideShow::SlideShow(Renderer* r, const char* pathPrefix, int xoff, int yoff, int layer, Mutex* fileMutex)
00817 {
00818     Display* disp = DMBoard::instance().display();
00819     this->screenWidth = disp->width();
00820     this->screenHeight = disp->height();
00821     this->screenPixels = this->screenWidth * this->screenHeight;
00822     this->drawXoff = xoff;
00823     this->drawYoff = yoff;
00824 
00825     // Assume screen->bpp == Bpp_16
00826     this->screenBytes = 2 * this->screenPixels;
00827 
00828     this->ImageBackBuffer = NULL;
00829     this->Sequence = NULL;
00830     this->allocatedSequenceItems = 0;
00831     this->usedSequenceItems = 0;
00832 
00833     this->pathPrefix = pathPrefix;
00834 
00835     this->CurrentSlot = NO_SLOT;
00836 
00837     memset(PreparedImages, 0, MaxNumPreparedImages * sizeof(Image::ImageData_t));
00838 
00839     this->fileMutex = fileMutex;
00840 
00841     this->rend = r;
00842     this->rendHnd = 0;
00843     this->layer = layer;
00844 
00845     this->callout = NULL;
00846 
00847     this->abortBeforeNextStep = false;
00848 }
00849 
00850 SlideShow::~SlideShow()
00851 {
00852     if (ImageBackBuffer != NULL) {
00853         free(ImageBackBuffer);
00854         ImageBackBuffer = NULL;
00855     }
00856     for (int i = 0; i < MaxNumPreparedImages; i++) {
00857         if (PreparedImages[i].pointerToFree != NULL) {
00858             free(PreparedImages[i].pointerToFree);
00859         }
00860     }
00861 
00862     freeSequence();
00863 
00864     if ((rendHnd != 0) && (rend != NULL)) {
00865       rend->unregisterUser(rendHnd);
00866     }
00867 
00868     //memset(PreparedImages, 0, MaxNumPreparedImages * sizeof(Image::ImageData_t));
00869 }
00870 
00871 SlideShow::SlideShowError SlideShow::prepare(const char* scriptFile)
00872 {
00873     uint8_t* pBuf = NULL;
00874     uint32_t size = 0;
00875     SlideShowError result = InvalidScript;
00876 
00877     do
00878     {
00879         if (ImageBackBuffer == NULL) {
00880             // Back buffer will be able to hold three images
00881             ImageBackBuffer = (image_t)malloc(screenBytes * 3);
00882             if (ImageBackBuffer == NULL) {
00883                 result = OutOfMemory;
00884                 break;
00885             }
00886         }
00887 
00888         // Read the contents of the file into a newly allocated buffer
00889         result = loadFile(scriptFile, &pBuf, &size);
00890         if (result != Ok)
00891         {
00892             break;
00893         }
00894 
00895         //printf("Parsing buffer...\n");
00896 
00897         // Parse buffer to create the script sequence
00898         result = parseScript((char*)pBuf);
00899 
00900     } while (0);
00901 
00902     // Release resources
00903     if (pBuf != NULL)
00904     {
00905         free(pBuf);
00906         pBuf = NULL;
00907     }
00908     if (result != Ok) {
00909         freeSequence();
00910     }
00911 
00912     return result;
00913 }
00914 
00915 SlideShow::SlideShowError SlideShow::run()
00916 {
00917   //printf("Executing script...\n");
00918   this->abortBeforeNextStep = false;
00919   return runScript();
00920 }
00921 
00922 void SlideShow::setCalloutHandler(calloutFunc func, int calloutId)
00923 {
00924   this->callout = func;
00925   this->calloutId = calloutId;
00926 }
00927 
00928 void SlideShow::releaseScreen(void)
00929 {
00930   if ((rendHnd != 0) && (rend != NULL)) {
00931     rend->unregisterUser(rendHnd);
00932   }
00933   rendHnd = 0;
00934 }