From f589fb2094d6301417635951baab9b0a12a325c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:41:48 +0000 Subject: [PATCH 1/9] Initial plan From c18d766f397da09cf69d1268f11b431bac077405 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:48:21 +0000 Subject: [PATCH 2/9] Add AI skills for device bindings, builds, documentation, and hardware abstraction Co-authored-by: krwq <660048+krwq@users.noreply.github.com> --- .github/skills/README.md | 169 +++++++ .github/skills/add-device-binding/SKILL.md | 215 +++++++++ .github/skills/debug-build-issues/SKILL.md | 264 +++++++++++ .github/skills/fix-api-conventions/SKILL.md | 354 ++++++++++++++ .../hardware-abstraction-check/SKILL.md | 431 ++++++++++++++++++ .../update-device-documentation/SKILL.md | 392 ++++++++++++++++ 6 files changed, 1825 insertions(+) create mode 100644 .github/skills/README.md create mode 100644 .github/skills/add-device-binding/SKILL.md create mode 100644 .github/skills/debug-build-issues/SKILL.md create mode 100644 .github/skills/fix-api-conventions/SKILL.md create mode 100644 .github/skills/hardware-abstraction-check/SKILL.md create mode 100644 .github/skills/update-device-documentation/SKILL.md diff --git a/.github/skills/README.md b/.github/skills/README.md new file mode 100644 index 0000000000..f2afcd7d6c --- /dev/null +++ b/.github/skills/README.md @@ -0,0 +1,169 @@ +# GitHub Copilot AI Skills for .NET IoT Repository + +This directory contains AI skills that help GitHub Copilot agents perform specialized tasks in the .NET IoT repository. Skills are automatically loaded by Copilot based on context and task requirements. + +## Available Skills + +### 1. [add-device-binding](./add-device-binding/SKILL.md) +**Purpose:** Guide for adding new IoT device bindings following repository conventions. + +**When to use:** +- Adding a new sensor, display, motor, or other hardware device binding +- Creating driver code under `src/devices/` +- Ensuring device follows .NET IoT patterns + +**Key features:** +- Device structure setup +- API design patterns (TryRead* methods, UnitsNet types) +- Resource management (IDisposable) +- Documentation requirements +- Sample application guidelines + +### 2. [debug-build-issues](./debug-build-issues/SKILL.md) +**Purpose:** Diagnose and resolve build, compilation, and SDK issues. + +**When to use:** +- Build fails with SDK resolution errors +- Package restore failures +- Long-running build timeouts +- CI/CD pipeline failures +- Memory issues during build + +**Key features:** +- Azure DevOps feeds troubleshooting +- Common build issues and solutions +- Alternative build approaches +- Expected timing reference +- Log location guidance + +### 3. [fix-api-conventions](./fix-api-conventions/SKILL.md) +**Purpose:** Ensure device bindings follow repository API conventions. + +**When to use:** +- Reviewing device binding code +- Fixing API design issues +- Code review identifies convention violations +- Modernizing older device bindings + +**Key features:** +- API naming conventions +- UnitsNet usage patterns +- Constructor design guidelines +- Resource management patterns +- Error handling best practices + +### 4. [update-device-documentation](./update-device-documentation/SKILL.md) +**Purpose:** Create and maintain comprehensive device documentation. + +**When to use:** +- Adding documentation for new device +- Updating existing device docs +- Adding wiring diagrams +- Improving code examples +- Adding XML documentation + +**Key features:** +- README structure and content +- Wiring information templates +- XML documentation patterns +- Code example guidelines +- Markdown linting compliance + +### 5. [hardware-abstraction-check](./hardware-abstraction-check/SKILL.md) +**Purpose:** Verify proper hardware abstraction and cross-platform compatibility. + +**When to use:** +- Reviewing new device binding code +- Code contains platform-specific APIs +- Ensuring cross-platform compatibility +- Validating no OS dependencies introduced + +**Key features:** +- Anti-pattern detection (P/Invoke, hardcoded paths) +- System.Device.* abstraction usage +- Automated compliance checks +- Cross-platform testing guidance +- Platform-specific code guidelines + +## How Skills Work + +GitHub Copilot agents automatically discover and use these skills when: +1. Task matches skill description +2. Agent needs domain-specific guidance +3. Context indicates skill would be helpful + +Skills are defined using the standard GitHub Copilot Agent Skills format: +- Each skill has its own directory +- `SKILL.md` file contains metadata (YAML frontmatter) and instructions +- Skills can include supporting files (scripts, examples, templates) + +## Skill Format + +Each `SKILL.md` follows this structure: + +```markdown +--- +name: skill-name +description: Brief description of what the skill does +license: MIT +--- + +## Purpose +What the skill helps with + +## When to Use This Skill +Specific scenarios for using the skill + +## Instructions +Detailed step-by-step guidance + +## Examples +Code examples and demonstrations + +## References +Links to related documentation +``` + +## Creating New Skills + +To add a new skill: + +1. Create directory: `.github/skills//` +2. Create `SKILL.md` with proper frontmatter +3. Include clear instructions and examples +4. Add references to relevant documentation +5. Test skill with Copilot agent + +## Skill Development Guidelines + +When creating or updating skills: + +- **Be specific:** Provide concrete, actionable instructions +- **Include examples:** Show code examples and commands +- **Reference documentation:** Link to relevant docs and conventions +- **Keep focused:** Each skill should address one specific domain +- **Test thoroughly:** Ensure instructions work as documented + +## Relationship to Copilot Instructions + +These skills complement the main [copilot-instructions.md](../copilot-instructions.md): + +- **Copilot Instructions:** General guidance loaded for all tasks +- **Skills:** Specialized, task-specific guidance loaded on-demand + +Skills should reference and build upon copilot instructions, not duplicate them. + +## Contributing + +When adding new skills, consider: +- Common issues encountered in the repository +- Repetitive tasks that need guidance +- Complex procedures that benefit from step-by-step instructions +- Platform-specific knowledge (build system, conventions, etc.) + +## References + +- [GitHub Copilot Agent Skills Documentation](https://docs.github.com/en/copilot/concepts/agents/about-agent-skills) +- [.NET IoT Copilot Instructions](../copilot-instructions.md) +- [.NET IoT Contributing Guide](../../Documentation/CONTRIBUTING.md) +- [Device Conventions](../../Documentation/Devices-conventions.md) diff --git a/.github/skills/add-device-binding/SKILL.md b/.github/skills/add-device-binding/SKILL.md new file mode 100644 index 0000000000..f449c299cd --- /dev/null +++ b/.github/skills/add-device-binding/SKILL.md @@ -0,0 +1,215 @@ +--- +name: add-device-binding +description: Guide for adding new IoT device bindings to the repository following .NET IoT conventions +license: MIT +--- + +## Purpose + +This skill helps Copilot agents create new IoT device bindings (sensors, displays, motors, etc.) that follow the repository's established patterns and conventions for System.Device.Gpio and Iot.Device.Bindings. + +## When to Use This Skill + +- Developer requests adding a new device binding for a sensor, display, motor, or other hardware component +- Creating a new driver under `src/devices/` +- Need to ensure the device follows .NET IoT conventions and patterns + +## Instructions + +### 1. Device Structure Setup + +Create the following directory structure under `src/devices/`: +``` +src/devices// +├── .csproj +├── .cs (main class) +├── samples/ +│ ├── .samples.csproj +│ └── Program.cs +├── tests/ (if applicable) +│ └── .Tests.csproj +└── README.md +``` + +### 2. Constructor & Dependencies + +- Accept hardware transports from the caller: `I2cDevice`, `SpiDevice`, `GpioController`, pin numbers, bus addresses +- Provide sensible defaults (e.g., common I²C addresses like 0x48) +- **Never hardcode board-specific details** +- Avoid singletons and global state + +**Example Constructor:** +```csharp +public Bmp280(I2cDevice i2cDevice, I2cAddress address = I2cAddress.Primary) +{ + _i2cDevice = i2cDevice ?? throw new ArgumentNullException(nameof(i2cDevice)); + _address = address; +} +``` + +### 3. API Design Patterns + +- Use **`TryRead*` methods** that return `bool` and set `out` parameters for sensor readings + ```csharp + public bool TryReadTemperature(out Temperature temperature) + ``` +- Use **UnitsNet** types for physical quantities (Temperature, Pressure, Length, etc.) +- Properties for values that don't change between calls +- Methods for values that may change +- Use enums/flags for registers, modes, scales +- Keep synchronous APIs predictable; only use `async` if genuine I/O concurrency needed + +### 4. Resource Management (CRITICAL) + +- **MUST implement `IDisposable`** +- Dispose hardware resources (I2C/SPI devices, GPIO pins) in the Dispose method +- If transport is passed by caller, dispose it unless `shouldDispose` flag says otherwise +- Design for failure: ensure exceptions leave device in consistent state + +**Example Disposal:** +```csharp +protected virtual void Dispose(bool disposing) +{ + if (_disposed) + return; + + if (disposing) + { + _i2cDevice?.Dispose(); + _i2cDevice = null; + } + + _disposed = true; +} +``` + +### 5. Error Handling + +- Guard against misuse with `ArgumentException`/`ArgumentNullException` +- For transient hardware issues, throw or return `false` in `Try*` patterns +- **Never return bogus data silently** +- Validate checksums/status bits where appropriate + +### 6. Documentation Requirements + +- XML documentation comments on all public APIs +- **Include units** in comments (°C, Pa, %RH, lux, etc.) +- Document parameter ownership (does caller own the transport?) +- README.md with: + - Device description and capabilities + - Wiring diagram or connection instructions + - Required pull-ups/pull-downs + - Expected ranges and units + - Code example demonstrating usage + +### 7. Sample Application + +Create a runnable sample in `samples/Program.cs`: +- Keep it simple and readable +- Demonstrate typical usage patterns +- Show proper disposal (using statements) +- Handle exceptions gracefully +- Don't hardcode board-specific paths + +**Example Sample:** +```csharp +using System; +using System.Device.I2c; +using Iot.Device.Bmp280; + +using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(1, Bmp280.DefaultI2cAddress)); +using Bmp280 sensor = new(i2cDevice); + +while (true) +{ + if (sensor.TryReadTemperature(out Temperature temp)) + { + Console.WriteLine($"Temperature: {temp.DegreesCelsius:F2} °C"); + } + Thread.Sleep(1000); +} +``` + +### 8. Cross-Platform Considerations + +- Use **System.Device.*** abstractions exclusively +- No P/Invoke or OS-specific syscalls +- No hardcoded paths to `/sys` or `/proc` +- If a feature is platform-only, guard it and fail gracefully + +### 9. Testing + +- Add unit tests for logic that can be isolated from hardware +- Focus on: framing/parsing functions, calculations, protocol logic +- Hardware-dependent tests should be clearly marked +- Ensure samples compile even without hardware + +### 10. Build Validation + +After creating the device: +```bash +cd src/devices/ +../../../dotnet.sh build + +cd samples +../../../../dotnet.sh build + +# Check for hardware abstraction violations +grep -r "Environment.OSVersion\|DllImport\|P/Invoke" . +``` + +## Review Checklist + +Before completing: +- [ ] Public API follows repo naming/style +- [ ] Members are XML-documented with units (°C, Pa, %RH, lux, etc.) +- [ ] Constructor accepts caller-provided transports +- [ ] Implements `IDisposable`; all hardware resources released +- [ ] Uses enums/consts for registers/addresses +- [ ] Validates timing and checksums +- [ ] `Try*` methods return accurate success/failure +- [ ] Adds sample application +- [ ] Adds device README with wiring info +- [ ] Adds tests for hardware-independent logic +- [ ] Builds successfully without errors +- [ ] No platform-specific code or P/Invoke + +## Examples + +### Good Device Binding Example +```csharp +public class Dht22 : IDisposable +{ + private GpioController? _controller; + private readonly int _pin; + private readonly bool _shouldDispose; + + public Dht22(int pin, GpioController? controller = null, bool shouldDispose = true) + { + _pin = pin; + _shouldDispose = shouldDispose || controller is null; + _controller = controller ?? new GpioController(); + } + + public bool TryReadTemperature(out Temperature temperature) + { + // Implementation that validates data and checksums + } + + public void Dispose() + { + if (_shouldDispose) + { + _controller?.Dispose(); + } + _controller = null; + } +} +``` + +## References + +- [Device Conventions](../../../Documentation/Devices-conventions.md) +- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) +- [Copilot Instructions](../../copilot-instructions.md) +- [UnitsNet Library](https://github.com/angularsen/UnitsNet) diff --git a/.github/skills/debug-build-issues/SKILL.md b/.github/skills/debug-build-issues/SKILL.md new file mode 100644 index 0000000000..343b08bd01 --- /dev/null +++ b/.github/skills/debug-build-issues/SKILL.md @@ -0,0 +1,264 @@ +--- +name: debug-build-issues +description: Guide for diagnosing and resolving build, compilation, and SDK issues in the .NET IoT repository +license: MIT +--- + +## Purpose + +This skill helps Copilot agents diagnose and fix build issues in the .NET IoT repository, which has specific requirements around Azure DevOps feeds, .NET SDK versions, and lengthy build times. + +## When to Use This Skill + +- Build fails with SDK resolution errors +- Package restore failures +- Compilation errors after making changes +- Long-running build timeouts +- CI/CD pipeline failures +- Memory issues during build + +## Instructions + +### 1. Understanding Build Requirements + +**CRITICAL Prerequisites:** +- Azure DevOps feeds access required for full builds +- .NET 8.0.300 SDK (specified in `global.json`) +- Build takes 30-45 minutes normally - **NEVER CANCEL** +- Test runs take 15-30 minutes + +### 2. Common Build Issues and Solutions + +#### SDK Resolution Errors +**Symptom:** `Could not resolve SDK Microsoft.DotNet.Arcade.Sdk` + +**Diagnosis:** +```bash +# Check SDK version +./dotnet.sh --version + +# Verify global.json +cat global.json +``` + +**Solutions:** +1. Azure DevOps feeds are inaccessible (network restriction) + - Document as known limitation + - Try alternative build approaches (see below) +2. SDK version mismatch + - Ensure .NET 8.0.300 SDK is installed + - `./dotnet.sh --version` will auto-download if needed + +#### Package Not Found Errors +**Symptom:** NuGet package restore failures + +**Diagnosis:** +```bash +# Check NuGet sources +cat NuGet.config + +# Check network connectivity to Azure DevOps +# (feeds are at Azure DevOps, not public NuGet) +``` + +**Solutions:** +1. Verify NuGet.config has correct sources +2. Check if Azure DevOps feeds are accessible +3. Try clearing NuGet cache: `dotnet nuget locals all --clear` + +#### Memory Issues During Build +**Symptom:** Out of memory errors, process killed + +**Solutions:** +```bash +# Disable parallel builds +./build.sh --restore --build /maxCpuCount:1 + +# Or build smaller subsets +cd src/devices/Bmp280 +../../../dotnet.sh build +``` + +#### Timeout Issues +**Symptom:** Build appears hung or times out + +**Important:** Builds legitimately take 30-45 minutes +- Set timeout to **60+ minutes** for full builds +- Set timeout to **45+ minutes** for test runs +- Use `initial_wait` parameter appropriately in bash commands + +### 3. Alternative Build Approaches + +When Azure DevOps feeds are inaccessible: + +#### Build Individual Samples +```bash +# Samples use public NuGet packages +cd samples/led-blink +../../dotnet.sh build +``` + +#### Test Basic IoT Functionality +```bash +./dotnet.sh new console -o test-project +cd test-project +./dotnet.sh add package System.Device.Gpio +./dotnet.sh add package Iot.Device.Bindings +./dotnet.sh build && ./dotnet.sh run +``` + +#### Build Individual Device Bindings +```bash +cd src/devices/ +../../../dotnet.sh build +``` + +### 4. Build Commands by Scenario + +#### Full Repository Build +```bash +# Use this for complete validation +./build.sh --restore --build --configuration Release +# Expected time: 30-45 minutes +# Timeout setting: 60+ minutes +``` + +#### Build with Packages +```bash +# For testing distribution +./build.sh --restore --build --pack --configuration Release +``` + +#### Run Tests +```bash +# All tests +./build.sh --test --configuration Release +# Expected time: 15-30 minutes + +# Specific test project +./dotnet.sh test src/devices/Dhtxx/tests/ +``` + +#### Individual Device Build +```bash +cd src/devices/Dhtxx +../../../dotnet.sh build +# Expected time: 1-3 minutes +``` + +### 5. Debugging Compilation Errors + +#### After Code Changes +```bash +# Build the specific project you changed +cd src/devices/ +../../../dotnet.sh build + +# Check for warnings/errors in output +# Fix compiler warnings - they're required by analyzers +``` + +#### Check for Common Issues +```bash +# Verify .editorconfig compliance +# Build will show analyzer warnings + +# Check for using directive issues +# Ensure proper namespace imports + +# Validate nullability +# Code should be null-safe with proper annotations +``` + +### 6. CI/CD Pipeline Issues + +When GitHub Actions workflows fail: + +```bash +# Check workflow status +gh run list --limit 5 + +# View specific run logs +gh run view --log + +# Common CI issues: +# - Markdown linting failures +# - Build timeouts (increase timeout) +# - Test failures (check if pre-existing) +``` + +#### Markdown Linting +```bash +npm install -g markdownlint-cli +markdownlint -c .markdownlint.json . +``` + +### 7. Log Locations + +When builds fail, check logs: +- Build logs: `artifacts/log/{Configuration}/` +- Test results: Published in CI artifacts +- Individual project logs: In project's bin/obj folders + +### 8. Cross-Platform Build Issues + +#### Linux vs Windows Issues +- Check for platform-specific files: `*.Linux.cs` vs `*.Windows.cs` +- Verify configurations in Visual Studio +- Use `System.Device.*` abstractions, not OS-specific APIs + +### 9. Diagnostic Commands + +```bash +# Check repository status +git --no-pager status +git --no-pager diff + +# Verify .NET installation +./dotnet.sh --version +./dotnet.sh --info + +# Check for stale build artifacts +ls -la artifacts/ + +# Clean build +rm -rf artifacts/ +./build.sh --restore --build --configuration Release + +# Check for platform abstraction violations +grep -r "Environment.OSVersion\|DllImport\|P/Invoke" src/devices// +``` + +### 10. When to Escalate + +Document and inform user when: +- Azure DevOps feeds are confirmed inaccessible (network policy) +- Build requires infrastructure changes +- Pre-existing test failures unrelated to changes +- Issues require maintainer intervention + +## Troubleshooting Workflow + +1. **Identify the error** - Read error messages carefully +2. **Check prerequisites** - Verify SDK version, network access +3. **Try minimal build** - Build just the affected component +4. **Check for pre-existing issues** - Build before your changes +5. **Clear and rebuild** - Remove artifacts and try clean build +6. **Use alternative approaches** - Try sample builds if main build blocked +7. **Document limitations** - Note if Azure DevOps access is issue + +## Expected Timing Reference + +| Command | Expected Time | Timeout Setting | +|---------|---------------|-----------------| +| `./build.sh --restore --build` | 30-45 minutes | 60+ minutes | +| `./build.sh --test` | 15-30 minutes | 45+ minutes | +| Individual device build | 1-3 minutes | 10 minutes | +| Sample project build | 30-60 seconds | 5 minutes | +| Full CI pipeline | 45-60 minutes | 90+ minutes | + +## References + +- [Copilot Instructions - Build Section](../../copilot-instructions.md#bootstrap-and-build-process) +- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) +- [Azure Pipelines Config](../../../azure-pipelines.yml) diff --git a/.github/skills/fix-api-conventions/SKILL.md b/.github/skills/fix-api-conventions/SKILL.md new file mode 100644 index 0000000000..6892c47509 --- /dev/null +++ b/.github/skills/fix-api-conventions/SKILL.md @@ -0,0 +1,354 @@ +--- +name: fix-api-conventions +description: Guide for ensuring device bindings follow .NET IoT API conventions and design patterns +license: MIT +--- + +## Purpose + +This skill helps Copilot agents review and fix device bindings to ensure they follow the repository's established API conventions, naming patterns, and design principles. + +## When to Use This Skill + +- Reviewing existing device binding code for convention compliance +- Fixing API design issues in device bindings +- Code review identifies convention violations +- Modernizing older device bindings to match current patterns + +## Instructions + +### 1. API Naming Conventions + +#### Methods vs Properties +- **Methods** (e.g., `ReadTemperature()`, `GetTemperature()`) for values that may change between calls +- **Properties** (e.g., `SomeRegister`) for values that don't change (except via setter) + +#### Naming Patterns +- Follow .NET naming rules: PascalCase for public members/types, camelCase for locals/fields +- Interfaces start with `I` (e.g., `ITemperatureSensor`) +- Async methods must have `Async` suffix and synchronous equivalent + +#### Read Methods +✅ **DO:** +```csharp +public bool TryReadTemperature(out Temperature temperature) +public Temperature ReadTemperature() +public bool TryGetPressure(out Pressure pressure) +``` + +❌ **DON'T:** +```csharp +public double GetTemp() // Use Temperature type, not double +public double ReadTemperature() // Should return Temperature or use Try pattern +public Temperature? ReadTemperature() // Use Try pattern instead of nullable +``` + +### 2. Value Types and Units + +#### Use UnitsNet Types +✅ **DO:** +```csharp +using UnitsNet; + +public bool TryReadTemperature(out Temperature temperature) +public Pressure ReadPressure() +public ElectricPotential ReadVoltage() +``` + +❌ **DON'T:** +```csharp +public double GetTemperatureCelsius() // Use Temperature type +public float GetPressurePa() // Use Pressure type +``` + +#### When UnitsNet Not Available +- Use SI units (International System of Units) +- Document units clearly in XML comments +```csharp +/// +/// Reads humidity in percent (0-100). +/// +/// Relative humidity in %RH +public double ReadHumidity() +``` + +#### Handling Invalid Values +✅ **DO:** +```csharp +public bool TryReadTemperature(out Temperature temperature) +{ + // Return false on failure, set valid value on success + if (/* read failed */) + { + temperature = default; + return false; + } + temperature = Temperature.FromDegreesCelsius(value); + return true; +} +``` + +❌ **DON'T:** +```csharp +public double ReadTemperature() +{ + return double.NaN; // Don't use sentinel values +} +``` + +### 3. Constructor Design + +#### Required Parameters Only +- Constructor should only require parameters device cannot work without +- Everything else should have default values +- Use Settings class for devices with many parameters + +✅ **DO:** +```csharp +public Bmp280(I2cDevice i2cDevice, I2cAddress address = I2cAddress.Primary) +public Dht22(int pin, GpioController? controller = null, bool shouldDispose = true) +``` + +❌ **DON'T:** +```csharp +public Bmp280(I2cDevice i2cDevice, int pollingDelay, bool enableFilter, + Oversampling tempOversampling, Oversampling pressOversampling) +// Too many required parameters - use Settings class +``` + +#### Integer Invalid Values +- Use `-1` for invalid/unassigned integer values (not `null` or `Nullable`) +```csharp +public int Pin { get; set; } = -1; // -1 indicates unassigned +``` + +### 4. Resource Management + +#### IDisposable Implementation +**MUST implement IDisposable if device owns hardware resources** + +✅ **DO:** +```csharp +public class Bmp280 : IDisposable +{ + private I2cDevice? _i2cDevice; + private bool _disposed; + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + _i2cDevice?.Dispose(); + _i2cDevice = null; + } + + _disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } +} +``` + +#### Transport Ownership +- **I2cDevice, SpiDevice, PwmChannel**: 1:1 with hardware, **should be disposed by device** +- **GpioController**: Can be shared, **add optional `shouldDispose` flag** (default true) + +✅ **DO:** +```csharp +public Dht22(int pin, GpioController? controller = null, bool shouldDispose = true) +{ + _pin = pin; + _shouldDispose = shouldDispose || controller is null; + _controller = controller ?? new GpioController(); +} + +public void Dispose() +{ + if (_shouldDispose) + { + _controller?.Dispose(); + } + _controller = null; +} +``` + +### 5. Register and Address Management + +#### Use Enums for Registers +✅ **DO:** +```csharp +private enum Register : byte +{ + ChipId = 0xD0, + Reset = 0xE0, + Status = 0xF3, + Control = 0xF4, + Config = 0xF5, + PressureData = 0xF7, + TemperatureData = 0xFA +} + +// Usage +byte value = Read(Register.ChipId); +``` + +❌ **DON'T:** +```csharp +private const byte CHIP_ID_REG = 0xD0; // Use enum instead +byte value = Read(0xD0); // Magic number +``` + +### 6. Error Handling + +#### Input Validation +✅ **DO:** +```csharp +public Sensor(int pin) +{ + if (pin < 0) + throw new ArgumentOutOfRangeException(nameof(pin), "Pin must be non-negative"); + _pin = pin; +} + +public void SetSamplingRate(int rate) +{ + if (rate < 1 || rate > 100) + throw new ArgumentOutOfRangeException(nameof(rate), "Rate must be 1-100 Hz"); + _samplingRate = rate; +} +``` + +#### Hardware Failures +✅ **DO:** +```csharp +public bool TryReadTemperature(out Temperature temperature) +{ + try + { + byte[] data = ReadRegister(Register.TempData); + if (!ValidateChecksum(data)) + { + temperature = default; + return false; + } + temperature = ParseTemperature(data); + return true; + } + catch (IOException) + { + temperature = default; + return false; + } +} +``` + +❌ **DON'T:** +```csharp +public Temperature ReadTemperature() +{ + try + { + return ParseTemperature(ReadRegister(Register.TempData)); + } + catch + { + return Temperature.FromDegreesCelsius(0); // Bogus data + } +} +``` + +### 7. Visibility and Access Modifiers + +#### Public API Minimalism +- Only most useful APIs should be public +- Advanced features should be `protected` (allows inheritance) +- Internal implementation details should be `private` or `internal` + +✅ **DO:** +```csharp +public class Sensor +{ + // Main functionality - public + public bool TryReadTemperature(out Temperature temp) { } + + // Advanced calibration - protected + protected void SetCalibrationValue(int index, double value) { } + + // Internal details - private + private byte[] ReadRawData() { } +} +``` + +### 8. Documentation Requirements + +#### XML Comments +✅ **DO:** +```csharp +/// +/// Reads the current temperature from the sensor. +/// +/// The temperature in degrees Celsius +/// True if read successful, false on communication error +/// +/// Reading takes approximately 10ms. Values range from -40°C to +85°C. +/// +public bool TryReadTemperature(out Temperature temperature) +``` + +### 9. Common Anti-Patterns to Fix + +❌ **Console I/O in Library Code** +```csharp +public void ReadSensor() +{ + var temp = ReadTemperature(); + Console.WriteLine($"Temp: {temp}"); // Move to sample, not library +} +``` + +❌ **Thread-Static Caches** +```csharp +[ThreadStatic] +private static byte[]? _buffer; // Hidden state, avoid +``` + +❌ **Background Threads Without Clear Ownership** +```csharp +private Thread? _pollingThread; // Ensure proper disposal and control +``` + +❌ **Board-Specific Hardcoded Paths** +```csharp +const string GpioPath = "/sys/class/gpio"; // Use abstractions +``` + +## Review Checklist + +Use this when reviewing device binding APIs: + +- [ ] Methods/properties used appropriately +- [ ] UnitsNet types used for physical quantities +- [ ] Try* pattern for operations that may fail +- [ ] No sentinel values (NaN, null) for failures +- [ ] Constructor has only required parameters +- [ ] IDisposable implemented correctly +- [ ] Transport ownership handled properly +- [ ] Enums used for registers/addresses +- [ ] Input validation with appropriate exceptions +- [ ] XML documentation with units +- [ ] Public API is minimal and focused +- [ ] No console I/O in library code +- [ ] No platform-specific code + +## References + +- [Device Conventions Document](../../../Documentation/Devices-conventions.md) +- [Copilot Instructions - API Design](../../copilot-instructions.md#device-binding-design) +- [UnitsNet Documentation](https://github.com/angularsen/UnitsNet) diff --git a/.github/skills/hardware-abstraction-check/SKILL.md b/.github/skills/hardware-abstraction-check/SKILL.md new file mode 100644 index 0000000000..972faa7211 --- /dev/null +++ b/.github/skills/hardware-abstraction-check/SKILL.md @@ -0,0 +1,431 @@ +--- +name: hardware-abstraction-check +description: Guide for ensuring device bindings maintain proper hardware abstraction and cross-platform compatibility +license: MIT +--- + +## Purpose + +This skill helps Copilot agents verify that device bindings use proper hardware abstractions (System.Device.*) instead of platform-specific code, ensuring compatibility across Linux, Windows, and embedded systems. + +## When to Use This Skill + +- Reviewing new device binding code +- Investigating cross-platform compatibility issues +- Code contains platform-specific APIs or P/Invoke +- Ensuring code works on Raspberry Pi, Windows IoT, and other platforms +- Validating changes don't introduce OS dependencies + +## Instructions + +### 1. Core Principle + +**Device bindings must use System.Device.* abstractions exclusively.** + +The repository provides cross-platform abstractions: +- `System.Device.Gpio` for GPIO pins +- `System.Device.I2c` for I²C communication +- `System.Device.Spi` for SPI communication +- `System.Device.Pwm` for PWM signals + +These abstractions handle platform differences internally. + +### 2. Anti-Patterns to Detect + +#### ❌ Direct File System Access +```csharp +// WRONG - hardcoded Linux GPIO paths +const string GpioPath = "/sys/class/gpio"; +File.WriteAllText("/sys/class/gpio/export", "17"); + +// WRONG - platform-specific device paths +var i2cDevice = new I2cUnixDevice("/dev/i2c-1", 0x48); +``` + +✅ **CORRECT - Use abstractions:** +```csharp +using System.Device.Gpio; +using System.Device.I2c; + +using GpioController controller = new(); +controller.OpenPin(17, PinMode.Output); + +I2cConnectionSettings settings = new(busId: 1, deviceAddress: 0x48); +using I2cDevice device = I2cDevice.Create(settings); +``` + +#### ❌ P/Invoke and DllImport +```csharp +// WRONG - platform-specific P/Invoke +[DllImport("libc.so.6")] +private static extern int ioctl(int fd, uint request, int value); + +// WRONG - Windows-specific +[DllImport("kernel32.dll")] +private static extern bool DeviceIoControl(...); +``` + +✅ **CORRECT - Device abstractions handle this internally** + +#### ❌ OS Detection and Branching +```csharp +// WRONG - OS-specific branching +if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) +{ + // Linux GPIO implementation +} +else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) +{ + // Windows GPIO implementation +} + +// WRONG - Environment checks +if (Environment.OSVersion.Platform == PlatformID.Unix) +{ + // Unix-specific code +} +``` + +✅ **CORRECT - Abstractions handle platform differences:** +```csharp +// Works on all platforms +using GpioController controller = new(); +controller.OpenPin(17, PinMode.Output); +``` + +#### ❌ Process Execution for Hardware Access +```csharp +// WRONG - shelling out to OS utilities +Process.Start("gpio", "mode 17 out"); +Process.Start("i2cset", "-y 1 0x48 0x00 0xFF"); +``` + +✅ **CORRECT - Use device APIs** + +### 3. Automated Detection Commands + +Run these checks on device binding code: + +```bash +# Check for P/Invoke usage +grep -r "DllImport\|P/Invoke" src/devices// + +# Check for OS detection +grep -r "Environment.OSVersion\|RuntimeInformation\|OSPlatform" src/devices// + +# Check for hardcoded paths +grep -r "/sys/\|/dev/\|/proc/" src/devices// + +# Check for process execution +grep -r "Process.Start\|ProcessStartInfo" src/devices// + +# All of these should return minimal or no results +``` + +### 4. Acceptable Platform-Specific Code + +Some cases may require platform-specific code: + +#### When Platform-Specific Code is Acceptable +1. **Feature is inherently platform-specific** (e.g., Windows-only hardware) +2. **Properly guarded with clear error messages** +3. **Documented as platform-specific in XML comments** +4. **Fails gracefully on unsupported platforms** + +✅ **Example of acceptable platform-specific code:** +```csharp +/// +/// Enables hardware feature X. Only supported on Linux. +/// +/// +/// Thrown on non-Linux platforms +/// +public void EnableAdvancedFeature() +{ + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + throw new PlatformNotSupportedException( + "Advanced feature X requires Linux kernel 5.0+"); + } + + // Platform-specific implementation +} +``` + +### 5. Using Device Abstractions Correctly + +#### GPIO Controller Usage +✅ **DO:** +```csharp +public class LedDevice : IDisposable +{ + private readonly GpioController _controller; + private readonly int _pin; + private readonly bool _shouldDispose; + + public LedDevice(int pin, GpioController? controller = null, + bool shouldDispose = true) + { + _pin = pin; + _shouldDispose = shouldDispose || controller is null; + _controller = controller ?? new GpioController(); + _controller.OpenPin(_pin, PinMode.Output); + } + + public void Dispose() + { + if (_shouldDispose) + { + _controller?.Dispose(); + } + } +} +``` + +#### I2C Device Usage +✅ **DO:** +```csharp +public class I2cSensor : IDisposable +{ + private I2cDevice _i2cDevice; + + public I2cSensor(I2cDevice i2cDevice) + { + _i2cDevice = i2cDevice ?? throw new ArgumentNullException(nameof(i2cDevice)); + } + + public byte ReadRegister(byte register) + { + Span writeBuffer = stackalloc byte[] { register }; + Span readBuffer = stackalloc byte[1]; + _i2cDevice.WriteRead(writeBuffer, readBuffer); + return readBuffer[0]; + } + + public void Dispose() + { + _i2cDevice?.Dispose(); + _i2cDevice = null; + } +} +``` + +#### SPI Device Usage +✅ **DO:** +```csharp +public class SpiDisplay : IDisposable +{ + private SpiDevice _spiDevice; + + public SpiDisplay(SpiDevice spiDevice) + { + _spiDevice = spiDevice ?? throw new ArgumentNullException(nameof(spiDevice)); + } + + public void WriteData(ReadOnlySpan data) + { + _spiDevice.Write(data); + } + + public void Dispose() + { + _spiDevice?.Dispose(); + _spiDevice = null; + } +} +``` + +### 6. Sample Code Guidelines + +Sample applications should also follow abstraction principles: + +✅ **DO:** +```csharp +// Platform-agnostic sample +using System.Device.Gpio; +using System.Device.I2c; +using Iot.Device.Bmp280; + +// Works on any platform with I2C support +I2cConnectionSettings settings = new(busId: 1, deviceAddress: Bmp280.DefaultI2cAddress); +using I2cDevice device = I2cDevice.Create(settings); +using Bmp280 sensor = new(device); + +Console.WriteLine($"Temperature: {sensor.ReadTemperature().DegreesCelsius}°C"); +``` + +❌ **DON'T:** +```csharp +// Platform-specific sample +#if LINUX + var device = new UnixI2cDevice("/dev/i2c-1", 0x76); +#elif WINDOWS + var device = new WindowsI2cDevice("I2C1", 0x76); +#endif +``` + +### 7. Testing Cross-Platform Compatibility + +#### Build on Multiple Platforms +```bash +# Test builds on different configurations +dotnet build -c Release + +# If possible, test on: +# - Linux (Raspberry Pi, Ubuntu) +# - Windows (Windows IoT, Desktop) +# - macOS (if GPIO simulator available) +``` + +#### Verify No Platform-Specific References +```bash +# Check project file for platform-specific packages +cat src/devices//.csproj | grep -i "windows\|linux\|unix" + +# Should only reference System.Device.* packages +``` + +### 8. Common Cross-Platform Issues + +#### Timing Differences +Some operations may have different timing characteristics across platforms: + +✅ **DO:** +```csharp +// Use conservative timing that works everywhere +Thread.Sleep(10); // Safe across platforms + +// Or use Stopwatch for precise timing +var sw = Stopwatch.StartNew(); +while (sw.ElapsedMilliseconds < 10) { } +``` + +#### Endianness +Be aware of byte order when working with multi-byte values: + +✅ **DO:** +```csharp +// Use BitConverter with explicit endianness +int value = BinaryPrimitives.ReadInt16LittleEndian(buffer); +``` + +### 9. Documentation Requirements + +When code must be platform-specific: + +✅ **DO:** +```csharp +/// +/// Enables high-speed mode. +/// +/// +/// Platform Support: +/// +/// Linux: Fully supported on kernel 5.0+ +/// Windows IoT: Not supported +/// Windows Desktop: Not supported +/// +/// +/// +/// Thrown on unsupported platforms +/// +public void EnableHighSpeedMode() +``` + +### 10. Review Checklist + +Use this when reviewing device binding for hardware abstraction: + +- [ ] No `DllImport` or P/Invoke declarations +- [ ] No hardcoded paths (`/sys/`, `/dev/`, `/proc/`) +- [ ] No `RuntimeInformation.IsOSPlatform` checks (unless justified) +- [ ] No `Environment.OSVersion` checks +- [ ] No `Process.Start` for hardware access +- [ ] Uses `System.Device.Gpio` for GPIO +- [ ] Uses `System.Device.I2c` for I²C +- [ ] Uses `System.Device.Spi` for SPI +- [ ] Uses `System.Device.Pwm` for PWM +- [ ] Transport objects (I2C/SPI/GPIO) passed from caller +- [ ] Platform-specific features properly documented +- [ ] Platform-specific features fail gracefully +- [ ] Sample code is platform-agnostic +- [ ] Builds successfully without platform-specific errors + +## Common Violations and Fixes + +### Violation 1: Direct GPIO Access +```csharp +// ❌ WRONG +File.WriteAllText("/sys/class/gpio/export", "17"); +File.WriteAllText("/sys/class/gpio/gpio17/direction", "out"); + +// ✅ CORRECT +using GpioController controller = new(); +controller.OpenPin(17, PinMode.Output); +``` + +### Violation 2: Platform Detection +```csharp +// ❌ WRONG +if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) +{ + _gpioPath = "/sys/class/gpio"; +} + +// ✅ CORRECT - Let abstractions handle it +using GpioController controller = new(); +``` + +### Violation 3: Process Execution +```csharp +// ❌ WRONG +Process.Start("i2cget", "-y 1 0x48"); + +// ✅ CORRECT +I2cConnectionSettings settings = new(1, 0x48); +using I2cDevice device = I2cDevice.Create(settings); +byte[] data = new byte[1]; +device.Read(data); +``` + +## Quick Validation Script + +Save as `check-abstraction.sh`: +```bash +#!/bin/bash +DEVICE_DIR=$1 + +echo "Checking hardware abstraction compliance for $DEVICE_DIR" +echo "" + +echo "Checking for P/Invoke..." +grep -rn "DllImport" "$DEVICE_DIR" || echo " ✓ No P/Invoke found" + +echo "" +echo "Checking for OS detection..." +grep -rn "RuntimeInformation\|OSPlatform\|Environment.OSVersion" "$DEVICE_DIR" || echo " ✓ No OS detection found" + +echo "" +echo "Checking for hardcoded paths..." +grep -rn "/sys/\|/dev/\|/proc/" "$DEVICE_DIR" || echo " ✓ No hardcoded paths found" + +echo "" +echo "Checking for process execution..." +grep -rn "Process.Start" "$DEVICE_DIR" || echo " ✓ No process execution found" + +echo "" +echo "Hardware abstraction check complete!" +``` + +Usage: +```bash +chmod +x check-abstraction.sh +./check-abstraction.sh src/devices/Bmp280 +``` + +## References + +- [System.Device.Gpio Documentation](https://docs.microsoft.com/dotnet/api/system.device.gpio) +- [System.Device.I2c Documentation](https://docs.microsoft.com/dotnet/api/system.device.i2c) +- [Copilot Instructions - Cross-Platform](../../copilot-instructions.md#cross-platform) +- [Device Conventions](../../../Documentation/Devices-conventions.md) diff --git a/.github/skills/update-device-documentation/SKILL.md b/.github/skills/update-device-documentation/SKILL.md new file mode 100644 index 0000000000..10dc2ff1a6 --- /dev/null +++ b/.github/skills/update-device-documentation/SKILL.md @@ -0,0 +1,392 @@ +--- +name: update-device-documentation +description: Guide for creating and maintaining comprehensive documentation for IoT device bindings +license: MIT +--- + +## Purpose + +This skill helps Copilot agents create and maintain high-quality documentation for device bindings, including README files, XML documentation, wiring diagrams, and usage examples. + +## When to Use This Skill + +- Adding documentation for a new device binding +- Updating existing device documentation +- Adding wiring diagrams or connection instructions +- Improving code examples in README files +- Adding XML documentation comments to APIs + +## Instructions + +### 1. Device README Structure + +Each device binding must have a `README.md` in its directory with these sections: + +```markdown +# DeviceName - Brief Description + +Brief overview of what the device does (1-2 sentences). + +## Documentation + +Link to device datasheet/specification. + +## Usage + +Basic code example showing typical usage. + +## Binding Notes + +Important information about this specific binding: +- Default I2C/SPI addresses +- Required configuration +- Known limitations +- Platform-specific considerations + +## References + +Links to: +- Datasheet +- Device manufacturer page +- Related bindings +``` + +### 2. Writing Effective Device Documentation + +#### Device Overview Section +✅ **DO:** +```markdown +# BME280 - Combined Temperature, Pressure, and Humidity Sensor + +The BME280 is a combined digital humidity, pressure and temperature sensor +manufactured by Bosch. It provides high precision measurements over I2C or SPI. +``` + +Include: +- Full device name and manufacturer +- What the device measures/does +- Communication protocol(s) supported + +#### Documentation Section +✅ **DO:** +```markdown +## Documentation + +- BME280 [datasheet](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf) +``` + +Always link to official datasheets and specifications. + +### 3. Usage Examples + +#### Code Example Requirements +- Show complete, runnable code +- Use `using` statements for proper disposal +- Include necessary namespace imports +- Show error handling +- Add comments explaining key steps +- Don't hardcode board-specific values + +✅ **DO:** +```csharp +## Usage + +**Important**: Make sure you properly setup the I2C pins for your device. + +```csharp +using System; +using System.Device.I2c; +using System.Threading; +using Iot.Device.Bmxx80; +using Iot.Device.Bmxx80.PowerMode; +using UnitsNet; + +// I2C address 0x76 is default, use 0x77 if SDO pin is high +using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(1, Bme280.DefaultI2cAddress)); +using Bme280 bme280 = new(i2cDevice); + +// Set sampling and filtering +bme280.TemperatureSampling = Sampling.Standard; +bme280.PressureSampling = Sampling.Standard; +bme280.HumiditySampling = Sampling.Standard; + +while (true) +{ + // Read sensor values + if (bme280.TryReadTemperature(out Temperature temperature)) + { + Console.WriteLine($"Temperature: {temperature.DegreesCelsius:F2} °C"); + } + + if (bme280.TryReadPressure(out Pressure pressure)) + { + Console.WriteLine($"Pressure: {pressure.Hectopascals:F2} hPa"); + } + + if (bme280.TryReadHumidity(out RelativeHumidity humidity)) + { + Console.WriteLine($"Humidity: {humidity.Percent:F2} %"); + } + + Thread.Sleep(1000); +} +\`\`\` +``` + +### 4. Wiring Information + +#### Wiring Diagram Requirements +Include wiring information showing: +- Pin connections between device and board +- Required pull-up/pull-down resistors +- Power supply requirements +- Common connection mistakes to avoid + +✅ **DO:** +```markdown +## Wiring + +### I2C Connection + +| BME280 Pin | Raspberry Pi Pin | +|------------|------------------| +| VCC | 3.3V (Pin 1) | +| GND | Ground (Pin 6) | +| SCL | GPIO3/SCL (Pin 5)| +| SDA | GPIO2/SDA (Pin 3)| +| SDO | Ground or 3.3V | + +**Note:** +- Pull-up resistors (4.7kΩ) are typically required on SCL and SDA lines +- SDO pin sets I2C address: Low = 0x76, High = 0x77 +- Use 3.3V power only, do not connect to 5V +``` + +### 5. Binding Notes Section + +Document important implementation details: + +✅ **DO:** +```markdown +## Binding Notes + +### Default Addresses +- Primary I2C address: 0x76 (SDO pin grounded) +- Secondary I2C address: 0x77 (SDO pin to VCC) + +### Measurement Timing +- Single measurement takes approximately 10ms +- Continuous mode updates at configured rate (0.5Hz to 16Hz) + +### Calibration +- Device includes factory calibration data +- Calibration is automatically read and applied by the binding + +### Known Limitations +- SPI mode not yet implemented +- Forced mode not supported, use normal mode instead +``` + +### 6. XML Documentation for APIs + +#### Public API Documentation +Every public member needs XML documentation: + +✅ **DO:** +```csharp +/// +/// Reads the current temperature from the BME280 sensor. +/// +/// +/// When this method returns true, contains the measured temperature. +/// When false, contains the default value. +/// +/// +/// True if the temperature was read successfully; false if communication +/// error occurred or data was invalid. +/// +/// +/// Temperature range: -40°C to +85°C with ±1°C accuracy. +/// Reading takes approximately 10ms in standard sampling mode. +/// +public bool TryReadTemperature(out Temperature temperature) +``` + +#### Include Units in Documentation +Always specify units: +```csharp +/// +/// Gets or sets the temperature oversampling rate. +/// Higher values provide better accuracy but slower measurements. +/// +/// Oversampling multiplier (1x, 2x, 4x, 8x, or 16x) +public Sampling TemperatureSampling { get; set; } +``` + +### 7. Property and Enum Documentation + +Document ranges and valid values: + +✅ **DO:** +```csharp +/// +/// Measurement sampling rate options. +/// +public enum Sampling +{ + /// + /// Measurement skipped (0x) + /// + Skipped = 0b000, + + /// + /// Oversampling x1 - fastest, least accurate + /// + UltraLowPower = 0b001, + + /// + /// Oversampling x2 + /// + LowPower = 0b010, + + /// + /// Oversampling x4 (recommended for most applications) + /// + Standard = 0b011 +} +``` + +### 8. Markdown Linting + +Ensure documentation passes markdown linting: + +```bash +# Install markdownlint +npm install -g markdownlint-cli + +# Check device README +markdownlint -c .markdownlint.json src/devices/Bme280/README.md + +# Fix common issues: +# - No trailing spaces +# - Blank line after headers +# - Proper list formatting +# - No bare URLs (use [text](url) format) +``` + +### 9. Common Documentation Patterns + +#### For Sensor Devices +```markdown +## Specifications + +- Measurement range: -40°C to +85°C +- Accuracy: ±1°C +- Resolution: 0.01°C +- Supply voltage: 1.8V to 3.6V +- Interface: I2C (up to 3.4 MHz) or SPI (up to 10 MHz) +``` + +#### For Display Devices +```markdown +## Specifications + +- Display size: 128x64 pixels +- Colors: Monochrome (white on black) +- Interface: I2C or SPI +- Typical current: 20mA at 3.3V +``` + +#### For Motor/Actuator Devices +```markdown +## Specifications + +- Control interface: PWM +- Operating voltage: 5-12V +- Maximum current: 2A per channel +- PWM frequency: 1kHz to 10kHz recommended +``` + +### 10. Documentation Review Checklist + +Before completing documentation: + +- [ ] README.md exists in device directory +- [ ] Device name and description are clear +- [ ] Link to datasheet/specification included +- [ ] Code example is complete and runnable +- [ ] Code example uses proper disposal (`using` statements) +- [ ] Wiring diagram or connection table included +- [ ] Required pull-ups/resistors documented +- [ ] Default I2C/SPI addresses documented +- [ ] Known limitations documented +- [ ] All public APIs have XML documentation +- [ ] Units specified in XML comments (°C, Pa, %RH, etc.) +- [ ] Markdown linting passes +- [ ] No hardcoded board-specific paths in examples +- [ ] Cross-platform considerations mentioned if applicable + +## Examples + +### Complete Example: Simple Sensor + +```markdown +# DHT22 - Temperature and Humidity Sensor + +DHT22 is a low-cost digital temperature and humidity sensor that uses a +one-wire protocol for communication. + +## Documentation + +- DHT22 [datasheet](https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT22.pdf) + +## Usage + +```csharp +using System; +using System.Device.Gpio; +using System.Threading; +using Iot.Device.DHTxx; +using UnitsNet; + +using GpioController controller = new(); +using Dht22 sensor = new(pin: 4, controller); + +while (true) +{ + if (sensor.TryReadTemperature(out Temperature temperature) && + sensor.TryReadHumidity(out RelativeHumidity humidity)) + { + Console.WriteLine($"Temp: {temperature.DegreesCelsius:F1}°C, " + + $"Humidity: {humidity.Percent:F1}%"); + } + else + { + Console.WriteLine("Read failed"); + } + + Thread.Sleep(2000); // DHT22 requires 2 second interval +} +\`\`\` + +## Wiring + +Connect DHT22 to Raspberry Pi: +- Pin 1 (VCC) to 3.3V +- Pin 2 (DATA) to GPIO4 with 4.7kΩ pull-up to 3.3V +- Pin 4 (GND) to Ground + +## Binding Notes + +- Minimum reading interval: 2 seconds +- Pull-up resistor (4.7kΩ) required on data line +- Temperature range: -40°C to +80°C (±0.5°C accuracy) +- Humidity range: 0-100% RH (±2-5% accuracy) +``` + +## References + +- [Device Conventions](../../../Documentation/Devices-conventions.md) +- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) +- [Copilot Instructions](../../copilot-instructions.md) +- [Markdown Style Guide](.markdownlint.json) From 9d5aa7f85993ff646a00117e9bb9f71e5a1108ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 16:53:40 +0000 Subject: [PATCH 3/9] Fix markdown linting errors in .github/skills directory - Add MD041 exception to .markdownlint.json for YAML frontmatter - Fix MD031: Add blank lines around fenced code blocks - Fix MD032: Add blank lines around lists - Fix MD022: Add blank lines around headings - Fix MD040: Specify language for code blocks - Fix MD036: Remove emphasis used as heading Co-authored-by: krwq <660048+krwq@users.noreply.github.com> --- .github/skills/add-device-binding/SKILL.md | 13 +++++- .github/skills/debug-build-issues/SKILL.md | 24 +++++++++++ .github/skills/fix-api-conventions/SKILL.md | 40 ++++++++++++++++++- .../hardware-abstraction-check/SKILL.md | 29 ++++++++++++++ .../update-device-documentation/SKILL.md | 19 +++++++++ .markdownlint.json | 1 + 6 files changed, 124 insertions(+), 2 deletions(-) diff --git a/.github/skills/add-device-binding/SKILL.md b/.github/skills/add-device-binding/SKILL.md index f449c299cd..28d98293f3 100644 --- a/.github/skills/add-device-binding/SKILL.md +++ b/.github/skills/add-device-binding/SKILL.md @@ -19,7 +19,8 @@ This skill helps Copilot agents create new IoT device bindings (sensors, display ### 1. Device Structure Setup Create the following directory structure under `src/devices/`: -``` + +```text src/devices// ├── .csproj ├── .cs (main class) @@ -39,6 +40,7 @@ src/devices// - Avoid singletons and global state **Example Constructor:** + ```csharp public Bmp280(I2cDevice i2cDevice, I2cAddress address = I2cAddress.Primary) { @@ -50,9 +52,12 @@ public Bmp280(I2cDevice i2cDevice, I2cAddress address = I2cAddress.Primary) ### 3. API Design Patterns - Use **`TryRead*` methods** that return `bool` and set `out` parameters for sensor readings + ```csharp public bool TryReadTemperature(out Temperature temperature) ``` + + - Use **UnitsNet** types for physical quantities (Temperature, Pressure, Length, etc.) - Properties for values that don't change between calls - Methods for values that may change @@ -67,6 +72,7 @@ public Bmp280(I2cDevice i2cDevice, I2cAddress address = I2cAddress.Primary) - Design for failure: ensure exceptions leave device in consistent state **Example Disposal:** + ```csharp protected virtual void Dispose(bool disposing) { @@ -105,6 +111,7 @@ protected virtual void Dispose(bool disposing) ### 7. Sample Application Create a runnable sample in `samples/Program.cs`: + - Keep it simple and readable - Demonstrate typical usage patterns - Show proper disposal (using statements) @@ -112,6 +119,7 @@ Create a runnable sample in `samples/Program.cs`: - Don't hardcode board-specific paths **Example Sample:** + ```csharp using System; using System.Device.I2c; @@ -147,6 +155,7 @@ while (true) ### 10. Build Validation After creating the device: + ```bash cd src/devices/ ../../../dotnet.sh build @@ -161,6 +170,7 @@ grep -r "Environment.OSVersion\|DllImport\|P/Invoke" . ## Review Checklist Before completing: + - [ ] Public API follows repo naming/style - [ ] Members are XML-documented with units (°C, Pa, %RH, lux, etc.) - [ ] Constructor accepts caller-provided transports @@ -177,6 +187,7 @@ Before completing: ## Examples ### Good Device Binding Example + ```csharp public class Dht22 : IDisposable { diff --git a/.github/skills/debug-build-issues/SKILL.md b/.github/skills/debug-build-issues/SKILL.md index 343b08bd01..a74c65122a 100644 --- a/.github/skills/debug-build-issues/SKILL.md +++ b/.github/skills/debug-build-issues/SKILL.md @@ -22,6 +22,7 @@ This skill helps Copilot agents diagnose and fix build issues in the .NET IoT re ### 1. Understanding Build Requirements **CRITICAL Prerequisites:** + - Azure DevOps feeds access required for full builds - .NET 8.0.300 SDK (specified in `global.json`) - Build takes 30-45 minutes normally - **NEVER CANCEL** @@ -30,9 +31,11 @@ This skill helps Copilot agents diagnose and fix build issues in the .NET IoT re ### 2. Common Build Issues and Solutions #### SDK Resolution Errors + **Symptom:** `Could not resolve SDK Microsoft.DotNet.Arcade.Sdk` **Diagnosis:** + ```bash # Check SDK version ./dotnet.sh --version @@ -42,6 +45,7 @@ cat global.json ``` **Solutions:** + 1. Azure DevOps feeds are inaccessible (network restriction) - Document as known limitation - Try alternative build approaches (see below) @@ -50,9 +54,11 @@ cat global.json - `./dotnet.sh --version` will auto-download if needed #### Package Not Found Errors + **Symptom:** NuGet package restore failures **Diagnosis:** + ```bash # Check NuGet sources cat NuGet.config @@ -62,14 +68,17 @@ cat NuGet.config ``` **Solutions:** + 1. Verify NuGet.config has correct sources 2. Check if Azure DevOps feeds are accessible 3. Try clearing NuGet cache: `dotnet nuget locals all --clear` #### Memory Issues During Build + **Symptom:** Out of memory errors, process killed **Solutions:** + ```bash # Disable parallel builds ./build.sh --restore --build /maxCpuCount:1 @@ -80,9 +89,11 @@ cd src/devices/Bmp280 ``` #### Timeout Issues + **Symptom:** Build appears hung or times out **Important:** Builds legitimately take 30-45 minutes + - Set timeout to **60+ minutes** for full builds - Set timeout to **45+ minutes** for test runs - Use `initial_wait` parameter appropriately in bash commands @@ -92,6 +103,7 @@ cd src/devices/Bmp280 When Azure DevOps feeds are inaccessible: #### Build Individual Samples + ```bash # Samples use public NuGet packages cd samples/led-blink @@ -99,6 +111,7 @@ cd samples/led-blink ``` #### Test Basic IoT Functionality + ```bash ./dotnet.sh new console -o test-project cd test-project @@ -108,6 +121,7 @@ cd test-project ``` #### Build Individual Device Bindings + ```bash cd src/devices/ ../../../dotnet.sh build @@ -116,6 +130,7 @@ cd src/devices/ ### 4. Build Commands by Scenario #### Full Repository Build + ```bash # Use this for complete validation ./build.sh --restore --build --configuration Release @@ -124,12 +139,14 @@ cd src/devices/ ``` #### Build with Packages + ```bash # For testing distribution ./build.sh --restore --build --pack --configuration Release ``` #### Run Tests + ```bash # All tests ./build.sh --test --configuration Release @@ -140,6 +157,7 @@ cd src/devices/ ``` #### Individual Device Build + ```bash cd src/devices/Dhtxx ../../../dotnet.sh build @@ -149,6 +167,7 @@ cd src/devices/Dhtxx ### 5. Debugging Compilation Errors #### After Code Changes + ```bash # Build the specific project you changed cd src/devices/ @@ -159,6 +178,7 @@ cd src/devices/ ``` #### Check for Common Issues + ```bash # Verify .editorconfig compliance # Build will show analyzer warnings @@ -188,6 +208,7 @@ gh run view --log ``` #### Markdown Linting + ```bash npm install -g markdownlint-cli markdownlint -c .markdownlint.json . @@ -196,6 +217,7 @@ markdownlint -c .markdownlint.json . ### 7. Log Locations When builds fail, check logs: + - Build logs: `artifacts/log/{Configuration}/` - Test results: Published in CI artifacts - Individual project logs: In project's bin/obj folders @@ -203,6 +225,7 @@ When builds fail, check logs: ### 8. Cross-Platform Build Issues #### Linux vs Windows Issues + - Check for platform-specific files: `*.Linux.cs` vs `*.Windows.cs` - Verify configurations in Visual Studio - Use `System.Device.*` abstractions, not OS-specific APIs @@ -232,6 +255,7 @@ grep -r "Environment.OSVersion\|DllImport\|P/Invoke" src/devices// ### 10. When to Escalate Document and inform user when: + - Azure DevOps feeds are confirmed inaccessible (network policy) - Build requires infrastructure changes - Pre-existing test failures unrelated to changes diff --git a/.github/skills/fix-api-conventions/SKILL.md b/.github/skills/fix-api-conventions/SKILL.md index 6892c47509..2dfc91c6b6 100644 --- a/.github/skills/fix-api-conventions/SKILL.md +++ b/.github/skills/fix-api-conventions/SKILL.md @@ -20,16 +20,20 @@ This skill helps Copilot agents review and fix device bindings to ensure they fo ### 1. API Naming Conventions #### Methods vs Properties + - **Methods** (e.g., `ReadTemperature()`, `GetTemperature()`) for values that may change between calls - **Properties** (e.g., `SomeRegister`) for values that don't change (except via setter) #### Naming Patterns + - Follow .NET naming rules: PascalCase for public members/types, camelCase for locals/fields - Interfaces start with `I` (e.g., `ITemperatureSensor`) - Async methods must have `Async` suffix and synchronous equivalent #### Read Methods + ✅ **DO:** + ```csharp public bool TryReadTemperature(out Temperature temperature) public Temperature ReadTemperature() @@ -37,6 +41,7 @@ public bool TryGetPressure(out Pressure pressure) ``` ❌ **DON'T:** + ```csharp public double GetTemp() // Use Temperature type, not double public double ReadTemperature() // Should return Temperature or use Try pattern @@ -46,7 +51,9 @@ public Temperature? ReadTemperature() // Use Try pattern instead of nullable ### 2. Value Types and Units #### Use UnitsNet Types + ✅ **DO:** + ```csharp using UnitsNet; @@ -56,14 +63,17 @@ public ElectricPotential ReadVoltage() ``` ❌ **DON'T:** + ```csharp public double GetTemperatureCelsius() // Use Temperature type public float GetPressurePa() // Use Pressure type ``` #### When UnitsNet Not Available + - Use SI units (International System of Units) - Document units clearly in XML comments + ```csharp /// /// Reads humidity in percent (0-100). @@ -73,7 +83,9 @@ public double ReadHumidity() ``` #### Handling Invalid Values + ✅ **DO:** + ```csharp public bool TryReadTemperature(out Temperature temperature) { @@ -89,6 +101,7 @@ public bool TryReadTemperature(out Temperature temperature) ``` ❌ **DON'T:** + ```csharp public double ReadTemperature() { @@ -99,17 +112,20 @@ public double ReadTemperature() ### 3. Constructor Design #### Required Parameters Only + - Constructor should only require parameters device cannot work without - Everything else should have default values - Use Settings class for devices with many parameters ✅ **DO:** + ```csharp public Bmp280(I2cDevice i2cDevice, I2cAddress address = I2cAddress.Primary) public Dht22(int pin, GpioController? controller = null, bool shouldDispose = true) ``` ❌ **DON'T:** + ```csharp public Bmp280(I2cDevice i2cDevice, int pollingDelay, bool enableFilter, Oversampling tempOversampling, Oversampling pressOversampling) @@ -117,7 +133,9 @@ public Bmp280(I2cDevice i2cDevice, int pollingDelay, bool enableFilter, ``` #### Integer Invalid Values + - Use `-1` for invalid/unassigned integer values (not `null` or `Nullable`) + ```csharp public int Pin { get; set; } = -1; // -1 indicates unassigned ``` @@ -125,9 +143,11 @@ public int Pin { get; set; } = -1; // -1 indicates unassigned ### 4. Resource Management #### IDisposable Implementation -**MUST implement IDisposable if device owns hardware resources** + +MUST implement IDisposable if device owns hardware resources. ✅ **DO:** + ```csharp public class Bmp280 : IDisposable { @@ -157,10 +177,12 @@ public class Bmp280 : IDisposable ``` #### Transport Ownership + - **I2cDevice, SpiDevice, PwmChannel**: 1:1 with hardware, **should be disposed by device** - **GpioController**: Can be shared, **add optional `shouldDispose` flag** (default true) ✅ **DO:** + ```csharp public Dht22(int pin, GpioController? controller = null, bool shouldDispose = true) { @@ -182,7 +204,9 @@ public void Dispose() ### 5. Register and Address Management #### Use Enums for Registers + ✅ **DO:** + ```csharp private enum Register : byte { @@ -200,6 +224,7 @@ byte value = Read(Register.ChipId); ``` ❌ **DON'T:** + ```csharp private const byte CHIP_ID_REG = 0xD0; // Use enum instead byte value = Read(0xD0); // Magic number @@ -208,7 +233,9 @@ byte value = Read(0xD0); // Magic number ### 6. Error Handling #### Input Validation + ✅ **DO:** + ```csharp public Sensor(int pin) { @@ -226,7 +253,9 @@ public void SetSamplingRate(int rate) ``` #### Hardware Failures + ✅ **DO:** + ```csharp public bool TryReadTemperature(out Temperature temperature) { @@ -250,6 +279,7 @@ public bool TryReadTemperature(out Temperature temperature) ``` ❌ **DON'T:** + ```csharp public Temperature ReadTemperature() { @@ -267,11 +297,13 @@ public Temperature ReadTemperature() ### 7. Visibility and Access Modifiers #### Public API Minimalism + - Only most useful APIs should be public - Advanced features should be `protected` (allows inheritance) - Internal implementation details should be `private` or `internal` ✅ **DO:** + ```csharp public class Sensor { @@ -289,7 +321,9 @@ public class Sensor ### 8. Documentation Requirements #### XML Comments + ✅ **DO:** + ```csharp /// /// Reads the current temperature from the sensor. @@ -305,6 +339,7 @@ public bool TryReadTemperature(out Temperature temperature) ### 9. Common Anti-Patterns to Fix ❌ **Console I/O in Library Code** + ```csharp public void ReadSensor() { @@ -314,17 +349,20 @@ public void ReadSensor() ``` ❌ **Thread-Static Caches** + ```csharp [ThreadStatic] private static byte[]? _buffer; // Hidden state, avoid ``` ❌ **Background Threads Without Clear Ownership** + ```csharp private Thread? _pollingThread; // Ensure proper disposal and control ``` ❌ **Board-Specific Hardcoded Paths** + ```csharp const string GpioPath = "/sys/class/gpio"; // Use abstractions ``` diff --git a/.github/skills/hardware-abstraction-check/SKILL.md b/.github/skills/hardware-abstraction-check/SKILL.md index 972faa7211..ebcb8c9c5b 100644 --- a/.github/skills/hardware-abstraction-check/SKILL.md +++ b/.github/skills/hardware-abstraction-check/SKILL.md @@ -23,6 +23,7 @@ This skill helps Copilot agents verify that device bindings use proper hardware **Device bindings must use System.Device.* abstractions exclusively.** The repository provides cross-platform abstractions: + - `System.Device.Gpio` for GPIO pins - `System.Device.I2c` for I²C communication - `System.Device.Spi` for SPI communication @@ -33,6 +34,7 @@ These abstractions handle platform differences internally. ### 2. Anti-Patterns to Detect #### ❌ Direct File System Access + ```csharp // WRONG - hardcoded Linux GPIO paths const string GpioPath = "/sys/class/gpio"; @@ -43,6 +45,7 @@ var i2cDevice = new I2cUnixDevice("/dev/i2c-1", 0x48); ``` ✅ **CORRECT - Use abstractions:** + ```csharp using System.Device.Gpio; using System.Device.I2c; @@ -55,6 +58,7 @@ using I2cDevice device = I2cDevice.Create(settings); ``` #### ❌ P/Invoke and DllImport + ```csharp // WRONG - platform-specific P/Invoke [DllImport("libc.so.6")] @@ -68,6 +72,7 @@ private static extern bool DeviceIoControl(...); ✅ **CORRECT - Device abstractions handle this internally** #### ❌ OS Detection and Branching + ```csharp // WRONG - OS-specific branching if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) @@ -87,6 +92,7 @@ if (Environment.OSVersion.Platform == PlatformID.Unix) ``` ✅ **CORRECT - Abstractions handle platform differences:** + ```csharp // Works on all platforms using GpioController controller = new(); @@ -94,6 +100,7 @@ controller.OpenPin(17, PinMode.Output); ``` #### ❌ Process Execution for Hardware Access + ```csharp // WRONG - shelling out to OS utilities Process.Start("gpio", "mode 17 out"); @@ -127,12 +134,14 @@ grep -r "Process.Start\|ProcessStartInfo" src/devices// Some cases may require platform-specific code: #### When Platform-Specific Code is Acceptable + 1. **Feature is inherently platform-specific** (e.g., Windows-only hardware) 2. **Properly guarded with clear error messages** 3. **Documented as platform-specific in XML comments** 4. **Fails gracefully on unsupported platforms** ✅ **Example of acceptable platform-specific code:** + ```csharp /// /// Enables hardware feature X. Only supported on Linux. @@ -155,7 +164,9 @@ public void EnableAdvancedFeature() ### 5. Using Device Abstractions Correctly #### GPIO Controller Usage + ✅ **DO:** + ```csharp public class LedDevice : IDisposable { @@ -183,7 +194,9 @@ public class LedDevice : IDisposable ``` #### I2C Device Usage + ✅ **DO:** + ```csharp public class I2cSensor : IDisposable { @@ -211,7 +224,9 @@ public class I2cSensor : IDisposable ``` #### SPI Device Usage + ✅ **DO:** + ```csharp public class SpiDisplay : IDisposable { @@ -240,6 +255,7 @@ public class SpiDisplay : IDisposable Sample applications should also follow abstraction principles: ✅ **DO:** + ```csharp // Platform-agnostic sample using System.Device.Gpio; @@ -255,6 +271,7 @@ Console.WriteLine($"Temperature: {sensor.ReadTemperature().DegreesCelsius}°C"); ``` ❌ **DON'T:** + ```csharp // Platform-specific sample #if LINUX @@ -267,6 +284,7 @@ Console.WriteLine($"Temperature: {sensor.ReadTemperature().DegreesCelsius}°C"); ### 7. Testing Cross-Platform Compatibility #### Build on Multiple Platforms + ```bash # Test builds on different configurations dotnet build -c Release @@ -278,6 +296,7 @@ dotnet build -c Release ``` #### Verify No Platform-Specific References + ```bash # Check project file for platform-specific packages cat src/devices//.csproj | grep -i "windows\|linux\|unix" @@ -288,9 +307,11 @@ cat src/devices//.csproj | grep -i "windows\|linux\|unix ### 8. Common Cross-Platform Issues #### Timing Differences + Some operations may have different timing characteristics across platforms: ✅ **DO:** + ```csharp // Use conservative timing that works everywhere Thread.Sleep(10); // Safe across platforms @@ -301,9 +322,11 @@ while (sw.ElapsedMilliseconds < 10) { } ``` #### Endianness + Be aware of byte order when working with multi-byte values: ✅ **DO:** + ```csharp // Use BitConverter with explicit endianness int value = BinaryPrimitives.ReadInt16LittleEndian(buffer); @@ -314,6 +337,7 @@ int value = BinaryPrimitives.ReadInt16LittleEndian(buffer); When code must be platform-specific: ✅ **DO:** + ```csharp /// /// Enables high-speed mode. @@ -354,6 +378,7 @@ Use this when reviewing device binding for hardware abstraction: ## Common Violations and Fixes ### Violation 1: Direct GPIO Access + ```csharp // ❌ WRONG File.WriteAllText("/sys/class/gpio/export", "17"); @@ -365,6 +390,7 @@ controller.OpenPin(17, PinMode.Output); ``` ### Violation 2: Platform Detection + ```csharp // ❌ WRONG if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) @@ -377,6 +403,7 @@ using GpioController controller = new(); ``` ### Violation 3: Process Execution + ```csharp // ❌ WRONG Process.Start("i2cget", "-y 1 0x48"); @@ -391,6 +418,7 @@ device.Read(data); ## Quick Validation Script Save as `check-abstraction.sh`: + ```bash #!/bin/bash DEVICE_DIR=$1 @@ -418,6 +446,7 @@ echo "Hardware abstraction check complete!" ``` Usage: + ```bash chmod +x check-abstraction.sh ./check-abstraction.sh src/devices/Bmp280 diff --git a/.github/skills/update-device-documentation/SKILL.md b/.github/skills/update-device-documentation/SKILL.md index 10dc2ff1a6..0bb11a554a 100644 --- a/.github/skills/update-device-documentation/SKILL.md +++ b/.github/skills/update-device-documentation/SKILL.md @@ -54,7 +54,9 @@ Links to: ### 2. Writing Effective Device Documentation #### Device Overview Section + ✅ **DO:** + ```markdown # BME280 - Combined Temperature, Pressure, and Humidity Sensor @@ -63,12 +65,15 @@ manufactured by Bosch. It provides high precision measurements over I2C or SPI. ``` Include: + - Full device name and manufacturer - What the device measures/does - Communication protocol(s) supported #### Documentation Section + ✅ **DO:** + ```markdown ## Documentation @@ -80,6 +85,7 @@ Always link to official datasheets and specifications. ### 3. Usage Examples #### Code Example Requirements + - Show complete, runnable code - Use `using` statements for proper disposal - Include necessary namespace imports @@ -88,6 +94,7 @@ Always link to official datasheets and specifications. - Don't hardcode board-specific values ✅ **DO:** + ```csharp ## Usage @@ -136,13 +143,16 @@ while (true) ### 4. Wiring Information #### Wiring Diagram Requirements + Include wiring information showing: + - Pin connections between device and board - Required pull-up/pull-down resistors - Power supply requirements - Common connection mistakes to avoid ✅ **DO:** + ```markdown ## Wiring @@ -167,6 +177,7 @@ Include wiring information showing: Document important implementation details: ✅ **DO:** + ```markdown ## Binding Notes @@ -190,9 +201,11 @@ Document important implementation details: ### 6. XML Documentation for APIs #### Public API Documentation + Every public member needs XML documentation: ✅ **DO:** + ```csharp /// /// Reads the current temperature from the BME280 sensor. @@ -213,7 +226,9 @@ public bool TryReadTemperature(out Temperature temperature) ``` #### Include Units in Documentation + Always specify units: + ```csharp /// /// Gets or sets the temperature oversampling rate. @@ -228,6 +243,7 @@ public Sampling TemperatureSampling { get; set; } Document ranges and valid values: ✅ **DO:** + ```csharp /// /// Measurement sampling rate options. @@ -277,6 +293,7 @@ markdownlint -c .markdownlint.json src/devices/Bme280/README.md ### 9. Common Documentation Patterns #### For Sensor Devices + ```markdown ## Specifications @@ -288,6 +305,7 @@ markdownlint -c .markdownlint.json src/devices/Bme280/README.md ``` #### For Display Devices + ```markdown ## Specifications @@ -298,6 +316,7 @@ markdownlint -c .markdownlint.json src/devices/Bme280/README.md ``` #### For Motor/Actuator Devices + ```markdown ## Specifications diff --git a/.markdownlint.json b/.markdownlint.json index 9c1a747ba9..1fca35cd4c 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -2,6 +2,7 @@ "MD012": false, "MD013": false, "MD033": false, + "MD041": false, "MD059": false, "MD060": false } From 28e767bd1c69f3eccdb8465f7d19fb9431a58cf7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:46:02 +0000 Subject: [PATCH 4/9] Use full GitHub URLs instead of relative paths in skill references Co-authored-by: krwq <660048+krwq@users.noreply.github.com> --- .github/skills/add-device-binding/SKILL.md | 6 +++--- .github/skills/debug-build-issues/SKILL.md | 6 +++--- .github/skills/fix-api-conventions/SKILL.md | 4 ++-- .github/skills/hardware-abstraction-check/SKILL.md | 4 ++-- .github/skills/update-device-documentation/SKILL.md | 8 ++++---- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/skills/add-device-binding/SKILL.md b/.github/skills/add-device-binding/SKILL.md index 28d98293f3..55bc747656 100644 --- a/.github/skills/add-device-binding/SKILL.md +++ b/.github/skills/add-device-binding/SKILL.md @@ -220,7 +220,7 @@ public class Dht22 : IDisposable ## References -- [Device Conventions](../../../Documentation/Devices-conventions.md) -- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) -- [Copilot Instructions](../../copilot-instructions.md) +- [Device Conventions](https://github.com/dotnet/iot/blob/main/Documentation/Devices-conventions.md) +- [Contributing Guidelines](https://github.com/dotnet/iot/blob/main/Documentation/CONTRIBUTING.md) +- [Copilot Instructions](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md) - [UnitsNet Library](https://github.com/angularsen/UnitsNet) diff --git a/.github/skills/debug-build-issues/SKILL.md b/.github/skills/debug-build-issues/SKILL.md index a74c65122a..77721db125 100644 --- a/.github/skills/debug-build-issues/SKILL.md +++ b/.github/skills/debug-build-issues/SKILL.md @@ -283,6 +283,6 @@ Document and inform user when: ## References -- [Copilot Instructions - Build Section](../../copilot-instructions.md#bootstrap-and-build-process) -- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) -- [Azure Pipelines Config](../../../azure-pipelines.yml) +- [Copilot Instructions - Build Section](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md#bootstrap-and-build-process) +- [Contributing Guidelines](https://github.com/dotnet/iot/blob/main/Documentation/CONTRIBUTING.md) +- [Azure Pipelines Config](https://github.com/dotnet/iot/blob/main/azure-pipelines.yml) diff --git a/.github/skills/fix-api-conventions/SKILL.md b/.github/skills/fix-api-conventions/SKILL.md index 2dfc91c6b6..0e9d4ee1a3 100644 --- a/.github/skills/fix-api-conventions/SKILL.md +++ b/.github/skills/fix-api-conventions/SKILL.md @@ -387,6 +387,6 @@ Use this when reviewing device binding APIs: ## References -- [Device Conventions Document](../../../Documentation/Devices-conventions.md) -- [Copilot Instructions - API Design](../../copilot-instructions.md#device-binding-design) +- [Device Conventions Document](https://github.com/dotnet/iot/blob/main/Documentation/Devices-conventions.md) +- [Copilot Instructions - API Design](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md#device-binding-design) - [UnitsNet Documentation](https://github.com/angularsen/UnitsNet) diff --git a/.github/skills/hardware-abstraction-check/SKILL.md b/.github/skills/hardware-abstraction-check/SKILL.md index ebcb8c9c5b..dd209c17aa 100644 --- a/.github/skills/hardware-abstraction-check/SKILL.md +++ b/.github/skills/hardware-abstraction-check/SKILL.md @@ -456,5 +456,5 @@ chmod +x check-abstraction.sh - [System.Device.Gpio Documentation](https://docs.microsoft.com/dotnet/api/system.device.gpio) - [System.Device.I2c Documentation](https://docs.microsoft.com/dotnet/api/system.device.i2c) -- [Copilot Instructions - Cross-Platform](../../copilot-instructions.md#cross-platform) -- [Device Conventions](../../../Documentation/Devices-conventions.md) +- [Copilot Instructions - Cross-Platform](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md#cross-platform) +- [Device Conventions](https://github.com/dotnet/iot/blob/main/Documentation/Devices-conventions.md) diff --git a/.github/skills/update-device-documentation/SKILL.md b/.github/skills/update-device-documentation/SKILL.md index 0bb11a554a..ee41f24ef9 100644 --- a/.github/skills/update-device-documentation/SKILL.md +++ b/.github/skills/update-device-documentation/SKILL.md @@ -405,7 +405,7 @@ Connect DHT22 to Raspberry Pi: ## References -- [Device Conventions](../../../Documentation/Devices-conventions.md) -- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) -- [Copilot Instructions](../../copilot-instructions.md) -- [Markdown Style Guide](.markdownlint.json) +- [Device Conventions](https://github.com/dotnet/iot/blob/main/Documentation/Devices-conventions.md) +- [Contributing Guidelines](https://github.com/dotnet/iot/blob/main/Documentation/CONTRIBUTING.md) +- [Copilot Instructions](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md) +- [Markdown Style Guide](https://github.com/dotnet/iot/blob/main/.markdownlint.json) From bebccf0f52beef7019e7a2ec9ed2dc0864c605c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:48:43 +0000 Subject: [PATCH 5/9] Fix sample project naming convention to use capital S (.Samples.csproj) Co-authored-by: krwq <660048+krwq@users.noreply.github.com> --- .github/skills/add-device-binding/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/skills/add-device-binding/SKILL.md b/.github/skills/add-device-binding/SKILL.md index 55bc747656..123a21cc95 100644 --- a/.github/skills/add-device-binding/SKILL.md +++ b/.github/skills/add-device-binding/SKILL.md @@ -25,7 +25,7 @@ src/devices// ├── .csproj ├── .cs (main class) ├── samples/ -│ ├── .samples.csproj +│ ├── .Samples.csproj │ └── Program.cs ├── tests/ (if applicable) │ └── .Tests.csproj From 07236187b73ec45467329dbee6124528c1bd7dd6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:52:04 +0000 Subject: [PATCH 6/9] Revert to relative paths in References sections per feedback Co-authored-by: krwq <660048+krwq@users.noreply.github.com> --- .github/skills/add-device-binding/SKILL.md | 6 +++--- .github/skills/debug-build-issues/SKILL.md | 6 +++--- .github/skills/fix-api-conventions/SKILL.md | 4 ++-- .github/skills/hardware-abstraction-check/SKILL.md | 4 ++-- .github/skills/update-device-documentation/SKILL.md | 8 ++++---- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/skills/add-device-binding/SKILL.md b/.github/skills/add-device-binding/SKILL.md index 123a21cc95..e398dbd0f1 100644 --- a/.github/skills/add-device-binding/SKILL.md +++ b/.github/skills/add-device-binding/SKILL.md @@ -220,7 +220,7 @@ public class Dht22 : IDisposable ## References -- [Device Conventions](https://github.com/dotnet/iot/blob/main/Documentation/Devices-conventions.md) -- [Contributing Guidelines](https://github.com/dotnet/iot/blob/main/Documentation/CONTRIBUTING.md) -- [Copilot Instructions](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md) +- [Device Conventions](../../../Documentation/Devices-conventions.md) +- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) +- [Copilot Instructions](../../copilot-instructions.md) - [UnitsNet Library](https://github.com/angularsen/UnitsNet) diff --git a/.github/skills/debug-build-issues/SKILL.md b/.github/skills/debug-build-issues/SKILL.md index 77721db125..a74c65122a 100644 --- a/.github/skills/debug-build-issues/SKILL.md +++ b/.github/skills/debug-build-issues/SKILL.md @@ -283,6 +283,6 @@ Document and inform user when: ## References -- [Copilot Instructions - Build Section](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md#bootstrap-and-build-process) -- [Contributing Guidelines](https://github.com/dotnet/iot/blob/main/Documentation/CONTRIBUTING.md) -- [Azure Pipelines Config](https://github.com/dotnet/iot/blob/main/azure-pipelines.yml) +- [Copilot Instructions - Build Section](../../copilot-instructions.md#bootstrap-and-build-process) +- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) +- [Azure Pipelines Config](../../../azure-pipelines.yml) diff --git a/.github/skills/fix-api-conventions/SKILL.md b/.github/skills/fix-api-conventions/SKILL.md index 0e9d4ee1a3..2dfc91c6b6 100644 --- a/.github/skills/fix-api-conventions/SKILL.md +++ b/.github/skills/fix-api-conventions/SKILL.md @@ -387,6 +387,6 @@ Use this when reviewing device binding APIs: ## References -- [Device Conventions Document](https://github.com/dotnet/iot/blob/main/Documentation/Devices-conventions.md) -- [Copilot Instructions - API Design](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md#device-binding-design) +- [Device Conventions Document](../../../Documentation/Devices-conventions.md) +- [Copilot Instructions - API Design](../../copilot-instructions.md#device-binding-design) - [UnitsNet Documentation](https://github.com/angularsen/UnitsNet) diff --git a/.github/skills/hardware-abstraction-check/SKILL.md b/.github/skills/hardware-abstraction-check/SKILL.md index dd209c17aa..ebcb8c9c5b 100644 --- a/.github/skills/hardware-abstraction-check/SKILL.md +++ b/.github/skills/hardware-abstraction-check/SKILL.md @@ -456,5 +456,5 @@ chmod +x check-abstraction.sh - [System.Device.Gpio Documentation](https://docs.microsoft.com/dotnet/api/system.device.gpio) - [System.Device.I2c Documentation](https://docs.microsoft.com/dotnet/api/system.device.i2c) -- [Copilot Instructions - Cross-Platform](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md#cross-platform) -- [Device Conventions](https://github.com/dotnet/iot/blob/main/Documentation/Devices-conventions.md) +- [Copilot Instructions - Cross-Platform](../../copilot-instructions.md#cross-platform) +- [Device Conventions](../../../Documentation/Devices-conventions.md) diff --git a/.github/skills/update-device-documentation/SKILL.md b/.github/skills/update-device-documentation/SKILL.md index ee41f24ef9..9a2b39ac93 100644 --- a/.github/skills/update-device-documentation/SKILL.md +++ b/.github/skills/update-device-documentation/SKILL.md @@ -405,7 +405,7 @@ Connect DHT22 to Raspberry Pi: ## References -- [Device Conventions](https://github.com/dotnet/iot/blob/main/Documentation/Devices-conventions.md) -- [Contributing Guidelines](https://github.com/dotnet/iot/blob/main/Documentation/CONTRIBUTING.md) -- [Copilot Instructions](https://github.com/dotnet/iot/blob/main/.github/copilot-instructions.md) -- [Markdown Style Guide](https://github.com/dotnet/iot/blob/main/.markdownlint.json) +- [Device Conventions](../../../Documentation/Devices-conventions.md) +- [Contributing Guidelines](../../../Documentation/CONTRIBUTING.md) +- [Copilot Instructions](../../copilot-instructions.md) +- [Markdown Style Guide](../../../.markdownlint.json) From c3215961956ef0631ae9da30988b91b7f27bd5e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:55:08 +0000 Subject: [PATCH 7/9] Clarify constructor guidelines and transport ownership requirements Co-authored-by: krwq <660048+krwq@users.noreply.github.com> --- .github/skills/add-device-binding/SKILL.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/skills/add-device-binding/SKILL.md b/.github/skills/add-device-binding/SKILL.md index e398dbd0f1..1412405a5e 100644 --- a/.github/skills/add-device-binding/SKILL.md +++ b/.github/skills/add-device-binding/SKILL.md @@ -35,8 +35,8 @@ src/devices// ### 2. Constructor & Dependencies - Accept hardware transports from the caller: `I2cDevice`, `SpiDevice`, `GpioController`, pin numbers, bus addresses -- Provide sensible defaults (e.g., common I²C addresses like 0x48) -- **Never hardcode board-specific details** +- Provide sensible defaults (e.g., common I2C addresses like 0x48) +- **Never hardcode board-specific details** (e.g., GPIO pin numbers, bus IDs, or hardware paths like `/dev/i2c-1`) - Avoid singletons and global state **Example Constructor:** @@ -68,7 +68,8 @@ public Bmp280(I2cDevice i2cDevice, I2cAddress address = I2cAddress.Primary) - **MUST implement `IDisposable`** - Dispose hardware resources (I2C/SPI devices, GPIO pins) in the Dispose method -- If transport is passed by caller, dispose it unless `shouldDispose` flag says otherwise +- **MUST provide a way for caller to retain ownership** of transports (e.g., via `shouldDispose` parameter, default true) +- If transport is passed by caller, only dispose it when `shouldDispose` is true or when device creates it - Design for failure: ensure exceptions leave device in consistent state **Example Disposal:** @@ -100,7 +101,7 @@ protected virtual void Dispose(bool disposing) - XML documentation comments on all public APIs - **Include units** in comments (°C, Pa, %RH, lux, etc.) -- Document parameter ownership (does caller own the transport?) +- Document parameter ownership: caller owns the transport unless `shouldDispose` parameter allows device to take ownership - README.md with: - Device description and capabilities - Wiring diagram or connection instructions From c1ffacfa457135e3aea3ccb3193dd84fed9e9820 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:58:25 +0000 Subject: [PATCH 8/9] Document README conventions for device bindings Co-authored-by: krwq <660048+krwq@users.noreply.github.com> --- .github/skills/add-device-binding/SKILL.md | 38 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/.github/skills/add-device-binding/SKILL.md b/.github/skills/add-device-binding/SKILL.md index 1412405a5e..6a67ad1abd 100644 --- a/.github/skills/add-device-binding/SKILL.md +++ b/.github/skills/add-device-binding/SKILL.md @@ -102,12 +102,38 @@ protected virtual void Dispose(bool disposing) - XML documentation comments on all public APIs - **Include units** in comments (°C, Pa, %RH, lux, etc.) - Document parameter ownership: caller owns the transport unless `shouldDispose` parameter allows device to take ownership -- README.md with: - - Device description and capabilities - - Wiring diagram or connection instructions - - Required pull-ups/pull-downs - - Expected ranges and units - - Code example demonstrating usage +- **README.md** must follow these conventions: + +#### README Title (First Heading) + +- Format: `# DeviceName - Brief functional description` +- Keep title short and descriptive (appears in device listings) +- Use device's official name/model number +- Brief description states what the device does (e.g., "Digital Temperature Sensor", "3 Axis Digital Compass") +- Examples: + - `# BMP180 - barometer, altitude and temperature sensor` + - `# HMC5883L - 3 Axis Digital Compass` + - `# ADS1115 - Analog to Digital Converter` + +#### Documentation Section (Second Heading) + +- **Must be `## Documentation`** (exact name) +- First item should **always link to official datasheet/documentation** +- Format: `[Datasheet](URL)` or `Product [datasheet](URL)` +- Additional items can list supported devices, features, or related docs +- Examples: + + ```markdown + ## Documentation + + - HMC5883L [datasheet](https://example.com/datasheet.pdf) + ``` + +#### Required Sections + +- `## Usage` - Code examples demonstrating typical usage +- Optional: `## Binding Notes` - Implementation-specific details +- Optional: Circuit diagrams, wiring instructions, sensor images ### 7. Sample Application From 07b3cb40cff01592ca2acc4bfdc28603f42dc70d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 17:01:10 +0000 Subject: [PATCH 9/9] Remove confusing grep command from build validation section Co-authored-by: krwq <660048+krwq@users.noreply.github.com> --- .github/skills/add-device-binding/SKILL.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/skills/add-device-binding/SKILL.md b/.github/skills/add-device-binding/SKILL.md index 6a67ad1abd..994c54d35e 100644 --- a/.github/skills/add-device-binding/SKILL.md +++ b/.github/skills/add-device-binding/SKILL.md @@ -189,9 +189,6 @@ cd src/devices/ cd samples ../../../../dotnet.sh build - -# Check for hardware abstraction violations -grep -r "Environment.OSVersion\|DllImport\|P/Invoke" . ``` ## Review Checklist