Changes

Jump to navigation Jump to search
added details about everything
 
==Overview==
The '''GE Flashpad''' is a Digital Radiography image sensor from approximately 2010, originally used in the '''GE Optima 220AMX''' mobile X-ray unit. It was designed to replace analog film in radiology, dramatically reducing image acquisition time from hours to seconds.
[[File:GE Flashpad.jpg|thumb|Flashpad with Anti-Scatter grid (left), manual and recovery dvd for 220amx and tether cord (right)]]
Due to its high original cost and specialized application, used units occasionally appear on professional B2B marketplaces in the $15,000–$50,000 range. On eBay, prices typically fall between $1,500 and $5,000, though units at this price point are often in poor condition and may fail the built-in self-test or not function at all.
{{Note|[[Artificial intelligence|AI]] assistance was used in writing this page for improved formatting and readability, as well as in the process of finding information, testing, and analyzing firmware dumps and backups.}}
 
== Purpose and Motivation ==
 
This project documents the reverse engineering of the GE FlashPad wireless
digital radiography detector used with the Optima XR200/220 AMX mobile X-ray
system, with the goal of freeing these detectors for independent use.
[[File:Xray capture pcb.png|thumb|Xray capture of a PCB for Reverse Engineering]]
Large numbers of these detectors reach the used market, but each one is
cryptographically and administratively bound to its original Optima 220 AMX
console. Once separated from that console, or once the console is
decommissioned, the detector is effectively useless even though the hardware is
fully functional. The aim of this work is to remove that artificial barrier so
that a standalone FlashPad can be paired, configured, and read out by any host,
without the half million dollar console it was sold with.
 
The intended beneficiaries are:
 
* Hobbyists, researchers, and engineers who want a high quality flat panel detector for their own imaging projects.
* Veterinary practices, which can put surplus human grade detectors to good use at a fraction of the cost of new equipment.
* Clinics and hospitals in countries and regions where a complete commercial system is unaffordable, allowing serviceable detectors to keep providing diagnostic imaging instead of being scrapped.
[[File:Xray current clamp multimeter.png|thumb|xray of a current clamp multimeter]]
This is done for human good. Every detector returned to service is one less
piece of working medical hardware sent to landfill, and potentially one more
place that can offer X-ray imaging where it otherwise could not.
 
All files, findings, protocol documentation, and tools produced by this project
are public and open source, so that anyone can study, reproduce, and build on
the work.
==Technical Specifications==
[[File:Ge flashpad tether cable pinout diagram.png|thumb|Pinout Diagram of the Tether cable]][[File:Ge flashpad tether wiring for ethernet cable.jpg|thumb|Professional Tether wiring to attach a Ethernet Cable and 12V socket to it.]]
The Flashpad uses a '''~40 × 40 cm CsI scintillator''' bonded to a [[Thin-film transistor|TFT]] photodetector array mounted on glass. The assembly is highly sensitive to shock and impact damage.
The theoretical 5 lp/mm spatial resolution is primarily limited in practice by the focal spot size of the X-ray source. Use of an anti-scatter grid can improve effective resolution.
 
=== Status of Reverse Engineering ===
 
{| class="wikitable"
|-
! What !! Status
|-
| Connect, beacon, ACK || Works
|-
| PORT_SETUP || Works
|-
| SIGNATURE_REQUEST / serial number readout || Works
|-
| Script download (Scripts 7, 8, 1) || Works
|-
| EXECUTE_SCRIPT || Works
|-
| EXECUTION_COMPLETE (dark acquisition) || Works
|-
| EXECUTION_COMPLETE (standard acquisition) || Needs real X-ray trigger to test
|-
| Image data on port 6660 || Does not work yet, under investigation. Will not send Imagedata yet.
|}
==Hardware Features==
===Ethernet interface===
There is a 100MBit Ethernet interface trough the Tether Cable which can be tapped and used for Communication.
Exposed metal contacts on the bottom connector are isolated via relays by default. Enabling Gigabit Ethernet connectivity requires shorting or driving two specific pins. This has not been investigated further at this time.
 
 
== Communication Protocol ==
 
This section documents the URP/PDAP protocol used by the GE Flashpad (codename '''Apollo''') to communicate with a host over Ethernet. All findings are based on live capture tests, configuration files, and reverse-engineering of the GE SuperBee software stack.
 
{{Note|All findings are based on a single unit and may not be fully accurate.}}
 
=== Network Setup ===
 
All findings were over Ethernet only, no UWB or WIFI has been used.
Default detector IP is <code>192.168.1.30</code>. Set your host to a static IP in the same subnet, <code>192.168.1.1</code> works fine.
 
At first by sending random bytes over Python it answered to port 48879 (0xBEEF), which seems to be either the default port or set by Python.
After SYSTEM_SETUP it got set to 5550.
 
 
{| class="wikitable"
|-
! Role !! IP !! Port !! Direction
|-
| All commands: host -> detector || 192.168.1.30 || '''8100''' (UDP) || Host sends here
|-
| Discovery beacons: detector -> host || - || '''4500''' (UDP) || Detector sends here initially
|-
| Protocol replies: detector -> host || - || '''5550''' (UDP) || Detector sends here after setup
|-
| Image pixel data: detector -> host || - || '''6660''' (UDP) || Detector streams frames here
|}
 
In practice you can listen on port '''5550''' for everything (beacons and replies) by advertising that port in both <code>SYSTEM_STARTUP</code> and <code>PORT_SETUP</code>. The detector sends to whichever port was most recently configured.
 
=== Protocol Layers ===
 
Two layers, carried over UDP:
 
; URP (Unified Registration Protocol)
: 8-byte wrapper on every packet. Handles sequencing and acknowledgement.
 
; PDAP (Proprietary Detector Access Protocol)
: The actual command layer, present inside URP packets when <code>CmdFlag = 0</code>.
 
Every UDP packet starts with a URP header:
 
<pre>
[SeqId : 4 bytes LE] [CmdFlag : 4 bytes LE]
</pre>
 
* <code>CmdFlag = 0</code> -- data packet, PDAP command follows.
* <code>CmdFlag = 1</code> -- bare ACK, no PDAP body. SeqId echoes the packet being acknowledged.
 
Both sides must ACK every data packet immediately. The detector silently drops packets with a SeqId it has already seen, so always increment SeqId for each new command.
 
When CmdFlag is 0, the PDAP header follows immediately:
 
<pre>
[cmd_type : 4 bytes LE] [payload_len : 4 bytes LE] [payload ...]
</pre>
 
=== Connecting to the Detector ===
 
The connection sequence is:
 
# Broadcast <code>SYSTEM_STARTUP</code> to tell the detector where to reply.
# The detector sends a <code>BEACON</code> back -- ACK it and sync your sequence counter.
# Send <code>PORT_SETUP</code> to configure the reply and image ports.
# Send <code>SIGNATURE_REQUEST</code> to read the detector identity (serial number, model, firmware, MAC).
 
==== Step 1: SYSTEM_STARTUP ====
 
Broadcast UDP to <code>192.168.1.255:8100</code>. Always uses <code>SeqId = 0</code>.
 
<pre>
URP : [00 00 00 00] SeqId = 0
[00 00 00 00] CmdFlag = 0
PDAP: [01 00 00 00] cmd_type = 1
[06 00 00 00] payload_len = 6
[15 AE] host reply port = 5550 (big-endian)
[C0 A8 01 01] host IP = 192.168.1.1 (network byte order)
</pre>
 
<syntaxhighlight lang="python">
import socket, struct
 
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind(("0.0.0.0", 5550))
 
HOST_IP = "192.168.1.1"
DET_IP = "192.168.1.30"
HOST_PORT = 5550
IMG_PORT = 6660
 
def make_urp_packet(seq_id, pdap_bytes):
return struct.pack("<II", seq_id, 0) + pdap_bytes
 
pdap = struct.pack("<II", 1, 6) + struct.pack(">H", HOST_PORT) + socket.inet_aton(HOST_IP)
sock.sendto(make_urp_packet(0, pdap), ("192.168.1.255", 8100))
</syntaxhighlight>
 
==== Step 2: Receiving the BEACON and ACKing ====
 
The detector broadcasts a <code>BEACON</code> (cmd_type=1) roughly every 2 seconds. After sending SYSTEM_STARTUP you should get one quickly. Parse the detector SeqId from the URP header and ACK it:
 
<syntaxhighlight lang="python">
data, addr = sock.recvfrom(4096)
det_seq = struct.unpack_from("<I", data, 0)[0]
 
# send bare ACK
ack = struct.pack("<II", det_seq, 1)
sock.sendto(ack, (DET_IP, 8100))
 
# all subsequent commands start from here
host_seq = det_seq + 1
</syntaxhighlight>
 
==== Step 3: PORT_SETUP ====
 
Tells the detector which host ports to use for replies and image data.
 
<pre>
PDAP: [02 00 00 00] cmd_type = 2
[04 00 00 00] payload_len = 4
[15 AE] host cmd port = 5550 (big-endian)
[1A 04] host image port = 6660 (big-endian)
</pre>
 
<syntaxhighlight lang="python">
pdap = struct.pack("<II", 2, 4) + struct.pack(">HH", HOST_PORT, IMG_PORT)
sock.sendto(make_urp_packet(host_seq, pdap), (DET_IP, 8100))
host_seq += 1
# expect bare ACK from detector
</syntaxhighlight>
 
==== Step 4: Reading the Serial Number (SIGNATURE_REQUEST) ====
 
Empty command, the detector replies with a 54-byte payload containing its identity.
 
<syntaxhighlight lang="python">
pdap = struct.pack("<II", 3, 0) # cmd_type=3, payload_len=0
sock.sendto(make_urp_packet(host_seq, pdap), (DET_IP, 8100))
host_seq += 1
 
# reply is 70 bytes total: 8 URP + 8 PDAP header + 54 payload
data, _ = sock.recvfrom(4096)
payload = data[16:] # skip URP (8) + PDAP header (8)
 
mac = payload[0:6]
serial = payload[22:34].rstrip(b'\x00 ').decode()
model = payload[34:46].rstrip(b'\x00 ').decode()
fw_bytes = payload[46:54]
firmware = ".".join(str(b) for b in fw_bytes)
 
print(f"MAC: {':'.join(f'{b:02X}' for b in mac)}")
print(f"Serial: {serial}")
print(f"Model: {model}")
print(f"Firmware: {firmware}")
</syntaxhighlight>
 
Expected output:
<pre>
MAC: 40:F4:A0:00:78:4D
Serial: UA45829-7
Model: 5340000-7
Firmware: 1.6.0.4.2.0.1.3
</pre>
 
=== Running an Acquisition ===
 
After the connection sequence above, download scripts to the detector and then execute them.
 
==== ROE Initialisation (Script 7) ====
 
Always run this first. It initialises the readout electronics and takes about 4-5 seconds. The detector sends host event ID 17 when done.
 
==== Dark / Offset Acquisition (Script 1) ====
 
No X-ray source required. Runs a dark-field exposure for offset calibration. Use this to verify the acquisition pipeline without a generator.
 
==== Standard Acquisition (Script 0) ====
 
Requires an actual X-ray exposure. <code>EXECUTION_COMPLETE</code> will '''not''' arrive without a real X-ray trigger.
 
==== Sequence Overview ====
 
<pre>
HOST DETECTOR
| |
|-- SYSTEM_STARTUP (broadcast) ----------->|
|<- bare ACK -------------------------------|
|<- BEACON (cmd_type=1) --------------------|
|-- bare ACK ------------------------------>|
| |
|-- PORT_SETUP (cmd_type=2) -------------->|
|<- bare ACK -------------------------------|
| |
|-- SIGNATURE_REQUEST (cmd_type=3) ------->|
|<- SIGNATURE_REPLY (54 bytes) -------------|
|-- bare ACK ------------------------------>|
| |
|-- GENERIC_SCRIPT Script7 (ROE init) ---->|
|<- bare ACK or SCRIPT_DOWNLOAD_REPLY ------|
| |
|-- GENERIC_SCRIPT Script1 (dark acq) ---->|
|<- bare ACK -------------------------------|
| |
|-- EXECUTE_SCRIPT (cmd_type=6) ---------->|
|<- bare ACK -------------------------------|
|<- EXECUTE_SCRIPT_REPLY (~230ms) ----------|
|-- bare ACK ------------------------------>|
|<- DETECTOR_STATE_NOTIFY (~890ms) ---------| state_id=17
|-- bare ACK ------------------------------>|
| |
|<- EXECUTION_COMPLETE (0x10000) -----------|
|-- bare ACK ------------------------------>|
| |
|<- IMAGE_XFER_STATUS_QUERY (0x30000) ------|
|-- bare ACK ------------------------------>|
|-- IMAGE_XFER_STATUS_REPLY (cmd_type=9) ->| numMissed=0
|<- bare ACK -------------------------------|
</pre>
 
=== Sequence Counter Rules ===
 
* <code>SYSTEM_STARTUP</code> always uses <code>SeqId = 0</code>.
* After the first beacon, set host SeqId to beacon_SeqId + 1.
* Increment SeqId by 1 for every new data packet (CmdFlag=0).
* Bare ACKs echo the SeqId of the packet being acknowledged and do not consume a SeqId.
* The detector silently drops any packet with a SeqId it has already processed, so never reuse one.
 
 
 
== Sensor Readout and Host Registration ==
 
This section documents the reverse engineered sensor telemetry interface and the
host registration (pairing) mechanism of the GE Optima XR200/220 AMX FlashPad
(URP detector, SuperBee, FW 1.6.0.4.2.0.1.3). All commands are PDAP over UDP to
the detector at port 8100; replies return to the host command port.
 
=== Sensor Readout ===
 
The detector exposes an analog sensor interface (the DEM, Detector Environment
Monitor) that is independent of the image transfer path and works regardless of
acquisition state.
 
==== Commands ====
 
{| class="wikitable"
! cmd_type !! Meaning !! Request payload !! Reply payload
|-
| 0x7900 || Raw sensor read || [sensorId:4 LE] || [value:4 LE] (12 bit ADC count)
|-
| 0x7902 || Converted sensor read || [sensorId:4 LE] || [value:4 LE] (engineering units, signed)
|-
| 0x7904 || Detailed / radio || [selector:4 LE] || [value:4 LE]
|}
 
Note: cmd 0x7902 IS supported on this firmware and returns calibrated
engineering units (millivolts for the supply rails, signed; 0.1 degree C for
temperatures). Earlier documentation that marked 0x7902 as unsupported is
incorrect. The host side conversion coefficients are not required; the detector
performs the conversion internally.
 
The full sensor map (name, sensorId) was recovered from the detector's own
[Sensor] configuration table, read back over the upload interface (see the
Registration section for the read protocol).
 
==== Power rails (live readings) ====
 
All supply rails read correctly via 0x7902 and are within normal range for a
flat panel detector. Representative readings:
 
{| class="wikitable"
! Sensor !! sensorId !! Converted !! Value
|-
| DCIN_RAW || 10 || 12100 mV || +12.10 V (main DC input)
|-
| LCORE_UNREG || 11 || 1724 mV || +1.72 V
|-
| LPANA_UNREG || 12 || 5776 mV || +5.78 V
|-
| LNANA_UNREG || 13 || -5801 mV || -5.80 V
|-
| SCAN_VCC || 14 || 5086 mV || +5.09 V (gate driver)
|-
| P5V_REF || 16 || 5025 mV || +5.03 V (5 V reference)
|-
| V_ON || 17 || 11085 mV || +11.09 V (TFT gate on)
|-
| V_OFF || 18 || -12378 mV || -12.38 V (TFT gate off)
|-
| V_COMMON || 19 || -9385 mV || -9.39 V
|-
| 3V3 || 29 || 3177 mV || +3.18 V (3.3 V logic)
|-
| VCC_UNREG || 37 || 3399 mV || +3.40 V
|-
| PARCPREG || 38 || 3768 mV || +3.77 V (ARC preamp +)
|-
| NARCPREG || 39 || -3732 mV || -3.73 V (ARC preamp -)
|-
| PANA_UNREG || 45 || 18352 mV || +18.35 V (photodiode bias +)
|-
| NANA_UNREG || 46 || -19251 mV || -19.25 V (photodiode bias -)
|}
 
Switched rails that are inactive while the panel is idle (PARCVA_U,
P5VA_SW, N5VA_SW, FGATE_NVC_L, FGATE_PVC_L, etc.) read at or near zero.
 
==== Known limitations ====
 
* '''Temperatures''' (Temp_Surface, sensorId 336; Temp_Panel, sensorId 352): the raw 0x7900 read rails at 0x3FF (1023, the ADC maximum), indicating an open thermistor path while the panel is idle. This is a hardware/state condition, not a command problem, and the temperature is not readable from the host in this state.
* '''Unimplemented sensors''': sensorIds 70 (Accelerator), 78 (Gravity), and 256 to 259 (Battery status, name, life, capacity), and 272 (Grid status) are not implemented on this DEM. The detector returns the leftover conversion register contents (a duplicate of a previously read sensor) rather than a real value, so these rows must be discarded.
* '''Accelerometer''': functional through a separate addressing scheme using raw cmd 0x7900 with selectors 0x42 (X), 0x43 (Y), 0x44 (Z), returning 12 bit per axis counts.
 
=== Host Registration (Pairing) ===
 
URP stands for Unified Registration Protocol. The detector maintains a host
list in its internal NOR flash. Image data is delivered only to a registered
primary host, so registration is a prerequisite for image transfer.
 
==== Host identity (MAC and HostId) ====
 
Each host is identified by a 16 character HostId derived deterministically from
the host's eth0 MAC address. The derivation (from the vendor generateHostId
script) is:
 
# Take the eth0 MAC, remove the colon separators, convert to upper case (12 hex characters).
# Prepend the last 4 characters to the full 12 characters.
# The result is 16 hex characters.
 
Example: MAC 00:6f:00:01:0a:3a becomes 006F00010A3A, then the last four (0A3A)
are prepended, giving HostId 0A3A006F00010A3A.
 
==== HostList structure ====
 
The host list is stored in flash at offset 0x940000 and can be read back over
the upload interface as data category 0x71. Layout:
 
Offset Size Field
0x00 16 DetectorDeviceId (ASCII)
0x10 16 ConnectionSecretKey (ASCII; "XXXXXXXXXXXXXXXX" when unset)
0x20 16 DetectorName (ASCII)
0x30 16 DetectorCode (ASCII)
0x40 2 CurrentNumberOfHosts (uint16 LE)
0x42 2 IndexToPrimaryHost (uint16 LE; 0xFFFF = none)
0x44 144*N Host entries, 144 bytes each:
+0x00 16 HostId (ASCII)
+0x10 .. host name / department string
+0x50 .. location string
... 4 CRC (big endian; see below)
 
==== HostList from the unit under test ====
 
Detector: MAC 40:F4:A0:00:78:4D, serial UA45829-7, model 5340000-7,
firmware 1.6.0.4.2.0.1.3. DetectorName starShape_green. ConnectionSecretKey
unset. CurrentNumberOfHosts = 3, IndexToPrimaryHost = 0xFFFF (no primary host).
 
{| class="wikitable"
! Index !! HostId !! Derived MAC !! Name
|-
| 0 || 2C6400045FB42C64 || 00:04:5F:B4:2C:64 || Haus 207 / ITS
|-
| 1 || B044E8393512B044 || E8:39:35:12:B0:44 || Not Initialized
|-
| 2 || 5CF800045FB15CF8 || 00:04:5F:B1:5C:F8 || Not_Initialized
|}
 
The unit is therefore not factory fresh; it carries registrations from a prior
deployment, but no primary host is currently designated.
 
==== Checksum (CRC) ====
 
The HostList (and other flash data blobs) are protected by a 4 byte trailing
CRC. Parameters:
 
* Polynomial: 0x04C11DB7
* Initial value: 0
* MSB first, augmented message style (the data bit is shifted into the LSB; no input or output reflection; no final XOR)
* Stored big endian
 
To generate: compute the CRC over the data followed by four zero bytes, then
append the result big endian. Verification: the CRC over (data plus stored CRC)
equals zero.
 
def crc(data, poly=0x04C11DB7, init=0):
c = init
for byte in data:
for bit in (0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01):
msb = c & 0x80000000
c = (c << 1) & 0xFFFFFFFF
if byte & bit: c |= 1
if msb: c ^= poly
return c
# trailer = crc(data + b"\x00\x00\x00\x00"), stored big endian
 
==== Read and write transport ====
 
Data blobs (including the HostList) are moved with a configure / buffer /
finalize sequence.
 
Read (upload, detector to host), non destructive:
 
{| class="wikitable"
! Step !! cmd_type !! host to detector !! detector to host
|-
| Configure || 0x13 || [uploadId:4 LE] || [status:1][totalSize:4 LE]
|-
| Buffer || 0x14 || [bufId:4 LE][numBytes:4 LE] || [bufId:4 LE][numBytes:4 LE][data]
|}
 
Write (download, host to detector), persistent (writes flash):
 
{| class="wikitable"
! Step !! cmd_type !! host to detector !! detector to host
|-
| Configure || 0x0E || [downloadId:4 LE][totalSize:4 LE] || [status:1]
|-
| Buffer || 0x0F || [bufId:4 LE][numBytes:4 LE][data] || [status:1][reserved:4]
|-
| Commit || 0x10 || (empty) || [status:1]
|}
 
bufId is a zero based chunk index. The HostList uses id 0x71 for both read and
write. The commit command (0x10) reuses the firmware flash path, so a malformed
download can corrupt flash; the operation is irreversible on this hardware.
 
==== Registering a new host ====
 
To register a host and make it the image destination, read the current HostList
(0x71), append a 144 byte entry carrying the new HostId, increment
CurrentNumberOfHosts, set IndexToPrimaryHost to the new entry's index,
recompute the trailing CRC, and write the blob back via the download sequence
(0x0E / 0x0F / 0x10).
 
 
== FlashPad Detector: Internal Flash Dump and Data Files ==
 
This section documents how the full contents of the detector's internal flash
were extracted over the network and what each recovered file contains. The
detector under test is a GE Optima XR200/220 AMX FlashPad (URP detector,
serial UA45829-7, MAC 40:F4:A0:00:78:4D, firmware 1.6.0.4.2.0.1.3).
 
=== Background ===
 
The detector's main storage is a Spansion/Cypress S29GL512P (marked
GL512P10FFCR2), a 512 Mbit (64 MB) parallel NOR flash. A direct chip read
requires bus access or desoldering and a programmer. However, the detector
firmware exposes its stored data blobs, including a full image of the flash,
through the read (upload) side of the data transport protocol. This makes a
complete, byte exact dump possible over UDP with no physical access.
 
=== Extraction method ===
 
The upload interface is the read counterpart of the firmware download path and
is non destructive (it only reports and returns data; nothing is written).
Each data category is identified by an 8 bit upload ID:
 
{| class="wikitable"
! Step !! cmd_type !! host to detector !! detector to host
|-
| Configure || 0x13 || [uploadId:4 LE] || [status:1][totalSize:4 LE]
|-
| Buffer || 0x14 || [bufId:4 LE][numBytes:4 LE] || [bufId:4 LE][numBytes:4 LE][data]
|}
 
A configure request returns status 0 and a total size for a valid ID, or a non
zero status for an unsupported ID. The dump tool sweeps all IDs from 0x00 to
0xFF, and for every readable ID it pulls the full blob in fixed size chunks
(bufId is a zero based chunk index) and writes it to a file. The 64 MB flash
image transfers as 65536 chunks of 1024 bytes.
 
=== Recovered files ===
 
A sweep of the unit returned 18 readable blobs:
 
{| class="wikitable"
! Upload ID !! Size (bytes) !! Contents
|-
| 0xFD || 67108864 || Full 64 MB NOR flash image
|-
| 0xFF || 16777216 || 16 MB region (firmware / FPGA mirror or image buffer)
|-
| 0xFE || 524288 || Bootloader (512 KB; SPI loader, Nios reset code)
|-
| 0x10 || 6815783 || Calibration map, dose level 1
|-
| 0x11 || 6815783 || Calibration map, dose level 2
|-
| 0x12 || 6815783 || Calibration map, dose level 3
|-
| 0x06 || 49254 || Table referencing conditioner/generator serial UA2010-8U005
|-
| 0x50 || 19938 || Per mode calibration coefficients
|-
| 0x51 || 19582 || Per mode calibration coefficients
|-
| 0x07 || 12187 || Sensor conversion table (text; see Sensor Readout)
|-
| 0x72 || 3001 || Shock / drop event log (text)
|-
| 0x0E || 624 || Panel geometry / configuration (binary)
|-
| 0x71 || 504 || Host list / registration record (see Host Registration)
|-
| 0x0F || 233 || Host to detector compatibility table (text)
|-
| 0x08 || 62 || Serial and model strings
|-
| 0x0A || 48 || Manufacturing codes
|-
| 0x52 || 30 || Serial string
|-
| 0x0B || 24 || Small marker / identifier
|}
 
=== Flash image layout (upload ID 0xFD) ===
 
A block scan of the 64 MB image shows the following regions:
 
{| class="wikitable"
! Range !! Contents
|-
| 0x000000 to 0x800000 || Firmware and FPGA configuration
|-
| 0x800000 to 0x940000 || Sparse configuration area
|-
| 0x940000 || Host list / registration record (matches upload ID 0x71)
|-
| 0x1000000 to 0x2800000 || Calibration and image data (16 to 40 MB)
|-
| 0x2800000 to 0x4000000 || Erased / unused (40 to 64 MB)
|}
 
The host list strings (the DetectorName starShape_green, the registered host
name Haus 207 / ITS, and the unset ConnectionSecretKey placeholder) appear at
0x940000, confirming that the 504 byte 0x71 read maps to this flash region.
 
=== Notes on individual files ===
 
* '''0x07 (sensor table)''': plain text, header DetectorSerialNumber = UA45829-7, revision 1.2. Lists every sensor by name, command (0x7902), and sensorId. Also carries panel geometry in its [Common] section: 16 bit depth, 2048 by 2048 pixels, active area from (12, 12) to (2035, 2035), pixel pitch 0.2 mm, corner radius 1416.8, panel saturation 150.
* '''0x10, 0x11, 0x12 (calibration maps)''': three distinct blobs of identical size, corresponding to the low, medium, and high dose calibration sets. Each begins with the firmware version and serial (header bytes 01 06 00 04 02 00 01 03 followed by the serial). Required to apply gain and offset correction to raw images.
* '''0xFE (bootloader)''': contains the strings spi_load.S and ../../boot and Nios II reset vector code.
* '''0x72 (shock log)''': text records of drop / vibration events with timestamps and per axis values; the same data is mirrored in the detector's small onboard EEPROM.
* '''0x06''': references a different serial, UA2010-8U005, likely the conditioner or generator board rather than the panel.
 
=== Significance ===
 
The complete flash image and all calibration data are recoverable over the
network without opening the detector, providing a full byte exact backup of the
unit before any write operation. The calibration maps are needed for image
correction, and the firmware image (the live, deployed build) is more complete
than the partial firmware files shipped on the recovery media.
 
 
 
=== Known Dead Ends ===
 
Things that were tried and did not work or led nowhere:
 
; 0xBEEF (48879) as reply port
: This was a bug in early test scripts. The port has no meaning in the protocol. Use 5550.
 
; CmdFlag=1 as data packet flag
: Early scripts had the URP fields swapped, setting CmdFlag=1 on data packets. The detector ignores all PDAP content in these packets. Power cycle the detector if this happened, it may retain stale port state.
 
; Image data on alternate ports
: Tried listening on 48879, 6660, 5550, 8100, 1050, 6661, 9999, 4444, 7000, 7001, 9001. Nothing arrived on any of them.
 
; PORT_SETUP byte order (big-endian)
: Current implementation sends port fields as big-endian. If the detector reads them as little-endian it computes port 44565 and 1050 instead of 5550 and 6660, which would explain why no image data arrives. Not yet confirmed.
 
; Image data streaming automatically after EXECUTE_SCRIPT
: Frames may not push during execution at all. The detector may require an explicit IMAGE_RETRIVAL_REQUEST (cmd_type=0x41) and IMAGE_RETRIVAL (cmd_type=0x98) after the 0x30000 notification before it streams anything. Not yet tested.
 
 
== Teardown / Internal Pictures / Hardware analysis ==
<div style="float:right; display:flex; gap:8px;">
[[File:GE Flashpad under the hood.jpg|thumb|none|220px|the Carbon fiber sleeve is held by 9 screws and can taken off without force.]]
[[File:Ge flashpad powersupply pcb in handle.jpg|thumb|none|220px|Power supply PCB]]
[[File:Ge flashpad uwb board pcb.jpg|thumb|none|220px|UWB PCB for Wireless USB using a RTU2705]]
[[File:Ge flashpad uwb pcb backside.jpg|thumb|Backside of UWB PCB]]
[[File:Ge flashpad power supply pcb backside.jpg|thumb|Backside of Power supply PCB]]
[[File:Ge flashpad main pcb closeup1.jpg|thumb|Main area of the PCB with its Altera Cyclone 3 FPGA]]
[[File:Ge flashpad main pcb closeup2.jpg|thumb|AD7892 is a 600ksps 12bit ADC, SN74LVC8T245 a 8bit bus transceiver and DG9408EDN a 8ch MUX]]
[[File:Ge flashpad bottom connector ethernet isolation pcb.jpg|thumb|Isolation PCB for bottom connector]]
[[File:Ge flashpad main pcb powersupply section.jpg|thumb|Powersupply section for FPGA and ROIC]]
[[File:Ge_flashpad_main_pcb_closeup_3.jpg|thumb|AD9764AR 14-Bit, 125 MSPS DAC and DS1682 integrated elapsed-time recorder]]
 
 
 
</div>

Navigation menu