#!/bin/sh
# retroDE_ps2 OSD path validation — Ch232 hardware bring-up helper.
#
# Writes a 9-character white-on-blue test message ("01234 ABC") into
# the Ch227/Ch229/Ch231 OSD tile RAM at cells (0,0)..(8,0), then
# asserts OSD_CTRL[0]=1 to enable the overlay. Use it to confirm the
# full HPS-to-video OSD path is alive on the DE25-Nano.
#
# The chars 0-9 + space + A,B,C are the glyphs currently populated in
# `osd_overlay_stub.font_rom`. Other ASCII codes will render as solid
# background blocks (correct "missing glyph" fallback) — see the Ch231
# section of the bring-up runbook.
#
# Usage:
#   ./ps2_osd_test.sh           # write message + enable overlay
#   ./ps2_osd_test.sh --off     # disable overlay (OSD_CTRL[0]=0)
#   ./ps2_osd_test.sh --clear   # zero the 9 cells + leave overlay enabled
#   ./ps2_osd_test.sh --status  # dump OSD_CTRL / tile RAM cells for inspection
#
# Uses `busybox devmem` (matching ps2_status.sh) — sidesteps the
# devmem2 0x?4-offset quirk and reads/writes a single 32-bit word per
# call.

set -u

BASE="${PS2_BRIDGE_BASE:-0x40000000}"
DEVMEM="${DEVMEM:-busybox devmem}"
MODE="${1:-write}"

# Bridge offsets.
OFF_OSD_CTRL=0x100
OFF_TILE_BASE=0x1000

# Compute an absolute address for a relative byte offset.
addr() {
    printf "0x%08x" $(( BASE + $1 ))
}

write32() {
    # $1 = relative offset, $2 = 32-bit value (hex)
    $DEVMEM "$(addr $1)" w "$2"
}

read32() {
    # $1 = relative offset; prints "0x%08x"
    $DEVMEM "$(addr $1)" w
}

# Cell encoder: 16-bit value = {bg[3:0], fg[3:0], char[7:0]}.
# Default fg=15 (white), bg=1 (blue) for the test message.
cell_val() {
    # $1 = char code (decimal), $2 = fg (0..15), $3 = bg (0..15)
    printf "0x%04x" $(( ($3 << 12) | ($2 << 8) | $1 ))
}

# Pack two 16-bit cells into a 32-bit word.
#   word = {high_cell, low_cell} = (high << 16) | low
# Software writes WORDS to the bridge; each word stores cells
# (col=N, row) in the low half and (col=N+1, row) in the high half
# at byte offset (row * 128 + (N & ~1) * 2).
pack_word() {
    # $1 = low 16-bit cell value, $2 = high 16-bit cell value
    printf "0x%08x" $(( ($2 << 16) | $1 ))
}

# Write a cell at (col, row). Performs a read-modify-write of the
# underlying 32-bit word so the neighboring cell in the same word
# is preserved.
write_cell() {
    # $1 = col, $2 = row, $3 = 16-bit cell value
    local col=$1 row=$2 val=$3
    local word_byte_off=$(( OFF_TILE_BASE + row * 128 + (col / 2) * 4 ))
    local current_word=$($DEVMEM "$(addr $word_byte_off)" w)
    # Strip the leading 0x for arithmetic.
    local cur=$(( current_word ))
    local new
    if [ $(( col % 2 )) -eq 0 ]; then
        # Low half — preserve high half.
        new=$(( (cur & 0xFFFF0000) | (val & 0xFFFF) ))
    else
        # High half — preserve low half.
        new=$(( (cur & 0x0000FFFF) | ((val & 0xFFFF) << 16) ))
    fi
    $DEVMEM "$(addr $word_byte_off)" w "$(printf '0x%08x' $new)"
}

# Char codes for our test message "01234 ABC".
MSG_CHARS="48 49 50 51 52 32 65 66 67"   # '0'..'4' ' ' 'A' 'B' 'C'
FG=15   # white
BG=1    # blue

write_message() {
    local col=0
    for code in $MSG_CHARS; do
        local val=$(cell_val "$code" $FG $BG)
        write_cell "$col" 0 "$val"
        col=$(( col + 1 ))
    done
}

clear_message() {
    local col=0
    for code in $MSG_CHARS; do
        write_cell "$col" 0 0x0000
        col=$(( col + 1 ))
    done
}

set_osd_enable() {
    # $1 = 0 or 1
    write32 $OFF_OSD_CTRL "0x0000000$1"
}

dump_status() {
    printf "OSD_CTRL    @ 0x%03x : %s\n" $OFF_OSD_CTRL "$(read32 $OFF_OSD_CTRL)"
    printf "Tile cells (col, row=0) words:\n"
    local off=0
    while [ $off -lt 20 ]; do
        local byte_off=$(( OFF_TILE_BASE + off * 4 ))
        printf "  word @ 0x%04x : %s   (cells %d, %d)\n" \
               "$byte_off" "$(read32 $byte_off)" $(( off * 2 )) $(( off * 2 + 1 ))
        off=$(( off + 1 ))
    done
}

case "$MODE" in
    --off)
        set_osd_enable 0
        echo "OSD disabled."
        ;;
    --clear)
        clear_message
        set_osd_enable 1
        echo "Cleared 9 cells, overlay still enabled."
        ;;
    --status)
        dump_status
        ;;
    *)
        write_message
        set_osd_enable 1
        echo 'Wrote "01234 ABC" at cells (0..8, 0), white on blue.'
        echo "Overlay enabled (OSD_CTRL[0]=1)."
        echo "The text should appear in the top-left of the HDMI image,"
        echo "overlaying the Ch171 quadrant test card."
        ;;
esac
