MZTC thermal camera integration — merge conflicts resolved against maintenance-10.x (supersedes PR #11005) - #11837
Conversation
Signed-off-by: William Dunn <wdunn001@gmail.com>
…r Dependency, Remove Duplicate OSD Header, Add Safe Reconnection API
Signed-off-by: William Dunn <wdunn001@gmail.com>
Signed-off-by: wdunn001 <your-email@example.com>
…ht#11005 # Conflicts: # .gitignore # src/main/CMakeLists.txt # src/main/config/parameter_group_ids.h # src/main/fc/cli.c # src/main/fc/fc_msp.c
The PR added /src/main/target and assorted CMake/CLion build artifacts (CMakeFiles, Makefile, CMakeCache.txt, eeprom.bin, inav_9.0.0_SITL) to .gitignore. /src/main/target would hide all future target boards from git status (962 files tracked there), and the rest are artifacts of a different project's build layout. maintenance-10.x already covers build output dirs (/build_*/, /build-*/, /build_hw/, build_sitl/), so the base version is correct on its own.
The 1.78 MB compiled firmware image was committed in the feature PR
("adding presets and updating docs") and is referenced nowhere in the
repo. Compiled binaries do not belong in the source tree.
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
The settings_md CI check failed: the committed docs/Settings.md was generated against an older settings.yaml (author's branch, March) and didn't match the generator output for the merged settings (enum tables now use the "Allowed Values" format). Regenerated with src/utils/update_cli_docs.py; verified stable (re-running produces no further changes).
PR Summary by QodoIntegrate MassZero thermal camera support with flash-safe gating
AI Description
Diagram
High-Level Assessment
Files changed (26)
|
Code Review by Qodo
1.
|
|
RAM / Flash usage vs. base branch — commit
See RAM/flash optimization guide for techniques to reduce usage. |
|
Test firmware build ready — commit Download firmware for PR #11837 247 targets built. Find your board's
|
MCU_FLASH_SIZE is defined per-MCU in cmake and, for SITL, only in src/main/target/SITL/target.h — which platform.h includes AFTER target/common.h. At the gate, SITL's MCU_FLASH_SIZE was therefore undefined (0 > 512 = false), silently compiling out USE_MZTC and the feature's SITL tooling (mztc_simulate CLI, thermal_bridge.py, simulated frame path). SITL has no flash constraint, so include SITL_BUILD (set by cmake/sitl.cmake) in the gate.
Review notes from the merge-resolution passFirst — thank you for the MZTC feature; the integration is substantial and the merge onto current A few notes came out of a close look at the merged result. I took a look at this with an AI-based tool I have — it may well be wrong on any of the points below, so please treat them as questions to check rather than a verdict, and correct me if I've misread something: Questions for the author1. MSP2 command IDs — do the 0x3000/0x3001 values collide with the Betaflight-compat range? 2. MSP2_MZTC_FRAME_DATA — could it be returning uninitialized stack data? 3. OSD module — is it scaffolding for a follow-up, or should it be wired up? 4. Serial framing — could the packet length math be off by one? 5. MSP2_SET_MZTC_CONFIG — should it validate ranges like the CLI settings do? 6. Dead code — mztc_camera_cli.c, msp_mztc.c, and the unit test?
7. Defaults — do the C reset template and settings.yaml agree? 8. Smaller items (for awareness):
What the merge itself changed (for transparency)For anyone reviewing: the merge-resolution commits did not alter the feature's behavior — they (1) merged |
Enabling the feature in SITL (previous commit) surfaced two latent issues in the feature code that only manifest when USE_MZTC is actually compiled in: - mztc_camera.c used fprintf(stderr, ...) via the SD() macro without including <stdio.h> (6 'stderr undeclared' compile errors). - mztc_camera_osd.c declared mztcOsdConfig via PG_DECLARE and used PG_MZTC_OSD_CONFIG (1047) but never registered the parameter group (undefined reference to mztcOsdConfig_System at link time). Added PG_REGISTER_WITH_RESET_TEMPLATE + PG_RESET_TEMPLATE following the mztcConfig pattern, with the MZTC_OSD_DEFAULT_* defines moved above the template so the macros resolve. SITL now compiles and links with the camera code active (verified via fresh cmake -DSITL=ON + make SITL build).
|
Update on the two build-blockers — resolved in the merge so SITL CI is green: Enabling the feature in SITL (the gate fix) surfaced two latent issues in
These are the author's code, completed minimally to make the feature build — Everything else from the earlier comment (MSP2 ID range, frame-data stub, |
…camera manual Answers all eight Qodo findings and all eight questions from the review comment on iNavFlight#11837, then corrects the driver against the BJ core serial protocol manual that ships with the camera. Serial protocol The old sender wrote a variable-length prefix of a fixed-layout struct. The checksum and the 0xFF terminator sat past that prefix. Neither was ever transmitted and uninitialized bytes went out in their place. The size field was payload+8 where the protocol says payload+4. For a full payload the computed length ran past the end of the struct. The packet is now built contiguously and matches the manual's own worked example byte for byte: brightness 100 is F0 05 36 78 02 00 64 14 FF. The receive parser is length driven. A 0xF0 or 0xFF byte inside a payload can no longer split or truncate a packet. Responses are decoded by class and subclass with per-payload length checks. Corrections from the camera manual Auto shutter values were off by one. The camera takes 0x01 temperature only, 0x02 time only and 0x03 time and temperature. It answers 0x00 with a threshold error. The driver sent the zero-based setting straight through. The default sent an out of range value. The shutter interval belongs to the camera. 0x7C/0x05 takes two bytes of minutes and the camera runs the schedule from it. The driver never sent that command and ran a competing host-side timer instead. The interval is pushed on connect now. mztc_ffc_interval accepts 1 to 60. TEMP_ONLY is how time-driven correction is turned off. The initialization status reply arrives on class 0x7D subclass 0x06. The host asks on 0x7C/0x14. The decoder matched the request address and never fired. Connection state Opening the UART no longer counts as a connected camera. The driver probes for the device model and reports connected once the camera answers. An established link that stops answering for three seconds is closed and retried. connection_quality is the share of recent probes answered. It was hardcoded to 100. The configuration burst moved out of the serial receive interrupt. Removed surfaces The camera exposes a UART for control and a composite video output for the picture. It has no digital data interface. Its manual defines 26 class and subclass pairs. None of them read a frame or a temperature. 0x78/0x01 appears only in the manual's invalid-subclass error example. 0x74/0x0C reads the ISP parameter version number. Frame data is removed. mztcFrameData_t, mztcGetFrameData(), MSP2_MZTC_FRAME_DATA, the undocumented 0x78/0x30 request and the rand() based simulator are all gone, along with frame_count and last_frame_time. Temperature is removed. camera_temperature, ambient_temperature, mztc_temperature_unit, mztc_temperature_alerts, mztc_alert_high_temp, mztc_alert_low_temp and MSP2_SET_MZTC_ALERTS are gone. Three settings were stored and validated but never transmitted. They did nothing. mztc_bad_pixel_removal drove an interactive on-screen cursor that a flight controller cannot walk. mztc_vignetting_correction is a one-shot action at 0x7C/0x0C that needs the lens on a uniform surface first. It becomes the mztc_vignetting command and MSP2_SET_MZTC_VIGNETTING. mztc_crosshair_enabled had no camera command at all. MSP The commands move out of 0x3000, where MSP2_BETAFLIGHT_BIND and MSP2_RX_BIND already live, into a contiguous block from 0x2240 to 0x2249. The identifiers nothing handled are dropped along with the duplicate aliases. Every field is serialized with sbufRead and sbufWrite. No struct is cast over the stream buffer. Padding and alignment stay off the wire. The config payload is 15 bytes and the status payload 7. SET_MZTC_CONFIG validates the whole request before applying any of it. An update_rate of zero was a reachable divide-by-zero in the camera task and an unbounded baudrate indexed past baudRates[]. OSD The module formatted strings and drew nothing. OSD_MZTC_STATUS replaces it as a real element driven by INAV's own layout and render pipeline. That grows OSD_ITEM_COUNT. Adding items moves the per-layout offsets in osdLayoutsConfig. PG_OSD_LAYOUTS_CONFIG therefore goes to version 4. Dead code mztc_camera_cli.c was not in CMakeLists, was never initialized and called APIs that do not exist. msp_mztc.c had a dispatch that was never invoked. Both are removed. msp_mztc.h stays for the command IDs and the payload layouts. mztc_shutter was identical to mztc_calibrate and mztc_simulate faked link liveness. mztc_save and mztc_defaults are added so the camera flash commands are reachable. Configuration The reset template is driven from the SETTING_*_DEFAULT macros. The fresh-EEPROM defaults and the CLI defaults cannot diverge. That settles the baudrate at 115200 and the mode at STANDBY. The limits live in the settings.yaml constants block. Compile-time assertions check that the C limits still match. A value the CLI rejects cannot be accepted over MSP. last_calibration widens to uint16 after wrapping at about 4.25 hours. The PG version goes to 1 because the PR test builds are already out. Tests The unit test properties were applied after the loop that creates every target. USE_MZTC never reached the compiler. The whole test body was preprocessed away. They move ahead of the loop. The tautological assertions are replaced with 40 tests across three suites. They cover the wire format against the hardware capture, the configuration validator, and the receive path driven through the serial callback. The receive tests exercise framing resynchronisation, payloads containing framing markers, checksum rejection, response dispatch, and the exact bytes the configuration burst puts on the wire. Five mutations confirmed the tests fail when each fixed bug is reintroduced. Docs The feature doc is rewritten around commands that exist. Its preset, camera management, video input and OSD settings were never implemented. docs/Settings.md is regenerated. The MSP messages are added by hand to msp_messages.json per docs/development/msp/README.md, with the MSP docs regenerated. Validated on three builds. SPEEDYBEEF405AIO with MZTC on, MATEKF722SE with MZTC off, and SITL. All three compile with no warnings in any MZTC file. 556 of 556 unit tests pass.
Follows the firmware changes in iNavFlight/inav#11837. MSP codes The commands move from 0x3000 into INAV's own range and now sit contiguously from 0x2240 to 0x2249. 0x3000 and 0x3001 are MSP2_BETAFLIGHT_BIND and MSP2_RX_BIND. The old block collided with them. The codes nothing implemented are dropped. CALIBRATE, INIT_STATUS, SAVE_CONFIG, RESTORE_DEFAULTS and RECONNECT had no firmware handler. MSP2_SET_MZTC_VIGNETTING is added. Payloads MSP2_MZTC_CONFIG is a fixed 15 byte payload read one field at a time. The old parser assumed an unpadded C struct and read the thresholds at offsets 17 and 21. The firmware struct had alignment padding there. Both offsets were wrong on the wire in both directions. The send path no longer writes float32. MSP2_MZTC_STATUS is a fixed 7 byte payload and is parsed at all now. It was never handled. connected is a real field, set only after the camera answers a command. Removed fields The five RC channel fields were never in the payload. The temperature fields, the frame fields, bad pixel removal, vignetting correction and the crosshair flag are gone from the firmware. The camera reports no temperature and no frame over its serial protocol. The other three were stored but never transmitted. Serial port index mztc_port is the zero-based serialPortIdentifier_e value that the firmware hands to openSerialPort(). Three places added 1 to it and special-cased UART6. That pointed the driver at the wrong UART. OSD The ten elements at invented ids 200 to 209 are replaced with the one the firmware provides, MZTC_STATUS at id 171. The old entries were gated on FC.FEATURES.MZTC. That does not exist. A localization string is added for the name. State FC.MZTC_CONFIG and FC.MZTC_STATUS are declared in fc.js resetState like every other FC block. MZTC_CONFIG was previously created ad-hoc by the MSP handler. Localization The MassZero block had been inserted into messages.json twice. All 17 keys were duplicated. JSON keeps the last definition, leaving the earlier copy as dead weight. The earlier copy is removed along with the strings for the settings that no longer exist. The operating mode help text described frame capture modes the firmware does not have. Dependency electron-prebuilt-compile is reverted along with the 13385 lines of package-lock churn it pulled in. Nothing in the tree references it.
…camera manual Answers all eight Qodo findings and all eight questions from the review comment on iNavFlight#11837, then corrects the driver against the BJ core serial protocol manual that ships with the camera. Serial protocol The old sender wrote a variable-length prefix of a fixed-layout struct. The checksum and the 0xFF terminator sat past that prefix. Neither was ever transmitted and uninitialized bytes went out in their place. The size field was payload+8 where the protocol says payload+4. For a full payload the computed length ran past the end of the struct. The packet is now built contiguously and matches the manual's own worked example byte for byte: brightness 100 is F0 05 36 78 02 00 64 14 FF. The receive parser is length driven. A 0xF0 or 0xFF byte inside a payload can no longer split or truncate a packet. Responses are decoded by class and subclass with per-payload length checks. Corrections from the camera manual Auto shutter values were off by one. The camera takes 0x01 temperature only, 0x02 time only and 0x03 time and temperature. It answers 0x00 with a threshold error. The driver sent the zero-based setting straight through. The default sent an out of range value. The shutter interval belongs to the camera. 0x7C/0x05 takes two bytes of minutes and the camera runs the schedule from it. The driver never sent that command and ran a competing host-side timer instead. The interval is pushed on connect now. mztc_ffc_interval accepts 1 to 60. TEMP_ONLY is how time-driven correction is turned off. The initialization status reply arrives on class 0x7D subclass 0x06. The host asks on 0x7C/0x14. The decoder matched the request address and never fired. Connection state Opening the UART no longer counts as a connected camera. The driver probes for the device model and reports connected once the camera answers. An established link that stops answering for three seconds is closed and retried. connection_quality is the share of recent probes answered. It was hardcoded to 100. The configuration burst moved out of the serial receive interrupt. Removed surfaces The camera exposes a UART for control and a composite video output for the picture. It has no digital data interface. Its manual defines 26 class and subclass pairs. None of them read a frame or a temperature. 0x78/0x01 appears only in the manual's invalid-subclass error example. 0x74/0x0C reads the ISP parameter version number. Frame data is removed. mztcFrameData_t, mztcGetFrameData(), MSP2_MZTC_FRAME_DATA, the undocumented 0x78/0x30 request and the rand() based simulator are all gone, along with frame_count and last_frame_time. Temperature is removed. camera_temperature, ambient_temperature, mztc_temperature_unit, mztc_temperature_alerts, mztc_alert_high_temp, mztc_alert_low_temp and MSP2_SET_MZTC_ALERTS are gone. The port and its baud rate now come from the Ports tab through findSerialPortConfig(FUNCTION_MZTC_CAMERA), the way every other serial peripheral in INAV works. Assigning the function is what enables the camera. mztc_enabled, mztc_port and mztc_baudrate are all gone. That removes the class of bug where the setting and the Ports tab could disagree about which UART the camera is on. Three further settings were stored and validated but never transmitted. They did nothing. mztc_bad_pixel_removal drove an interactive on-screen cursor that a flight controller cannot walk. mztc_vignetting_correction is a one-shot action at 0x7C/0x0C that needs the lens on a uniform surface first. It becomes the mztc_vignetting command and MSP2_SET_MZTC_VIGNETTING. mztc_crosshair_enabled had no camera command at all. MSP The commands move out of 0x3000, where MSP2_BETAFLIGHT_BIND and MSP2_RX_BIND already live, into a contiguous block from 0x2240 to 0x2249. The identifiers nothing handled are dropped along with the duplicate aliases. Every field is serialized with sbufRead and sbufWrite. No struct is cast over the stream buffer. Padding and alignment stay off the wire. The config payload is 12 bytes and the status payload 7. SET_MZTC_CONFIG validates the whole request before applying any of it. An update_rate of zero was a reachable divide-by-zero in the camera task and an unbounded baudrate indexed past baudRates[]. OSD The module formatted strings and drew nothing. OSD_MZTC_STATUS replaces it as a real element driven by INAV's own layout and render pipeline. That grows OSD_ITEM_COUNT. Adding items moves the per-layout offsets in osdLayoutsConfig. PG_OSD_LAYOUTS_CONFIG therefore goes to version 4. Dead code mztc_camera_cli.c was not in CMakeLists, was never initialized and called APIs that do not exist. msp_mztc.c had a dispatch that was never invoked. Both are removed. msp_mztc.h stays for the command IDs and the payload layouts. mztc_shutter was identical to mztc_calibrate and mztc_simulate faked link liveness. mztc_save and mztc_defaults are added so the camera flash commands are reachable. Configuration The reset template is driven from the SETTING_*_DEFAULT macros. The fresh-EEPROM defaults and the CLI defaults cannot diverge. That settles the baudrate at 115200 and the mode at STANDBY. The limits live in the settings.yaml constants block. Compile-time assertions check that the C limits still match. A value the CLI rejects cannot be accepted over MSP. last_calibration widens to uint16 after wrapping at about 4.25 hours. The PG version goes to 1 because the PR test builds are already out. Tests The unit test properties were applied after the loop that creates every target. USE_MZTC never reached the compiler. The whole test body was preprocessed away. They move ahead of the loop. The tautological assertions are replaced with 38 tests across three suites. They cover the wire format against the hardware capture, the configuration validator, and the receive path driven through the serial callback. The receive tests exercise framing resynchronisation, payloads containing framing markers, checksum rejection, response dispatch, and the exact bytes the configuration burst puts on the wire. Five mutations confirmed the tests fail when each fixed bug is reintroduced. Docs The feature doc is rewritten around commands that exist. Its preset, camera management, video input and OSD settings were never implemented. docs/Settings.md is regenerated. The MSP messages are added by hand to msp_messages.json per docs/development/msp/README.md, with the MSP docs regenerated. Validated on three builds. SPEEDYBEEF405AIO with MZTC on, MATEKF722SE with MZTC off, and SITL. All three compile with no warnings in any MZTC file. 554 of 554 unit tests pass.
…camera manual Answers all eight Qodo findings and all eight questions from the review comment on iNavFlight#11837, then corrects the driver against the BJ core serial protocol manual that ships with the camera. Serial protocol The old sender wrote a variable-length prefix of a fixed-layout struct. The checksum and the 0xFF terminator sat past that prefix. Neither was ever transmitted and uninitialized bytes went out in their place. The size field was payload+8 where the protocol says payload+4. For a full payload the computed length ran past the end of the struct. The packet is now built contiguously and matches the manual's own worked example byte for byte: brightness 100 is F0 05 36 78 02 00 64 14 FF. The receive parser is length driven. A 0xF0 or 0xFF byte inside a payload can no longer split or truncate a packet. Responses are decoded by class and subclass with per-payload length checks. Corrections from the camera manual Auto shutter values were off by one. The camera takes 0x01 temperature only, 0x02 time only and 0x03 time and temperature. It answers 0x00 with a threshold error. The driver sent the zero-based setting straight through. The default sent an out of range value. The shutter interval belongs to the camera. 0x7C/0x05 takes two bytes of minutes and the camera runs the schedule from it. The driver never sent that command and ran a competing host-side timer instead. The interval is pushed on connect now. mztc_ffc_interval accepts 1 to 60. TEMP_ONLY is how time-driven correction is turned off. The initialization status reply arrives on class 0x7D subclass 0x06. The host asks on 0x7C/0x14. The decoder matched the request address and never fired. Connection state Opening the UART no longer counts as a connected camera. The driver probes for the device model and reports connected once the camera answers. An established link that stops answering for three seconds is closed and retried. connection_quality is the share of recent probes answered. It was hardcoded to 100. The configuration burst moved out of the serial receive interrupt. Removed surfaces The camera exposes a UART for control and a composite video output for the picture. It has no digital data interface. Its manual defines 26 class and subclass pairs. None of them read a frame or a temperature. 0x78/0x01 appears only in the manual's invalid-subclass error example. 0x74/0x0C reads the ISP parameter version number. Frame data is removed. mztcFrameData_t, mztcGetFrameData(), MSP2_MZTC_FRAME_DATA, the undocumented 0x78/0x30 request and the rand() based simulator are all gone, along with frame_count and last_frame_time. Temperature is removed. camera_temperature, ambient_temperature, mztc_temperature_unit, mztc_temperature_alerts, mztc_alert_high_temp, mztc_alert_low_temp and MSP2_SET_MZTC_ALERTS are gone. The port and its baud rate now come from the Ports tab through findSerialPortConfig(FUNCTION_MZTC_CAMERA), the way every other serial peripheral in INAV works. Assigning the function is what enables the camera. mztc_enabled, mztc_port and mztc_baudrate are all gone. That removes the class of bug where the setting and the Ports tab could disagree about which UART the camera is on. Three further settings were stored and validated but never transmitted. They did nothing. mztc_bad_pixel_removal drove an interactive on-screen cursor that a flight controller cannot walk. mztc_vignetting_correction is a one-shot action at 0x7C/0x0C that needs the lens on a uniform surface first. It becomes the mztc_vignetting command and MSP2_SET_MZTC_VIGNETTING. mztc_crosshair_enabled had no camera command at all. MSP The commands move out of 0x3000, where MSP2_BETAFLIGHT_BIND and MSP2_RX_BIND already live, into a contiguous block from 0x2240 to 0x2249. The identifiers nothing handled are dropped along with the duplicate aliases. Every field is serialized with sbufRead and sbufWrite. No struct is cast over the stream buffer. Padding and alignment stay off the wire. The config payload is 12 bytes and the status payload 7. SET_MZTC_CONFIG validates the whole request before applying any of it. An update_rate of zero was a reachable divide-by-zero in the camera task and an unbounded baudrate indexed past baudRates[]. OSD The module formatted strings and drew nothing. OSD_MZTC_STATUS replaces it as a real element driven by INAV's own layout and render pipeline. That grows OSD_ITEM_COUNT. Adding items moves the per-layout offsets in osdLayoutsConfig. PG_OSD_LAYOUTS_CONFIG therefore goes to version 4. Dead code mztc_camera_cli.c was not in CMakeLists, was never initialized and called APIs that do not exist. msp_mztc.c had a dispatch that was never invoked. Both are removed. msp_mztc.h stays for the command IDs and the payload layouts. mztc_shutter was identical to mztc_calibrate and mztc_simulate faked link liveness. mztc_save and mztc_defaults are added so the camera flash commands are reachable. Configuration The reset template is driven from the SETTING_*_DEFAULT macros. The fresh-EEPROM defaults and the CLI defaults cannot diverge. That settles the baudrate at 115200 and the mode at STANDBY. The limits live in the settings.yaml constants block. Compile-time assertions check that the C limits still match. A value the CLI rejects cannot be accepted over MSP. last_calibration widens to uint16 after wrapping at about 4.25 hours. The PG version goes to 1 because the PR test builds are already out. Tests The unit test properties were applied after the loop that creates every target. USE_MZTC never reached the compiler. The whole test body was preprocessed away. They move ahead of the loop. The tautological assertions are replaced with 38 tests across three suites. They cover the wire format against the hardware capture, the configuration validator, and the receive path driven through the serial callback. The receive tests exercise framing resynchronisation, payloads containing framing markers, checksum rejection, response dispatch, and the exact bytes the configuration burst puts on the wire. Five mutations confirmed the tests fail when each fixed bug is reintroduced. Docs The feature doc is rewritten around commands that exist. Its preset, camera management, video input and OSD settings were never implemented. docs/Settings.md is regenerated. The MSP messages are added by hand to msp_messages.json per docs/development/msp/README.md, with the MSP docs regenerated. Validated on three builds. SPEEDYBEEF405AIO with MZTC on, MATEKF722SE with MZTC off, and SITL. All three compile with no warnings in any MZTC file. 554 of 554 unit tests pass.
mztc_mode offered eight values and none of them did anything. Every use across the tree was a range check, a stored value or a status echo. No mode was ever sent to the camera. The camera protocol has no matching command. Its ALERT value needed a scene temperature that this core does not report. It is replaced by mztc_preset, a named bundle of the image settings the camera does have. Selecting one writes the palette, brightness, contrast, digital enhancement, both denoise levels, the shutter mode and the correction interval. CUSTOM is the default and writes nothing. A hand-tuned configuration therefore survives. Zoom and mirror are never written. Zoom belongs to the pilot and mirror describes how the camera is mounted. Two constraints shape the values. Temporal denoising averages across frames. On a moving airframe it therefore smears targets and leaves trails. Spatial denoising trades noise for sharpness. A person at search range is a few pixels wide. Both stay low except in SURVEILLANCE, where loiter leaves little motion to smear. mztc_update_rate is removed. It did not control serial traffic. The probe has its own 500 ms gate. Its range allowed 30 Hz on a task that runs at 10 Hz. Its description named a frame rate for frame data that was removed earlier. The MSP config payload drops from 12 bytes to 11 and MSP2_SET_MZTC_MODE becomes MSP2_SET_MZTC_PRESET. The parameter group version goes to 2. Removing two fields and adding one shifts every offset. An older record read at the new offsets would apply garbage to real camera settings. The CLI gains mztc_preset. It lists the presets when called with no argument. mztc_reconnect moves into the alphabetical block. mztc_config states its 0-100 range. Tests go from 38 to 41. The new ones pin that every preset produces a valid configuration, that CUSTOM writes nothing, and that a preset leaves zoom and mirror alone. A fourth pins that CUSTOM does not repair an already invalid configuration. That is a real consequence of writing nothing. The feature doc is rewritten around presets. Two errors in its previous application setups are corrected. Search and rescue used a temporal denoise of 70. That smears the small target it is meant to find. Industrial inspection claimed absolute temperature accuracy from a camera that reports no temperature. The MSP payload size in that doc was stale at 15 bytes. Verified on 247 of 247 targets with warnings as errors, 557 of 557 unit tests, and a cross-artifact audit of the header against settings.yaml, the MSP header, fc_msp.c wire order, msp_messages.json, both generated docs and the CLI.
THERMAL CALIBRATE is a box mode that runs one flat field correction on the rising edge of the switch. Holding it does not repeat the correction. The box is only offered when the camera has a UART assigned in the Ports tab. That is the same rule the Configuration and OSD tabs use. Firing it is safe in any attitude. The correction uses the camera's own internal shutter as the reference. The sensor cannot see the scene while it runs. The camera already performs the same correction on its own timer. Vignetting correction deliberately stays a CLI command. It has no protective shutter and captures whatever the lens faces. The camera manual states that the lens must face a uniform surface first. Otherwise the current scene is superimposed on every later image. Manual background correction and the bad pixel commands are not implemented for the same reason. MZTC_ZOOM is adjustment function 61. It steps the digital zoom through 1x, 2x, 4x and 8x. It goes through mztcSetZoom. That writes the camera and stores the level together. The switch position and the saved setting therefore still agree after a reconnect. It logs a blackbox inflight adjustment event like every other adjustment in that file. Both appear in the configurator Modes tab with no configurator change. That tab builds from MSP_BOXIDS and the firmware box list. The adjustment table in Inflight Adjustments.md was stale at 58 while the enum already reached 60. The two missing upstream entries are added alongside the new one.
mztc_preset could be written two ways with different results. The mztc_preset CLI command and MSP2_SET_MZTC_PRESET called mztcSetPreset. That writes the eight owned values. Writing the field through the settings framework, as "set mztc_preset = SEARCH" does, stored a byte and applied nothing. The setting then named a preset whose values were not in effect. That is the defect the old mode enum had. A control that reads as doing something has to do it. The driver now tracks which preset the stored values reflect and applies any change it sees. Every route agrees: the CLI command, the CLI set, the configurator dropdown and MSP2_SET_MZTC_PRESET. Boot deliberately does not reapply. mztcInit seeds the tracking value from the saved preset. The saved field values already reflect it. Reapplying at boot would discard tuning done after the preset was chosen. Three tests added, one of which found a gap in the existing suite. IS_RC_MODE_ACTIVE was never stubbed. The calibrate switch added in the previous commit therefore had no unit coverage at all. It has coverage now, including that it fires once per flip and not on every task tick while held. Each test was mutation checked. Removing the apply-on-change, seeding the tracking value wrongly at boot, and turning the switch from edge to level triggered each fail exactly one test. The boot test failed its first mutation check by passing when it should not have. mztcInit returns early while the driver is already initialised. The test never reached the code it claimed to cover. A mztcTestForceReinit hook fixes that. This is the same shape as the USE_MZTC problem this branch already fixed, where a whole test body was preprocessed away and every test still passed. 560 of 560 unit tests pass. SITL builds with warnings as errors.
Companion to the firmware in iNavFlight/inav#11837. Serial port MZTC_CAMERA is registered as a peripheral serial function. Assigning it to a UART in the Ports tab is what enables the camera. The firmware finds the port and its baud rate through findSerialPortConfig(), the way every other serial peripheral works, so there is no separate port or enable setting to keep in step. The camera ships at 115200. MSP Ten commands in INAV's own range, contiguous from 0x2240 to 0x2249. The firmware answers MSP2_MZTC_CONFIG with a fixed 12 byte payload and MSP2_MZTC_STATUS with 7 bytes. Both are read and written one field at a time, so no compiler padding reaches the wire. connected is only set once the camera has answered a command, so an open UART on its own does not report a camera. Configuration tab A declarative section carrying data-setting attributes, in the same style as the gimbal and headtracker sections. The Settings framework handles load and save, so the section needs no JavaScript. All twelve firmware settings are exposed and nothing else is. OSD MZTC_STATUS at id 171, matching OSD_MZTC_STATUS in the firmware. It shows a three letter link state.
|
@wdunn001 @sensei-hacker I have tried testing this with I set the baud in the ports tab to 115200 and selected The other disappointment I observed is the lack of means to control the cameras functions by RC. The only way I could find is MSP commands. Which is not of much use if you don't use a ground station. |
|
odd it does exactly as you say I made a pr while back not sure if its in yes https://github.com/sensei-hacker/inav/pull/50/changes/6a7be5111ffc326856b68e3fe9c4379c1a1f37e3..c263066700340386e9017a1b02bb72215c4f559a#diff-179a479a4711d70ec45b54f0e28301dd28fce9d29712200fe36b70b644bb980b |
MZTC: address the review findings on iNavFlight#11837 and correct the driver against the camera manual
Ah, I did not see that PR. I just merged it! Now we'll give Qodo and Sonarqube a few minutes to point anything out, and we can then look at the now-merged version. |
May I request you update the test firmware? @wdunn001 Does the firmware you wrote a while back also include inflight RC function control. |
It should rebuild as soon as the code is able to compile. It looks like sensei-hacker#50 may have created a some merge conflicts? |
…ht#11837 # Conflicts: # docs/development/msp/README.md # docs/development/msp/inav_enums.json # docs/development/msp/inav_enums_ref.md # src/main/config/parameter_group_ids.h # src/main/fc/fc_msp_box.c # src/main/fc/rc_modes.h # src/main/io/osd.h # src/main/io/serial.h
|
I reolved the merge conflicts again, but it's still failing to build on F722. Milestoning to inav 10.1 |
maintenance-10.x now assigns id 172 to MZTC_STATUS (4e7526d), matching the firmware where iNavFlight/inav#11837 appends OSD_MZTC_STATUS after OSD_TERRAIN_AGL. The profile name elements move to 173-175 so the ids stay unique once both land; osd-item-id-uniqueness would fail otherwise.
Where the F722 failure comes fromI reproduced CI job The same target fails on plain
Unrelated PRs fail the same job. The 32 bytes that were oursThe difference above is 32 bytes. Those were avoidable.
All five now sit behind Every translation unit that reaches those three headers includes Verification
|
Summary
This is an automated merged + conflict-resolved version of PR #11005 (Mass Zero
Thermal Camera integration, author wdunn001). It shows exactly what the
feature would look like once PR #11005's branch is brought up to date with
maintenance-10.x— a clean, reviewable feature diff (26 files, allMZTC-related or its flash-gating).
Why this PR exists: PR #11005's branch is 5 months old (last commit
2026-03-26) and is CONFLICTING/DIRTY against
maintenance-10.x. This PRcarries the author's feature merged onto current maintenance-10.x with
conflicts resolved and two fixes applied, so reviewers can see the real
change without a 1245-commit branch delta.
What it contains
to them): MZTC camera drivers, MSP2_MZTC_* commands (0x3000–0x3007),
CLI commands, OSD elements, settings, docs, unit tests.
.gitignore— base version taken verbatim (PR's entries dropped:/src/main/targetwould hide future target boards; the rest wereforeign CMake/CLion artifacts)
src/main/CMakeLists.txt— union (mztc files + mavlink module files)src/main/config/parameter_group_ids.h— MZTC PGs renumbered1045/1046 → 1046/1047 (maintenance-10.x now uses 1045 for
PG_DRONECAN_CONFIG);PG_INAV_ENDconditional on USE_MZTCsrc/main/fc/cli.c— base'stimer_output_modeargs kept (featureadds no timer output modes); mztc CLI entries guarded by USE_MZTC
src/main/fc/fc_msp.c— union of MSP2_MZTC_* SET cases + base's newMSP2_INAV_* cases
USE_MZTCgated#if (MCU_FLASH_SIZE > 512)incommon.h(wasunconditional), and
#ifdef USE_MZTCguards completed incli.c,fc_init.c,fc_tasks.c(the author's guard work was incomplete —prototypes were under
USE_ASSERT; function bodies/command table/initcalls/task entry were unguarded).
inav_9.0.0_SPEEDYBEEF405AIO.hex(1.78 MB compiled binary,unreferenced).
Validation
FLASH 78.6%, RAM 96.4%
clean; FLASH 95.1%, RAM 51.3%; zero warnings, zero missing symbols
Relationship to PR #11005
original discussion.
superseded. The author is credited for the feature via the preserved
commit history.
master).
Notes for review
src/main/io/mztc_camera_cli.cis dead code (not in CMakeLists.txt,mztcCliInit()never called) — flagged for the author to remove;left as-is to keep the author's content intact.
condition: USE_MZTC, unit-test USE_MZTC define) were verified sound.