Metadata-Version: 2.4
Name: embflasher
Version: 0.1.1
Summary: Cross-platform CMSIS-DAP firmware programmer driven by CMSIS FLM flash algorithms
License-Expression: MIT
Project-URL: Homepage, https://github.com/your-org/embflasher
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Embedded Systems
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyocd<0.46,>=0.45
Dynamic: license-file

# embflasher

Cross-platform CMSIS-DAP firmware programmer driven by CMSIS FLM flash algorithms, built on [pyOCD](https://pyocd.io/).

```
CLI
 ↓
Python API (embflasher.flash)
 ↓
pyOCD
 ↓
DAPLink / CMSIS-DAP
 ↓
MCU
```

Supports macOS, Windows, and Linux (Ubuntu).

## Installation

```
pip install embflasher
```

Local development:

```
git clone <repo-url>
cd embflasher
pip install -e .
```

## Usage

```
embflasher --help
embflasher probe list
embflasher flash firmware.hex --flm chip.flm
```

Minimal usage — only `firmware` and `--flm` are required, everything else uses a sensible default (sector erase, verify on, reset on, 100k SWD frequency, `cortex_m` target):

```
embflasher flash firmware.bin --flm NS800RT50x9.FLM
```

If more than one DAPLink/CMSIS-DAP probe is connected, select one explicitly:

```
embflasher probe list
embflasher flash firmware.hex --flm chip.flm --probe <unique-id>
```

Full option list:

```
embflasher flash firmware.{bin,hex,elf} --flm chip.flm
  [--probe <unique-id>]
  [--erase auto|sector|chip]      (default: sector)
  [--no-verify]
  [--no-reset]
  [--bin-address 0x...]           (.bin only; default: FLM's Flash start)
  [--frequency 100k]              (default: 100k)
  [--connect halt|pre-reset|under-reset|attach]  (default: under-reset)
  [--target cortex_m]             (default: cortex_m)
  [--ram-start 0x20000000]        (default: 0x20000000)
  [--ram-size 0x...]              (default: max(64KiB, FLM minimum))
```

## Python API

```python
from embflasher import flash, list_probes

flash(firmware="app.hex", flm="chip.flm")

# with overrides
flash(
    firmware="app.bin",
    flm="chip.flm",
    probe="0123456789ABCDEF",
    target="cortex_m",
    frequency="4M",
    erase="chip",
    verify=True,
    reset=True,
)

print(list_probes())
```

## Requirements

- Python >= 3.10
- A DAPLink or CMSIS-DAP compatible debug probe
- pyOCD (installed automatically as a dependency)

### USB permissions on Linux

On Ubuntu/Linux, the debug probe usually needs a udev rule to be accessible without root. pyOCD ships one:

```
python -m pyocd pack update   # optional, first run
sudo curl -o /etc/udev/rules.d/50-cmsis-dap.rules \
  https://raw.githubusercontent.com/pyocd/pyOCD/main/udev/50-cmsis-dap.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
```

Then unplug and replug the probe.

## Releasing a new version (maintainers)

Pushing commits to `main` does **not** publish anything by itself. Publishing to PyPI only happens when a GitHub Release is created, and that Release must point at a tag. The chain is:

```
bump version in pyproject.toml
        ↓
git commit + git push (to main)
        ↓
git tag vX.Y.Z + git push origin vX.Y.Z
        ↓
gh release create vX.Y.Z   (or create it from the GitHub web UI)
        ↓
GitHub Actions: .github/workflows/publish.yml runs automatically
        ↓
  1. checkout, python -m build  → builds dist/*.whl and dist/*.tar.gz
  2. uploads them as a workflow artifact
  3. downloads the artifact into the `pypi` environment job
  4. pypa/gh-action-pypi-publish uploads them to PyPI via
     Trusted Publishing (OIDC) — no API token needed
        ↓
pip install embflasher   ← now installs the new version
```

Step-by-step for a real release:

```bash
# 1. bump the version
#    edit pyproject.toml: version = "0.1.2"
git add pyproject.toml
git commit -m "Bump version to 0.1.2"
git push origin main

# 2. tag the commit that should be released
git tag -a v0.1.2 -m "v0.1.2"
git push origin v0.1.2

# 3. create the GitHub Release — THIS is what triggers the publish workflow
gh release create v0.1.2 --title "v0.1.2" --notes "..."
```

After step 3, check progress with:

```bash
gh run list --workflow=publish.yml --limit 1
gh run watch
```

Notes:

- Creating just a tag does **not** trigger anything. The workflow only fires `on: release: types: [published]`.
- The PyPI project must have a "pending publisher" (or an existing Trusted Publisher) configured once, at https://pypi.org/manage/account/publishing/, pointing at this repo (`codeing-link/embflasher`), workflow file `publish.yml`, and environment name `pypi`. This is a one-time, manual step done on pypi.org — it cannot be automated from the repo.
- The repo also needs a GitHub Environment named `pypi` (Settings → Environments) for the OIDC trust relationship declared in `publish.yml` (`environment: pypi`, `permissions: id-token: write`).
- PyPI does not allow re-uploading the same version number. If a release fails partway, bump the version again rather than retrying the same tag.
- This works the same whether the repository is public or private — Trusted Publishing is based on the OIDC token GitHub issues for the workflow run, not on repo visibility.

## License

MIT
