Screenshot

Source: src/screenshot.c · 112 lines · 4 functions.

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

encodeScreenshotBase64() · source line 32
static size_t encodeScreenshotBase64(const uint8_t *input, size_t input_size, char *output)
  1. Executesize_t input_index = 0U;
  2. Executesize_t output_index = 0U;
  3. WHILE loopinput_index < input_size

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

      1. Executeconst size_t remaining = input_size - input_index;
      2. Executeconst uint32_t block = (uint32_t)input[input_index] << 16U | (remaining > 1U ? (uint32_t)input[input_index + 1U] << 8U : 0U) | (remaining > 2U ? input[input_index + 2U] : 0U);
      3. Executeoutput[output_index++] = screenshot_base64_alphabet[(block >> 18U) & 0x3fU];
      4. Executeoutput[output_index++] = screenshot_base64_alphabet[(block >> 12U) & 0x3fU];
      5. Executeoutput[output_index++] = remaining > 1U ? screenshot_base64_alphabet[(block >> 6U) & 0x3fU] : '=';
      6. Executeoutput[output_index++] = remaining > 2U ? screenshot_base64_alphabet[block & 0x3fU] : '=';
      7. Executeinput_index += remaining >= 3U ? 3U : remaining;
  4. Exit this functionreturn output_index;
Read original function source
static size_t encodeScreenshotBase64(const uint8_t *input, size_t input_size, char *output)
{
    size_t input_index = 0U;
    size_t output_index = 0U;
    while (input_index < input_size) {
        const size_t remaining = input_size - input_index;
        const uint32_t block = (uint32_t)input[input_index] << 16U |
            (remaining > 1U ? (uint32_t)input[input_index + 1U] << 8U : 0U) |
            (remaining > 2U ? input[input_index + 2U] : 0U);
        output[output_index++] = screenshot_base64_alphabet[(block >> 18U) & 0x3fU];
        output[output_index++] = screenshot_base64_alphabet[(block >> 12U) & 0x3fU];
        output[output_index++] = remaining > 1U ?
            screenshot_base64_alphabet[(block >> 6U) & 0x3fU] : '=';
        output[output_index++] = remaining > 2U ? screenshot_base64_alphabet[block & 0x3fU] : '=';
        input_index += remaining >= 3U ? 3U : remaining;
    }
    return output_index;
}
sendScreenshotBase64() · source line 51
static bool sendScreenshotBase64(const uint8_t *pixels)

Calls into this documentation:

  1. FOR loopsize_t offset = 0U; offset < SCREENSHOT_RGB565_BYTES; offset += SCREENSHOT_BASE64_INPUT_BYTES

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

      1. Executeconst size_t remaining = SCREENSHOT_RGB565_BYTES - offset;
      2. Executeconst size_t input_size = remaining < SCREENSHOT_BASE64_INPUT_BYTES ? remaining : SCREENSHOT_BASE64_INPUT_BYTES;
      3. Executechar line[sizeof(screenshot_data_prefix) + SCREENSHOT_BASE64_OUTPUT_BYTES + 1U];
      4. Executeconst size_t prefix_size = sizeof(screenshot_data_prefix) - 1U;
      5. Executememcpy(line, screenshot_data_prefix, prefix_size);
      6. Executeconst size_t encoded_size = encodeScreenshotBase64(pixels + offset, input_size, line + prefix_size);
      7. Executeline[prefix_size + encoded_size] = '\n';
      8. Executeconst size_t line_size = prefix_size + encoded_size + 1U;
      9. Decisionfwrite(line, 1U, line_size, stdout) != line_size
        True
        1. Exit this functionreturn false;
        False

        Continue after this decision.

  2. Exit this functionreturn fflush(stdout) == 0;
Read original function source
static bool sendScreenshotBase64(const uint8_t *pixels)
{
    for (size_t offset = 0U; offset < SCREENSHOT_RGB565_BYTES;
         offset += SCREENSHOT_BASE64_INPUT_BYTES) {
        const size_t remaining = SCREENSHOT_RGB565_BYTES - offset;
        const size_t input_size = remaining < SCREENSHOT_BASE64_INPUT_BYTES ?
            remaining : SCREENSHOT_BASE64_INPUT_BYTES;
        char line[sizeof(screenshot_data_prefix) + SCREENSHOT_BASE64_OUTPUT_BYTES + 1U];
        const size_t prefix_size = sizeof(screenshot_data_prefix) - 1U;
        memcpy(line, screenshot_data_prefix, prefix_size);
        const size_t encoded_size = encodeScreenshotBase64(pixels + offset, input_size,
                                                            line + prefix_size);
        line[prefix_size + encoded_size] = '\n';
        const size_t line_size = prefix_size + encoded_size + 1U;
        if (fwrite(line, 1U, line_size, stdout) != line_size) return false;
    }
    return fflush(stdout) == 0;
}
screenshotRequest() · source line 70
void screenshotRequest(const char *source_label)
  1. Decisionsource_label == NULL || source_label[0] == '\0'
    True
    1. Executesource_label = "unknown";
    False

    Continue after this decision.

  2. Executeconst size_t label_length = strnlen(source_label, sizeof(screenshot_source_label) - 1U);
  3. Executememcpy(screenshot_source_label, source_label, label_length);
  4. Executescreenshot_source_label[label_length] = '\0';
  5. Executescreenshot_requested = true;
Read original function source
void screenshotRequest(const char *source_label)
{
    if (source_label == NULL || source_label[0] == '\0') source_label = "unknown";
    const size_t label_length = strnlen(source_label, sizeof(screenshot_source_label) - 1U);
    memcpy(screenshot_source_label, source_label, label_length);
    screenshot_source_label[label_length] = '\0';
    screenshot_requested = true;
}
screenshotCapturePresentation() · source line 79
void screenshotCapturePresentation(const uint16_t *presentation_frame)

Calls into this documentation:

  1. Decisionscreenshot_notice_visible && (xTaskGetTickCount() - screenshot_notice_started_at) >= pdMS_TO_TICKS(SCREENSHOT_NOTICE_MS)
    True
      1. ExecuteglobalOverlayClearItem(SCREENSHOT_NOTICE_OVERLAY_ITEM);
      2. Executescreenshot_notice_visible = false;
    False

    Continue after this decision.

  2. Decision!screenshot_requested || presentation_frame == NULL
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  3. Executescreenshot_requested = false;
  4. Executechar header[SCREENSHOT_SOURCE_LABEL_LENGTH + 48U];
  5. Executeconst int header_length = snprintf(header, sizeof(header), "\nMINI_ARCADE_SCREENSHOT BASE64RGB565LE 320 170 %s\n", screenshot_source_label);
  6. Executeconst bool header_valid = header_length > 0 && (size_t)header_length < sizeof(header);
  7. Executeconst bool sent = header_valid && fwrite(header, 1U, (size_t)header_length, stdout) == (size_t)header_length && sendScreenshotBase64((const uint8_t *)presentation_frame) && fputs("MINI_ARCADE_SCREENSHOT END\n", stdout) >= 0 && fflush(stdout) == 0;
  8. Decision!sent
    True
      1. ExecuteESP_LOGE(TAG, "Screenshot USB write incomplete");
      2. Exit this functionreturn;
    False

    Continue after this decision.

  9. ExecuteESP_LOGI(TAG, "Screenshot sent: %u RGB565 bytes", (unsigned)SCREENSHOT_RGB565_BYTES);
  10. Execute(void)globalOverlaySetItem(SCREENSHOT_NOTICE_OVERLAY_ITEM, "SCREENSHOT SENT", 40, 76, 2, C64_COLOR_LIGHT_GREEN);
  11. Executescreenshot_notice_started_at = xTaskGetTickCount();
  12. Executescreenshot_notice_visible = true;
Read original function source
void screenshotCapturePresentation(const uint16_t *presentation_frame)
{
    if (screenshot_notice_visible &&
        (xTaskGetTickCount() - screenshot_notice_started_at) >=
            pdMS_TO_TICKS(SCREENSHOT_NOTICE_MS)) {
        globalOverlayClearItem(SCREENSHOT_NOTICE_OVERLAY_ITEM);
        screenshot_notice_visible = false;
    }

    if (!screenshot_requested || presentation_frame == NULL) return;
    screenshot_requested = false;

    // Text-only Base64 lines keep arbitrary RGB565 byte values separate from console logging.
    char header[SCREENSHOT_SOURCE_LABEL_LENGTH + 48U];
    const int header_length = snprintf(header, sizeof(header),
                                       "\nMINI_ARCADE_SCREENSHOT BASE64RGB565LE 320 170 %s\n",
                                       screenshot_source_label);
    const bool header_valid = header_length > 0 && (size_t)header_length < sizeof(header);
    const bool sent = header_valid && fwrite(header, 1U, (size_t)header_length, stdout) ==
        (size_t)header_length &&
        sendScreenshotBase64((const uint8_t *)presentation_frame) &&
        fputs("MINI_ARCADE_SCREENSHOT END\n", stdout) >= 0 && fflush(stdout) == 0;
    if (!sent) {
        ESP_LOGE(TAG, "Screenshot USB write incomplete");
        return;
    }
    ESP_LOGI(TAG, "Screenshot sent: %u RGB565 bytes", (unsigned)SCREENSHOT_RGB565_BYTES);

    // Set this after the bytes are sent, so the saved image remains an exact screen capture.
    (void)globalOverlaySetItem(SCREENSHOT_NOTICE_OVERLAY_ITEM, "SCREENSHOT SENT", 40, 76, 2,
                               C64_COLOR_LIGHT_GREEN);
    screenshot_notice_started_at = xTaskGetTickCount();
    screenshot_notice_visible = true;
}
Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "screenshot.h"

#include "c64_colors.h"
#include "esp_log.h"
#include "global_overlay.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include <stdio.h>
#include <string.h>

#define SCREENSHOT_WIDTH 320U
#define SCREENSHOT_HEIGHT 170U
#define SCREENSHOT_RGB565_BYTES (SCREENSHOT_WIDTH * SCREENSHOT_HEIGHT * sizeof(uint16_t))
#define SCREENSHOT_BASE64_INPUT_BYTES 192U
#define SCREENSHOT_BASE64_OUTPUT_BYTES \
    (((SCREENSHOT_BASE64_INPUT_BYTES + 2U) / 3U) * 4U)
#define SCREENSHOT_SOURCE_LABEL_LENGTH 48U
#define SCREENSHOT_NOTICE_MS 1000U
#define SCREENSHOT_NOTICE_OVERLAY_ITEM 1U

static const char *const TAG = "screenshot";
static const char screenshot_base64_alphabet[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char screenshot_data_prefix[] = "MINI_ARCADE_SCREENSHOT DATA ";
static bool screenshot_requested;
static char screenshot_source_label[SCREENSHOT_SOURCE_LABEL_LENGTH] = "unknown";
static bool screenshot_notice_visible;
static TickType_t screenshot_notice_started_at;

static size_t encodeScreenshotBase64(const uint8_t *input, size_t input_size, char *output)
{
    size_t input_index = 0U;
    size_t output_index = 0U;
    while (input_index < input_size) {
        const size_t remaining = input_size - input_index;
        const uint32_t block = (uint32_t)input[input_index] << 16U |
            (remaining > 1U ? (uint32_t)input[input_index + 1U] << 8U : 0U) |
            (remaining > 2U ? input[input_index + 2U] : 0U);
        output[output_index++] = screenshot_base64_alphabet[(block >> 18U) & 0x3fU];
        output[output_index++] = screenshot_base64_alphabet[(block >> 12U) & 0x3fU];
        output[output_index++] = remaining > 1U ?
            screenshot_base64_alphabet[(block >> 6U) & 0x3fU] : '=';
        output[output_index++] = remaining > 2U ? screenshot_base64_alphabet[block & 0x3fU] : '=';
        input_index += remaining >= 3U ? 3U : remaining;
    }
    return output_index;
}

static bool sendScreenshotBase64(const uint8_t *pixels)
{
    for (size_t offset = 0U; offset < SCREENSHOT_RGB565_BYTES;
         offset += SCREENSHOT_BASE64_INPUT_BYTES) {
        const size_t remaining = SCREENSHOT_RGB565_BYTES - offset;
        const size_t input_size = remaining < SCREENSHOT_BASE64_INPUT_BYTES ?
            remaining : SCREENSHOT_BASE64_INPUT_BYTES;
        char line[sizeof(screenshot_data_prefix) + SCREENSHOT_BASE64_OUTPUT_BYTES + 1U];
        const size_t prefix_size = sizeof(screenshot_data_prefix) - 1U;
        memcpy(line, screenshot_data_prefix, prefix_size);
        const size_t encoded_size = encodeScreenshotBase64(pixels + offset, input_size,
                                                            line + prefix_size);
        line[prefix_size + encoded_size] = '\n';
        const size_t line_size = prefix_size + encoded_size + 1U;
        if (fwrite(line, 1U, line_size, stdout) != line_size) return false;
    }
    return fflush(stdout) == 0;
}

void screenshotRequest(const char *source_label)
{
    if (source_label == NULL || source_label[0] == '\0') source_label = "unknown";
    const size_t label_length = strnlen(source_label, sizeof(screenshot_source_label) - 1U);
    memcpy(screenshot_source_label, source_label, label_length);
    screenshot_source_label[label_length] = '\0';
    screenshot_requested = true;
}

void screenshotCapturePresentation(const uint16_t *presentation_frame)
{
    if (screenshot_notice_visible &&
        (xTaskGetTickCount() - screenshot_notice_started_at) >=
            pdMS_TO_TICKS(SCREENSHOT_NOTICE_MS)) {
        globalOverlayClearItem(SCREENSHOT_NOTICE_OVERLAY_ITEM);
        screenshot_notice_visible = false;
    }

    if (!screenshot_requested || presentation_frame == NULL) return;
    screenshot_requested = false;

    // Text-only Base64 lines keep arbitrary RGB565 byte values separate from console logging.
    char header[SCREENSHOT_SOURCE_LABEL_LENGTH + 48U];
    const int header_length = snprintf(header, sizeof(header),
                                       "\nMINI_ARCADE_SCREENSHOT BASE64RGB565LE 320 170 %s\n",
                                       screenshot_source_label);
    const bool header_valid = header_length > 0 && (size_t)header_length < sizeof(header);
    const bool sent = header_valid && fwrite(header, 1U, (size_t)header_length, stdout) ==
        (size_t)header_length &&
        sendScreenshotBase64((const uint8_t *)presentation_frame) &&
        fputs("MINI_ARCADE_SCREENSHOT END\n", stdout) >= 0 && fflush(stdout) == 0;
    if (!sent) {
        ESP_LOGE(TAG, "Screenshot USB write incomplete");
        return;
    }
    ESP_LOGI(TAG, "Screenshot sent: %u RGB565 bytes", (unsigned)SCREENSHOT_RGB565_BYTES);

    // Set this after the bytes are sent, so the saved image remains an exact screen capture.
    (void)globalOverlaySetItem(SCREENSHOT_NOTICE_OVERLAY_ITEM, "SCREENSHOT SENT", 40, 76, 2,
                               C64_COLOR_LIGHT_GREEN);
    screenshot_notice_started_at = xTaskGetTickCount();
    screenshot_notice_visible = true;
}