Slideshow

Source: src/slideshow.c · 148 lines · 10 functions.

Screen captures

Views of this part running on the Mini Arcade.

Slideshow screen on the Mini Arcade
Slideshow showing an image on the display.

Screen / module overview

  1. Enter slideshow

    Scan supported image names, sort the list and randomly choose the first slide.

  2. Any images available?

    If none, display NO IMAGE FILES and the directory. Otherwise request decoding.

  3. Advance the slide

    Manual next or the two-second timer selects the next slide and marks decoding pending.

  4. Decode pending image

    Build its path and call imageDecodeFile() into the shared framebuffer. A failure enters IMAGE FAILED status.

  5. Draw and repeat

    Keep the decoded picture and add source status. SD source switching exists only when TF_CARD_ENABLED is compiled in.

Module entry points

These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.

How to read these diagrams

Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.

These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.

Functions in this file

slideshowDirectory() · source line 28
static const char *slideshowDirectory(void)
  1. Preprocessor directive#if TF_CARD_ENABLED
  2. Exit this functionreturn source == SLIDESHOW_SPIFFS ? SPIFFS_SLIDESHOW_DIRECTORY : SD_SLIDESHOW_DIRECTORY;
  3. Preprocessor directive#else
  4. Exit this functionreturn SPIFFS_SLIDESHOW_DIRECTORY;
  5. Preprocessor directive#endif
Read original function source
static const char *slideshowDirectory(void)
{
#if TF_CARD_ENABLED
    return source == SLIDESHOW_SPIFFS ? SPIFFS_SLIDESHOW_DIRECTORY : SD_SLIDESHOW_DIRECTORY;
#else
    return SPIFFS_SLIDESHOW_DIRECTORY;
#endif
}
sortSlides() · source line 37
static void sortSlides(void)
  1. FOR loopunsigned i = 0; i < slide_count; ++i

    Repeat body while the loop condition permits; then continue below.

    1. FOR loopunsigned j = i + 1U; j < slide_count; ++j

      Repeat body while the loop condition permits; then continue below.

        1. Decisionstrcmp(filenames[i], filenames[j]) <= 0
          True
          1. Next loop iterationcontinue;
          False

          Continue after this decision.

        2. Executechar swap[MAX_FILENAME];
        3. Executememcpy(swap, filenames[i], sizeof(swap));
        4. Executememcpy(filenames[i], filenames[j], sizeof(swap));
        5. Executememcpy(filenames[j], swap, sizeof(swap));
Read original function source
static void sortSlides(void)
{
    for (unsigned i = 0; i < slide_count; ++i) for (unsigned j = i + 1U; j < slide_count; ++j) {
        if (strcmp(filenames[i], filenames[j]) <= 0) continue;
        char swap[MAX_FILENAME];
        memcpy(swap, filenames[i], sizeof(swap));
        memcpy(filenames[i], filenames[j], sizeof(swap));
        memcpy(filenames[j], swap, sizeof(swap));
    }
}
loadSlideList() · source line 48
static bool loadSlideList(void)

Calls into this documentation:

  1. Executeslide_count = 0;
  2. ExecuteDIR *directory = opendir(slideshowDirectory());
  3. Decisiondirectory == NULL
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  4. Executestruct dirent *entry;
  5. WHILE loop(entry = readdir(directory)) != NULL && slide_count < MAX_SLIDES

    Repeat body while the loop condition permits; then continue below.

      1. Decision!imageIsSupportedName(entry->d_name)
        True
        1. Next loop iterationcontinue;
        False

        Continue after this decision.

      2. Executeconst size_t length = strlen(entry->d_name);
      3. Decisionlength >= MAX_FILENAME
        True
        1. Next loop iterationcontinue;
        False

        Continue after this decision.

      4. Executememcpy(filenames[slide_count], entry->d_name, length + 1U);
      5. Execute++slide_count;
  6. Executeclosedir(directory);
  7. ExecutesortSlides();
  8. Exit this functionreturn slide_count != 0;
Read original function source
static bool loadSlideList(void)
{
    slide_count = 0;
    DIR *directory = opendir(slideshowDirectory());
    if (directory == NULL) return false;
    struct dirent *entry;
    while ((entry = readdir(directory)) != NULL && slide_count < MAX_SLIDES) {
        if (!imageIsSupportedName(entry->d_name)) continue;
        const size_t length = strlen(entry->d_name);
        if (length >= MAX_FILENAME) continue;
        memcpy(filenames[slide_count], entry->d_name, length + 1U);
        ++slide_count;
    }
    closedir(directory);
    sortSlides();
    return slide_count != 0;
}
decodeSlide() · source line 66
static bool decodeSlide(uint16_t *frame)

Calls into this documentation:

  1. Executechar path[sizeof(SPIFFS_SLIDESHOW_DIRECTORY) + MAX_FILENAME + 1U];
  2. Executeconst int written = snprintf(path, sizeof(path), "%s/%s", slideshowDirectory(), filenames[current_slide]);
  3. Decisionwritten < 0 || (size_t)written >= sizeof(path)
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  4. Exit this functionreturn imageDecodeFile(path, frame);
Read original function source
static bool decodeSlide(uint16_t *frame)
{
    char path[sizeof(SPIFFS_SLIDESHOW_DIRECTORY) + MAX_FILENAME + 1U];
    const int written = snprintf(path, sizeof(path), "%s/%s", slideshowDirectory(), filenames[current_slide]);
    if (written < 0 || (size_t)written >= sizeof(path)) return false;
    return imageDecodeFile(path, frame);
}
loadCurrentSource() · source line 74
static void loadCurrentSource(uint32_t now_ms)

Calls into this documentation:

  1. Executestatus = loadSlideList() ? SLIDES_OK : SLIDES_NO_FILES;
  2. Executecurrent_slide = slide_count > 1U ? esp_random() % slide_count : 0U;
  3. Executedecode_pending = status == SLIDES_OK;
  4. Executenext_slide_at = now_ms;
Read original function source
static void loadCurrentSource(uint32_t now_ms)
{
    status = loadSlideList() ? SLIDES_OK : SLIDES_NO_FILES;
    current_slide = slide_count > 1U ? esp_random() % slide_count : 0U;
    decode_pending = status == SLIDES_OK;
    next_slide_at = now_ms;
}
startSlideshow() · source line 82
void startSlideshow(uint32_t now_ms)

Calls into this documentation:

  1. Executerunning = true;
  2. Preprocessor directive#if TF_CARD_ENABLED
  3. Executesource = SLIDESHOW_SPIFFS;
  4. Preprocessor directive#endif
  5. ExecuteloadCurrentSource(now_ms);
Read original function source
void startSlideshow(uint32_t now_ms)
{
    running = true;
#if TF_CARD_ENABLED
    source = SLIDESHOW_SPIFFS;
#endif
    loadCurrentSource(now_ms);
}
stopSlideshow() · source line 91
void stopSlideshow(void)
  1. Executerunning = false;
  2. Executedecode_pending = false;
Read original function source
void stopSlideshow(void)
{
    running = false;
    decode_pending = false;
}
slideshowAction() · source line 97
void slideshowAction(bool next, bool toggle_source, uint32_t now_ms)

Calls into this documentation:

  1. Decision!running
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Preprocessor directive#if TF_CARD_ENABLED
  3. Decisiontoggle_source
    True
      1. Executesource = source == SLIDESHOW_SPIFFS ? SLIDESHOW_SD : SLIDESHOW_SPIFFS;
      2. ExecuteloadCurrentSource(now_ms);
      3. Exit this functionreturn;
    False

    Continue after this decision.

  4. Preprocessor directive#else
  5. Execute(void)toggle_source;
  6. Preprocessor directive#endif
  7. Decisionstatus != SLIDES_OK || !next
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  8. Executecurrent_slide = (current_slide + 1U) % slide_count;
  9. Executedecode_pending = true;
  10. Executenext_slide_at = now_ms + SLIDE_DELAY_MS;
Read original function source
void slideshowAction(bool next, bool toggle_source, uint32_t now_ms)
{
    if (!running) return;
#if TF_CARD_ENABLED
    if (toggle_source) {
        source = source == SLIDESHOW_SPIFFS ? SLIDESHOW_SD : SLIDESHOW_SPIFFS;
        loadCurrentSource(now_ms);
        return;
    }
#else
    (void)toggle_source;
#endif
    if (status != SLIDES_OK || !next) return;
    current_slide = (current_slide + 1U) % slide_count;
    decode_pending = true;
    next_slide_at = now_ms + SLIDE_DELAY_MS;
}
updateSlideshow() · source line 115
void updateSlideshow(uint16_t *frame, uint32_t now_ms)

Calls into this documentation:

  1. Decision!running || status != SLIDES_OK || frame == NULL
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Decisionnow_ms >= next_slide_at
    True
      1. Decision!decode_pending
        True
        1. Executecurrent_slide = (current_slide + 1U) % slide_count;
        False

        Continue after this decision.

      2. Executedecode_pending = true;
      3. Executenext_slide_at = now_ms + SLIDE_DELAY_MS;
    False

    Continue after this decision.

  3. Decision!decode_pending
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  4. Executestatus = decodeSlide(frame) ? SLIDES_OK : SLIDES_BAD_IMAGE;
  5. Executedecode_pending = false;
Read original function source
void updateSlideshow(uint16_t *frame, uint32_t now_ms)
{
    if (!running || status != SLIDES_OK || frame == NULL) return;
    if (now_ms >= next_slide_at) {
        if (!decode_pending) current_slide = (current_slide + 1U) % slide_count;
        decode_pending = true;
        next_slide_at = now_ms + SLIDE_DELAY_MS;
    }
    if (!decode_pending) return;
    status = decodeSlide(frame) ? SLIDES_OK : SLIDES_BAD_IMAGE;
    decode_pending = false;
}
drawSlideshow() · source line 128
void drawSlideshow(uint16_t *frame)

Calls into this documentation:

  1. Decision!running || frame == NULL
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Decisionstatus != SLIDES_OK
    True
      1. Executeclear(frame, COLOR_BLACK);
      2. Executedraw_text_centred(frame, 160, 62, status == SLIDES_NO_FILES ? "NO IMAGE FILES" : "IMAGE FAILED", 2, COLOR_RED);
      3. Executedraw_text_centred(frame, 160, 91, slideshowDirectory(), 1, COLOR_WHITE);
      4. Preprocessor directive#if TF_CARD_ENABLED
      5. Executedraw_text_centred(frame, 160, 142, "C SOURCE BOOT BACK", 1, COLOR_LIGHTGRAY);
      6. Preprocessor directive#else
      7. Executedraw_text_centred(frame, 160, 142, "BOOT BACK", 1, COLOR_LIGHTGRAY);
      8. Preprocessor directive#endif
      9. Exit this functionreturn;
    False

    Continue after this decision.

  3. Preprocessor directive#if TF_CARD_ENABLED
  4. Executedraw_text(frame, 4, 158, source == SLIDESHOW_SPIFFS ? "SPIFFS C: SD" : "SD C: SPIFFS", 1, COLOR_WHITE);
  5. Preprocessor directive#else
  6. Executedraw_text(frame, 4, 158, "SPIFFS", 1, COLOR_WHITE);
  7. Preprocessor directive#endif
Read original function source
void drawSlideshow(uint16_t *frame)
{
    if (!running || frame == NULL) return;
    if (status != SLIDES_OK) {
        clear(frame, COLOR_BLACK);
        draw_text_centred(frame, 160, 62, status == SLIDES_NO_FILES ? "NO IMAGE FILES" : "IMAGE FAILED", 2, COLOR_RED);
        draw_text_centred(frame, 160, 91, slideshowDirectory(), 1, COLOR_WHITE);
#if TF_CARD_ENABLED
        draw_text_centred(frame, 160, 142, "C SOURCE  BOOT BACK", 1, COLOR_LIGHTGRAY);
#else
        draw_text_centred(frame, 160, 142, "BOOT BACK", 1, COLOR_LIGHTGRAY);
#endif
        return;
    }
#if TF_CARD_ENABLED
    draw_text(frame, 4, 158, source == SLIDESHOW_SPIFFS ? "SPIFFS  C: SD" : "SD  C: SPIFFS", 1, COLOR_WHITE);
#else
    draw_text(frame, 4, 158, "SPIFFS", 1, COLOR_WHITE);
#endif
}
Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "slideshow.h"
#include "hardware_features.h"
#include "game_graphics.h"
#include "PET2001_font.h"
#include "image_decoder.h"
#include "esp_random.h"
#include <dirent.h>
#include <stdio.h>
#include <string.h>

#define SPIFFS_SLIDESHOW_DIRECTORY "/spiffs/slideshow"
#define SD_SLIDESHOW_DIRECTORY "/sdcard/slideshow"
#define MAX_SLIDES 64
#define MAX_FILENAME 64
#define SLIDE_DELAY_MS 2000U

typedef enum { SLIDES_OK, SLIDES_NO_FILES, SLIDES_BAD_IMAGE } SlideshowStatus;
typedef enum { SLIDESHOW_SPIFFS, SLIDESHOW_SD } SlideshowSource;

static char filenames[MAX_SLIDES][MAX_FILENAME];
static unsigned slide_count, current_slide;
static uint32_t next_slide_at;
static bool running, decode_pending;
static SlideshowStatus status;
#if TF_CARD_ENABLED
static SlideshowSource source;
#endif

static const char *slideshowDirectory(void)
{
#if TF_CARD_ENABLED
    return source == SLIDESHOW_SPIFFS ? SPIFFS_SLIDESHOW_DIRECTORY : SD_SLIDESHOW_DIRECTORY;
#else
    return SPIFFS_SLIDESHOW_DIRECTORY;
#endif
}

static void sortSlides(void)
{
    for (unsigned i = 0; i < slide_count; ++i) for (unsigned j = i + 1U; j < slide_count; ++j) {
        if (strcmp(filenames[i], filenames[j]) <= 0) continue;
        char swap[MAX_FILENAME];
        memcpy(swap, filenames[i], sizeof(swap));
        memcpy(filenames[i], filenames[j], sizeof(swap));
        memcpy(filenames[j], swap, sizeof(swap));
    }
}

static bool loadSlideList(void)
{
    slide_count = 0;
    DIR *directory = opendir(slideshowDirectory());
    if (directory == NULL) return false;
    struct dirent *entry;
    while ((entry = readdir(directory)) != NULL && slide_count < MAX_SLIDES) {
        if (!imageIsSupportedName(entry->d_name)) continue;
        const size_t length = strlen(entry->d_name);
        if (length >= MAX_FILENAME) continue;
        memcpy(filenames[slide_count], entry->d_name, length + 1U);
        ++slide_count;
    }
    closedir(directory);
    sortSlides();
    return slide_count != 0;
}

static bool decodeSlide(uint16_t *frame)
{
    char path[sizeof(SPIFFS_SLIDESHOW_DIRECTORY) + MAX_FILENAME + 1U];
    const int written = snprintf(path, sizeof(path), "%s/%s", slideshowDirectory(), filenames[current_slide]);
    if (written < 0 || (size_t)written >= sizeof(path)) return false;
    return imageDecodeFile(path, frame);
}

static void loadCurrentSource(uint32_t now_ms)
{
    status = loadSlideList() ? SLIDES_OK : SLIDES_NO_FILES;
    current_slide = slide_count > 1U ? esp_random() % slide_count : 0U;
    decode_pending = status == SLIDES_OK;
    next_slide_at = now_ms;
}

void startSlideshow(uint32_t now_ms)
{
    running = true;
#if TF_CARD_ENABLED
    source = SLIDESHOW_SPIFFS;
#endif
    loadCurrentSource(now_ms);
}

void stopSlideshow(void)
{
    running = false;
    decode_pending = false;
}

void slideshowAction(bool next, bool toggle_source, uint32_t now_ms)
{
    if (!running) return;
#if TF_CARD_ENABLED
    if (toggle_source) {
        source = source == SLIDESHOW_SPIFFS ? SLIDESHOW_SD : SLIDESHOW_SPIFFS;
        loadCurrentSource(now_ms);
        return;
    }
#else
    (void)toggle_source;
#endif
    if (status != SLIDES_OK || !next) return;
    current_slide = (current_slide + 1U) % slide_count;
    decode_pending = true;
    next_slide_at = now_ms + SLIDE_DELAY_MS;
}

void updateSlideshow(uint16_t *frame, uint32_t now_ms)
{
    if (!running || status != SLIDES_OK || frame == NULL) return;
    if (now_ms >= next_slide_at) {
        if (!decode_pending) current_slide = (current_slide + 1U) % slide_count;
        decode_pending = true;
        next_slide_at = now_ms + SLIDE_DELAY_MS;
    }
    if (!decode_pending) return;
    status = decodeSlide(frame) ? SLIDES_OK : SLIDES_BAD_IMAGE;
    decode_pending = false;
}

void drawSlideshow(uint16_t *frame)
{
    if (!running || frame == NULL) return;
    if (status != SLIDES_OK) {
        clear(frame, COLOR_BLACK);
        drawPet2001TextCentredTransparent(frame, 160, 62, status == SLIDES_NO_FILES ? "NO IMAGE FILES" : "IMAGE FAILED", COLOR_RED, 2);
        drawPet2001TextCentredTransparent(frame, 160, 91, slideshowDirectory(), COLOR_WHITE, 1);
#if TF_CARD_ENABLED
        drawPet2001TextCentredTransparent(frame, 160, 142, "C SOURCE  BOOT BACK", COLOR_LIGHTGRAY, 1);
#else
        drawPet2001TextCentredTransparent(frame, 160, 142, "BOOT BACK", COLOR_LIGHTGRAY, 1);
#endif
        return;
    }
#if TF_CARD_ENABLED
    drawPet2001TextTransparent(frame, 4, 158, source == SLIDESHOW_SPIFFS ? "SPIFFS  C: SD" : "SD  C: SPIFFS", COLOR_WHITE, 1);
#else
    drawPet2001TextTransparent(frame, 4, 158, "SPIFFS", COLOR_WHITE, 1);
#endif
}