diff --git a/.github/workflows/arstack-winget-manifest.yml b/.github/workflows/arstack-winget-manifest.yml deleted file mode 100644 index 285317450..000000000 --- a/.github/workflows/arstack-winget-manifest.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: ARStack Studio WinGet Manifest - -on: - pull_request: - paths: - - 'scripts/generate_winget_manifest.py' - - 'docs/INSTALL.md' - - '.github/workflows/arstack-winget-manifest.yml' - workflow_dispatch: - inputs: - package_version: - description: 'Unique WinGet package version, e.g. 0.2.0' - required: true - type: string - release_tag: - description: 'Published and verified GitHub stable release tag' - required: true - type: string - installer_type: - description: 'Match the actual installer technology for that release' - required: true - type: choice - options: - - inno - - nullsoft - -permissions: - contents: read - -jobs: - validate-generator: - name: Validate WinGet manifest generation tool - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - uses: actions/checkout@v4 - - name: Check Python generator - run: | - python3 -m py_compile scripts/generate_winget_manifest.py - python3 scripts/generate_winget_manifest.py --help - - prepare-manifest: - name: Generate exact verified installer manifests - needs: validate-generator - if: ${{ github.event_name == 'workflow_dispatch' }} - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@v4 - - name: Generate manifest using published installer SHA-256 - env: - PACKAGE_VERSION: ${{ inputs.package_version }} - RELEASE_TAG: ${{ inputs.release_tag }} - INSTALLER_TYPE: ${{ inputs.installer_type }} - run: | - set -euo pipefail - python3 scripts/generate_winget_manifest.py \ - --version "$PACKAGE_VERSION" \ - --tag "$RELEASE_TAG" \ - --installer-type "$INSTALLER_TYPE" - grep -R 'InstallerSha256: [0-9A-F]\{64\}' dist/winget - - - uses: actions/upload-artifact@v4 - with: - name: arstack-studio-winget-manifests - path: dist/winget/ - if-no-files-found: error - retention-days: 30 diff --git a/.github/workflows/m3h1-cross-platform-release.yml b/.github/workflows/m3h1-cross-platform-release.yml new file mode 100644 index 000000000..c9968c935 --- /dev/null +++ b/.github/workflows/m3h1-cross-platform-release.yml @@ -0,0 +1,166 @@ +name: Publish M3.H.1 Cross-Platform Packaging Release + +on: + pull_request: + paths: + - '.github/workflows/m3h1-cross-platform-release.yml' + - 'docs/releases/M3H1_CROSS_PLATFORM_RELEASE.md' + push: + branches: [main] + paths: + - '.github/workflows/m3h1-cross-platform-release.yml' + - 'docs/releases/M3H1_CROSS_PLATFORM_RELEASE.md' + workflow_dispatch: + +permissions: + contents: read + actions: read + +concurrency: + group: m3h1-once-release + cancel-in-progress: false + +jobs: + validate: + name: Validate immutable cross-platform packaging plan + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - name: Verify release notes and pinned Linux acceptance + run: | + set -euo pipefail + grep -Fq 'same verified M3.H SV/PTP core' docs/releases/M3H1_CROSS_PLATFORM_RELEASE.md + grep -Fq 'Linux x86_64' docs/releases/M3H1_CROSS_PLATFORM_RELEASE.md + test -s docs/INSTALL.md + test ! -e scripts/generate_winget_manifest.py + test ! -e .github/workflows/arstack-winget-manifest.yml + echo 'PASS: packaging-only plan and direct downloads' + + publish: + name: Publish Windows + verified Linux with exact SHA provenance + needs: validate + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: write + actions: read + env: + GH_TOKEN: ${{ github.token }} + ORIGINAL_TAG: processbus-sim-m3h-20261024 + CROSS_PLATFORM_TAG: processbus-sim-m3h1-20261024 + ORIGINAL_SOURCE_TAG_SHA: a4b6e53d0dbbcababc55ba8a4ff97ade6f2a6200 + LINUX_ACCEPTANCE_RUN: '40089029880' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Confirm original release and accepted Linux run + run: | + set -euo pipefail + test "$(git rev-parse "$ORIGINAL_TAG^{commit}")" = "$ORIGINAL_SOURCE_TAG_SHA" + gh api "repos/$GITHUB_REPOSITORY/releases/latest" > /tmp/release-latest.json + gh api "repos/$GITHUB_REPOSITORY/releases/tags/$ORIGINAL_TAG" > /tmp/release-original.json + gh api "repos/$GITHUB_REPOSITORY/actions/runs/$LINUX_ACCEPTANCE_RUN" > /tmp/linux-run.json + python3 - <<'PY' + import json + original=json.load(open('/tmp/release-original.json')) + latest=json.load(open('/tmp/release-latest.json')) + linux=json.load(open('/tmp/linux-run.json')) + assert original['id']==422544367 and not original['prerelease'] and not original['draft'] + assert latest['id']==original['id'], 'A newer stable release already exists; do not supersede' + assert linux['conclusion']=='success' and linux['path'].endswith('m3h-exact-tag-linux-artifact.yml'), 'Linux candidate not accepted' + assert linux['head_sha']=='95d846e7c2ca06878f4a301c5e477002c4e00f77', 'Unexpected acceptance head' + expected={ + 'ARStack-ProcessBus-M3H-win-x64-setup.exe':'4902e8bf44e78fc55a139ce84a1273f0768ef6fe10000f5d0f85d75d2f6c736e', + 'ARStack-ProcessBus-M3H-win-x64-portable.zip':'ca01424e4102aa65e353737024ebf3258b4d2f614fa60d932c95c353ee228d8f', + 'ARStack-ESP32P4-ProcessBus-M3H-firmware.bin':'61c508e9bf1357eb964d2b817b260b6a0e985446ddd68de1d45d9467e25c4607', + 'firmware-manifest.json':'b2878148a1cda30f11a4c93a200bcba07bb63548aa571de8d05260c2ef630f9a', + 'SHA256SUMS.txt':'c7674d1a97b77b66adda12216f7d5e460f86da5cb07fd1d1f02bf3011b99c876', + } + assets={x['name']:(x.get('digest') or '').removeprefix('sha256:') for x in original['assets']} + assert assets==expected, 'Original five release artifacts do not match accepted hashes' + print('PASS: original stable release untouched and exact Linux acceptance validated') + PY + if gh release view "$CROSS_PLATFORM_TAG" >/dev/null 2>&1; then + echo 'Cross-platform release tag already exists; refusing overwrite' >&2 + exit 1 + fi + + - name: Download five original verified release assets + run: | + set -euo pipefail + mkdir -p staging + gh release download "$ORIGINAL_TAG" --dir staging + + - name: Fetch independently accepted M3.H Linux CI package + uses: actions/download-artifact@v4 + with: + name: m3h-exact-tag-linux-candidate + run-id: 40089029880 + github-token: ${{ github.token }} + path: linux-candidate + + - name: Verify Linux artifact and build cross-platform checksum manifest + run: | + set -euo pipefail + (cd linux-candidate && sha256sum -c ARStack-Studio-M3H-exact-tag-linux-x86_64.sha256) + cp linux-candidate/ARStack-Studio-M3H-exact-tag-linux-x86_64.AppImage staging/ARStack-Studio-linux-x86_64.AppImage + python3 - <<'PY' + from pathlib import Path + import hashlib,json + root=Path('staging') + expected={ + 'ARStack-ProcessBus-M3H-win-x64-setup.exe':'4902e8bf44e78fc55a139ce84a1273f0768ef6fe10000f5d0f85d75d2f6c736e', + 'ARStack-ProcessBus-M3H-win-x64-portable.zip':'ca01424e4102aa65e353737024ebf3258b4d2f614fa60d932c95c353ee228d8f', + 'ARStack-ESP32P4-ProcessBus-M3H-firmware.bin':'61c508e9bf1357eb964d2b817b260b6a0e985446ddd68de1d45d9467e25c4607', + 'firmware-manifest.json':'b2878148a1cda30f11a4c93a200bcba07bb63548aa571de8d05260c2ef630f9a' + } + for n,d in expected.items(): + assert hashlib.sha256((root/n).read_bytes()).hexdigest()==d, f'Immutable original bytes changed: {n}' + assert json.loads((root/'firmware-manifest.json').read_text())['buildId']=='a922e9bdba4e57a4' + # Old original checksum file is retained in the source M3.H release; + # replace it ONLY in this new cross-platform release to include Linux. + (root/'SHA256SUMS.txt').unlink() + names=sorted(x.name for x in root.iterdir() if x.is_file() and x.name!='SHA256SUMS.txt') + (root/'SHA256SUMS.txt').write_text(''.join( + hashlib.sha256((root/n).read_bytes()).hexdigest()+' '+n+'\n' for n in names)) + linux='ARStack-Studio-linux-x86_64.AppImage' + (root/'ARStack-Studio-linux-x86_64.sha256').write_text( + hashlib.sha256((root/linux).read_bytes()).hexdigest()+' '+linux+'\n') + print('PASS: same Windows/firmware bytes, verified Linux, new checksums') + PY + (cd staging && sha256sum -c SHA256SUMS.txt && sha256sum -c ARStack-Studio-linux-x86_64.sha256) + test "$(find staging -maxdepth 1 -type f | wc -l)" = 7 + + - name: Publish new stable packaging-only release + run: | + set -euo pipefail + gh release create "$CROSS_PLATFORM_TAG" staging/* \ + --repo "$GITHUB_REPOSITORY" \ + --target "$ORIGINAL_SOURCE_TAG_SHA" \ + --title "ARStack Process Bus Simulator M3.H.1 — Cross-Platform Edition" \ + --notes-file docs/releases/M3H1_CROSS_PLATFORM_RELEASE.md \ + --latest + + - name: Verify published release is complete without mutating original + run: | + set -euo pipefail + gh api "repos/$GITHUB_REPOSITORY/releases/tags/$CROSS_PLATFORM_TAG" > /tmp/release-cross-platform.json + gh api "repos/$GITHUB_REPOSITORY/releases/tags/$ORIGINAL_TAG" > /tmp/release-original-after.json + python3 - <<'PY' + import json,hashlib + before=json.load(open('/tmp/release-original.json')) + old=json.load(open('/tmp/release-original-after.json')) + new=json.load(open('/tmp/release-cross-platform.json')) + assert not new['draft'] and not new['prerelease'] and new['tag_name']=='processbus-sim-m3h1-20261024' + def records(r): + return sorted((a['id'],a['name'],a['size'],a.get('digest')) for a in r['assets']) + assert records(before)==records(old), 'Original M3.H assets changed' + assert len(new['assets'])==7 + for a in new['assets']: + actual=hashlib.sha256(open('staging/'+a['name'],'rb').read()).hexdigest() + assert a.get('digest')=='sha256:'+actual, 'New release hash mismatch: '+a['name'] + print('PASS: new stable Windows+Linux release verified; original M3.H assets and identity preserved') + PY diff --git a/README.md b/README.md index 06028a2f5..e2926b21e 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ For active SV/PTP transmission, use an **isolated laboratory Ethernet network**, | Windows Portable ZIP | **Available** in the [latest release](https://github.com/masarray/arstack61850/releases/latest) | | Matched ESP32-P4 firmware | **Available** with the same release | | Linux AppImage | Shown in the [latest release](https://github.com/masarray/arstack61850/releases/latest) when a tested package is published | -| Windows package manager | [WinGet preparation and status](docs/INSTALL.md#windows-package-manager--winget) | Every published Windows release includes the application dependencies and a matched firmware package; no C++ build environment is required for ordinary installation. @@ -53,7 +52,8 @@ Every published Windows release includes the application dependencies and a matc ARStack is built to make IEC 61850 experiments more accessible to engineers, students and automation enthusiasts around the world. - **[Ask a question or report a problem](SUPPORT.md)** — share what you tried and what happened. -- **[Share an interoperability experiment](docs/COMMUNITY_TESTING.md)** — feedback from independent laboratory setups helps improve the project. +- **[Share an interoperability experiment](docs/COMMUNITY_TESTING.md)** — independent lab experiences help improve the project; [browse community reports](docs/community/README.md). +- **[SCL import help](docs/SCL_TROUBLESHOOTING.md)** — a practical path when imported SV fields do not appear. - **[Contribute](CONTRIBUTING.md)** — improvements to documentation, software, tests and examples are welcome. ARStack uses the [GPL-3.0 license](LICENSE). It is a laboratory simulation and engineering tool, not a certified primary measurement or UTC reference device. diff --git a/SUPPORT.md b/SUPPORT.md index 651c4996c..1851bd8b0 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -8,7 +8,7 @@ Use the [simple bug-report form](https://github.com/masarray/arstack61850/issues Useful details include the Studio release, Windows version, ESP32-P4 firmware build if connected, the exact error shown and the last action you tried. -**SCL import issue?** Share a screenshot of the validation result and, if permissible, a sanitized SCL/CID/SCD/IID file that reproduces it. Never share confidential installation data. +**SCL import issue?** Follow the [SCL import troubleshooting steps](docs/SCL_TROUBLESHOOTING.md). Share the Studio version, stream selection and a sanitized sample if possible. Never share confidential installation data. **Can't find the board?** Check the USB data cable and serial device selection; use **Configuration → Firmware** to verify the ESP32-P4 and install matching firmware. diff --git a/docs/COMMUNITY_TESTING.md b/docs/COMMUNITY_TESTING.md index 7dc48a3d8..0bed64434 100644 --- a/docs/COMMUNITY_TESTING.md +++ b/docs/COMMUNITY_TESTING.md @@ -2,7 +2,7 @@ Have you tried ARStack with a simulator, analyzer, protection relay or bay controller in your own lab? Your results can help the international IEC 61850 community discover useful configurations and improve ARStack. -**[Share an interoperability report](https://github.com/masarray/arstack61850/issues/new?template=interoperability.yml)** · [Ask for help](../SUPPORT.md) +**[Share an interoperability report](https://github.com/masarray/arstack61850/issues/new?template=interoperability.yml)** · [Browse community reports](community/README.md) · [Ask for help](../SUPPORT.md) ## What is helpful to share? diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 90b4e5719..580481fd9 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -65,7 +65,7 @@ Adjust a voltage or current setpoint and observe the generated waveform. Open a ## Need help? -Check the [installation guide](INSTALL.md) or [support guide](../SUPPORT.md). If a file does not import or a device will not connect, share the Studio version, the error message and a sanitized example file if possible. +Check the [installation guide](INSTALL.md) or [support guide](../SUPPORT.md). For an SCL import where SV ID or MAC address does not appear, follow the [SCL troubleshooting guide](SCL_TROUBLESHOOTING.md). If a device will not connect, share the Studio version and the displayed error. Want to publish observations from another IEC 61850 tool or device? See the [community testing guide](COMMUNITY_TESTING.md). diff --git a/docs/INSTALL.md b/docs/INSTALL.md index cebd10344..008271866 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -18,7 +18,7 @@ To download a verified copy without starting the installer, run `& $script -Down ## Linux (x86_64) -When the latest GitHub release offers `ARStack-Studio-linux-x86_64.AppImage`, download it, mark it executable (`chmod +x`) and open it. You can also install it into your home folder with: +For Linux x86_64, download `ARStack-Studio-linux-x86_64.AppImage` from the [latest stable release](https://github.com/masarray/arstack61850/releases/latest) when listed. Mark it executable (`chmod +x`) and open it. You can also install it into your home folder with: ```bash curl -fLsS https://raw.githubusercontent.com/masarray/arstack61850/main/scripts/install-linux.sh -o /tmp/arstack-install-linux.sh @@ -27,18 +27,6 @@ bash /tmp/arstack-install-linux.sh The install script checks the matching published SHA-256. It will explain when the current release does not yet contain a Linux build rather than downloading an older or unverified binary. The AppImage build is only published after Linux CI succeeds. -## Windows Package Manager / WinGet - -WinGet uses an indexed, versioned package manifest. The release tooling prepares a manifest from the actual installer and SHA-256 once a release is final. The Microsoft community repository must accept the package **before** a public `winget install MasArray.ARStackStudio` command works; until then, use the Windows command above. A script or README alone does not register a WinGet package. - -Maintainer command (requires a tagged release with a unique Windows package version): - -```bash -python3 scripts/generate_winget_manifest.py --version X.Y.Z --installer-type inno -``` - -Review the generated YAML, validate with WinGet tooling, and submit it to [microsoft/winget-pkgs](https://github.com/microsoft/winget-pkgs). Use `--installer-type nullsoft` for the earlier NSIS installer format. - ## First lab experiment 1. Open **ARStack Studio** and start from the built-in 4I+4V profile. diff --git a/docs/SCL_TROUBLESHOOTING.md b/docs/SCL_TROUBLESHOOTING.md new file mode 100644 index 000000000..a8e57d7fd --- /dev/null +++ b/docs/SCL_TROUBLESHOOTING.md @@ -0,0 +1,35 @@ +# SCL import troubleshooting — find your SV stream + +If ARStack Studio opens an SCL file but does not show the SV ID, multicast MAC or publisher configuration you expected, these steps help narrow down what happened. + +## 1. Start with the latest Studio + +Download the [latest stable release](https://github.com/masarray/arstack61850/releases/latest). Check the installed version in Studio before comparing behavior with other engineering tools. + +## 2. Open the actual engineering file + +Use **Open SCL** with your `.scd`, `.cid`, `.icd` or `.iid` file. Successful XML import tells you the file was read; it does not automatically select an SV publisher or deploy it to the board. + +Look for the file's IED, AccessPoint, logical device, SV control block and DataSet. If the file contains several publishers, select the intended SV stream before evaluating its fields. + +## 3. Check the publisher address mapping + +For a stream configured in SCL, `svID` is commonly associated with `SampledValueControl`, while multicast MAC address and APPID appear in the relevant `Communication/ConnectedAP/SMV/Address` mapping. A valid file can have more than one candidate stream. + +If the SV ID or MAC is blank, inspect the Studio stream selection and validation messages. A file that opens successfully might still lack a selectable deployment profile in the current reference workflow. + +## 4. Try the 4I+4V Quick Start + +Choose **4I+4V Quick Start** and verify that the supported SV publisher profile appears. This is a useful comparison against the imported SCL. For real network output, firmware on the ESP32-P4 must match the Studio release. + +## 5. Share a reproducer + +If the SV fields still do not appear: + +- Note the **ARStack Studio version** and which SCL IED / stream you selected. +- Capture a screenshot of the import result and any validation messages. +- Share the smallest **sanitized SCL** file that reproduces the behavior, either through the [bug report form](https://github.com/masarray/arstack61850/issues/new?template=bug_report.yml) or a private message/link to the maintainer when you are already in contact. + +Remove project names, substation identifiers and other confidential engineering data before sharing files. We welcome files generated by different IEC 61850 engineering environments because they help make import workflows easier for everyone. + +[Back to Getting Started](GETTING_STARTED.md) · [Support](../SUPPORT.md) diff --git a/docs/community/README.md b/docs/community/README.md new file mode 100644 index 000000000..6c705d0e0 --- /dev/null +++ b/docs/community/README.md @@ -0,0 +1,26 @@ +# Community IEC 61850 experiments + +Real experiences from independent engineering labs help other users learn how to experiment with SV and PTP. + +**[Browse submitted experiments](https://github.com/masarray/arstack61850/issues?q=is%3Aissue+%22Community+test%3A%22)** · **[Share your experiment](https://github.com/masarray/arstack61850/issues/new?template=interoperability.yml)** · [First-run tutorial](../GETTING_STARTED.md) + +## What you can share + +A simple diagram of your test network, a screenshot, a sanitized SV/PTP capture, or a short explanation of the behavior you observed is enough to start. You may use ARStack with analyzers, simulated IEC 61850 subscribers, protection relays or bay controllers. + +Try telling other engineers: + +1. **Setup:** ARStack Studio version and firmware, plus receiver/analyzer model and revision if known. +2. **Configuration:** SV APPID, svID, 4I+4V sample profile, PTP mode and Ethernet test topology. +3. **Observation:** What happened? What worked well? What would you like to see improved? +4. **Evidence (optional):** Screenshot, decoded frame summary or sanitized packet capture. + +## How results are described + +A report contributed by an engineer is credited as a **community observation** for that particular setup. When reproduced independently, the record can be updated to distinguish the verified result. + +Only actual reports are listed in the [GitHub community test tracker](https://github.com/masarray/arstack61850/issues?q=is%3Aissue+%22Community+test%3A%22); this page does not manufacture compatibility claims or imply endorsement by manufacturers. + +## Keep the lab isolated + +Never connect an unsolicited SV publisher or simulated PTP grandmaster to a live substation process bus. Remove station identifiers, addresses, credentials and proprietary configuration data from any files you share. diff --git a/docs/releases/M3H1_CROSS_PLATFORM_RELEASE.md b/docs/releases/M3H1_CROSS_PLATFORM_RELEASE.md new file mode 100644 index 000000000..dd77e3193 --- /dev/null +++ b/docs/releases/M3H1_CROSS_PLATFORM_RELEASE.md @@ -0,0 +1,21 @@ +# ARStack Studio M3.H.1 — Cross-Platform Packaging Update + +**Windows and Linux desktop packages · same verified M3.H SV/PTP core** + +This packaging update adds a Linux x86_64 AppImage to the existing Windows installer and portable packages. **No ESP32-P4 firmware or SV/PTP timing implementation has changed.** The Linux AppImage is built from the exact existing M3.H tag and validated with native/headless AppImage checks. Existing Windows binaries and firmware are copied byte-for-byte from the original stable release, with matching SHA-256. + +## Download + +Choose the file for your operating system: + +- **Windows 10/11 x64:** `ARStack-ProcessBus-M3H-win-x64-setup.exe` or Portable ZIP. +- **Linux x86_64:** `ARStack-Studio-linux-x86_64.AppImage`, with matching `.sha256` checksum. +- **ESP32-P4 board:** the existing matched firmware image, bundled with the Windows packages and included in the Linux AppImage. + +Use [Getting Started](https://github.com/masarray/arstack61850/blob/main/docs/GETTING_STARTED.md) to begin. The same 4I+4V / 4,000 frames/s SV publisher and laboratory PTP grandmaster emulator are included. + +## Engineering evidence + +The M3.H acceptance capture measured 163,048 contiguous Sampled Values packets, 3,999.884 frames/s and `smpSynch=2` throughout the recorded interval. The [original technical record](https://github.com/masarray/arstack61850/blob/main/docs/releases/PROCESS_BUS_SIMULATOR_M3H_PUBLIC_20261024.md) contains measured details. + +The Windows Setup/Portable and firmware assets retain their original hashes and source build identity; this release changes only cross-platform distribution. Run active SV/PTP experiments on an **isolated laboratory Ethernet network**. diff --git a/index.html b/index.html index d8fcc7ff6..ba62854f6 100644 --- a/index.html +++ b/index.html @@ -71,7 +71,7 @@

Your own IEC 61850 Process Bus lab.

Build-specific checksums and metadata are provided on the release page: SHA256SUMS.txt · firmware-manifest.json · M3.H measured benchmark.

- +