Microscope camera kiosk
Touchscreen kiosk for the Raspberry Pi HQ camera (IMX477) used as a microscope: live preview from boot, raw frame recording, full-resolution stills, and automatic capture-SSD mounting. - app.py: GTK3 fullscreen UI over cage — preview, REC/STOP, PHOTO, 90-degree rotate button, tap-to-open exposure/gain/settings sliders, and an "SSD NOT MOUNTED" badge - camera.py: picamera2 wrapper with separate video (ISP preview + packed 12-bit raw) and still (4056x3040) configurations - recorder.py: writer thread turning the raw stream into one Bayer frame per file plus index.jsonl/session.json, with dropped/missed accounting - photos.py: still capture to DNG + JPEG, and a background worker that renders a viewable 16-bit sRGB TIFF from the 12-bit Bayer frame - storage.py: SSD mount state and the date/time/format session layout - tools/unpack_raw.py: desktop-side unpacker/demosaicer - system/ + install.sh: systemd units, udev rule, mount helper, sudoers Note: raw frames are written byte-for-byte as the sensor produced them, so they stay decodeable regardless of how the stills pipeline evolves.
This commit is contained in:
96
system/microscope-ssd
Executable file
96
system/microscope-ssd
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
# Manage the microscope capture SSD mount.
|
||||
#
|
||||
# microscope-ssd mount mount the SSD (waits briefly for it to appear)
|
||||
# microscope-ssd umount flush and unmount safely
|
||||
# microscope-ssd status print: mounted | stale | unmounted | absent
|
||||
#
|
||||
# Called by the udev-triggered microscope-ssd-mount.service when the drive is
|
||||
# plugged in, by fstab at boot, and by the kiosk UI (through a NOPASSWD sudoers
|
||||
# entry) when the operator taps MOUNT SSD.
|
||||
#
|
||||
# stdout stays machine-readable (status) while everything also lands in a log
|
||||
# file, because udev and systemd capture stdout in ways that are awkward to read.
|
||||
set -u
|
||||
|
||||
MOUNT_POINT="${MICROSCOPE_MOUNT:-/mnt/microscope}"
|
||||
UUID="${MICROSCOPE_UUID:-caf4320b-0fa3-4674-bfa9-f17f6165f681}"
|
||||
OWNER="${MICROSCOPE_OWNER:-tyler:tyler}"
|
||||
DEV="/dev/disk/by-uuid/${UUID}"
|
||||
LOG_FILE="${MICROSCOPE_LOG:-/run/microscope-ssd.log}"
|
||||
|
||||
log() {
|
||||
local message="microscope-ssd: $*"
|
||||
echo "$message" >>"$LOG_FILE" 2>/dev/null || true
|
||||
echo "$message"
|
||||
}
|
||||
|
||||
in_mounts() { grep -qs " ${MOUNT_POINT} " /proc/self/mounts; }
|
||||
|
||||
do_status() {
|
||||
# 'stale' means a mount entry survived a yank: the device node is gone.
|
||||
if in_mounts; then
|
||||
if [ -e "$DEV" ]; then echo mounted; else echo stale; fi
|
||||
elif [ -e "$DEV" ]; then
|
||||
echo unmounted
|
||||
else
|
||||
echo absent
|
||||
fi
|
||||
}
|
||||
|
||||
do_mount() {
|
||||
mkdir -p "$MOUNT_POINT"
|
||||
|
||||
if in_mounts; then
|
||||
if [ -e "$DEV" ]; then
|
||||
log "already mounted"
|
||||
return 0
|
||||
fi
|
||||
log "clearing stale mount entry"
|
||||
umount -l "$MOUNT_POINT" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
for _ in $(seq 1 40); do
|
||||
[ -e "$DEV" ] && break
|
||||
sleep 0.25
|
||||
done
|
||||
if [ ! -e "$DEV" ]; then
|
||||
log "SSD not present ($DEV)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if mount -t ext4 -o noatime,errors=remount-ro "$DEV" "$MOUNT_POINT"; then
|
||||
chown "$OWNER" "$MOUNT_POINT" 2>/dev/null || true
|
||||
chmod 755 "$MOUNT_POINT" 2>/dev/null || true
|
||||
log "mounted $DEV at $MOUNT_POINT"
|
||||
return 0
|
||||
fi
|
||||
log "mount failed"
|
||||
return 1
|
||||
}
|
||||
|
||||
do_umount() {
|
||||
if ! in_mounts; then
|
||||
log "not mounted"
|
||||
return 0
|
||||
fi
|
||||
sync
|
||||
if umount "$MOUNT_POINT"; then
|
||||
log "unmounted (safe to unplug)"
|
||||
return 0
|
||||
fi
|
||||
log "unmount failed - something is still using $MOUNT_POINT"
|
||||
return 1
|
||||
}
|
||||
|
||||
ACTION="${1:-status}"
|
||||
case "$ACTION" in
|
||||
mount|umount) log "--- $(date -Is) action=$ACTION euid=$(id -u) ---" ;;
|
||||
esac
|
||||
|
||||
case "$ACTION" in
|
||||
mount) do_mount ;;
|
||||
umount) do_umount ;;
|
||||
status) do_status ;;
|
||||
*) echo "usage: $0 {mount|umount|status}" >&2; exit 2 ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user