Releases: mitchdetailed/CAN-Triple-Device-Manager
Release list
CAN Triple Device Manager 1.1.16 — the per-user install can install the drivers (device firmware 1.0.5)
A small release with one functional fix, and a large change to what this repository publishes. The application itself is unchanged from 1.1.15 — same features, same device firmware 1.0.5. If your installs are the ordinary administrator kind and you are already on 1.1.15, there is nothing here you need.
The fix: a per-user install can install the drivers
Setup offers a per-user install for machines where you would rather not elevate. That route was silently skipping the ST-Link USB drivers, so the Initial Programming Tool could not talk to a probe and a blank board could not be programmed — with nothing on screen explaining why.
Windows does not allow a per-user driver install: the driver store is machine state, and no installer can arrange around that. What Setup can do is ask, and now does.
- A per-user install shows a Device drivers checkbox, ticked, that raises one elevation prompt after the files are copied.
- Declining is a supported answer, not a failure. The Manager talks to a programmed device over the serial port with no driver at all; only SWD programming of a blank board needs one. Setup says so once and carries on.
- A Start Menu entry, Install ST-Link USB Drivers, does it later — after a declined prompt, after admin rights arrive, or after another vendor's tool overwrites the driver store.
Administrator installs are untouched: still silent, still automatic, and the checkbox is hidden there so nobody is asked twice for the same thing.
The firmware is no longer published as source-shaped headers
This repository is meant to carry the firmware as a file — the .ctf, the bootloader, the programming kit — alongside the application's source and the installer. It was also carrying firmware/include in full: 22 headers, including the complete command table, the record layouts, the flash store's design and the licence record.
firmware/include is now four generated files: script_vm.h, script_exec.h, fw_image.h, and a protocol.h reduced to the one struct the others need. They are produced by stripping every comment from the firmware's own headers, so the declarations are byte-identical to the binary they describe while none of its reasoning travels.
A public clone still builds. That is checked rather than assumed: configuring and building this tree from scratch links both CANTripleDeviceManager.exe and CANTripleInitialProgramming.exe.
DESIGN.md is redacted to match. It keeps what a host integrator needs — the command table, payload shapes, chunk sizes, the capacities the application enforces, the store version Send checks — and loses the device's storage internals.
The repository's history was rewritten to remove those headers from earlier commits and release tarballs. If you have an old clone, re-clone rather than pull.
Documentation
The manuals and the published headers were corrected extensively against the code: a wrong device capacity, a command table missing nineteen opcodes, write-chunk sizes computed from record widths that had changed, and a stale description of what one access password gates. These were documentation errors only — no behaviour changed — but the wrong chunk size would have sent an oversized payload, so they are worth naming.
Install: download CANTripleDeviceManager-Setup_Windows_x64.exe below and run it. Windows 10/11 x64; the installer carries the Qt runtime, device firmware 1.0.5, the initial programming kit and the ST-Link drivers.
CAN Triple Device Manager 1.1.15 — firmware licensing and secure packages (device firmware 1.0.5)
Two releases' worth since 1.1.13. Ships device firmware 1.0.5, up from 1.0.4 — and this one changes what the device is.
⚠ Read before updating
Firmware 1.0.5 is required. Every feature below talks to commands that did not exist before it; the Device Manager says so, rather than failing quietly, but update the firmware first.
Secure packages built before this release no longer open. The
.ct3scontainer is at format 2. Rebuild them from their.ct3with the new Secure Configuration Builder — a package now carries an install policy, and a file without one is refused by name.A plain Send no longer stamps a configuration version. The version a unit reports now comes from the package that installed it. Bench work leaves the number alone.
The device now has a licence
Online → Firmware License Manager… writes five values into the unit: manufacturer, model, version, a Firmware Key and an FW Updater Password. They live in their own flash pages, survive a Send, a Clear and a firmware update, and the two secrets are never read back — not by this application, not by any command.
The two are deliberately different things. The password is the gate: blank means anyone who connects can rewrite the licence; set means the device demands it first. The key is the claim: it is what a unit proves to show which licence it holds, and it is what a secure package checks. It is also a master key over the access passwords, so a package proving it can re-provision a unit whose customer has locked it — stated plainly in the manual, because it is a real elevation.
The record is written to two pages, ping-ponged: a power cut mid-Apply leaves the old licence intact rather than a blank, licensable unit.
This replaces the fleet identity, which was compiled into the firmware and could only change with a rebuild — fine for an identity, useless for a licence.
The device knows what it physically is
Online → Get Device Info… reads the manufacturing record burned into the STM32's OTP: manufacturer, product, hardware version, serial number and date. Burned once, unchangeable by anything. An unburned part reads as Unknown throughout, and a read that faults is reported the same way rather than resetting the unit.
Secure packages carry their own rules
File → Secure Configuration Builder… replaces Save Secure Config. It takes a .ct3, attaches a policy, and writes a .ct3s: optional matches on the licence's manufacturer, model and version; a Firmware Key the device must prove — not optional, and not a string compare — the access passwords the package sets as it installs, and the package version it stamps on the unit.
Send Secure Configuration enforces all of it before the device is touched, before the Send password is asked for, and before a single record goes out. A refusal names the field and both values. An unlicensed unit takes no packages at all — issue a licence first.
Passwords a package sets land atomically with the configuration, which closes a documented trap: access keys live in a write-once header, so passwords set through Set Access Passwords on an already-configured unit only ever lasted until the next power cycle. A package install re-commits that header anyway.
Removed
Fleet Identity, Upload Configuration, Lock Configuration to Device, Verify Configuration and Save Secure Config, each for the same reason: what it did is now done better elsewhere, or was three clicks from irrelevant. The .ct3s password-protected mode went with them — it was the one mode that withheld anything from a reader of this source, and it is gone by decision; what stops a package being used where it should not be is the licence match, which is a different guarantee and is not presented as the same one.
Found in review before this shipped
The pre-release build's device would sign its own challenge — a cable and no secret was enough for master-key authority on any licensed unit. Fixed with domain-separated labels on the two directions the key is used in, pinned by a test that performs the attack, and mutation-checked from all three sites. It never reached a release; it is listed here because the fix is visible in the wire format.
Install: download CANTripleDeviceManager-1.1.15-Setup_Windows_x64.exe below and run it. Windows x64; the installer carries the Qt runtime, device firmware 1.0.5 and the ST-Link drivers.
CAN Triple Device Manager 1.1.13 — the transmit Offset is in channel units (device firmware 1.0.4)
Two releases' worth since 1.1.11. Ships device firmware 1.0.4, up from 1.0.3.
⚠ Check your transmit rows before flashing
Any transmit row with a non-zero Offset now puts a different number on the wire — unless its Bit Resolution is exactly
1, where the old and new rules give the same answer.A row tuned against the old behaviour wants its Offset divided by the Bit Resolution to keep sending what it sent. An Offset of 12 at resolution 0.001 was moving the value by 0.012; it now moves it by 12.
The config store is unchanged (v18), so a device keeps its configuration across this update — it's the arithmetic applied to it that moved.
The transmit Offset is in channel units
Reported: a transmit row at resolution 0.001 with Offset 12 moved the value by 0.012, not by 12. That was correct for the rule in place — the offset was a bias applied after the resolution divided, so it counted in raw counts — and it wasn't what the field means anywhere else in the application.
| Receive | physical = raw × Bit Resolution + Offset (unchanged) |
| Transmit | raw = (physical + Offset) ÷ Bit Resolution |
So at resolution 0.1: transmitting 0 with Offset 12 sends 120, and transmitting 5 with Offset −1 sends 40.
The Offset keeps its sign in both directions, which is the point of it — but that also means the two are still deliberately not inverses. Transmitting to another CAN Triple that receives with the same Offset applies it twice; negate it on one of the two rows. The same goes for an ECU decoding the DBC way.
The preview was contradicting itself
Which is why the rule was hard to see. The line above the range printed Physical = raw × factor + offset on both kinds of row — that's the receive mapping — while the range two lines below was computed from the transmit one. The line that matched the expectation was the wrong one.
A transmit row now states its own mapping: raw = (Physical + 12) ÷ 0.001, with a range that agrees with it.
The multiplexor is not a channel (1.1.12)
A multiplexed DBC message imports as a compound section, and each multiplexor value becomes an identifier whose selector is the multiplexor signal's own bits. Importing that signal as a channel row as well put a channel on top of its own selector — and the device writes the selector into the frame after the channels, so the section editor refused to save it, complaining about a row nobody chose to add.
The row is still shown — it's how you see which signal picks the variant — but with no tick box, and the Details column says it becomes the identifier.
Install: download CANTripleDeviceManager-1.1.13-Setup_Windows_x64.exe below and run it. Windows x64; the installer carries the Qt runtime, device firmware 1.0.4 and the ST-Link drivers.
CAN Triple Device Manager 1.1.11 — DBC units land on real ones (device firmware 1.0.3)
Two changes, both about not letting a field say something the application cannot keep. Device firmware is unchanged at 1.0.3, so updating from 1.1.10 costs a device nothing — no store migration, no reconfiguration.
DBC units land on ones this application offers
A .dbc writes its unit as free text and every tool spells it differently — degC, °C and Celsius are one unit, and none of them is how this application spells it. The import took the string verbatim, so a channel arrived carrying a unit no list contained: it matched no other channel, could not be picked from any combo, and had to be retyped afterwards.
| the file says | you now get |
|---|---|
degC, °C, Celsius |
C |
degF |
F |
kph, kmh |
km/h |
mph, mi/h |
mile/h |
1/min, rev/min |
rpm |
Nm/deg (unknown) |
(pick one), flagged |
The Unit column is editable now — it was read-only, which made an unmapped unit a dead end. It offers exactly the units the Channel Type has, and changing the type resets the unit to that type's default, because a Pressure channel measured in rpm is not something the application can express.
A unit nothing matches is flagged, not guessed. The cell reads (pick one) in the warning colour and its tooltip quotes what the file actually said. Leave it and the channel imports unitless, which the import notes list at the end.
Nothing converts the numbers. The unit is a label on the value the scaling already produces.
hPa→mbaris exact, butatm→barandkV→Vare relabels — if the readings are wrong, the Bit Resolution is what scales them.
Name fields stop where the device does
Channel names are stored in 31 bytes and message names in 17. The message name box had no cap at all — the label arrived in 1.1.10 and the field was left free — and the channel boxes counted characters against a budget measured in bytes.
For an ASCII name the two agree, which is why it never showed. Sixteen CJK characters is sixteen characters and forty-eight bytes: a character cap let that through, the mapper clipped it on the way to the device, and a Get returned something shorter than the screen showed. Every name field now stops at the byte, never mid-character.
Install: download CANTripleDeviceManager-1.1.11-Setup_Windows_x64.exe below and run it. Windows x64; the installer carries the Qt runtime, device firmware 1.0.3 and the ST-Link drivers.
CAN Triple Device Manager 1.1.10 — section names survive a Get (device firmware 1.0.3, store v18)
⚠ Read this before updating a device
This release ships device firmware 1.0.3, which moves the configuration store from v17 to v18. Every table behind the message table shifts, so a v17 image is refused rather than misread.
A unit updated to 1.0.3 comes up with no configuration and must be sent one again. Save your
.ct3first. This is the designed behaviour, not corruption — the store fails closed rather than reading old records at new offsets — but it is a step to plan for rather than discover.
Section names now survive a Get Configuration
They never used to. CanMessageConfig had no name field, so the host recovered names by matching the device's messages against the document already open — which works only when there is a document to match against. A Get from a unit this copy had never configured came back with every section named Receive 0x640, invented from the id.
Messages and relays each carry an 18-byte label now — 17 characters and a NUL. So a Get onto a blank document returns ECU Broadcast, not Receive 0x640.
On a Get the device wins over the open document, because a Get reads what is on the unit. Anything the device stored no name for — an older store, or a message nobody named — falls through to the previous behaviour untouched. A name longer than 17 characters is clipped when sent, and the app says so rather than letting a name come back silently different from the one on screen.
What paid for it
The configuration region is fixed at 131,072 bytes and stood 1,504 bytes from full, so this was never a question of room but of which table pays:
| before | after | |
|---|---|---|
| messages | 500 × 16 B = 8,000 | 500 × 32 B = 16,000 |
| relays | 32 × 16 B = 512 | 32 × 32 B = 1,024 |
| device script | 512 × 64 B = 32,768 | 384 × 64 B = 24,576 |
| region margin | 1,504 | 1,184 |
The device script ceiling is now 24 KB of bytecode rather than 32 KB. That is far more than any of the shipped examples compiles to, and the example suite is held to the new limit — but if you have a very large script, check it still fits before updating.
Why 18 bytes and not 32: it lands the message record on exactly 32 bytes, which the store's 8-byte padding leaves alone. Nineteen would pad the slot to 40 and cost another 4,000 bytes for one more character.
Also
The configuration transfer chunk sizes are computed from the record widths and moved with them (WRITE_CHUNK_MESSAGES 35 → 15, relays 44 → 16, READ_CHUNK_MESSAGES 125 → 50). No change you can see, but it is why a Send still fits the wire.
Install: download CANTripleDeviceManager-1.1.10-Setup_Windows_x64.exe below and run it. Windows x64; the installer carries the Qt runtime, device firmware 1.0.3 and the ST-Link drivers.
CAN Triple Device Manager 1.1.9 — a FOLLOW counter compares the value (device firmware 1.0.2)
This release updates the device firmware to 1.0.2 (from 1.0.1). The configurator itself is unchanged since 1.1.8 — two installers that flash different firmware should not share a number.
A FOLLOW counter now compares the value
Follow Changes read its input as a boolean. For as long as the mode has existed the engine took the Follow input through a > 0 test, so what it counted was the input crossing zero rather than changing:
| Input goes | Counted before | Counted now |
|---|---|---|
| 3000 → 3100 → 3200 | 0 | 3 |
| 0 → 1 → 0 | 2 | 2 |
| 3200 → 3200 (repeat) | 0 | 0 |
The mode is documented as tracking a channel's value in four places — the protocol header, the counters help page, the counters dialog, and the comment directly above the line itself. Only the code disagreed.
It compares the value now: any change, by any amount, in either direction. A repeated reading is not a change, so a cyclic message re-sending the same value does not step — counting frames is what the message option on Up/Down is for.
Two details worth stating:
- Exact inequality. A decoded signal is a scaled integer or an exact float off the wire, so equal frames compare equal. Any epsilon large enough to absorb float noise would also swallow a real change in the low digit, which is what this counter exists to notice.
- Non-finite readings are ignored rather than counted for ever.
NaN != NaNis true, so an unguarded comparison would step on every pass for as long as the input stayed poisoned.
If you use Follow to count a flag toggling, you still get exactly that — a flag is a value like any other, and 0 → 1 is a change either way. What changes is that the numeric case works at all.
Compatibility
No wire change. The protocol version and the config store version (v17) are untouched, so a configuration written by any 1.1.x release loads unchanged and the .ct3 format is unaffected. Device image: 65,376 bytes, 53.2% of its slot, crc32 0x54F321ED.
Updating the firmware is Online → Update Firmware; the installer carries the image.
Install: download CANTripleDeviceManager-1.1.9-Setup_Windows_x64.exe below and run it. Windows x64; the installer carries the Qt runtime, device firmware 1.0.2 and the ST-Link drivers.
CAN Triple Device Manager 1.1.8 — DBC names read like names (device firmware 1.0.1)
Two changes since 1.1.6. Device firmware unchanged at 1.0.1.
DBC signal names import with underscores as spaces
A DBC signal name has to be a C identifier, so an author who means "Engine Speed" is obliged to write Engine_Speed. The underscore is the file format's limitation, not part of the name — and every hand-made channel in this application is spelled with spaces. Imported ones now match: Engine_Speed arrives as Engine Speed.
Runs collapse and the ends are trimmed, so Engine__Speed imports as "Engine Speed" and _Rpm as "Rpm". It is a default, not a rule — the name column in the import dialog is editable, so type the underscore back if you want it. Message names are untouched.
Under the hood, for anyone reading the source: the substitution deliberately does not happen in the parser. A .dbc file refers to its own signals by the underscored name, and a SIG_VALTYPE_ line — which is what marks a signal as a float — is matched against it. Renaming in the parser would leave that line matching nothing, and every float in the file would quietly decode as raw integer bits. So the parser keeps the file's spelling and the substitution sits at the one point where a signal becomes a channel.
The title bar names the version
CAN Triple Device Manager 1.1.8 - Untitled. The version was readable only through Help → About, and "which build is that on?" is the first question about any behaviour worth reporting — so it belongs where it can be read without opening anything, and where a screenshot of a problem carries it for free. The document name, the unsaved marker and the [protected] suffix still follow it.
Install: download CANTripleDeviceManager-1.1.8-Setup_Windows_x64.exe below and run it. Windows x64; the installer carries the Qt runtime, the device firmware image and the ST-Link drivers.
CAN Triple Device Manager 1.1.6 — the Source column names what generates a channel (device firmware 1.0.1)
One fix since 1.1.5. Device firmware unchanged at 1.0.1.
A transmit message is not a channel's Source
The Channel Editor's Source column named CAN n · <transmit message> as where a channel comes from. It is where the channel goes: a transmit row reads the value and puts it on the wire. Naming it under "Source" inverted the direction of the column, and for a channel that is only transmitted it also disclosed which message carries it — which this column has no business reporting.
The fix was a deletion. The column had its own walk of the document, a second implementation of a rule the model already owns for Check Channels and the Config Summary — and that one had the direction right all along. The column is now a lookup, so the three views answer in the same words.
Four more disagreements came out with it, each naming as a source something the device never generates:
- a relay's leftover rows, from a section re-typed to Message Relay
- a compound identifier whose ID Mask is 0 — the mapper skips it, so its rows are never decoded
- the output of an inactive calculation
- Off sections, excluded by a second rule of the column's own
A Transmit CRC8's publish channel is still a source. The device computes the checksum and writes that channel on every compose — so "transmit" was never the test; "does the device write it" is.
"not generated" is a new answer, distinct from "unused". Unused means neither generated nor used, and it is exactly the set Check Channels offers to delete — so a channel a transmit message carries must not land in it.
Install: download CANTripleDeviceManager-1.1.6-Setup_Windows_x64.exe below and run it. Windows x64; the installer carries the Qt runtime, the device firmware image and the ST-Link drivers.
CAN Triple Device Manager 1.1.5 — frame order and reserved bits (device firmware 1.0.1)
Four releases' worth of work since 1.1.1 (1.1.2 through 1.1.5). Device firmware unchanged at 1.0.1.
Bits the device writes are off limits to channels
A compound identifier's selector and a Transmit CRC8's stamped byte go into the frame after the channels, so a channel placed there is not sharing those bits — it is replaced by them, and the frame stops carrying what the configuration says it carries. These are now refused rather than warned about. The rule was computed in four places before this and one of them disagreed; it lives once now, and the Frame Layout map shades every bit already spoken for.
Channel lists read in frame order
Start Bit, then Bit Length, then name — in the Communications Setup pane and in the section editor's own list, on one shared comparator so the two views of a message cannot disagree. In the editor it is the stored order, because that list's index is the row's index in the message.
New… belongs to the writing side of the channel picker
What a transmit row, a math input or a table axis reads has to be produced on the device first — a receive row, a calculation, a constant — so a channel invented where it is only read has nothing filling it and would carry its default value forever. Every output picker still creates one, and so does Tools → Channel Editor.
Message type gating
A message set to Off grays its channels tab instead of offering rows that would go nowhere. The rows are kept, so switching a message off and back on returns it intact. A new message now starts as Off, so its type is chosen rather than inherited.
Save As offers JSON
Optional, never a default, and never something a Save on a sealed file turns into.
The clamp preview names the limit that actually binds
On a non-wrapping transmit row the firmware clamps to the channel's declared range first and the field's second. The preview named only the second, describing a field the value could never reach.
Install: download CANTripleDeviceManager-1.1.5-Setup_Windows_x64.exe below and run it. Windows x64; the installer carries the Qt runtime, the device firmware image and the ST-Link drivers.
CAN Triple Device Manager 1.1.1 — review fixes (device firmware 1.0.1)
A fix release, from a full review of the project. Device firmware moves to 1.0.1 — a straight patch, no store change, so configurations load as they are and no unit needs reconfiguring.
Fixed
A new document kept the last one's Message Passwords. File → New cleared every other document secret but not the four Message Passwords, so opening a protected configuration and then starting a new one carried its derived keys forward — where a save would persist them, a send would program them onto a device, and a later Get Configuration would keep them in preference to the device's own.
A non-finite reading is now clamped (firmware 1.0.1). A channel's range is the device's clamp, but it was applied with ordered comparisons only — and every comparison against a NaN is false. A float signal fed a NaN bit pattern from the bus passed through unclamped and poisoned the value table for everything downstream: math, conditions, transmit. Non-finite values now pin to the range minimum, the same answer a value below the range already got. Proven on hardware: NaN and +Inf injected into a signal ranged −100…100 both present −100.
A failed script rolls back completely. A script that changed the configuration and then failed was restored — but only if the change had been registered. A binding that altered something and then raised an error (a bad field type, say) left that change in place, silently, without even marking the document modified. The snapshot is now restored on any failure.
Smaller things. The CAN viewer's inject button no longer stacks two transactions if pressed twice while a device is slow to answer. A script constant too large for a 32-bit float is now refused by name instead of surfacing as an "internal compiler error". A communications template's parsed passwords are no longer discarded (nothing depended on them — the messages carry their own keys). Four comments that had drifted from the code were corrected, including a send-gate message naming a menu that does not exist.
Tested
The three parts of the program that talk to a device — the configuration transfer, the firmware uploader, and the Protect Communication send gate — had no tests, because their whole surface needs a serial port. They have tests now, and the transfer and uploader run against the real firmware library, performing the same conversation they perform on a bench unit rather than against a stub that would simply agree with them.
Each new test was checked by reintroducing the bug it guards and confirming the test fails: a send gate that lets a silent device through, a configuration write that tolerates a refusal, a truncated password record, the password leak itself, and a weakened range check.
🤖 Generated with Claude Code