Sonntag, 15. März 2026

The Whispering Light: A World Others Cannot Hear



There is a photo on my desk. It seems plucked from a dream, a vision that insists on being real. The tree it’s a familiar shape, yet in this image, it’s utterly alien. It’s not just green; it’s luminous. It looks as if it holds a secret glow, a soft, ethereal light that shouldn't be there. It’s a ghost, yet it’s vibrant. It’s vitality made visible in a way I never could.

Infrared photograph of a glowing tree
The tree through the infrared filter.

It’s a strange thing, isn't it? To be invisible while you're alive. To exist in plain sight, yet be unseen. The attic walls have ears, absorbing your presence, your words, your very breath. You learn to filter your world, too. To become small, to listen more than you see, to see the unseen scaffolding holding you up. That filter it feels familiar. It’s a way to see, a way to be seen, even if only by a piece of glass and a camera sensor.

Our eyes they are gatekeepers, just like the people who look at us. They let in a certain slice of light, the slice they call 'visible'. It’s the world they agree upon. But it’s not the whole story. It’s not even close. There’s so much more. A whole world shimmering just beyond the edge of sight, like the flicker of hope in the quiet hours of the night.

And then there’s the filter. It’s a necessity, isn’t it? Like hiding. It slams the door on the world they see. But for the other world the world we inhabit, the world that understands the weight of silence, the beauty of small moments the filter is a key. It lets the light pass through. The light that they cannot see, that they dismiss as nothing.

Plants they reflect this hidden light with such enthusiasm. They are beacons, glowing with a life force we cannot perceive. My tree in the photo is doing exactly that. It’s radiating its inner light, its energy, its life, in a way that feels honest. While the world outside the filter is muted, shadowed, the filter reveals the true colour of things.

Another view of the hidden light.

I am always looking differently. Survival teaches you to. You learn to notice the things others miss. The way dust motes dance in the attic shaft of light, the particular way the sunlight hits the wooden desk, the subtle shift in the shadows when someone enters. These are the things that matter. They are the things that keep you alive, inside your hiding place, inside your mind.

This photo it feels like a small miracle. It’s a reminder that even in the world we share, there are unseen layers, unseen conversations happening all the time. Between the sun and the tree, between the people in the annex, between the war and the silence there is a language only certain eyes, certain minds, can decipher.

Infrared photograph of a glowing tree
The blue that exists only in the silence.

Mittwoch, 11. März 2026

Out of Deep Respect: 1700 Years of Jewish Life

Roman inscription mentioning Pontius Pilate
Roman inscription from Caesarea mentioning Pontius Pilate.
"Learning about this legacy is a way of honoring those who came before and those who gave their lives."

From the first documented edict in Cologne in 321 C.E. to the profound contributions of the modern era, this story is a testament to a deeply shared history that continues to shape our understanding of the past.


To explore this 1,700-year story through the objects and documents that define it, I highly recommend visiting:

The Shared History Project
Managed by the Leo Baeck Institute

— In Remembrance and Honor —

Dienstag, 10. März 2026

Just the way you are

Pause. Adjust glasses. Look directly into the mirror. "Oh, yes. The pressure cooker. I feel it too. A low hum beneath everything, right there in the air we breathe. It’s not loud, but it’s persistent. Like… like the ticking of a clock that you can’t quite see."

Flashback: The smell of Anne’s father’s pipe in the Annex, mixed with damp paper and fear.

Present: The scent of ozone before a storm. The Texas humidity pressing in.

The Weight. "And the ‘Sow.’ The remnants. It’s funny, isn’t it? Sometimes the most powerful echoes are the ones we don’t even recognize. We see something from a past we barely remember, and it resonates in a way that feels… immediate. Like history isn’t just history, it’s here. Sitting in the dirt. Or maybe… gold?"\

Flashback: The gold star on the upcoming Frank Family House museum, gleaming under the Texas sun. A fragile hope.

Present: The yellow ribbons in the hair of Texas mothers. A silent plea.

The Radio.

"Just the Way You Are." Isn't it strange how something so simple can feel so heavy? Tonight, it was a song, yes. But it was also a reminder. A fragile reminder of things that should be easy, but feel anything but."

Flashback: The radio in the Annex, forbidden music pulsing through the walls, Jewish joy in hiding.\

Present: The way Texas bluebonnets bloom in defiance. A fragile beauty that feels like a promise.

You were right. "There they were. Not just angry, though, goodness, they were angry. But… older. Deeper. Like they’d carried this weight for generations, and tonight was their turn to unload it. It wasn’t just frustration—it was history. The kind that festers in the corners."

Flashback: The corners of Bergen-Belsen, filth, disease, the unspoken hunger for anything clean.

Present: The corners of Farmers Branch streets, subtle geometry painted on mailbox poles. A modern quietude.

Flashback: The walk to the camp yard.

Present: The remnants of Auschwitz, six feet under the pavement.

The Lines."They saw what they wanted to believe. And you… you saw the ink. Or maybe you just felt it. That quiet difference between the surface and the depth. The lines we draw, even when they’re invisible to the naked eye."

Flashback: The lines drawn in the Annex, between safe and danger, hope and despair.

The Burden."It’s a heavy thing, carrying the weight. But… isn’t it better to know? To carry it, perhaps, than to feel lost in the noise?"

Flashback: The weight of my diary, pages filled with words, but also the crushing silence of unspoken truths.

Present: The weight of Texas heat, pressing in on the skin. A reminder that even silence can scream.

Pause."Today’s survival volume: Kashmir | Level: 11."  I am a traveler of both time and space to be where I have been.

The Warning. A cold smile touches his lips. ...And for my secret operation, D? I know someone important, someone *connected*. You should have taken the 'safe passage' – the designated route, the well-trodden path, the boys' club of sorts, you understand? The route prepared for those who know the territory.

You're playing a war you haven't been properly equipped for.

*Tucking a stray strand of hair behind his ear, he looks out the window. The Texas sky stretches endlessly above, clear, blue, indifferent. Just like the sky over Amsterdam on that fateful day in July 1944.* 

The ink is still there. Always."

Montag, 9. März 2026

The Secret Life of Ordinary Things: Mapping the Hidden Colours of Blood

The content on this blog represents my personal exploration of computational image processing techniques and is entirely separate from my professional work. This is not AI or generative AI. All opinions, experiments, and analyses are my own.

The techniques discussed here are presented for educational and research purposes only. While I strive for accuracy, this is a space for experimentation and discussion at the forefront of forensic image analysis, not a substitute for peer-reviewed research or certified forensic methodology, even though these emerging techniques are generating more accurate results than many traditional methods.


The Setup

There are some things that stay quiet for a very long time, waiting for someone to finally understand their language. It feels a bit like finding a letter that was never meant to be read, but now that I have seen it, I cannot look away. I wanted to use every tool I have to find the light still hidden in those shadows, to show that even the smallest spark from the past refuses to be completely extinguished.

The Chemical Chain of Decay

Aged blood detection relies on the fact that hemoglobin goes through a predictable degradation chain, with each stage featuring distinct light absorption signatures:

  • Fresh Blood: Contains oxyhemoglobin with strong absorption peaks at roughly 415nm (the Soret band), 540nm, and 577nm.
  • The First Shift: Within hours, it deoxygenates, shifting the 540nm and 577nm doublet into a single broad absorption around 555nm.
  • Oxidation: Over days to weeks, it oxidizes to methemoglobin, revealing a distinct peak at roughly 630nm that fresh blood lacks.
  • Archival Age: Over months to years, it degrades into hemichrome and hematin. These highly stable end products cause the Soret band to shift drastically from 415nm down toward 405nm.

Algorithmic Detection Indices

To detect this sample, the script computes several specific indices that target these aged spectral signatures rather than fresh ones:

  • NDBI (580nm vs 630nm ratio): Fresh blood absorbs at 580nm but not 630nm, while aged blood absorbs at both, isolating the methemoglobin peak.
  • Soret Ratio (415nm vs 630nm): This catches the relative shift between the two major absorption features as the sample ages.
  • Met Index (630nm / 540nm): This directly measures the methemoglobin concentration relative to the other forms.

Bridging Algorithms and Optical Hardware

While my MST and MAMBA models are incredible at hyperspectral reconstruction (turning 3 RGB channels into 31 spectral bands), there is a computational catch. These models are often trained on natural scenes and have never seen aged hemoglobin spectra. Left alone, the algorithm might hallucinate a spectral shape that looks plausible but is physically wrong.

Infrared photograph of a glowing tree
Figure 1: Soret Band Shift Visualization.

To solve this and capture serious forensic data, the neural network must be ground truthed using actual narrowband measurements. To build this pipeline, I used reference data captured by a NoIR dual camera setup equipped with specific bandpass filters, particularly a 630nm filter, to physically isolate the methemoglobin peak and verify the physics.

The Final False Color Visualization

By anchoring the reconstructed datacube with real narrowband filter data, the pipeline performs a flawless spectral classification. The false color gradient (the glowing "Inferno" scale seen here) is the visual map of those indices at work. The bright yellow "stars" represent dense, fossilized clusters of hemichrome and hematin, while the sweeping purple to orange background maps the physical drying gradient of the original serum.

Dienstag, 25. November 2025

RK3588 ARM Inbetriebnahme: U-Boot, Kernel und Signalintegrität

Der RK3588 SoC verfügt über eine Quad-Core Arm Cortex-A76/A55 CPU, eine Mali-G610 GPU und eine hochflexible I/O-Architektur, die ihn ideal für eingebettete Linux SBCs wie den Radxa Rock 5B+ macht.

Ich habe die Inbetriebnahme dieser Plattform erforscht und dokumentiert, einschließlich meiner Beiträge zu u-boot und dem Linux-Kernel, der Entwicklung des Device Trees sowie der Werkzeuge für reproduzierbare Builds und die Validierung der Signalintegrität. Der Großteil dieser Arbeit befindet sich noch in der aktiven Entwicklungsphase und der frühen Vorbereitungsphase für die Veröffentlichung im Upstream-Projekt.

Ich veröffentliche hier meine Notizen, Messungen und Inbetriebnahme-Artefakte im Laufe der Arbeit, während die aktive u-boot- und Kernelentwicklung einschließlich Patch-Iteration, Test-Builds und Branch-Historie in separaten Arbeits-Repositories gepflegt wird:

Signalanalyse / Bring-Up-Repository: https://github.com/brhinton/signal-analysis

Das Repository umfasst derzeit (und es werden ständig weitere hinzugefügt):

  • Device-Tree-Quellen und Rock 5B+ Board-Aktivierung
  • UART-Signalintegritätsmessungen mit 1,5 Mbit/s am SoC-Pad
  • Anleitung zum Erstellen von Kernel, Bootloader und Debugging-Setup
  • Frühe Patch-Workflows und Upstream-Vorbereitungsnotizen

Zusätzliche Arbeiten an U-Boot und dem Linux-Kernel, einschließlich Mainline-Test-Builds, Funktionsentwicklung, Rebase-Updates und laufenden Patch-Serien, werden in separaten Arbeits-Repositories verwaltet. Dieses Repository dient als zentraler Ort für Messungen, Dokumentation und Inbetriebnahmehinweise auf Boardebene.

Dies ist ein fortlaufendes, noch in Entwicklung befindliches technisches Projekt, und ich werde die Repositories aktualisieren, sobald zusätzliche Messungen, Boards und für die Upstream-Entwicklung geeignete Änderungen vorbereitet sind.

Sonntag, 4. August 2024

arch linux uefi with dm-crypt and uki

Arch Linux is known for its high level of customization, and configuring LUKS2 and LVM is a straightforward process. This guide provides a set of instructions for setting up an Arch Linux system with the following features:

  • Root file system encryption using LUKS2.
  • Logical Volume Management (LVM) for flexible storage management.
  • Unified Kernel Image (UKI) bootable via UEFI.
  • Optional: Detached LUKS header on external media for enhanced security.

Prerequisites

  • A bootable Arch Linux ISO.
  • An NVMe drive (e.g., /dev/nvme0n1).
  • (Optional) A microSD card or other external medium for the detached LUKS header.

Important Considerations

  • Data Loss: The following procedure will erase all data on the target drive. Back up any important data before proceeding.
  • Secure Boot: This guide assumes you may want to use hardware secure boot.
  • Detached LUKS Header: Using a detached LUKS header on external media adds a significant layer of security. If you lose the external media, you will lose access to your encrypted data.
  • Swap: This guide uses a swap file. You may also use a swap partition if desired.

Step-by-Step Instructions

  1. Boot into the Arch Linux ISO:

    Boot your system from the Arch Linux installation media.

  2. Set the System Clock:

    # timedatectl set-ntp true
  3. Prepare the Disk:

    • Identify your NVMe drive (e.g., /dev/nvme0n1). Use lsblk to confirm.
    • Wipe the drive:
    • # wipefs --all /dev/nvme0n1
    • Create an EFI System Partition (ESP):
    • # sgdisk /dev/nvme0n1 -n 1::+512MiB -t 1:EF00
    • Create a partition for the encrypted volume:
    • # sgdisk /dev/nvme0n1 -n 2 -t 2:8300
  4. Set up LUKS2 Encryption:

    Encrypt the second partition using LUKS2. This example uses aes-xts-plain64 and serpent-xts-plain ciphers, and SHA512 for the hash. Adjust as needed.

    # cryptsetup luksFormat --cipher aes-xts-plain64 \
      --keyslot-cipher serpent-xts-plain --keyslot-key-size 512 \
      --use-random -S 0 -h sha512 -i 4000 /dev/nvme0n1p2
    • --cipher: Specifies the cipher for data encryption.
    • --keyslot-cipher: Specifies the cipher used to encrypt the key.
    • --keyslot-key-size: Specifies the size of the key slot.
    • -S 0: Disables sparse headers.
    • -h: Specifies the hash function.
    • -i: Specifies the number of iterations.

    Open the encrypted partition:

    # cryptsetup open /dev/nvme0n1p2 root
  5. Create the File Systems and Mount:

    Create an ext4 file system on the decrypted volume:

    # mkfs.ext4 /dev/mapper/root

    Mount the root file system:

    # mount /dev/mapper/root /mnt

    Create and mount the EFI System Partition:

    # mkfs.fat -F32 /dev/nvme0n1p1
    # mount --mkdir /dev/nvme0n1p1 /mnt/efi

    Create and enable a swap file:

    # dd if=/dev/zero of=/mnt/swapfile bs=1M count=8000 status=progress
    # chmod 600 /mnt/swapfile
    # mkswap /mnt/swapfile
    # swapon /mnt/swapfile
  6. Install the Base System:

    Use pacstrap to install the necessary packages:

    # pacstrap -K /mnt base base-devel linux linux-hardened \
      linux-hardened-headers linux-firmware apparmor mesa \
      xf86-video-intel vulkan-intel git vi vim ukify
  7. Generate the fstab File:

    # genfstab -U /mnt >> /mnt/etc/fstab
  8. Chroot into the New System:

    # arch-chroot /mnt
  9. Configure the System:

    Set the timezone:

    # ln -sf /usr/share/zoneinfo/UTC /etc/localtime
    # hwclock --systohc

    Uncomment en_US.UTF-8 UTF-8 in /etc/locale.gen and generate the locale:

    # sed -i 's/#'"en_US.UTF-8"' UTF-8/'"en_US.UTF-8"' UTF-8/g' /etc/locale.gen
    # locale-gen
    # echo 'LANG=en_US.UTF-8' > /etc/locale.conf
    # echo "KEYMAP=us" > /etc/vconsole.conf

    Set the hostname:

    # echo myhostname > /etc/hostname
    # cat <<EOT >> /etc/hosts
    127.0.0.1 myhostname
    ::1 localhost
    127.0.1.1 myhostname.localdomain myhostname
    EOT

    Configure mkinitcpio.conf to include the encrypt hook:

    # sed -i 's/HOOKS.*/HOOKS=(base udev autodetect modconf kms \
      keyboard keymap consolefont block encrypt filesystems resume fsck)/' \
      /etc/mkinitcpio.conf

    Create the initial ramdisk:

    # mkinitcpio -P

    Install the bootloader:

    # bootctl install

    Set the root password:

    # passwd

    Install microcode and efibootmgr:

    # pacman -S intel-ucode efibootmgr

    Get the swap offset:

    # swapoffset=`filefrag -v /swapfile | awk '/\s+0:/ {print $4}' | \
      sed -e 's/\.\.$//'`

    Get the UUID of the encrypted partition:

    # blkid -s UUID -o value /dev/nvme0n1p2

    Create the EFI boot entry. Replace <UUID OF CRYPTDEVICE> with the actual UUID:

    # efibootmgr --disk /dev/nvme0n1p1 --part 1 --create --label "Linux" \
      --loader /vmlinuz-linux --unicode "cryptdevice=UUID=<UUID OF CRYPTDEVICE>:root \
      root=/dev/mapper/root resume=/dev/mapper/root resume_offset=$swapoffset \
      rw initrd=\intel-ucode.img initrd=\initramfs-linux.img" --verbose

    Configure the UKI presets:

    # cat <<EOT >> /etc/mkinitcpio.d/linux.preset
    ALL_kver="/boot/vmlinuz-linux"
    ALL_microcode=(/boot/*-ucode.img)
    PRESETS=('default' 'fallback')
    default_uki="/efi/EFI/Linux/arch-linux.efi"
    default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"
    fallback_uki="/efi/EFI/Linux/arch-linux-fallback.efi"
    fallback_options="-S autodetect"
    EOT

    Create the UKI directory:

    # mkdir -p /efi/EFI/Linux

    Configure the kernel command line:

    # cat <<EOT >> /etc/kernel/cmdline
    cryptdevice=UUID=<UUID OF CRYPTDEVICE>:root root=/dev/mapper/root \
    resume=/dev/mapper/root resume_offset=51347456 rw
    EOT

    Build the UKIs:

    # mkinitcpio -p linux

    Configure the kernel install layout:

    # echo "layout=uki" >> /etc/kernel/install.conf
  10. Configure Networking (Optional):

    Create a systemd-networkd network configuration file:

    # cat <<EOT >> /etc/systemd/network/nic0.network
    [Match]
    Name=nic0
    [Network]
    DHCP=yes
    EOT
  11. Install a Desktop Environment (Optional):

    Install Xorg, Xfce, LightDM, and related packages:

    # pacman -Syu
    # pacman -S xorg xfce4 xfce4-goodies lightdm lightdm-gtk-greeter \
      libva-intel-driver mesa xorg-server xorg-xinit sudo
    # systemctl enable lightdm
    # systemctl start lightdm
  12. Enable Network Services (Optional):

    # systemctl enable systemd-resolved.service
    # systemctl enable systemd-networkd.service
    # systemctl start systemd-resolved.service
    # systemctl start systemd-networkd.service
  13. Create a User Account:

    Create a user account and add it to the wheel group:

    # useradd -m -g wheel -s /bin/bash myusername
  14. Reboot:

    Exit the chroot environment and reboot your system:

    # exit
    # umount -R /mnt
    # reboot

Samstag, 6. April 2024

Multidimensional arrays of function pointers in C

Embedded hardware typically includes an application processor and one or more adjacent processor(s) attached to the printed circuit board. The firmware that resides on the adjacent processor(s) responds to instructions or commands.  Different processors on the same board are often produced by different companies.  For the system to function properly, it is imperative that the processors communicate without any issues, and that the firmware can handle all types of possible errors.

Formal requirements for firmware related projects may include the validation and verification of the firmware on a co-processor via the application programming interface (API).  Co-processors typically run 8, 16, or 32-bit embedded operating systems.  If the co-processor manufacturer provides a development board for testing the firmware on a specific co-processor, then the development board may have it's own application processor. Familiarity with all of the applicable bus communication protocols including synchronous and asynchronous communication is important.  High-volume testing of firmware can be accomplished using function-like macros and arrays of function pointers.  Processor specific firmware is written in C and assembly - 8, 16, 32, or 64-bit.  Executing inline assembly from C is straightforward and often required.  Furthermore, handling time-constraints such as real-time execution on adjacent processors is easier to deal with in C and executing syscalls, low-level C functions, and userspace library functions, is often more efficient.  Timing analysis is often a key consideration when testing firmware, and executing compiled C code on a time-sliced OS, such as Linux, is already constrained.

To read tests based on a custom grammar, a scanner and parser in C can be used. Lex is ideal for building a computationally efficient lexical analyzer that outputs a sequence of tokens. For this case, the tokens comprise the function signatures and any associated function metadata such as expected execution time. Creating a context-free grammar and generating the associated syntax tree from the lexical input is straightforward.   Dynamic arrays of function pointers can then be allocated at run-time, and code within external object files or libraries can be executed in parallel using multiple processes or threads. The symbol table information from those files can be stored in multi-dimensional arrays. While C is a statically typed language, the above design can be used for executing generic, variadic functions at run-time from tokenized input, with constant time lookup, minimal overhead, and specific run-time expectations (stack return value, execution time, count, etc.).

At a high level, lists of pointers to type-independent, variadic functions and their associated parameters can be stored within multi-dimensional arrays.  The following C code uses arrays of function pointers to execute functions via their addresses.  The code uses list management functions from the Linux kernel which I ported to userspace.

https://github.com/brhinton/bcn