Slideshow
Source: src/slideshow.c · 148 lines · 10 functions.
Screen captures
Views of this part running on the Mini Arcade.

Screen / module overview
- Enter slideshow
Scan supported image names, sort the list and randomly choose the first slide.
- Any images available?
If none, display NO IMAGE FILES and the directory. Otherwise request decoding.
- Advance the slide
Manual next or the two-second timer selects the next slide and marks decoding pending.
- Decode pending image
Build its path and call imageDecodeFile() into the shared framebuffer. A failure enters IMAGE FAILED status.
- 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)
- Preprocessor directive
#if TF_CARD_ENABLED - Exit this function
return source == SLIDESHOW_SPIFFS ? SPIFFS_SLIDESHOW_DIRECTORY : SD_SLIDESHOW_DIRECTORY; - Preprocessor directive
#else - Exit this function
return SPIFFS_SLIDESHOW_DIRECTORY; - 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)
- FOR loop
unsigned i = 0; i < slide_count; ++iRepeat body while the loop condition permits; then continue below.
- FOR loop
unsigned j = i + 1U; j < slide_count; ++jRepeat body while the loop condition permits; then continue below.
- Decision
strcmp(filenames[i], filenames[j]) <= 0True- Next loop iteration
continue;
FalseContinue after this decision.
- Execute
char swap[MAX_FILENAME]; - Execute
memcpy(swap, filenames[i], sizeof(swap)); - Execute
memcpy(filenames[i], filenames[j], sizeof(swap)); - Execute
memcpy(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:
- Execute
slide_count = 0; - Execute
DIR *directory = opendir(slideshowDirectory()); - Decision
directory == NULLTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
struct dirent *entry; - WHILE loop
(entry = readdir(directory)) != NULL && slide_count < MAX_SLIDESRepeat body while the loop condition permits; then continue below.
- Decision
!imageIsSupportedName(entry->d_name)True- Next loop iteration
continue;
FalseContinue after this decision.
- Execute
const size_t length = strlen(entry->d_name); - Decision
length >= MAX_FILENAMETrue- Next loop iteration
continue;
FalseContinue after this decision.
- Execute
memcpy(filenames[slide_count], entry->d_name, length + 1U); - Execute
++slide_count;
- Execute
closedir(directory); - Execute
sortSlides(); - Exit this function
return 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:
- Execute
char path[sizeof(SPIFFS_SLIDESHOW_DIRECTORY) + MAX_FILENAME + 1U]; - Execute
const int written = snprintf(path, sizeof(path), "%s/%s", slideshowDirectory(), filenames[current_slide]); - Decision
written < 0 || (size_t)written >= sizeof(path)True- Exit this function
return false;
FalseContinue after this decision.
- Exit this function
return 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:
- Execute
status = loadSlideList() ? SLIDES_OK : SLIDES_NO_FILES; - Execute
current_slide = slide_count > 1U ? esp_random() % slide_count : 0U; - Execute
decode_pending = status == SLIDES_OK; - Execute
next_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:
- Execute
running = true; - Preprocessor directive
#if TF_CARD_ENABLED - Execute
source = SLIDESHOW_SPIFFS; - Preprocessor directive
#endif - Execute
loadCurrentSource(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)
- Execute
running = false; - Execute
decode_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:
- Decision
!runningTrue- Exit this function
return;
FalseContinue after this decision.
- Preprocessor directive
#if TF_CARD_ENABLED - Decision
toggle_sourceTrue- Execute
source = source == SLIDESHOW_SPIFFS ? SLIDESHOW_SD : SLIDESHOW_SPIFFS; - Execute
loadCurrentSource(now_ms); - Exit this function
return;
FalseContinue after this decision.
- Preprocessor directive
#else - Execute
(void)toggle_source; - Preprocessor directive
#endif - Decision
status != SLIDES_OK || !nextTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
current_slide = (current_slide + 1U) % slide_count; - Execute
decode_pending = true; - Execute
next_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:
- Decision
!running || status != SLIDES_OK || frame == NULLTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
now_ms >= next_slide_atTrue- Decision
!decode_pendingTrue- Execute
current_slide = (current_slide + 1U) % slide_count;
FalseContinue after this decision.
- Execute
decode_pending = true; - Execute
next_slide_at = now_ms + SLIDE_DELAY_MS;
FalseContinue after this decision.
- Decision
!decode_pendingTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
status = decodeSlide(frame) ? SLIDES_OK : SLIDES_BAD_IMAGE; - Execute
decode_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:
- Decision
!running || frame == NULLTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
status != SLIDES_OKTrue- Execute
clear(frame, COLOR_BLACK); - Execute
draw_text_centred(frame, 160, 62, status == SLIDES_NO_FILES ? "NO IMAGE FILES" : "IMAGE FAILED", 2, COLOR_RED); - Execute
draw_text_centred(frame, 160, 91, slideshowDirectory(), 1, COLOR_WHITE); - Preprocessor directive
#if TF_CARD_ENABLED - Execute
draw_text_centred(frame, 160, 142, "C SOURCE BOOT BACK", 1, COLOR_LIGHTGRAY); - Preprocessor directive
#else - Execute
draw_text_centred(frame, 160, 142, "BOOT BACK", 1, COLOR_LIGHTGRAY); - Preprocessor directive
#endif - Exit this function
return;
FalseContinue after this decision.
- Preprocessor directive
#if TF_CARD_ENABLED - Execute
draw_text(frame, 4, 158, source == SLIDESHOW_SPIFFS ? "SPIFFS C: SD" : "SD C: SPIFFS", 1, COLOR_WHITE); - Preprocessor directive
#else - Execute
draw_text(frame, 4, 158, "SPIFFS", 1, COLOR_WHITE); - 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
}