andy ec6d2578ae fix(da07): decode the E-frame tail as the CT serial - drop the phantom disp field (BL-E5 part 1)
Verified against the repo's first real DA-07 capture (157 frames, saved as
tests/da07/fixtures/capture-2026-06-12-refresh.txt): the ~E payload ends at the
alarm byte, followed only by an optional 8-byte CT sensor serial - there is no
disp field and no name field on the wire. The phantom disp read (inherited from
the VB6, which had the same bug feeding its hidden Disp column) ate the serial's
first byte, producing the reported "Tag column cuts off the first characters"
symptom.

Removed disp everywhere: decoder E branch, ChannelRecord, the Channels-tab Disp
column (later columns shift left one), controller.set_channel_disp, encoder
CH_DISP (ICD §11 has no ~D field 9), the simulator's disp byte, repo snapshot,
and help text. The simulator now emits the wire-faithful E layout (serial-only
tail). The Tag column shows name -> serial -> catalog default, matching legacy
precedence; a written name lives only in the local model until ~P (the presumed
custom-name frame, absent from this capture) is decoded - BL-E5 part 2 stays
open, needs-capture.

The capture also re-confirmed no ~H arrives during a refresh (it streams
periodically afterwards), which is what made the stale-model revert fire every
second once live. Docs updated: BL-E5 part 1 done, HW-VERIFICATION item 8
resolved, field-notes entry added.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 09:42:57 -04:00
2026-06-11 16:45:47 -04:00
2026-06-11 16:45:47 -04:00

CIMTechniques Service Suite

A modern Python 3 + PySide6 rebuild of CIMTechniques' legacy VB6 instrument tools — a unified, signed, single-install application for configuring and monitoring CIMTechniques sensor stations over serial / RS-232 during production and in the field.

The suite is a monorepo: a shared core package, a shell launcher, and one module per instrument family. You install, sign, and update one app.

Module Instrument Status
DA-12 DA-12 Monitoring Station Functionally complete against simulator; hardware verification pending
DA-07 ("eLink") DA-07 station (Station → Devices → Channels) Functionally complete against simulator; hardware verification pending
IOModbus Config-driven Modbus RTU master (bundled device catalog) Functionally complete against simulator; hardware verification pending

All three modules are rebuilt from their original VB6 baselines (preserved read-only under cim_suite/modules/<id>/legacy/). The outstanding milestone is verification against real DA-12, DA-07, and Modbus hardware.

Quick start

Requires Windows and Python 3.11+.

# Setup
py -m venv .venv
.venv\Scripts\python -m pip install -e ".[dev]"

# Run against the in-memory simulator (no hardware needed — the normal dev path)
.venv\Scripts\python -m cim_suite.shell.app --module da12 --simulate
.venv\Scripts\python -m cim_suite.shell.app --module da07 --simulate
.venv\Scripts\python -m cim_suite.shell.app --module iomodbus --simulate

# Run against real hardware on a serial port
.venv\Scripts\python -m cim_suite.shell.app --module da12 --port COM3

# Open the suite launcher (module card grid)
.venv\Scripts\python -m cim_suite.shell.app

The simulator (SimulatedStation) speaks the real wire protocol, so the whole app — and the full test suite — runs headless with no instrument attached.

Development

# Tests (headless; UI tests run offscreen via pytest-qt)
.venv\Scripts\python -m pytest -q

# Lint
.venv\Scripts\python -m ruff check cim_suite tests

A green pytest and a clean ruff are both part of "done" here.

Building a standalone app

# One-folder executable (PyInstaller)
.venv\Scripts\pyinstaller --noconfirm --distpath packaging\dist --workpath packaging\build packaging\suite.spec

# Windows installer (requires Inno Setup 6). Pass the version so the installer and
# Add/Remove Programs match the app — it's single-sourced from pyproject.toml:
$v = .venv\Scripts\python -c "import cim_suite; print(cim_suite.__version__)"
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" /DAppVersion=$v packaging\installer.iss

Versioning & releases

The suite uses Semantic Versioning (MAJOR.MINOR.PATCH). There are two records of change, with different audiences:

  • Git history — the technical record. Every commit uses the Conventional Commit format <type>: <description>.
  • CHANGELOG.md — the human-facing record: plain-language release notes for the (non-technical) people who use the app. It's also shown in-app via the What's new button on the start page.
Commit type Meaning Version bump In changelog?
feat A new user-facing capability minor Yes (Added / Changed)
fix A bug fix patch Yes (Fixed)
feat! / BREAKING CHANGE: in body Removes or breaks existing behavior major Yes (Changed / Removed)
docs, style, refactor, perf, test, build, ci, chore, revert Internal work none Collapsed to one "maintenance" line, or dropped
# One-time on a fresh clone: install the commit-message validation hook
.venv\Scripts\python scripts\setup_hooks.py

# Bump the version (deterministic; edits pyproject.toml only). --dry-run to preview.
.venv\Scripts\python scripts\bump.py --dry-run
.venv\Scripts\python scripts\bump.py            # auto-detect from commits
.venv\Scripts\python scripts\bump.py --minor    # or force a bump level

# Draft release notes: in Claude Code run  /release-notes  (collects commits, drafts
# plain-language entries for your review, and only writes CHANGELOG.md once approved).
# Under the hood it calls:
.venv\Scripts\python scripts\release_notes.py --json

The version string lives in one place[project] version in pyproject.toml; cim_suite.__version__ reads from it, and the installer takes it via /DAppVersion. The bump level is computed from commit prefixes, never by an LLM. The changelog prose is the only LLM-assisted step and is never committed without review. Releases start from the last vX.Y.Z git tag (or a --baseline <rev> you pass when there's no tag yet).

Cutting a release (order matters — draft notes before bumping, so the suggested version is correct):

  1. /release-notes in Claude Code → review/approve the draft → it writes CHANGELOG.md.
  2. python scripts\bump.py → updates pyproject.toml.
  3. git commit -am "chore: release X.Y.Z" (the release commit itself doesn't bump).
  4. git tag vX.Y.Z
  5. git push --follow-tags (pushes the commit and the new tag together).

Architecture

Five strictly-ordered layers. The protocol core is pure (no I/O, no Qt) and the device is swappable — this is the central discipline, not an accident.

Layer Package Role
Shared core cim_suite/core Protocol primitives, transport interface + pyserial reader, theme/design system, config, export engine
Protocol (pure) cim_suite/modules/<id>/protocol Framing, decode (frame → dataclass), encode (command → wire string). No I/O; fully unit-tested
Transport cim_suite/modules/<id>/transport SimulatedStation in-memory fake; real serial transport lives in core
Domain cim_suite/modules/<id>/domain In-memory models, calibration, logging, and the StationController hub
UI cim_suite/modules/<id>/ui MainWindow + tabbed thin views that render models and call controller methods
Shell cim_suite/shell Entry point, module registry, launcher landing page, suite window

Data flows one way in, one way out, through the StationController:

transport (reader thread) → controller → framer → decode → models → *Changed signals → UI
UI edit → controller.set_* → encode → transport.write

Note: the modules deliberately do not share a protocol. DA-12 streams big-endian fixed-point {...} frames unsolicited; DA-07 uses a little-endian, IEEE-754-float, checksummed ~...\r dialect over a polled ACK handshake; IOModbus is a standard half-duplex Modbus RTU master driven by a bundled register-map catalog (no proprietary protocol of its own). See docs/SUITE-ARCHITECTURE.md and CLAUDE.md for the full rationale.

Documentation

Doc What it covers
CLAUDE.md Orientation + working conventions (the best starting point)
docs/SUITE-ARCHITECTURE.md Monorepo / multi-module design
docs/RUNNING.md Running the app
docs/REBUILD-STATUS.md Point-in-time rebuild status
docs/BACKLOG.md Live to-do list
docs/HARDWARE-VERIFICATION.md Protocol details to confirm against real hardware
docs/DESIGN-SYSTEM.md Suite-wide visual standard
docs/EXPORT.md .xlsx export engine + adoption checklist
docs/VB6-MIGRATION-PLAYBOOK.md Reverse-engineering traps from the VB6 port
CHANGELOG.md Human-facing release notes (see Versioning & releases above)

License

Proprietary — © CIMTechniques. All rights reserved.

Description
A unified, modern architecture rebuild of the DA-12 and DA-07 service tool and IOModbus apps (with the ability to add further modules as needed).
Readme 12 MiB
Languages
Python 57.9%
Visual Basic 6.0 41.8%
PowerShell 0.2%
Inno Setup 0.1%