Linux-native CC5X PIC workflow — pack-driven headers, managed #pragma config,
CrossOver/Wine builds, and optional IPECMD flashing, all from one checked-in manifest.
- Why This Exists
- Requirements
- Installation
- Setup
- Usage — CLI
- Usage — Desktop GUI
- Usage — VS Code extension
- Manifest reference
- Packaging
- Testing & validation
- Supported scope
- Repository layout
- Limitations
- Acknowledgments & credits
cc5x-helper is a Linux-native replacement for the useful engineering workflows behind BKND's SETCC.EXE.
It is built for CC5X-target PIC families only:
PIC10FPIC12FPIC16F
The tool does not try to recreate the old Windows GUI. It replaces the parts that matter in practice:
- device-pack discovery
- pack-driven CC5X header generation
- config-symbol discovery and managed
#pragma configemission - manifest-based project state instead of opaque
setcc.pxk - CrossOver/Wine-backed CC5X builds from Linux
- optional device programming through MPLAB IPECMD (PICkit 4/5, SNAP, ICD4)
- an optional MPLAB-free open-source flasher for the PICkit 4 (
pk4prog/) - an optional desktop GUI and a VS Code extension
SETCC.EXE is a Windows-only Borland/VCL application. It hides project state in setcc.pxk, depends on Microchip metadata layouts that have changed over time, and is awkward to automate on Linux.
This project takes the modern route:
- prefer Microchip PIC DFP
.atpackarchives - normalize
.PIC,.ini, andcfgdatainto one device model - generate deterministic CC5X-style output
- keep project state in source control
- validate generated headers with the real
CC5X.EXE
| Requirement | Needed for | Notes |
|---|---|---|
| Python ≥ 3.12 | everything | declared in pyproject.toml (requires-python = ">=3.12") |
| uv | recommended install/runner | manages the virtualenv, dependencies, and the bundled console scripts |
CC5X compiler (CC5X.EXE) |
build, header validation |
proprietary, from B Knudsen Data (Norway). Not bundled — you supply it |
| Wine or CrossOver | running the Windows CC5X.EXE on Linux |
invoked through a "runner" (see Setup) |
| Microchip device packs | device discovery, header/config generation | .atpack DFP archives, or an installed MPLAB X pack cache |
| MPLAB X / IPECMD + a PICkit | the optional program command |
only needed if you flash hardware from this tool |
| PyQt6 ≥ 6.6 | the optional desktop GUI | installed via the gui extra |
This repo does not bundle proprietary CC5X binaries or Microchip packs as tracked source files. You must obtain them separately and point the tool at them.
git clone <this-repo> cc5x-helper
cd cc5x-helper
# Create the venv and install the project + runtime deps (e.g. defusedxml):
uv sync
# Include the GUI and/or dev (pytest, flake8) extras as needed:
uv sync --extra gui --extra devuv sync creates a project virtualenv and installs the two console entry points
declared in pyproject.toml:
cc5x-helper→ the CLI (cc5x_setcc_native:main)cc5x-helper-gui→ the desktop GUI (requires theguiextra)
Run them through uv run (no manual venv activation needed):
uv run cc5x-helper doctor
uv run cc5x-helper list-devices --family 16F
uv run --extra gui cc5x-helper-guiuv run can fetch dependencies on the fly:
uv run --with defusedxml python tools/cc5x_setcc_native.py doctorpython3 -m venv .venv && source .venv/bin/activate
pip install -e . # base CLI
pip install -e ".[gui]" # + desktop GUI
pip install -e ".[dev]" # + pytest/flake8The examples below use
uv run cc5x-helper …. If you installed with pip and activated the venv, drop theuv runprefix and just callcc5x-helper …. You can always fall back touv run python tools/cc5x_setcc_native.py ….
cc5x-helper discovers device metadata, the compiler, and a runner automatically,
with environment-variable overrides for anything in a non-default location. Run
doctor at any time to see what was found and what is still missing.
Obtain CC5X.EXE from B Knudsen Data and either:
- place it at the default path
cc5x_paid/CC5X/CC5X.EXEinside the repo, or - point at it explicitly with
CC5X_COMPILER, or per-project with--compiler.
export CC5X_COMPILER="$HOME/tools/CC5X/CC5X.EXE"The runner is the launcher that executes the Windows CC5X.EXE on Linux. It is a
command template: the compiler path is inserted wherever you write the {compiler}
placeholder. If the runner has no {compiler} placeholder it is treated as
self-contained — i.e. it already knows which compiler to run — and only the CC5X
options and the source file are appended. (This replaces an older rule that keyed off the
runner's filename, so renaming a wrapper no longer changes behavior.)
Minimal Wine runner — Wine needs the compiler path, so include the placeholder (a bare
wine runner without it fails with a clear "add the {compiler} placeholder" error):
uv run cc5x-helper build --project setcc-native.json --edition production --runner "wine {compiler}"A pass-through wrapper script (forwards its arguments to Wine/CrossOver) also needs the
compiler, so invoke it with the placeholder, e.g. ~/apps/cc5x-run.sh {compiler}:
#!/usr/bin/env bash
# Forward all CC5X arguments through Wine (or cxrun for a CrossOver bottle).
exec wine "$@"
# CrossOver example:
# exec /opt/cxoffice/bin/cxrun --bottle CC5X -- "$@"chmod +x ~/apps/cc5x-run.sh
export CC5X_RUNNER="$HOME/apps/cc5x-run.sh {compiler}"A self-contained wrapper that hard-codes the compiler path internally (like the
default cc5x-run.sh, which runs 'C:\Program Files\...\CC5X.EXE' "$@") needs no
placeholder — set the runner to just the script path.
With no CC5X_RUNNER set, the tool looks for cc5x-run.sh next to the installed
package and one directory above it (install-relative, not a fixed path — so this
works the same regardless of whose machine or home directory it's checked out into);
the default CrossOver bottle is ~/.cxoffice/CC5X. Override either with the env vars
or manifest fields if your layout differs.
Point the tool at Microchip device-pack metadata using any of:
- drop
Microchip.*.atpackarchives into~/appsor~/Downloads(scanned by default), or - set
CC5X_ATPACK_DIRSto a:-separated list of directories holding.atpackfiles, or - rely on an installed MPLAB X pack cache (
~/.mchp_packs/Microchip, or setCC5X_PACK_ROOTS/MPLABX_PACKS).
export CC5X_ATPACK_DIRS="$HOME/microchip/packs"Packs go stale over time — see §6 for how to check for and pull in newer Microchip releases, including an opt-in daily auto-update timer.
To flash hardware with the program command you need MPLAB X's ipecmd and a
supported programmer (PICkit 4/5, SNAP, ICD4). IPECMD is auto-discovered under
installed MPLAB X versions, or set CC5X_IPECMD:
export CC5X_IPECMD="/opt/microchip/mplabx/v6.30/mplab_platform/mplab_ipe/ipecmd.sh"This tool never touches the MPLAB X IDE itself — only mplab_platform/mplab_ipe
(the ipecmd CLI), mplab_platform/bin (its launcher dependency,
common-vars.sh), the bundled JRE under sys/java/…, and whichever
packs/Microchip/<family>_DFP / <tool>_TP directories match your devices and
programmer. A stock MPLAB X install is ~7GB; the pieces above are typically
under 2GB.
scripts/prune_mplabx.sh deletes everything else in place (full IDE, MCC,
docs, ARM packs, unused device families, unused programmer tool packs). Review
it before running — it needs sudo since MPLAB X is usually root-owned, and
it's destructive against a real install outside this repo.
sudo sh scripts/prune_mplabx.sh /opt/microchip/mplabx/v6.30By default it keeps the PIC10F/PIC12F/PIC16F pack families this repo
supports (PIC10-12Fxxx_DFP, PIC12-16F1xxx_DFP, PIC16F1xxxx_DFP,
PIC16Fxxx_DFP) plus PICkit4_TP and PICkit5_TP. Before running it on a new
machine:
-
Edit the
PICkit4_TP PICkit5_TPkeep-list in the script to match the programmer(s) you actually own (SNAP→Snap_TP,ICD4→ICD4_TP, etc. — list the exact directory names underpacks/Microchipon your machine). -
If you add support for a device outside
PIC10F/PIC12F/PIC16F, add its pack family to the keep-list first, or the prune will delete metadata you need. -
Do not relocate the pruned directory tree.
ipecmd.shandcommon-vars.shhardcode the JRE path (sys/java/zulu8…) as an absolute path baked in at install time — pruning in place keeps that path valid; copying the result elsewhere breaks it unless you also patch those two scripts. -
After pruning, confirm
ipecmdstill runs anddoctorstill reports the expected devices:/opt/microchip/mplabx/v6.30/mplab_platform/mplab_ipe/ipecmd.sh -P PIC16F1509 -TPPK4 uv run cc5x-helper doctor
MPLAB X's bundled pack cache (or a manually downloaded .atpack) is a point-in-time
snapshot; Microchip keeps publishing newer _DFP releases after you install. packs-check
queries packs.download.microchip.com (read-only, network) for the latest published
version of every pack family backing a locally discovered PIC10F/PIC12F/PIC16F
device, and packs-update downloads (and SHA-256-verifies) any that are newer:
uv run cc5x-helper packs-check
uv run cc5x-helper packs-update # downloads newer .atpack archives
uv run cc5x-helper packs-update --dry-run # preview without downloading
uv run cc5x-helper packs-update --family PIC16F1xxxx_DFP --force # re-fetch one familyBoth commands only ever run when you invoke them directly — no other command makes a
network call on its own. Downloads land in ~/.cc5x/atpacks by default (already
included in --dest's default and in discover_atpack_dirs()'s scan list, so a fresh
download is picked up immediately by every other command); set CC5X_ATPACK_DIRS first
to redirect them elsewhere, or pass --dest.
Automatic updates (opt-in). To stop checking manually, install a systemd --user
timer that runs packs-update once a day (no sudo; only installed if you run this):
scripts/install-packs-autoupdate-timer.shThis writes ~/.config/systemd/user/cc5x-packs-update.{service,timer}, enables the
timer (OnCalendar=daily, RandomizedDelaySec=30min, Persistent=true so a missed
run catches up after the machine was off), and downloads newer packs the same way the
manual command above does. Check on it with:
systemctl --user list-timers cc5x-packs-update.timer
journalctl --user -u cc5x-packs-update.serviceUninstall with systemctl --user disable --now cc5x-packs-update.timer.
| Variable | Purpose |
|---|---|
CC5X_COMPILER |
Path to CC5X.EXE (overrides the default repo path) |
CC5X_RUNNER |
Launcher used to run the Windows compiler (e.g. wine {compiler} or a wrapper script; a bare interpreter needs the {compiler} placeholder) |
CC5X_ATPACK_DIRS |
:-separated dirs containing Microchip.*.atpack archives; packs-update also downloads to its first entry |
CC5X_PACK_ROOTS / MPLABX_PACKS |
:-separated roots of unpacked <family>/<version>/… pack trees |
CC5X_IPECMD |
Path to ipecmd.sh/ipecmd.exe for the program command |
uv run cc5x-helper doctordoctor reports discovered pack/device counts, the selected runner and compiler
(and whether they exist), CrossOver/Wine status, and an overall ready flag.
Discover what is locally available:
uv run cc5x-helper list-devices --family 10F --family 16F
uv run cc5x-helper doctorInspect a device from the installed packs:
uv run cc5x-helper describe-device --device PIC16F1509Generate a CC5X-style header straight from pack metadata:
uv run cc5x-helper render-pack-header --device PIC16F1509Render a managed config block from pack metadata:
uv run cc5x-helper render-pack-config --device PIC16F1509 --include-defaultsThe checked-in replacement for setcc.pxk is setcc-native.json (see
Manifest reference).
# 1. Create a manifest
uv run cc5x-helper project-init --device PIC16F1509project-init defaults the build entry point to src/main.c and scaffolds it with a minimal, non-empty starter (#include
the device header + an empty main()) if it doesn't already exist yet — never
overwrites a file you've started editing. An empty source is not just unhelpful:
CC5X's Wine binary exits non-zero on a 0-byte file with no diagnostic text at all,
which looks like a silent crash.
# 2. Validate it
uv run cc5x-helper project-validate
# 3. Sync the chosen edition's config into the source file
uv run cc5x-helper sync-config --project setcc-native.json --edition production
# 4. Build from the manifest
uv run cc5x-helper build --project setcc-native.json --edition productionInspect and edit the manifest from the CLI:
uv run cc5x-helper project-list-editions
uv run cc5x-helper project-show --edition production
uv run cc5x-helper project-edit --header-mode existing --header-path include/16F1509.H
# Manage an edition's config symbols and build options:
uv run cc5x-helper project-set-config --edition production --set FOSC=INTOSC --set WDTE=OFF
uv run cc5x-helper project-set-build-options --edition production --option -a
uv run cc5x-helper project-edit-edition --edition release --copy-from productionMutation commands reject changes the validator would refuse (e.g. an empty config
value) without writing the manifest. Other read commands include describe-device,
list-config, list-pack-config, probe, intellisense, debug-stub (generate the
CDL debug/trace stub + map for a project), debug-monitor (decode a CDL capture into a
named, timestamped trace), and artifacts — run uv run cc5x-helper --help for the
full list.
Add --dry-run to build to print the compiler command line without running it,
or --timeout-seconds N to abort the compiler after N seconds.
# Program the device's hex image via a PICkit 4 (default tool).
# Device-modifying actions confirm first — see "Confirmation" below.
uv run cc5x-helper program --project setcc-native.json --edition production
# Other operations and tools
uv run cc5x-helper program --action verify --device PIC16F1509 --hex build/app.hex --tool PK5
uv run cc5x-helper program --action erase --device PIC16F1509 --dry-run--action accepts program / verify / erase / blank-check; --tool accepts
IPECMD -TP codes (PK4, PK5, SNAP, ICD4). Use --ipe-arg to pass raw
IPECMD flags (e.g. --ipe-arg=-W2.5 to power the target), --dry-run to preview
the command, and --timeout-seconds N to abort IPECMD after N seconds.
Confirmation for device-modifying actions. program and erase write to the
chip, so they require explicit authorization before running (verify / blank-check
and any --dry-run are read-only and never prompt):
- In an interactive terminal you are prompted to type
yesto proceed. - Pass
--yesto authorize without a prompt (use this in scripts). - In
--jsonmode or a non-interactive shell there is no prompt: the command returns aconfirmation_requirederror unless--yesis given.
The GUI and VS Code extension pass --yes automatically after their own
"writes to hardware" confirmation; generated VS Code tasks omit it and prompt in
the integrated terminal.
pk4prog/ is a self-contained Go programmer that drives a PICkit 4
/ Snap directly over USB — no MPLAB IPE, no ipecmd, no Microchip account. It
speaks the PICkit 4's reverse-engineered GEN4 script protocol, with the PIC16
ICSP command sequences ported from Microchip's own DFP scripts (see
pk4prog/references/).
cd pk4prog
go build -o pk4prog ./cmd/pk4prog
./pk4prog id # read device ID
./pk4prog program --hex firmware.hex # auto-erase, program, verifyDefault target is PIC16F17146; PIC16F18456 is selectable with --device.
For the PIC16F17146 Curiosity Nano board — including programming over its
on-board nEDBG debugger (via open-source pymcuprog) instead of a standalone
PICkit 4 — see pk4prog/docs/curiosity-nano.md.
Status: the GEN4 transport and DFP-derived command sequences are implemented and unit-tested, but hardware bring-up against real silicon is still pending — see
pk4prog/TODO.md. Prefer the IPECMDprogramcommand above for known-good flashing until bring-up is complete.
uv run --extra gui cc5x-helper-gui
# or, from a packaged binary:
./dist/cc5x-helper-guiInside the GUI:
Help → Help ContentsorF1for the full new-user help system.Help → Help For Current TaborShift+F1for context help.- Each main tab also has its own
Helpbutton, plus a persistentHelptab.
The GUI exposes the same workflow in three tabs:
- Environment — run
doctorand browse local device-pack coverage - Devices — probe/describe a device, list config symbols, render headers and config blocks
- Projects — create/load manifests, edit project fields, manage editions, sync config, launch builds
If a Linux desktop session forces an incompatible Qt platform theme:
QT_QPA_PLATFORM=xcb uv run --extra gui cc5x-helper-guiA VS Code extension lives in vscode/cc5x-vscode. It builds and
programs projects by shelling out to this helper and to IPECMD.
Build and install it locally:
cd vscode/cc5x-vscode
npm install
npm run compile # or: npx @vscode/vsce package → cc5x-vscode-0.1.0.vsixThen install the .vsix via Extensions → … → Install from VSIX, or run the
extension from VS Code's Extension Development Host (F5).
The extension activates when the workspace contains setcc-native.json and adds
the CC5X: commands Doctor, Build, Program Device, Create Project, Select
Device, Edit Config, Sync Config, Generate Header, Refresh IntelliSense, Generate
VS Code Tasks, Refresh Artifacts, Open Artifact, plus status bar widgets for
Doctor (readiness), Build, and Program Device (one click each). Program
Device shows a modal "writes to hardware" confirmation before flashing.
IntelliSense support goes beyond quieting false positives: it generates a clang VFS
overlay that redirects the editor's C/C++ parser to a stripped, standard-C copy of
the device header (CC5X's char LATC @ 0x1A; address-binding syntax has no
standard-C equivalent) so the editor gets real type information for every
register — without touching the file CC5X actually compiles. On top of that, an
independent case-mismatch check flags any identifier whose lowercase form matches a
declared register/bit but whose case doesn't (e.g. latc vs. LATC, which CC5X
treats as different, undeclared symbols) and offers a "Change to 'X'" quick fix in
either direction.
Workspace Trust required. Because the extension runs the workspace-configured Python interpreter, helper script, and IPECMD, it only operates in trusted workspaces. In an untrusted folder the commands are disabled until you trust it.
Relevant settings (cc5x.*): pythonPath, helperPath, manifest,
programmerTool, ipecmdPath, commandTimeoutSeconds. You can also generate
.vscode/tasks.json from the CLI:
uv run cc5x-helper vscode-tasks --project setcc-native.json --tool PK4project-init writes a manifest like this:
{
"version": 1,
"device": "PIC16F1509",
"compiler": "/path/to/CC5X/CC5X.EXE",
"runner": "wine {compiler}",
"mplab_root": null,
"header": { "mode": "generated", "path": "generated_headers/16F1509.H" },
"config_source": "src/main.c",
"main_source": "src/main.c",
"build_options": [],
"editions": {
"debug": { "config": {}, "build_options": [] },
"production": { "config": {}, "build_options": [] }
}
}| Field | Meaning |
|---|---|
device |
Target PIC (e.g. PIC16F1509) |
compiler |
Path to CC5X.EXE (defaults from CC5X_COMPILER) |
runner |
Launcher for the Windows compiler (e.g. wine {compiler}; a bare interpreter needs the {compiler} placeholder) |
header.mode |
generated (pack-derived), supplied, or existing |
header.path |
Header file path used/produced for the build |
header.bit_name_format |
Optional generated-header bit naming: combined (default), long (REGISTER_BIT), or short (BIT) |
config_source / main_source |
File that receives synced config / the build entry point |
build_options |
Extra CC5X flags applied to every edition |
editions |
Named build variants, each with its own config map and build_options |
The manifest can name arbitrary executables (
compiler,runner), so treat it as trusted input — only build from manifests you control.
Built with uv + PyInstaller:
bash tools/build_linux_executable.sh # CLI → dist/cc5x-helper
bash tools/build_linux_executable.sh gui # GUI → dist/cc5x-helper-guiEquivalent direct commands (PyInstaller version pinned for reproducible builds — see
PYINSTALLER_VERSION in the script for the current value):
uv run --python 3.13 --with pyinstaller==6.21.0 pyinstaller \
--onefile --name cc5x-helper --paths tools tools/cc5x_setcc_native.py
# --extra gui is required: without it uv builds in an env where the GUI entrypoint's
# `import PyQt6` is unresolved and PyInstaller bundles no Qt runtime.
uv run --python 3.13 --extra gui --with pyinstaller==6.21.0 pyinstaller \
--onefile --name cc5x-helper-gui --paths tools tools/cc5x_helper_gui.pyUnit tests (pytest is configured in pyproject.toml):
uv run --extra dev pytestLint:
uv run --extra dev flake8 tools testsReal-compiler header validation (needs a working compiler + runner):
uv run python tools/validate_generated_headers.py --json
uv run python tools/validate_generated_headers.py --all-shipped --json
uv run python tools/validate_generated_headers.py --all-packs --jsonThis project targets CC5X-supported device families only. It does not claim PIC18 support.
Compiler-validated generated headers currently exist for:
PIC10F200,PIC10F320,PIC10F322PIC12F1501,PIC12F1840PIC16F1509,PIC16F15244,PIC16F15313,PIC16F1789,PIC16F18325,PIC16F18446,PIC16F18857,PIC16F19195
Validation uses the real CC5X.EXE under CrossOver/Wine.
For BKND-header parity work, --all-shipped expands the gate to every shipped
PIC10F/PIC12F/PIC16F device header found under cc5x_paid/CC5X, compiling
both the generated header and the shipped-header control for each device. Its exit
status gates generated-header success; shipped-control failures are still reported in
the JSON/text output as third-party header diagnostics.
--all-packs goes further: it enumerates every PIC10F/PIC12F/PIC16F device
discoverable in local packs (not just the BKND-shipped subset) and compiles a
generated header for each. See SUPPORT_MATRIX.md for current
results (309/311 devices).
- tools — helper CLI, GUI, and library code
- packs.py — pack discovery, version selection, device lookup
- picmeta.py — normalized parsing of
.PIC,.ini,cfgdata - headergen.py — CC5X-style header and config-section generation
- project.py —
setcc-native.jsonmanifest model and validation
- tests — unit tests for pack parsing and project manifests
- pk4prog — MPLAB-free open-source PICkit 4/Snap flasher (Go; GEN4 protocol) for enhanced-midrange PIC16F1xxxx
- vscode/cc5x-vscode — VS Code extension
- NATIVE_SETCC.md — operator notes and command examples
- SUPPORT_MATRIX.md — validated devices and current project boundaries
- The generated-header parity gate covers the BKND-shipped flash
PIC10F/PIC12F/PIC16Fheaders that map to pack metadata; older OTP/EPROM12C/16Cheaders remain outside the pack-driven generator scope. - The manifest workflow covers the useful persisted state from
setcc.pxk, not every GUI preference. - This repo does not bundle proprietary CC5X binaries or Microchip packs as tracked source files.
The CC5X C compiler and its companion tool SETCC are the work of, and
Copyright © B Knudsen Data, Norway, 1992 – 2026. CC5X.EXE, SETCC.EXE, the
CC5X device headers (*.h), and the CC5X C dialect are proprietary products of
B Knudsen Data — all rights reserved by their author. See
https://www.bknd.com/ for licensing and the official distribution.
cc5x-helper is an independent, unofficial Linux workflow that drives the
CC5X toolchain. It is not produced, endorsed, or supported by B Knudsen Data,
and it neither includes nor redistributes any B Knudsen Data software. You must
obtain CC5X.EXE (and any CC5X headers you reference) directly from B Knudsen
Data under their license terms; this project only invokes the compiler you supply.
"CC5X" and "SETCC" are used here solely to identify the compatible upstream tools.
The device metadata this tool consumes — MPLAB® X, the ipecmd/IPE tooling, the
PICkit™ programmers, and the Device Family Pack (.atpack/_DFP) archives with
their .PIC/.ini/cfgdata contents — are products of, and
Copyright © Microchip Technology Inc. cc5x-helper neither includes nor
redistributes any Microchip software or device packs; you must obtain them
separately from Microchip under their license terms, and this project only reads
the packs you supply. PIC®, PIC10/PIC12/PIC16, MPLAB®, PICkit™, MPLAB SNAP, and
related marks are trademarks or registered trademarks of Microchip Technology Inc.
in the U.S.A. and other countries. All trademarks are the property of their
respective owners. This project is not affiliated with, endorsed by, or supported
by Microchip Technology Inc.
The cc5x-helper source in this repository is licensed under the MIT
LICENSE and does not extend to any third-party CC5X or Microchip
components.