Technical description of the TM5000 GPIB control system as it is actually built in
src/. It supersedes the original v3.5 planning document. For the build
toolchain see BUILD.md; for the cross-version bug history see
FINDINGS.md; for version history see ../CHANGELOG.md.
TM5000 is a single-process, menu-driven DOS application that controls Tektronix TM5000-series instruments over GPIB (IEEE-488) and acquires, analyzes, plots, and prints/export their measurements. It is a modular C rewrite (v3.0+) of the original monolithic source, split so every translation unit stays within the DOS 64 KB segment limit.
- Language/target: C89, OpenWatcom, 16-bit real-mode MS-DOS, 80286 + optional 80287.
- Memory model: large (
-ml) — code and data pointers are far; data items ≥100 bytes go far automatically (-zt100),constlives in the code segment (-zc). - Display: CGA 320×200 4-color.
- GPIB hardware: Personal488 (IOtech/CEC) via the vendor
ieeeiodriver shim.
main.c program entry, globals, 287 detect, init/cleanup
│
┌──────────┼─────────────────────────────────────────────┐
│ │ │
io layer instruments data/persistence math ui/display
─────── ─────────── ──────────────── ──── ──────────
gpib.c modules.c data.c math_functions.c ui.c
ieeeio_w.c module_funcs.c export_enhanced.c math_enhanced.c ui_math_menus.c
(DC5009/DC5010/ config_profiles.c graphics.c
DM5010/DM5120/ print.c
PS5004/PS5010/
FG5010)
asm (optimization, currently dormant): cga_asm mem286 fixed286 trig287_simple
| File | Responsibility |
|---|---|
main.c / tm5000.h |
Entry point, all global definitions, 287 detection, the single shared header (system types, instrument config structs, globals as extern, constants). |
gpib.c/.h |
GPIB transport: generic gpib_write/read, SRQ/serial-poll, and DM5120/DM5010-specific I/O wrappers, over ieeeio_w. |
ieeeio_w.c / ieeeio.h |
Vendor Personal488 driver glue (Watcom port of IOtech IEEEIO). Lowest layer. |
modules.c/.h |
Per-instrument drivers, configure_modules, single_measurement, continuous_monitor, and validate_enabled_modules. Largest unit. |
module_funcs.c/.h |
Interactive "advanced configuration" menus / comm-test helpers per instrument. |
data.c/.h |
Per-module buffer alloc/store, .tm5/.cfg text persistence, enhanced-export types. |
export_enhanced.c |
Metadata-rich CSV/TSV export and real-time streaming export. |
config_profiles.c/.h |
Full-system configuration profiles saved to PROFILES.DAT. |
math_functions.c/.h |
FFT (pure C), differentiation, integration, smoothing, core statistics. |
math_enhanced.c |
Dual-trace ops, statistics, digital filtering, curve fitting (linear/poly/exp), correlation, cross-correlation, phase/delay. |
ui.c/.h |
Top-level menus, input helpers, the integration hub (calculate_statistics, file/profile/export menus). |
ui_math_menus.c |
CGA front-ends for the enhanced-math operations. |
graphics.c/.h |
CGA primitives, the waveform/graph engine, unit scaling (get_units_for_type + the per-unit helpers), mouse. |
print.c/.h |
Text and PostScript reports over LPT1. |
#pragma pack(1)
typedef struct { /* one instrument slot (or computed-result slot) */
float far *module_data; /* sample buffer (far) */
char description[12];
float last_reading;
unsigned int module_data_count;
unsigned int module_data_size;
unsigned char module_type; /* MOD_NONE / MOD_DC5009 ... MOD_FG5010 */
unsigned char slot_number;
unsigned char gpib_address;
unsigned char enabled:1;
unsigned char is_result:1; /* computed (FFT/math) trace - see §5 */
unsigned char reserved:6;
} tm5000_module;
#pragma pack()
measurement_system { tm5000_module modules[10]; int gpib_devices[10]; ... } /* g_system */
trace_info { label, data, x_scale, x_offset, unit_type, enabled, ... } /* g_traces[10] */
fft_config { input_points, output_points, window_type, output_format, flags } /* g_fft_config */The system supports up to 10 slots. Per-instrument settings live in parallel
g_<inst>_config[10] arrays; config_profile captures all of them plus graph/FFT/panel
state for save/restore.
- All bus I/O funnels through
gpib.cover the Personal488 shim (ieeeio_w.c); logical slot ↔ GPIB address mapping isaddress = slot + base. - Seven instrument drivers live in
modules.c. DC5009 and DC5010 share one implementation: the 22 byte-identicaldc5010_*routines forward to theirdc5009_*counterparts; only the DC5010-unique features (rise/fall time, A±B totalize, burst) are separate. - DM5120 buffered acquisition defaults to an internal (
TALK,CONT) trigger so the buffer self-fills without external trigger hardware;EXTis opt-in per the advanced config.
A measurement slot normally maps to a real instrument. Computed results (FFT,
differentiation, integration, smoothing, dual-trace math) are also stored in a module
slot, but with module_type == MOD_NONE, gpib_address == 0, and is_result == 1.
module_is_result(slot) recognizes such a slot either by the is_result flag or
derived from state (MOD_NONE with allocated data) — the derived test lets computed
traces survive a .tm5/.cfg reload, which does not serialize the flag. This is used by:
validate_enabled_modules()— never purges a computed-result slot as a "phantom".continuous_monitor()— never counts, clears, or GPIB-reads a computed-result slot.sync_traces_with_modules()— preserves the computed trace'sunit_type/x_scale/x_offsetinstead of reclassifying it bymodule_type.
This is the v3.6 fix for the long-standing "computed traces get wiped" regression (see FINDINGS #1).
- FFT (
math_functions.c): pure-C, power-of-2, 64–1024 points, with Rectangular/Hamming/Hanning/Blackman windows. Uses the 80287 when present; falls back to a coarse software DFT otherwise (approximate, ≤64-point — a coprocessor is recommended). Output formats: dB (threshold1e-12, floor-240 dB), linear, power. When the requested output size is smaller than N/2 the spectrum is peak-preserving decimated across the full 0..Nyquist span with a correspondingly scaled frequency axis. - Enhanced analysis (
math_enhanced.c): dual-trace operations; basic/rolling statistics; digital filtering; curve fitting — linear, polynomial (order 2–3, with X centered+scaled for numerical conditioning), and exponential; Pearson correlation; cross-correlation (per-lag overlap-normalized, double-precision accumulators) and phase/delay analysis (peak-alignment lag over the reliable lag range). - Result traces are written into a computed-result slot (§5) and displayed like any trace.
.tm5measurement files /.cfgconfiguration files: line-oriented text. A file has aGlobalData:block, aModuleData:marker, thenSlot<n>:<count>records with samples, ending atEndOfFile. Loading resynchronizes to theModuleData:marker (tolerant of a global-count mismatch) and warns if the marker is absent.- Configuration profiles (
config_profiles.c): the full multi-instrument + graph/FFT/ panel state toPROFILES.DAT, checksum-validated. - Enhanced export (
export_enhanced.c): CSV/TSV with metadata/timestamps/settings and optional real-time streaming.
OpenWatcom, large model, 286 target — see BUILD.md for the exact flags. Two size-relevant build options are enabled:
wcc -zm— emit each function in its own segment, so thatwlink OPTION ELIMINATEcan drop every unreferenced function (and the dormant assembly modules) from the image. OpenWatcom's linker has no identical-code folding, so duplicate functions are still consolidated in source (e.g. the DC5009/DC5010 forwarders).
Result: tm5000.exe ≈ 270 KB (dead-stripped), within the 640 KB conventional-memory
budget with room for the 1024-sample × 10-module far buffers.
cga_asm.asm, mem286.asm, fixed286.asm, and trig287_simple.asm contain CGA/286/287
optimization routines that are not currently called from C (only extern-declared).
With OPTION ELIMINATE they are stripped from the image, so they cost nothing today; they
remain in the tree as scaffolding to wire in (or remove) later.
- The non-287 software-DFT FFT path is approximate and low-resolution; accurate FFTs need a coprocessor.
tm5000.his a "god header" (all subsystem prototypes); header/API hygiene cleanups are tracked for a future pass.- See FINDINGS.md for the code-verified cross-version regression analysis and ../CHANGELOG.md for what changed in each release.
As-built for v3.6. Update this document when the module structure, data layout, or build options change.