diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index b2576e7..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM ghcr.io/adamrodwell/plc-next-ghcr:2024 \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ae4f3ad..1d76b95 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,12 @@ { "name": "PLCNext Dev Container", - "image": "ghcr.io/cyberflaneurx/plc-next-ghcr:latest", + "image": "ghcr.io/adamrodwell/plc-next-ghcr:2024", + "mounts": [ + "source=${localEnv:HOME}/.claude,target=/home/plc/.claude,type=bind,consistency=cached" + ], + "containerEnv": { + "ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY}" + }, "customizations": { "vscode": { "settings": { @@ -34,10 +40,12 @@ "aaron-bond.better-comments", "ms-azuretools.vscode-docker", "dillonkearns.vscode-gtest-adapter", - "GitHub.vscode-pull-request-github" + "GitHub.vscode-pull-request-github", + "anthropic.claude-code" ] } }, + "postCreateCommand": "curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash - && sudo apt-get install -y nodejs && sudo npm install -g @anthropic-ai/claude-code", "remoteUser": "plc", - "workspaceFolder": "/workspace" -} \ No newline at end of file + "workspaceFolder": "/workspaces/PLCnext" +} diff --git a/.github/workflows/static-code-analysis.yml b/.github/workflows/static-code-analysis.yml index b00c903..d5af0e3 100644 --- a/.github/workflows/static-code-analysis.yml +++ b/.github/workflows/static-code-analysis.yml @@ -14,17 +14,14 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 - - - name: Authenticate Docker with GitHub Container Registry - run: docker login --username cyberflaneurx --password ${{ secrets.GH_PAT }} ghcr.io + uses: actions/checkout@v4 - name: Pull Docker image - run: docker pull ghcr.io/cyberflaneurx/plc-next-ghcr:latest + run: docker pull ghcr.io/adamrodwell/plc-next-ghcr:2024 - name: Start Docker Container run: | - docker run -d --name plcnext_container -v $(pwd):/code -w /code ghcr.io/cyberflaneurx/plc-next-ghcr:latest sleep infinity + docker run -d --name plcnext_container -v $(pwd):/code -w /code ghcr.io/adamrodwell/plc-next-ghcr:2024 sleep infinity - name: Ensure Permissions Inside Container run: | diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ea8ee68 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,121 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Environment + +This project runs inside a Docker dev container (`ghcr.io/cyberflaneurx/plc-next-ghcr:latest`) using VSCode Dev Containers. All PLCnext CLI tools (`plcncli`) and the cross-compilation SDK are pre-installed in the container. The remote user is `plc`. + +The PLCnext SDK targets the **AXCF2152** controller (ARM Cortex-A9, `arm-pxc-linux-gnueabi`) with SDK at `/opt/plcnext_axcf2152_sdk_2023/`. C++ standard is **C++14**. + +## Build Commands + +All commands are run from within a project directory (e.g., `src/projects/StarterKit`): + +```bash +# Generate code and config (required when port definitions change) +export BUILD_TYPE=Release +plcncli generate code --verbose +plcncli generate config --verbose + +# Build (cross-compiles for ARM target) +plcncli build --verbose + +# Deploy (creates .pcwlx library file in bin/) +plcncli deploy + +# Full generate + build + deploy (equivalent to plcnext_gen_build task) +export BUILD_TYPE=Release && plcncli generate code --verbose && plcncli generate config --verbose && plcncli build --verbose && plcncli deploy +``` + +**Use `plcnext_build` (no generate)** when only `.cpp`/`.hpp` logic changed. +**Use `plcnext_gen_build` (with generate)** when port definitions, component/program metadata annotations, or project structure changed. + +## Static Analysis + +```bash +# Run cppcheck on all projects +cppcheck --quiet --enable=warning --force --error-exitcode=2 src/projects + +# With unusedFunction suppressed (as used in CI) +cppcheck --quiet --enable=warning --force --error-exitcode=2 --suppress=unusedFunction src/projects/StarterKit +``` + +## Scaffolding New Projects/Components/Programs + +```bash +# New project (sets target to AXCF2152 automatically) +cd src/projects && plcncli new project -n --force +cd && plcncli set target --add -n AXCF2152 + +# New component within a project +cd src/projects/ && plcncli new component -n + +# New program within a component +cd src/projects/ && plcncli new program -n -c + +# After scaffolding, always regenerate +plcncli generate all +``` + +## Architecture + +### PLCnext Component Model (ARP Framework) + +Each PLCnext project compiles to a shared library (`.so`) packaged as a `.pcwlx` file for use in PLCnext Engineer. + +The ARP (Automation Runtime Platform) framework structures code into three layers: + +- **Library** (`*Library.hpp/.cpp`) — auto-generated; registers the library with the runtime. Do not edit manually. +- **Component** (`*Component.hpp/.cpp`) — manages lifecycle (`Initialize`, `LoadConfig`, `SetupConfig`, `ResetConfig`, `PowerDown`) and owns a `ProgramProvider`. Inherits `ComponentBase` and `ProgramComponentBase`. +- **Program** (`*Program.hpp/.cpp`) — contains the cyclic execution logic in `Execute()`. Inherits `ProgramBase`. + +The `intermediate/` directory contains auto-generated files (code and config metadata). **Do not manually edit files in `intermediate/`** — they are regenerated by `plcncli generate`. + +### Port Annotation System + +Ports (I/O variables exposed to the PLCnext GDS/OPC-UA) are declared using comment annotations in header files: + +```cpp +//#port +//#attributes(Input|Opc) +//#name(MyPortName) +Arp::boolean myField_; +``` + +Port attributes: `Input`, `Output`, `Retain`, `Opc`. After changing any port annotations, `plcncli generate code` and `plcncli generate config` must be re-run. + +### Project Structure + +``` +src/projects// +├── plcnext.proj # Project metadata (target: AXCF2152) +├── CMakeLists.txt # CMake build; links ArpDevice and ArpProgramming +├── src/ # Hand-written source files (Component, Program headers/impls) +├── intermediate/ +│ ├── code/ # Auto-generated: Library, ProgramProvider, *.meta.cpp +│ └── config/ # Auto-generated: .libmeta, .typemeta, .compmeta, .progmeta +└── external/ # Place dependent libraries here +``` + +### Output Artifact + +The built `.pcwlx` file is copied to `/home/plc/Windows_PLCNextEngineer_Libraries` (accessible from the Windows host) for import into PLCnext Engineer. + +## Code Style + +Formatting is enforced by clang-format-14 with `.clang-format` at the repo root: +- Allman brace style, 4-space indent, 100-column limit +- Pointer alignment: right (`int *ptr`) +- Includes sorted, trailing comments aligned + +Format-on-save is configured in the dev container. To format manually: `clang-format-14 -i `. + +## CI + +GitHub Actions (`.github/workflows/static-code-analysis.yml`) runs on push/PR to `main`: +1. Pulls the dev container image +2. Runs `cppcheck` +3. Runs `plcncli generate code`, `generate config`, `build`, `deploy` + +Requires `GH_PAT` secret for authenticating with `ghcr.io`. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8c7e151 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +services: + dev: + image: ghcr.io/adamrodwell/plc-next-ghcr:2024 + volumes: + - .:/workspace:cached + - ~/.claude:/home/plc/.claude + command: sleep infinity + environment: + - SHELL=/bin/zsh + - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} diff --git a/src/projects/StarterKit/plcnext.proj b/src/projects/StarterKit/plcnext.proj index 0490244..8ef605f 100644 --- a/src/projects/StarterKit/plcnext.proj +++ b/src/projects/StarterKit/plcnext.proj @@ -5,5 +5,5 @@ StarterKit true true - AXCF2152,2023.0.0 LTS (23.0.0.65) + AXCF2152,24.0.9.199 \ No newline at end of file