Skip to content

feat(ops243): add internal hardware trigger - #221

Merged
jewbetcha merged 12 commits into
open-flight:mainfrom
JPMarhefka:agent/hardware-trigger
Oct 11, 2026
Merged

jewbetcha merged 12 commits into
open-flight:mainfrom
JPMarhefka:agent/hardware-trigger

Conversation

@JPMarhefka

@JPMarhefka JPMarhefka commented Aug 18, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds an opt-in OPS243 internal hardware-trigger capture strategy for rolling-buffer mode.

  • Requires and validates OPS243-A firmware v1.3.2 or newer in the 1.3 release train; v1.3.1 is rejected because of a vendor data-sequence bug.
  • Adds --trigger hardware with hardware-mode defaults of a 25 mph outbound threshold, SM25, S#6, and 30 ksps.
  • Configures the OPS243 internal trigger, waits for the board-generated I/Q dump, parses the capture, and re-arms with PA.
  • Never clears serial input once the board is armed, and re-arms the board if the tail of a dump arrives without its start (orphaned_dump), so the trigger cannot get stuck idle.
  • Adds recovery for delayed UART output after a re-arm timeout.
  • Threads the hardware-trigger options through the server, monitor, and kiosk script.
  • Preserves the existing sound-trigger default and --sound-pre-trigger behavior.
  • Adds focused driver, strategy, CLI-forwarding, and documentation coverage.

Why was this required?

The existing rolling-buffer path depends on the external SEN-14262 sound-trigger edge. The OPS243 can perform the speed-trigger decision internally, allowing installations with the internal trigger wiring to capture the rolling I/Q history without requiring the sound-trigger module.

This is opt-in so existing installations continue to use sound mode unchanged. Hardware mode is intentionally limited to the OPS243 trigger path; unrelated experimental analysis, replay, board-diagnostic, clock, and UI work is not included.

Re-arm fix (firmware 1.3.2)

On 1.3.2 the board drops to idle power mode after an internal-trigger dump, with every detector setting intact. The original re-arm used GC, which resets those settings and rebuilds them over about 2.5 s. Motion during the rebuild fired the trigger, either in the unguarded gap right after GC or just after the live ST threshold was restored. The rebuild's command replies and reset_input_buffer calls consumed that dump, and the board sat idle with nothing left to re-arm it (blue LED stuck on). It reproduced reliably by waving rapidly past the radar: stuck after 1–3 triggers.

Re-arm now sends only PA after draining the finished dump. That takes about 0.4 s instead of 2.5 s and has no unguarded window. Input is never cleared after the board is live. As a backstop, a Q array that arrives before any capture marker is treated as an orphaned dump and the idle board is re-armed. Both new wait_for_hardware_trigger options are opt-in, so the sound path is unchanged.

Automated tests

  • uv run --extra camera pytest tests/ -q: 1804 passed, 10 skipped
  • uv run ruff check src/openflight/: passed
  • uv run pylint src/openflight/ --fail-under=9: passed, 9.60/10
  • ruff format --check flags 5 files with diffs that are already on main; none come from this PR.

The focused tests cover command ordering, firmware and parameter validation, dump-boundary filtering, dump parsing, PA-only re-arm, dumps that start immediately after arming or re-arming, orphaned-dump detection and re-arm, re-arm recovery, accepted/rejected captures, strategy selection, and CLI forwarding.

Manual (human) testing

Firmware v1.3.2 (OPS243-A rev D6 over the J3 UART at 230,400 baud, Raspberry Pi 5), merged with current main:

  • Startup validates firmware 1.3.2 and arms ST-25, S#6, S=30, SM25. No false triggers while idle.
  • Before the re-arm fix: rapid motion left the board idle (PowerMode: Idle or Pulse) after 1–3 triggers, reproduced three times.
  • PA-only re-arm driver loop under continuous motion: 12/12 dumps captured, never stuck.
  • Full server (--trigger hardware) with the fix: 9/9 dumps re-armed (6 accepted, 3 correctly rejected below 35 mph), 0 orphaned dumps, 0 re-arm failures, 0 errors. The LED cleared after every trigger.
  • Hand-wave testing does not measure ball/club parsing accuracy; the earlier ball results below are from v1.3.1.

Earlier testing on firmware v1.3.1 by the original author: about 9/10 representative shots parsed correctly as swings with SM25. S#6 beat S#4 and S#8. No ambient false triggers with magnitude above 20. About 8/10 club-only practice swings still produced full outputs, which is a known object-classification limitation.

Sound mode was not physically tested on this branch. The sound-trigger code path is unchanged, and the new wait options are opt-in.

Checklist

  • Single feature/fix: this PR is scoped to the OPS243 internal hardware trigger
  • Automated tests included
  • Manual testing described
  • Python tests pass
  • Pylint passes
  • Ruff passes
  • Documentation and changelog updated
  • No unrelated changes mixed in

🤖 Generated with Claude Code

@JPMarhefka
JPMarhefka marked this pull request as ready for review August 18, 2026 22:15
@JPMarhefka
JPMarhefka requested a review from jewbetcha as a code owner August 18, 2026 22:15
Copilot AI lite review requested due to automatic review settings August 18, 2026 22:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in OPS243 internal hardware-trigger strategy for rolling-buffer capture, threading new configuration flags through the kiosk script and server so installations without the external sound-trigger module can still capture I/Q history (while keeping sound-trigger as the default).

Changes:

  • Add OPS243 driver support for configuring, waiting on, parsing, and re-arming the internal speed-trigger rolling-buffer dump (firmware-gated to v1.3.1).
  • Extend server/kiosk CLI plumbing with --trigger hardware plus hardware-mode defaults/overrides (threshold, magnitude, pre-trigger split) and corresponding validation.
  • Add focused tests and documentation for the new trigger mode and its operational constraints.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/test_start_kiosk.py Verifies kiosk CLI forwarding behavior for hardware trigger defaults and overrides.
tests/test_server.py Adds server CLI parsing/forwarding tests for hardware trigger mode and its constraints.
tests/test_rolling_buffer.py Registers/validates the new trigger strategy and adds behavior tests for accept/reject/re-arm flows.
tests/test_ops243.py Adds focused OPS243 command-ordering, validation, re-arm, and recovery tests for internal triggering.
src/openflight/server.py Adds hardware trigger CLI flags/validation and threads trigger kwargs into monitor startup.
src/openflight/rolling_buffer/trigger.py Implements HardwareTriggeredCapture strategy around board-managed trigger + host-side validation + re-arm.
src/openflight/rolling_buffer/monitor.py Configures OPS243 internal trigger on connect when trigger_type == "hardware".
src/openflight/rolling_buffer/init.py Exposes HardwareTriggeredCapture from the rolling_buffer package.
src/openflight/ops243.py Implements firmware validation, internal-trigger configuration, re-arm, and UART recovery behavior.
scripts/start-kiosk.sh Adds kiosk flag parsing and forwarding for hardware-trigger-specific settings.
README.md Documents the new opt-in hardware trigger mode and links to the new guide.
docs/rolling_buffer_spin_detection.md Clarifies the default sound-trigger pipeline and references the new hardware trigger option.
docs/hardware-trigger.md New guide describing command ordering, defaults, and retest expectations for internal triggering.
docs/CHANGELOG.md Adds an Unreleased changelog entry describing the new hardware trigger mode and constraints.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/openflight/server.py Outdated
Comment thread docs/hardware-trigger.md Outdated
@jewbetcha

Copy link
Copy Markdown
Member

This is great, and much needed. However we are waiting on Omnipresence for a way to update OPS radars to this version that doesn't require their extra device. Will ping them again to see if this is a realistic ask.

@HuggeK HuggeK mentioned this pull request Aug 26, 2026
1 task done
@HuggeK

HuggeK commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

So do we have the hex file to flash with the new firmware?

@JPMarhefka

Copy link
Copy Markdown
Contributor Author

So do we have the hex file to flash with the new firmware?

Send an email to Rob at customerservice@omnipresense.com. He will be able to get you the file once it's public and help you find the correct model SEGGER.

@HuggeK

HuggeK commented Aug 29, 2026 •

Copy link
Copy Markdown
Collaborator

Review note: version != required in validate_internal_trigger_firmware() is exact-equality, so any future OPS243-A release (1.3.2+) gets refused even if it still supports STn/SMn. A >= comparison or a documented allowlist would age better.

Correcting my earlier version of this comment: I claimed boards reporting 1.5.2 would be blocked today. AN-010 rev AE Table 9 shows the OPS243-A line runs 1.2.3 → 1.3.1, with the SWn/SFn/STn/SMn enhancements only in 1.3.1 — so the pin is a genuine capability requirement, not just a tested-on marker. The 1.5.2 in docs/ops243-uart-migration.md:148 isn't on that line.

@HuggeK

HuggeK commented Aug 29, 2026 •

Copy link
Copy Markdown
Collaborator

Docs suggestion for docs/hardware-trigger.md — the firmware prerequisite could name the two things that are easy to get wrong:

  • Run ?P first. Some rev D2+ boards use the XMC4700, most others the XMC4500; XMCFlasher needs the right one selected.
  • The hex isn't publicly downloadable — request it from customerservice@omnipresense.com. Flashing goes through the keyed J2 JTAG header, not the J3 UART link OpenFlight already uses.

The J2 JTAG header physical is:
standard ARM Cortex debug header: fine-pitch 0.05"/1.27mm, keyed/shrouded. That's what SEGGER/Adafruit call the "9-pin 0.05""

When shopping for cables for your SEGGER programmer.

Also worth a warning: AN-013 says never press Erase — it wipes factory settings and persistent memory, which is where A! stores rolling-buffer mode.

Not blocking; the code change is unaffected.

@HuggeK

HuggeK commented Aug 29, 2026 •

Copy link
Copy Markdown
Collaborator

waiting on Omnipresence for a way to update OPS radars ... that doesn't require their extra device

Possible cheap path. The OPS243's I/O is 3.3 V (this repo already wires Pi GPIO straight to J3 with no level shifter), and the XMC4500/4700 speaks SWD, which OpenOCD supports via its in-tree xmc4xxx driver. So a Raspberry Pi Debug Probe ($12) — or direct Pi GPIO on a Pi 4 — could in principle flash it without a SEGGER.

Caveats: XMCFlasher won't drive a CMSIS-DAP probe, so this is OpenOCD-only and off the vendor-supported path. Unverified on this board: BMI/boot-mode handling (J-Link does it automatically) and whether the part is read-protected. J2 is a keyed fine-pitch header, so it needs a proper cable — worth asking OmniPreSense for the pinout.

Vendor-blessed alternative: the SEGGER J-Link EDU Mini, which AN-013 links directly (adafruit.com/product/3571, $75.95).

Worth 30 minutes on a spare board. I wouldn't try it on the only radar in a build.

@HuggeK

HuggeK commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

So do we have the hex file to flash with the new firmware?

Send an email to Rob at customerservice@omnipresense.com. He will be able to get you the file once it's public and help you find the correct model SEGGER.

Email sent!

@HuggeK

HuggeK commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Instructions on how to apply the firmware update:
AN-013-F_Code Update.pdf

@HuggeK

HuggeK commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator
image Got an answer back on this.

HuggeK added a commit to HuggeK/openflight that referenced this pull request Sep 4, 2026
…hain to the DS3502

PR open-flight#221 adds an opt-in OPS243 internal hardware trigger (firmware v1.3.1) that needs no SEN-14262, so call it out in the Sound Trigger section as an optional path that is not merged yet, and say under the Cost Summary that the Sound Trigger line drops out on that path. Totals are unchanged.

Document that the Qwiic-to-Dupont cable's chain can continue from the LIS3DH's second STEMMA QT socket further down to the DS3502 digital potentiometer, and give the DS3502 row that wiring plan plus the note that it is moot if the sound trigger goes away.

Claude-Session: https://claude.ai/code/session_01Y55yaLV4h2SVf5EVHN7Yz8

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
HuggeK added a commit to HuggeK/openflight that referenced this pull request Sep 9, 2026
…hain to the DS3502

PR open-flight#221 adds an opt-in OPS243 internal hardware trigger (firmware v1.3.1) that needs no SEN-14262, so call it out in the Sound Trigger section as an optional path that is not merged yet, and say under the Cost Summary that the Sound Trigger line drops out on that path. Totals are unchanged.

Document that the Qwiic-to-Dupont cable's chain can continue from the LIS3DH's second STEMMA QT socket further down to the DS3502 digital potentiometer, and give the DS3502 row that wiring plan plus the note that it is moot if the sound trigger goes away.

Claude-Session: https://claude.ai/code/session_01Y55yaLV4h2SVf5EVHN7Yz8

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
@HuggeK

HuggeK commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

New information from Sandy on the OPS team in the discord server:

OPSandy — 19:40
Hello all. This is Sandy from OmniPreSense with some updates on our OPS243 radar sensor.
First, sorry we’ve been out of stock recently. We try to always have units in stock but ran out early in August. Our next OPS243 build is now in stock, and we expect to ship out all backlog by end of this week.
Second, we have an update on the new features added to the Rolling Buffer mode. We added a new speed trigger feature and ability to output the processed speed values along with the raw I/Q data. This was put in v1.3.1 which we started to ship to some customers but found a late bug related to the data sequence. We have fixed this and have an updated v1.3.2 code which is going on sensors shipping out this week. We are contacting customers who received v1.3.1 about methods to update to v1.3.2. If you have a Segger programmer, and would like to update the code on your OPS243, please send me a message here or via email on our website.
We are updating applications documents (AN-10, AN-27) with more details of the features and will post them here and on our website.
HuggeK — 19:44
Great! Thanks guys for the communication. Will we be able to point people to get this v1.3.2 from your website or be able to include the file on GitHub?
OPSandy — Igår 19:56
Let me check on this. Maybe we can have it posted on GitHub here.

JedS — 20:39

Is there any chance that an OTA update will be released in the future?
OPSandy — 23:18
We're investigating OTA but it's a bit more involved code. If we find a path that looks promising I'll update.
Coby — 00:09

OPSandy — 07:51
Here's the new API commands in the v1.3.2 code for the OPS243. The new features are the speed trigger which is set with the STxnnn with nnn being the speed and set as negative speed for going away (ex. ST-20 for ball/club speed going away at 20mph). There's a special signal magnitude threshold setting for this trigger (SMnn). The other feature is to have the OPS243 process the I/Q data and output speed-magnitude data which is turned on with the SZ command.

image

Here's an example of the output from the speed processing turned on (SZ command). It's easy to see the club speed initially increasing due to the cosine error, peaking at the true speed, and then dropping off. The ball appears slightly past the peak club speed and carries on to the end. The graph is color coded by signal magnitude. This had 8 blocks of 128 samples captured prior to the speed trigger which you can see to the left. There's a lot of 0 data so a better setting is probably 4 blocks of 128 samples (S#4 API command).
image
OPSandy — 08:00
Here's a graph of the equivalent data I/Q plots. Note the scale on the left side, there is no saturation from the club which was a driver. The ball to sensor distance was 6 ft. We've tested with this distance at 5 ft. and see a lot more saturation from the club being so close to the sensor. We're testing adjustments to Tx power and other settings to see what is optimal for 5 ft. placement. We also test with the sensor angled slightly up from parallel from the ground (10 deg up) so that the ball spends more time as its going up in the sweet spot of the sensor field of view.

image

OPSandy — 08:09
Here's the I/Q and speed data for this shot if anyone wants to look at the details. Overall the ball was detected out to 18.3 ft. (5.6m). The last reported ball signal magnitude was 36 and dropping slowly so realistically if it wasn't for memory space cutting off the ball probably would have been detected 25-30 ft. (7.6-9.1m) out.
SJMuni_Shot25_Time1798_IQ_260908.txt
SJMuni_Shot25_Time1798_speed_260908.txt

So we would need this code to gate to >1.3.2 and hoepfully we will be able to point people to update it - also we need to update the AN-XXX documents included in our repo when the new ones are released and point people in the direction on how to update their boards.

@HuggeK

HuggeK commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

@JPMarhefka Also was succesfull upgrading mine to 1.3.2 - I got an SEGGER jlink EDU mini and for that the Jlink driver install process need to be run as adminstrator and the legacy jlink usb driver need to be ticked when installing that. Other than that it went well and verified with Putty.
image

HuggeK added a commit to HuggeK/openflight that referenced this pull request Sep 21, 2026
Put the deprecated K-LD7 parts and wiring and the filament-estimate paragraph in collapsible details blocks. Remove the DS3502 digital potentiometer, its Qwiic-to-Qwiic cable, its two cable-length rows and the chain sentence in the Qwiic-to-Dupont row: the internal trigger in PR open-flight#221 makes a software gain trim on the sound detector moot.

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
HuggeK added a commit to HuggeK/openflight that referenced this pull request Sep 21, 2026
Add the 200 mm Raspberry Pi display cable (SC1131) the Touch Display 2
needs in the openflight-enclosure v3 case, where the Pi and UPS mount to
the shell rather than the screen and the ~100 mm ribbon in the box does
not reach (openflight-enclosure#11).

Document power input on the v3 case: the shell has no USB-C opening, so
a USB-C supply is captive and a detachable supply is the DC route. Add
the no-solder parts for it (a pre-wired 5.5 x 2.1 mm panel jack, Tensility
10-03609 on Mouser or Amazon DC-099 kits; two Wago 221-412 for the XH
header option; the Adafruit 369 screw-terminal plug for the barrel option
into the X1202's own jack, with the plug dimensions), fed at 12 V because
the XH input is rated for about 3 A. Note that 5 A USB-C pass-throughs
are hard to find.

Give every Mouser ProductDetail link the ?qs= token from the shared
Mouser project, which is the form Mouser still resolves, add Amazon
options beside them, and move the Qwiic-to-Dupont row to the SparkFun
CAB-17261 the project carries.

Move every measured distance out of the product rows into the collapsible
cable-lengths section and replace the v2 table with runs measured on the
v3 STEP, including the display and camera ribbons, Ethernet, both DC jack
options and both button-hole options. Record that both rear holes in the
v3 shell are 12.5 mm, so the 16 mm Adafruit 1445 needs the CAD hole
opened or a 12 mm button.

Replace the v2 insert and screw table with a link to the enclosure
repository's Required hardware page, re-base the filament estimate on the
v3 print set from the STL mesh volumes (~750 g PETG, ~$17) inside a
collapsible block, and fold the deprecated K-LD7 section into one too.

Drop the DS3502 potentiometer and its cable, since the internal trigger
in PR open-flight#221 makes a software gain trim moot; drop the IARC case and the
X1206 input-range comparison; correct the internal-trigger firmware to
OPS243-A 1.3.2.

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
HuggeK added a commit to HuggeK/openflight that referenced this pull request Sep 21, 2026
Add the 200 mm Raspberry Pi display cable (SC1131) the Touch Display 2
needs in the openflight-enclosure v3 case, where the Pi and UPS mount to
the shell rather than the screen and the ~100 mm ribbon in the box does
not reach (openflight-enclosure#11).

Document power input on the v3 case: the shell has no USB-C opening, so
a USB-C supply is captive and a detachable supply is the DC route. Add
the no-solder parts for it (a pre-wired 5.5 x 2.1 mm panel jack, Tensility
10-03609 on Mouser or Amazon DC-099 kits; two Wago 221-412 for the XH
header option; the Adafruit 369 screw-terminal plug for the barrel option
into the X1202's own jack, with the plug dimensions), fed at 12 V because
the XH input is rated for about 3 A. Note that 5 A USB-C pass-throughs
are hard to find.

Give every Mouser ProductDetail link the ?qs= token from the shared
Mouser project, which is the form Mouser still resolves, add Amazon
options beside them, and move the Qwiic-to-Dupont row to the SparkFun
CAB-17261 the project carries.

Move every measured distance out of the product rows into the collapsible
cable-lengths section and replace the v2 table with runs measured on the
v3 STEP, including the display and camera ribbons, Ethernet, both DC jack
options and both button-hole options. Record that both rear holes in the
v3 shell are 12.5 mm, so the 16 mm Adafruit 1445 needs the CAD hole
opened or a 12 mm button.

Replace the v2 insert and screw table with a link to the enclosure
repository's Required hardware page, re-base the filament estimate on the
v3 print set from the STL mesh volumes (~750 g PETG, ~$17) inside a
collapsible block, and fold the deprecated K-LD7 section into one too.

Explain the PR open-flight#221 internal-trigger path next to the sound trigger: the
OPS243-A fires the capture itself on firmware 1.3.2, every unit can be
brought to that release, sensors shipping since September 2026 arrive
with it, and older ones are flashed over the J2 JTAG header with a SEGGER
J-Link and Infineon's XMCFlasher per AN-013 with the hex from OmniPreSense
support. Add the J-Link EDU Mini row (about $76) so the cost of that
choice sits next to the $18 detector.

Drop the DS3502 potentiometer and its cable, since the internal trigger
in PR open-flight#221 makes a software gain trim moot; drop the IARC case, the
X1206 input-range comparison and the cost-summary paragraph that itemised
the complete-build line; correct the internal-trigger firmware to
OPS243-A 1.3.2.

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
jewbetcha pushed a commit that referenced this pull request Sep 21, 2026
Spell out, next to the sound trigger, what the PR #221 internal trigger
changes and what it costs: the OPS243-A fires the rolling-buffer capture
itself on firmware 1.3.2, every OPS243-A can be brought to that release,
sensors shipping since OmniPreSense's September 2026 note arrive with it,
and older units are flashed over the J2 JTAG header with a SEGGER J-Link
and Infineon's XMCFlasher following AN-013, with the hex requested from
OmniPreSense support. Add a J-Link EDU Mini row (about $76, tokenised
Mouser link from the shared project, Amazon and Adafruit alternatives) so
that cost sits next to the $18 detector, and say the same in the Cost
Summary.

Drop the Cost Summary paragraph that itemised the complete-build line;
the table already carries it.

Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
jewbetcha added a commit that referenced this pull request Sep 21, 2026
docs(parts): explain the PR #221 internal-trigger firmware path
@HuggeK

HuggeK commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Will also add that I needed to fiddel with XMCflasher as the application is designed before javaFX was remove from the JDK - got it working with OpenJDK 27 + JavaFX 27 on windows 11 with the following:

**Flashing the OPS243 on Windows: two blockers that hit before XMCFlasher even opens**

I got the SEGGER + XMCFlasher path working on Windows 11 (JDK 27, J-Link V9.78). Neither blocker is an OPS243 problem, but both cost time, so noting them here for whoever writes the firmware-update doc.

1. XMCFlasher does not start on any Java newer than 8

XMCFlasher 1.1.0.202103021918 ships a JAR built against Java 1.8.0_162, and its launcher is a single line:

start /b javaw -jar %~dp0\xmcflasher.jar --gui

JavaFX stopped shipping inside the JDK at Java 11, so on any current JDK it dies before showing a window:

Exception in thread "main" java.lang.NoClassDefFoundError: javafx/application/Application
	at com.infineon.XMCFlasher.MainCommandLine.<clinit>(MainCommandLine.java:45)

Installing a JavaFX SDK and setting PATH_TO_FX does not fix this. The JVM never reads that variable — it is only a convention from OpenJFX's own getting-started commands. JavaFX has to be passed explicitly:

javaw --module-path "<javafx-sdk>\lib" --add-modules javafx.controls,javafx.fxml ^
      --enable-native-access=javafx.graphics,ALL-UNNAMED ^
      -jar "<install-dir>\XMCFlasher.jar" --gui

Verified working with OpenJDK 21 + JavaFX 21.0.7 and OpenJDK 27 + JavaFX 27. The app only uses javafx.controls and javafx.fxml and no com.sun.javafx internals, so no --add-exports hacks are needed.

Why --enable-native-access, and making the Start Menu shortcut use the new launcher

--enable-native-access=javafx.graphics,ALL-UNNAMED is only needed on JDK 24+. Without it, JDK 24 and later print JEP 472 restricted-method warnings when JavaFX and BridJ load their native libraries. Those warnings are scheduled to become hard errors in a future JDK, so the flag is worth setting now.

The Start Menu shortcut does not run the .bat directly. It runs resources\launch-tool.exe, which reads the "path" field out of resources\tool-details.json and launches whatever is named there. So a fixed launcher only takes effect for the registered app once that JSON points at it:

"path": "C:\Infineon\Tools\XMCFlasher\1.1.0.202103021918\/XMCFlasher-javafx.bat"

I left the vendor XMCFlasher.bat untouched and added a second launcher beside it that prefers JAVA_HOME and PATH_TO_FX when set, falls back to hardcoded paths, and fails with a readable message instead of a stack trace when either path is wrong. Note that an Infineon Developer Center update of the tool will overwrite that JSON.

2. The J-Link USB driver is not installed by default

With the probe plugged in, XMCFlasher said to check that an emulator is connected, and Device Manager showed the probe with error code 28, "drivers for this device are not installed". The J-Link software pack itself was installed fine — XMCFlasher loaded JLink_x64.dll V9.78 without complaint. What was missing was the USB driver binding the probe to that DLL.

The fix is to rerun the SEGGER J-Link installer and tick "Install legacy USB Driver for J-Link", which is unticked by default.

Why the legacy driver, and how to verify the probe before opening XMCFlasher

SEGGER probes enumerate in one of two modes. In WinUSB mode they use USB product ids 1020 and up, and Windows binds its own driver with no SEGGER package needed. In the older mode they enumerate as 1366:0101, which only JLink.inf (the legacy package) claims. The installer leaves the box unticked because current probes ship in WinUSB mode, so a probe sitting in the older mode ends up with no driver at all.

Quickest check, before launching XMCFlasher:

"C:\Program Files\SEGGER\JLink_V978\JLink.exe"
J-Link> ShowEmuList

An empty list means the driver is missing, no matter what the install folder contains. After the legacy driver is installed and the probe is replugged, it lists the probe's serial number. pnputil /enum-drivers | findstr /i SEGGER is the same check from the driver-store side.

Optionally, once the probe works, J-Link Configurator can switch it to WinUSB mode permanently so the legacy driver is never needed again, which helps if you flash from more than one PC.

Relevance to this PR

With both of these cleared, flashing is unblocked on Windows. Worth remembering that the gate in validate_internal_trigger_firmware() is still exact-equality against 1.3.1, so a board updated to the 1.3.2 that OmniPreSense now ships gets refused with:

RuntimeError: Internal hardware trigger requires OPS243 firmware v1.3.1; detected v1.3.2.

Also useful: run ?P before flashing to confirm whether the board is XMC4500 or XMC4700, since XMCFlasher needs the right device selected. Any serial terminal works for that — PuTTY in Serial mode needs local echo forced on and local line editing forced off, since the OPS243 acts on two-character commands with no Enter.

I ran to get up putty setup:
"C:\Program Files\PuTTY\putty.exe" -serial COM5 -sercfg 57600,8,n,1,N
switching out COM5 to COM3 for my board. Check your Device Manager under COM ports what your board is connected as. And then just ran command ?V to get the version from the OPS as displayed above.

I have a tech issue with Infineon if they can fix their XMCFlasher tool so no need to do this hoolahops.

@JPMarhefka

Copy link
Copy Markdown
Contributor Author

Will also add that I needed to fiddel with XMCflasher as the application is designed before javaFX was remove from the JDK - got it working with OpenJDK 27 + JavaFX 27 on windows 11 with the following:

Flashing the OPS243 on Windows: two blockers that hit before XMCFlasher even opens

I'm working on fixing the hardware trigger with the current OpenFlight codebase and OPS 1.3.2. There was a slight regression, but it should be finished soon. Thanks for putting together the docs for this!

SamLeft222 added a commit to SamLeft222/openflight that referenced this pull request Sep 26, 2026
…ight#221)

Brings open-flight/openflight PR open-flight#221 (head 73eacc7) onto this branch as
one change: --trigger hardware lets the OPS243-A start its rolling-buffer
dump from its own speed trigger (ST/SM, 6 pre-trigger segments), so no
sound detector is needed. Requires OPS243-A firmware 1.3.2+, checked at
startup. Conflicts resolved by keeping this branch's orphaned-dump
handling alongside the PR's re-arm recovery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@HuggeK

HuggeK commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

Just dropping it here that Cormac and Jamorro is working on updating the firmware on the IWR to make it better and we could trigger the OPS through software via the pi on a detector on the IWr - also could be a way forward to deprecate the sound trigger. More discussion took place in the discord friday and saturday. I summarized it: https://discord.com/channels/1512485363875057674/1553678130537832499 (which would not require for people with both OPS and IWR to find a way to flash their OPS´s to 1.3.2)

@HuggeK

HuggeK commented Oct 10, 2026

Copy link
Copy Markdown
Collaborator

From OPSandy 2026-10-02 05:55:

We're moving forward with this and will implement both the hardware signal and a message upon speed trigger detected. The trigger signal will stay high from speed trigger detected to completion of the rolling buffer sampling. With this, if you wanted to sync camera video directly to the sampled data, you have some markers such as start of the sampling at trigger and make an adjustment for the S#n setting and then end of sampling. We will have this in a new v1.3.3 which we'll be testing over the coming couple weeks.

jewbetcha and others added 2 commits October 10, 2026 18:21
Resolve conflicts:
- docs/get-started/parts.md: keep main's "why this is worth wanting" note
  and expanded OmniPreSense contact details, with the PR's post-merge
  framing ("1.3.2 or newer in the 1.3 train", --trigger hardware usage).
  Drop the "mode is still unmerged" clause, which this PR makes stale.
- tests/test_server.py, tests/test_start_kiosk.py: keep both sides'
  newly added tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On OPS243-A firmware 1.3.2 the board drops to idle power mode after an
internal-trigger dump, with every detector setting intact. Re-arming with
GC reset those settings, and motion during the ~2.5 s rebuild could fire
the trigger: either in the unguarded gap right after GC, or just after the
live ST threshold was restored. The rebuild's command replies and
reset_input_buffer calls then consumed that dump, the wait loop never saw
a capture marker, and the board sat idle with nothing left to re-arm it
(blue LED stuck on). Reproduced on hardware by waving rapidly past the
radar; it stuck after 1-3 triggers.

- Re-arm with PA only: drain the finished dump, then resume sampling.
  Re-arm drops from ~2.5 s to ~0.4 s and has no unguarded window.
- Never clear serial input once the board is live, after the startup arm
  or a re-arm. wait_for_hardware_trigger gains discard_pending_input;
  the hardware strategy passes False. Pre-marker output is skipped anyway.
- Backstop: with detect_orphaned_dump, a Q array that arrives before any
  capture marker is reported as an orphaned dump, and the strategy
  re-arms the idle board and records an "orphaned_dump" diagnostic.
  The sound path keeps its existing behaviour (both options opt-in).
- Fix the truncated Raspberry Pi retest checklist in the docs and add a
  rapid-motion re-arm check.

Verified on a v1.3.2 OPS243-A over UART: 12/12 PA re-arms under
continuous motion in a driver loop, then 9/9 dumps re-armed through the
server with zero stuck states, orphans, or re-arm failures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jewbetcha

Copy link
Copy Markdown
Member

@JPMarhefka I merged current main into this branch to clear the conflicts and pushed a re-arm fix on top. Here's why the re-arm changed.

Bug (firmware 1.3.2): after an internal-trigger dump, the board drops to PowerMode: Idle or Pulse and keeps all its detector settings. The GC re-arm reset those settings and rebuilt them over about 2.5 s. Motion during that rebuild fired the trigger, either in the gap right after GC or just after ST-25 was restored. The rebuild's _send_command replies and reset_input_buffer calls then swallowed that dump, the wait loop never saw a capture marker, and the board stayed idle with nothing to re-arm it (blue LED stuck on). Waving rapidly past the radar reproduced it after 1–3 triggers.

Fix (c4715a4):

  • Re-arm is now PA only, after draining the finished dump. I checked with ?? that the settings survive a dump on 1.3.2. This reverses the old "no PA" assertion in the tests. I assume that choice came from 1.3.1, which the driver now rejects; tell me if there was another reason.
  • Serial input is never cleared once the board is live.
  • Backstop: a Q array that arrives before any capture marker is treated as an orphaned dump, and the board is re-armed.
  • Both new wait_for_hardware_trigger options are opt-in, so the sound path is unchanged.

Hardware results on a v1.3.2 OPS243-A over UART: 12/12 PA re-arms under continuous motion in a driver loop, then 9/9 through the server with no stuck states. The PR description now has the details. I also fixed the truncated Raspberry Pi retest checklist in docs/hardware-trigger.md.

🤖 Generated with Claude Code

main added a cost note linking to "#internal-trigger-instead-pr-221", but
this PR renames that heading to "Internal Hardware Trigger", so the strict
docs build failed on a missing anchor. Point the link at
#internal-hardware-trigger and drop the "if PR open-flight#221 lands" framing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jewbetcha
jewbetcha merged commit 8d681d0 into open-flight:main Oct 11, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants