Compare commits

...

20 Commits

Author SHA1 Message Date
Sumanth Rayancha
90b6f258f0 test: initial attempt at tests with Claude Code 2025-08-11 22:21:14 -04:00
Andrew Welker
e1e32cea6f fix: use correct line endings for verbatim strings 2025-08-06 08:55:08 -05:00
Andrew Welker
e31df338d6 chore: remove duplication namespace declaration
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-07 10:06:59 -05:00
Andrew Welker
d14058fc32 chore: update local build version 2025-07-04 16:23:02 -05:00
Andrew Welker
04d6508c80 feat: modify factory loading
Updating IDeviceFactory to resolve [FEATURE]-Refactor Plugin loading mechanism  #1065.
This change should be backwards-compatible with existing plugins that use the EssentialsPluginDeviceFactory<T> class,
as the interfaces are implemented by the various base classes.

In addition, the correct assembly name is now printed when a type is loaded.
2025-07-04 16:07:45 -05:00
Andrew Welker
1cbc8194ec feat: remove context file for storing values 2025-07-04 16:03:00 -05:00
Andrew Welker
6d2cd75cbe chore: move all files to file-scoped namespace 2025-07-04 16:02:32 -05:00
Andrew Welker
8b873b7248 feat: modify plugin loading process 2025-07-04 13:33:56 -05:00
Andrew Welker
58a2a5c008 docs: update XML docs 2025-07-04 13:07:21 -05:00
Andrew Welker
cc7e2ab675 chore: fix issues related to remving crestron usings 2025-07-04 12:46:08 -05:00
Andrew Welker
dc900f3f31 docs: add XML comments 2025-07-04 12:37:41 -05:00
Andrew Welker
562f0ba793 wip: package updates 2025-07-04 12:37:41 -05:00
jtalborough
9c3c924a29 fix: adjust installation steps for prerequisites based on environment detection 2025-07-04 12:37:41 -05:00
jtalborough
9b5af60a46 fix: update condition for CPZ copy target and remove obsolete workflows 2025-07-04 12:37:41 -05:00
jtalborough
a99b0a1fac feat: enhance plugin dependency management in PluginLoader 2025-07-04 12:37:41 -05:00
jtalborough
7591913a9c wip: address performance issues in plugin loading and versioning 2025-07-04 12:37:41 -05:00
jtalborough
66a6612b65 fix: update target framework to net8 and bump PepperDashCore version to 2.0.0-alpha-462
BREAKING CHANGE: Target Framework is now .NET 8:
2025-07-04 12:37:21 -05:00
jtalborough
688cf34153 feat: implement WebSocket classes and update culture settings; bump PepperDashCore version 2025-07-04 11:53:02 -05:00
jtalborough
0c59237232 fix: update target frameworks and package references; change culture to InvariantCulture 2025-07-04 11:52:43 -05:00
jtalborough
88eec9a3f1 fix: update package references and clean up unused imports 2025-07-04 11:52:01 -05:00
585 changed files with 51367 additions and 49683 deletions

56
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: CI Build and Test
on:
push:
branches: [ main, develop, net8-updates ]
pull_request:
branches: [ main, develop, net8-updates ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Run tests
run: dotnet test --no-restore --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage
- name: Generate coverage report
uses: danielpalme/ReportGenerator-GitHub-Action@5.2.0
with:
reports: coverage/**/coverage.cobertura.xml
targetdir: coverage-report
reporttypes: Html;Cobertura;MarkdownSummary
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage-report/Cobertura.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
- name: Write coverage summary
run: cat coverage-report/Summary.md >> $GITHUB_STEP_SUMMARY
if: always()
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results
path: |
coverage/
coverage-report/

View File

@@ -0,0 +1,247 @@
name: Essentials v3 Development Build
on:
push:
branches:
- feature-3.0.0/*
- hotfix-3.0.0/*
- release-3.0.0/*
- development-3.0.0
env:
SOLUTION_PATH: .
SOLUTION_FILE: PepperDash.Essentials
VERSION: 0.0.0-buildtype-buildnumber
BUILD_TYPE: Debug
RELEASE_BRANCH: main
jobs:
Build_Project_4-Series:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Detect environment (Act vs GitHub)
- name: Detect environment
id: detect_env
run: |
if [ -n "$ACT" ]; then
echo "is_local=true" >> $GITHUB_OUTPUT
else
echo "is_local=false" >> $GITHUB_OUTPUT
fi
- name: Install prerequisites
run: |
if [ "${{ steps.detect_env.outputs.is_local }}" == "true" ]; then
# For Act - no sudo needed
apt-get update
apt-get install -y curl wget libicu-dev git unzip
else
# For GitHub runners - sudo required
sudo apt-get update
sudo apt-get install -y curl wget libicu-dev git unzip
fi
- name: Set Version Number
id: setVersion
shell: bash
run: |
latestVersion="3.0.0"
newVersion=$latestVersion
phase=""
newVersionString=""
if [[ $GITHUB_REF =~ ^refs/pull/.* ]]; then
phase="beta"
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
elif [[ $GITHUB_REF =~ ^refs/heads/hotfix-3.0.0/.* ]]; then
phase="hotfix"
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
elif [[ $GITHUB_REF =~ ^refs/heads/feature-3.0.0/.* ]]; then
phase="alpha"
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
elif [[ $GITHUB_REF == "refs/heads/development-3.0.0" ]]; then
phase="beta"
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
elif [[ $GITHUB_REF =~ ^refs/heads/release-3.0.0/.* ]]; then
version=$(echo $GITHUB_REF | awk -F '/' '{print $NF}' | sed 's/v//')
phase="rc"
newVersionString="${version}-${phase}-${GITHUB_RUN_NUMBER}"
else
# For local builds or unrecognized branches
newVersionString="${newVersion}-local"
fi
echo "version=$newVersionString" >> $GITHUB_OUTPUT
# Create Build Properties file
- name: Create Build Properties
run: |
cat > Directory.Build.props << EOF
<Project>
<PropertyGroup>
<Version>${{ steps.setVersion.outputs.version }}</Version>
<AssemblyVersion>${{ steps.setVersion.outputs.version }}</AssemblyVersion>
<FileVersion>${{ steps.setVersion.outputs.version }}</FileVersion>
<InformationalVersion>${{ steps.setVersion.outputs.version }}</InformationalVersion>
<PackageVersion>${{ steps.setVersion.outputs.version }}</PackageVersion>
<NuGetVersion>${{ steps.setVersion.outputs.version }}</NuGetVersion>
</PropertyGroup>
</Project>
EOF
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
- name: Restore NuGet Packages
run: dotnet restore ${SOLUTION_FILE}.sln
- name: Build Solution
run: dotnet build ${SOLUTION_FILE}.sln --configuration ${BUILD_TYPE} --no-restore
# Copy the CPZ file to the output directory with version in the filename
- name: Copy and Rename CPZ Files
run: |
mkdir -p ./output/cpz
# Find the main CPZ file in the build output
if [ -f "./src/PepperDash.Essentials/bin/${BUILD_TYPE}/net8/PepperDashEssentials.cpz" ]; then
cp "./src/PepperDash.Essentials/bin/${BUILD_TYPE}/net8/PepperDashEssentials.cpz" "./output/cpz/PepperDashEssentials.${{ steps.setVersion.outputs.version }}.cpz"
echo "Main CPZ file copied and renamed successfully."
else
echo "Warning: Main CPZ file not found at expected location."
find ./src -name "*.cpz" | xargs -I {} cp {} ./output/cpz/
fi
- name: Pack Solution
run: dotnet pack ${SOLUTION_FILE}.sln --configuration ${BUILD_TYPE} --output ./output/nuget --no-build
# List build artifacts (runs in both environments)
- name: List Build Artifacts
run: |
echo "=== Build Artifacts ==="
echo "NuGet Packages:"
find ./output/nuget -type f | sort
echo ""
echo "CPZ/CPLZ Files:"
find ./output -name "*.cpz" -o -name "*.cplz" | sort
echo "======================="
# Enhanced package inspection for local runs
- name: Inspect NuGet Packages
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== NuGet Package Details ==="
for pkg in $(find ./output/nuget -name "*.nupkg"); do
echo "Package: $(basename "$pkg")"
echo "Size: $(du -h "$pkg" | cut -f1)"
# Extract and show package contents
echo "Contents:"
unzip -l "$pkg" | tail -n +4 | head -n -2
echo "--------------------------"
# Try to extract and show the nuspec file (contains metadata)
echo "Metadata:"
unzip -p "$pkg" "*.nuspec" 2>/dev/null | grep -E "(<id>|<version>|<description>|<authors>|<dependencies>)" || echo "Metadata extraction failed"
echo "--------------------------"
done
echo "==========================="
# Tag creation - GitHub version
- name: Create tag for non-rc builds (GitHub)
if: ${{ !contains(steps.setVersion.outputs.version, 'rc') && steps.detect_env.outputs.is_local == 'false' }}
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git tag ${{ steps.setVersion.outputs.version }}
git push --tags origin
# Tag creation - Act mock version
- name: Create tag for non-rc builds (Act Mock)
if: ${{ !contains(steps.setVersion.outputs.version, 'rc') && steps.detect_env.outputs.is_local == 'true' }}
run: |
echo "Would create git tag: ${{ steps.setVersion.outputs.version }}"
echo "Would push tag to: origin"
# Release creation - GitHub version
- name: Create Release (GitHub)
if: steps.detect_env.outputs.is_local == 'false'
id: create_release
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
artifacts: 'output/cpz/*,output/**/*.cplz'
generateReleaseNotes: true
prerelease: ${{contains('debug', env.BUILD_TYPE)}}
tag: ${{ steps.setVersion.outputs.version }}
# Release creation - Act mock version with enhanced output
- name: Create Release (Act Mock)
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== Mock Release Creation ==="
echo "Would create release with:"
echo "- Tag: ${{ steps.setVersion.outputs.version }}"
echo "- Prerelease: ${{contains('debug', env.BUILD_TYPE)}}"
echo "- Artifacts matching pattern: output/cpz/*,output/**/*.cplz"
echo ""
echo "Matching artifacts:"
find ./output/cpz -type f
find ./output -name "*.cplz"
# Detailed info about release artifacts
echo ""
echo "Artifact Details:"
for artifact in $(find ./output/cpz -type f; find ./output -name "*.cplz"); do
echo "File: $(basename "$artifact")"
echo "Size: $(du -h "$artifact" | cut -f1)"
echo "Created: $(stat -c %y "$artifact")"
echo "MD5: $(md5sum "$artifact" | cut -d' ' -f1)"
echo "--------------------------"
done
echo "============================"
# NuGet setup - GitHub version
- name: Setup NuGet (GitHub)
if: steps.detect_env.outputs.is_local == 'false'
run: |
dotnet nuget add source https://nuget.pkg.github.com/pepperdash/index.json -n github -u pepperdash -p ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text
# NuGet setup - Act mock version
- name: Setup NuGet (Act Mock)
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== Mock NuGet Setup ==="
echo "Would add GitHub NuGet source: https://nuget.pkg.github.com/pepperdash/index.json"
echo "======================="
# Publish to NuGet - GitHub version
- name: Publish to Nuget (GitHub)
if: steps.detect_env.outputs.is_local == 'false'
run: dotnet nuget push ./output/nuget/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
# Publish to NuGet - Act mock version
- name: Publish to Nuget (Act Mock)
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== Mock Publish to NuGet ==="
echo "Would publish the following packages to https://api.nuget.org/v3/index.json:"
find ./output/nuget -name "*.nupkg" | sort
echo "============================="
# Publish to GitHub NuGet - GitHub version
- name: Publish to Github Nuget (GitHub)
if: steps.detect_env.outputs.is_local == 'false'
run: dotnet nuget push ./output/nuget/*.nupkg --source github --api-key ${{ secrets.GITHUB_TOKEN }}
# Publish to GitHub NuGet - Act mock version
- name: Publish to Github Nuget (Act Mock)
if: steps.detect_env.outputs.is_local == 'true'
run: |
echo "=== Mock Publish to GitHub NuGet ==="
echo "Would publish the following packages to the GitHub NuGet registry:"
find ./output/nuget -name "*.nupkg" | sort
echo "=================================="

View File

View File

@@ -0,0 +1,42 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A8B8F24D-3181-45BF-9ED3-F734E04F0BC8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Core", "src\PepperDash.Core\PepperDash.Core.csproj", "{1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Core", "src\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj", "{2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B8B8F24D-3181-45BF-9ED3-F734E04F0BC9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Core.Tests", "tests\PepperDash.Essentials.Core.Tests\PepperDash.Essentials.Core.Tests.csproj", "{3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A}.Release|Any CPU.Build.0 = Release|Any CPU
{2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B}.Release|Any CPU.Build.0 = Release|Any CPU
{3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7A} = {A8B8F24D-3181-45BF-9ED3-F734E04F0BC8}
{2E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7B} = {A8B8F24D-3181-45BF-9ED3-F734E04F0BC8}
{3E5D8C7C-A4D0-4D0E-A6B0-9E3F3D9C8B7C} = {B8B8F24D-3181-45BF-9ED3-F734E04F0BC9}
EndGlobalSection
EndGlobal

166
TESTING_STRATEGY.md Normal file
View File

@@ -0,0 +1,166 @@
# PepperDash Essentials Unit Testing Strategy
## Problem Statement
The PepperDash Essentials framework is tightly coupled to Crestron hardware libraries that only run on Crestron devices, making it impossible to run unit tests on development machines or in CI/CD pipelines.
## Solution: Abstraction Layer Pattern
### 1. Core Abstractions Created
We've implemented abstraction interfaces that decouple business logic from Crestron hardware:
- **`ICrestronControlSystem`** - Abstracts the control system hardware
- **`IRelayPort`** - Abstracts relay functionality
- **`IDigitalInput`** - Abstracts digital inputs with event handling
- **`IVersiPort`** - Abstracts VersiPort I/O
### 2. Adapter Pattern Implementation
Created adapter classes that wrap Crestron objects in production:
```csharp
// Production code uses adapters
var controlSystem = new CrestronControlSystemAdapter(Global.ControlSystem);
var processor = new CrestronProcessorTestable("key", controlSystem);
// Test code uses mocks
var mockControlSystem = new Mock<ICrestronControlSystem>();
var processor = new CrestronProcessorTestable("key", mockControlSystem.Object);
```
### 3. Testable Classes
Refactored classes to accept abstractions via dependency injection:
- **`CrestronProcessorTestable`** - Accepts `ICrestronControlSystem`
- **`GenericRelayDeviceTestable`** - Accepts `IRelayPort`
## Implementation Steps
### Step 1: Identify Dependencies
```bash
# Find Crestron dependencies
grep -r "using Crestron" --include="*.cs"
```
### Step 2: Create Abstractions
Define interfaces that mirror the Crestron API surface you need:
```csharp
public interface IRelayPort
{
void Open();
void Close();
void Pulse(int delayMs);
bool State { get; }
}
```
### Step 3: Implement Adapters
Wrap Crestron objects with adapters:
```csharp
public class RelayPortAdapter : IRelayPort
{
private readonly Relay _relay;
public void Open() => _relay.Open();
// ... other methods
}
```
### Step 4: Refactor Classes
Accept abstractions in constructors:
```csharp
public class CrestronProcessorTestable
{
public CrestronProcessorTestable(string key, ICrestronControlSystem processor)
{
// Use abstraction instead of concrete type
}
}
```
### Step 5: Write Tests
Use mocking frameworks to test business logic:
```csharp
[Fact]
public void OpenRelay_CallsRelayPortOpen()
{
var mockRelay = new Mock<IRelayPort>();
var device = new GenericRelayDeviceTestable("test", mockRelay.Object);
device.OpenRelay();
mockRelay.Verify(r => r.Open(), Times.Once);
}
```
## Test Project Structure
```
tests/
├── PepperDash.Essentials.Core.Tests/
│ ├── Abstractions/ # Tests for abstraction adapters
│ ├── Devices/ # Device-specific tests
│ └── *.csproj # Test project file
└── README.md # Testing documentation
```
## CI/CD Integration
### GitHub Actions Workflow
The `.github/workflows/ci.yml` file runs tests automatically on:
- Push to main/develop branches
- Pull requests
- Generates code coverage reports
### Running Tests Locally
```bash
# Run all tests
dotnet test
# Run with coverage
dotnet test --collect:"XPlat Code Coverage"
# Run specific tests
dotnet test --filter "FullyQualifiedName~CrestronProcessor"
```
## Benefits
1. **Unit Testing Without Hardware** - Tests run on any machine
2. **CI/CD Integration** - Automated testing in pipelines
3. **Better Design** - Encourages SOLID principles
4. **Faster Development** - No need for hardware to test logic
5. **Higher Code Quality** - Catch bugs before deployment
## Migration Guide
### For Existing Code
1. Identify classes with Crestron dependencies
2. Create abstraction interfaces
3. Implement adapters
4. Create testable versions accepting abstractions
5. Write unit tests
### For New Code
1. Always code against abstractions, not Crestron types
2. Use dependency injection
3. Write tests first (TDD approach)
## Current Test Coverage
- ✅ CrestronProcessor relay management
- ✅ GenericRelayDevice operations
- ✅ Digital input event handling
- ✅ VersiPort analog/digital operations
## Next Steps
1. Expand abstractions for more Crestron components
2. Increase test coverage across all modules
3. Add integration tests with mock hardware
4. Document testing best practices
5. Create code generation tools for adapters
## Tools Used
- **xUnit** - Test framework
- **Moq** - Mocking library
- **FluentAssertions** - Readable assertions
- **Coverlet** - Code coverage
- **GitHub Actions** - CI/CD
## Summary
By introducing an abstraction layer between the business logic and Crestron hardware dependencies, we've successfully enabled unit testing for the PepperDash Essentials framework. This approach allows development and testing without physical hardware while maintaining full compatibility with Crestron systems in production.

7
runtimeconfig.json Normal file
View File

@@ -0,0 +1,7 @@
{
"runtimeOptions": {
"configProperties": {
"System.Globalization.Invariant": false
}
}
}

View File

@@ -1,6 +1,6 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>2.4.0-local</Version> <Version>3.0.0-local</Version>
<InformationalVersion>$(Version)</InformationalVersion> <InformationalVersion>$(Version)</InformationalVersion>
<Authors>PepperDash Technology</Authors> <Authors>PepperDash Technology</Authors>
<Company>PepperDash Technology</Company> <Company>PepperDash Technology</Company>

View File

@@ -8,8 +8,8 @@ using Crestron.SimplSharp;
using PepperDash.Core; using PepperDash.Core;
namespace PepperDash.Core namespace PepperDash.Core;
{
/// <summary> /// <summary>
/// Defines the string event handler for line events on the gather /// Defines the string event handler for line events on the gather
/// </summary> /// </summary>
@@ -176,4 +176,3 @@ namespace PepperDash.Core
Stop(); Stop();
} }
} }
}

View File

@@ -5,13 +5,13 @@ using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using PepperDash.Core; using PepperDash.Core;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable
/// </summary>
public class CommunicationStreamDebugging
{ {
/// <summary>
/// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable
/// </summary>
public class CommunicationStreamDebugging
{
/// <summary> /// <summary>
/// Device Key that this instance configures /// Device Key that this instance configures
/// </summary> /// </summary>
@@ -129,14 +129,14 @@ namespace PepperDash.Core
DebugExpiryPeriod.Dispose(); DebugExpiryPeriod.Dispose();
DebugExpiryPeriod = null; DebugExpiryPeriod = null;
} }
} }
/// <summary> /// <summary>
/// The available settings for stream debugging /// The available settings for stream debugging
/// </summary> /// </summary>
[Flags] [Flags]
public enum eStreamDebuggingSetting public enum eStreamDebuggingSetting
{ {
/// <summary> /// <summary>
/// Debug off /// Debug off
/// </summary> /// </summary>
@@ -153,14 +153,14 @@ namespace PepperDash.Core
/// Debug both received and transmitted data /// Debug both received and transmitted data
/// </summary> /// </summary>
Both = Rx | Tx Both = Rx | Tx
} }
/// <summary> /// <summary>
/// The available settings for stream debugging response types /// The available settings for stream debugging response types
/// </summary> /// </summary>
[Flags] [Flags]
public enum eStreamDebuggingDataTypeSettings public enum eStreamDebuggingDataTypeSettings
{ {
/// <summary> /// <summary>
/// Debug data in byte format /// Debug data in byte format
/// </summary> /// </summary>
@@ -173,5 +173,4 @@ namespace PepperDash.Core
/// Debug data in both byte and text formats /// Debug data in both byte and text formats
/// </summary> /// </summary>
Both = Bytes | Text, Both = Bytes | Text,
}
} }

View File

@@ -3,13 +3,13 @@ using Crestron.SimplSharp;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Config properties that indicate how to communicate with a device for control
/// </summary>
public class ControlPropertiesConfig
{ {
/// <summary>
/// Config properties that indicate how to communicate with a device for control
/// </summary>
public class ControlPropertiesConfig
{
/// <summary> /// <summary>
/// The method of control /// The method of control
/// </summary> /// </summary>
@@ -89,5 +89,4 @@ namespace PepperDash.Core
public ControlPropertiesConfig() public ControlPropertiesConfig()
{ {
} }
}
} }

View File

@@ -16,17 +16,17 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
namespace PepperDash.Core namespace PepperDash.Core;
{
/// <summary>
/// Delegate for notifying of socket status changes
/// </summary>
/// <param name="client"></param>
public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client);
/// <summary> /// <summary>
/// EventArgs class for socket status changes /// Delegate for notifying of socket status changes
/// </summary> /// </summary>
/// <param name="client"></param>
public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client);
/// <summary>
/// EventArgs class for socket status changes
/// </summary>
public class GenericSocketStatusChageEventArgs : EventArgs public class GenericSocketStatusChageEventArgs : EventArgs
{ {
/// <summary> /// <summary>
@@ -46,19 +46,19 @@ namespace PepperDash.Core
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericSocketStatusChageEventArgs() { } public GenericSocketStatusChageEventArgs() { }
} }
/// <summary> /// <summary>
/// Delegate for notifying of TCP Server state changes /// Delegate for notifying of TCP Server state changes
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state); public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state);
/// <summary> /// <summary>
/// EventArgs class for TCP Server state changes /// EventArgs class for TCP Server state changes
/// </summary> /// </summary>
public class GenericTcpServerStateChangedEventArgs : EventArgs public class GenericTcpServerStateChangedEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -76,20 +76,20 @@ namespace PepperDash.Core
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericTcpServerStateChangedEventArgs() { } public GenericTcpServerStateChangedEventArgs() { }
} }
/// <summary> /// <summary>
/// Delegate for TCP Server socket status changes /// Delegate for TCP Server socket status changes
/// </summary> /// </summary>
/// <param name="socket"></param> /// <param name="socket"></param>
/// <param name="clientIndex"></param> /// <param name="clientIndex"></param>
/// <param name="clientStatus"></param> /// <param name="clientStatus"></param>
public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus); public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus);
/// <summary> /// <summary>
/// EventArgs for TCP server socket status changes /// EventArgs for TCP server socket status changes
/// </summary> /// </summary>
public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -130,13 +130,13 @@ namespace PepperDash.Core
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericTcpServerSocketStatusChangeEventArgs() { } public GenericTcpServerSocketStatusChangeEventArgs() { }
} }
/// <summary> /// <summary>
/// EventArgs for TCP server com method receive text /// EventArgs for TCP server com method receive text
/// </summary> /// </summary>
public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -181,13 +181,13 @@ namespace PepperDash.Core
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericTcpServerCommMethodReceiveTextArgs() { } public GenericTcpServerCommMethodReceiveTextArgs() { }
} }
/// <summary> /// <summary>
/// EventArgs for TCP server client ready for communication /// EventArgs for TCP server client ready for communication
/// </summary> /// </summary>
public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -205,13 +205,13 @@ namespace PepperDash.Core
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericTcpServerClientReadyForcommunicationsEventArgs() { } public GenericTcpServerClientReadyForcommunicationsEventArgs() { }
} }
/// <summary> /// <summary>
/// EventArgs for UDP connected /// EventArgs for UDP connected
/// </summary> /// </summary>
public class GenericUdpConnectedEventArgs : EventArgs public class GenericUdpConnectedEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -244,8 +244,5 @@ namespace PepperDash.Core
Connected = connected; Connected = connected;
} }
}
} }

View File

@@ -7,13 +7,13 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core.Logging; using PepperDash.Core.Logging;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// A class to handle secure TCP/IP communications with a server
/// </summary>
public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
{ {
/// <summary>
/// A class to handle secure TCP/IP communications with a server
/// </summary>
public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
{
private const string SplusKey = "Uninitialized Secure Tcp _client"; private const string SplusKey = "Uninitialized Secure Tcp _client";
/// <summary> /// <summary>
/// Stream debugging /// Stream debugging
@@ -950,6 +950,4 @@ namespace PepperDash.Core
handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication));
} }
#endregion #endregion
}
} }

View File

@@ -19,13 +19,13 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core.Logging; using PepperDash.Core.Logging;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Generic secure TCP/IP client for server
/// </summary>
public class GenericSecureTcpIpClient_ForServer : Device, IAutoReconnect
{ {
/// <summary>
/// Generic secure TCP/IP client for server
/// </summary>
public class GenericSecureTcpIpClient_ForServer : Device, IAutoReconnect
{
/// <summary> /// <summary>
/// Band aid delegate for choked server /// Band aid delegate for choked server
/// </summary> /// </summary>
@@ -904,6 +904,4 @@ namespace PepperDash.Core
handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication));
} }
#endregion #endregion
}
} }

View File

@@ -17,13 +17,13 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core.Logging; using PepperDash.Core.Logging;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Generic secure TCP/IP server
/// </summary>
public class GenericSecureTcpIpServer : Device
{ {
/// <summary>
/// Generic secure TCP/IP server
/// </summary>
public class GenericSecureTcpIpServer : Device
{
#region Events #region Events
/// <summary> /// <summary>
/// Event for Receiving text /// Event for Receiving text
@@ -1080,5 +1080,4 @@ namespace PepperDash.Core
} }
} }
#endregion #endregion
}
} }

View File

@@ -8,13 +8,13 @@ using PepperDash.Core.Logging;
using Renci.SshNet; using Renci.SshNet;
using Renci.SshNet.Common; using Renci.SshNet.Common;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
///
/// </summary>
public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
{ {
/// <summary>
///
/// </summary>
public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
{
private const string SPlusKey = "Uninitialized SshClient"; private const string SPlusKey = "Uninitialized SshClient";
/// <summary> /// <summary>
/// Object to enable stream debugging /// Object to enable stream debugging
@@ -542,7 +542,7 @@ namespace PepperDash.Core
this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes)); this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes));
} }
} }
#endregion #endregion
} }
@@ -588,5 +588,4 @@ public class SshConnectionChangeEventArgs : EventArgs
IsConnected = isConnected; IsConnected = isConnected;
Client = client; Client = client;
} }
}
} }

View File

@@ -6,13 +6,13 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace PepperDash.Core namespace PepperDash.Core;
{
/// <summary> /// <summary>
/// A class to handle basic TCP/IP communications with a server /// A class to handle basic TCP/IP communications with a server
/// </summary> /// </summary>
public class GenericTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect public class GenericTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
{ {
private const string SplusKey = "Uninitialized TcpIpClient"; private const string SplusKey = "Uninitialized TcpIpClient";
/// <summary> /// <summary>
/// Object to enable stream debugging /// Object to enable stream debugging
@@ -508,9 +508,9 @@ namespace PepperDash.Core
} }
} }
/// <summary> /// <summary>
/// Configuration properties for TCP/SSH Connections /// Configuration properties for TCP/SSH Connections
/// </summary> /// </summary>
public class TcpSshPropertiesConfig public class TcpSshPropertiesConfig
{ {
/// <summary> /// <summary>
@@ -562,5 +562,3 @@ namespace PepperDash.Core
} }
} }
}

View File

@@ -19,13 +19,13 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core.Logging; using PepperDash.Core.Logging;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Generic TCP/IP client for server
/// </summary>
public class GenericTcpIpClient_ForServer : Device, IAutoReconnect
{ {
/// <summary>
/// Generic TCP/IP client for server
/// </summary>
public class GenericTcpIpClient_ForServer : Device, IAutoReconnect
{
/// <summary> /// <summary>
/// Band aid delegate for choked server /// Band aid delegate for choked server
/// </summary> /// </summary>
@@ -770,6 +770,4 @@ namespace PepperDash.Core
handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication));
} }
#endregion #endregion
}
} }

View File

@@ -17,13 +17,13 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core.Logging; using PepperDash.Core.Logging;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Generic TCP/IP server device
/// </summary>
public class GenericTcpIpServer : Device
{ {
/// <summary>
/// Generic TCP/IP server device
/// </summary>
public class GenericTcpIpServer : Device
{
#region Events #region Events
/// <summary> /// <summary>
/// Event for Receiving text /// Event for Receiving text
@@ -1007,5 +1007,4 @@ namespace PepperDash.Core
} }
} }
#endregion #endregion
}
} }

View File

@@ -8,13 +8,13 @@ using Crestron.SimplSharp.CrestronSockets;
using Newtonsoft.Json; using Newtonsoft.Json;
using PepperDash.Core.Logging; using PepperDash.Core.Logging;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Generic UDP Server device
/// </summary>
public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging
{ {
/// <summary>
/// Generic UDP Server device
/// </summary>
public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging
{
private const string SplusKey = "Uninitialized Udp Server"; private const string SplusKey = "Uninitialized Udp Server";
/// <summary> /// <summary>
/// Object to enable stream debugging /// Object to enable stream debugging
@@ -318,11 +318,11 @@ namespace PepperDash.Core
Server.SendData(bytes, bytes.Length); Server.SendData(bytes, bytes.Length);
} }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class GenericUdpReceiveTextExtraArgs : EventArgs public class GenericUdpReceiveTextExtraArgs : EventArgs
{ {
/// <summary> /// <summary>
@@ -363,11 +363,11 @@ namespace PepperDash.Core
public GenericUdpReceiveTextExtraArgs() { } public GenericUdpReceiveTextExtraArgs() { }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class UdpServerPropertiesConfig public class UdpServerPropertiesConfig
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -392,5 +392,4 @@ namespace PepperDash.Core
{ {
BufferSize = 32768; BufferSize = 32768;
} }
}
} }

View File

@@ -1,12 +1,12 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Client config object for TCP client with server that inherits from TcpSshPropertiesConfig and adds properties for shared key and heartbeat
/// </summary>
public class TcpClientConfigObject
{ {
/// <summary>
/// Client config object for TCP client with server that inherits from TcpSshPropertiesConfig and adds properties for shared key and heartbeat
/// </summary>
public class TcpClientConfigObject
{
/// <summary> /// <summary>
/// TcpSsh Properties /// TcpSsh Properties
/// </summary> /// </summary>
@@ -55,5 +55,4 @@ namespace PepperDash.Core
/// </summary> /// </summary>
[JsonProperty("receiveQueueSize")] [JsonProperty("receiveQueueSize")]
public int ReceiveQueueSize { get; set; } public int ReceiveQueueSize { get; set; }
}
} }

View File

@@ -4,13 +4,13 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities
/// </summary>
public class TcpServerConfigObject
{ {
/// <summary>
/// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities
/// </summary>
public class TcpServerConfigObject
{
/// <summary> /// <summary>
/// Uique key /// Uique key
/// </summary> /// </summary>
@@ -56,5 +56,4 @@ namespace PepperDash.Core
/// Receive Queue size must be greater than 20 or defaults to 20 /// Receive Queue size must be greater than 20 or defaults to 20
/// </summary> /// </summary>
public int ReceiveQueueSize { get; set; } public int ReceiveQueueSize { get; set; }
}
} }

View File

@@ -4,13 +4,13 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Crestron Control Methods for a comm object
/// </summary>
public enum eControlMethod
{ {
/// <summary>
/// Crestron Control Methods for a comm object
/// </summary>
public enum eControlMethod
{
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -75,5 +75,4 @@ namespace PepperDash.Core
/// Secure TCP/IP /// Secure TCP/IP
/// </summary> /// </summary>
SecureTcpIp SecureTcpIp
}
} }

View File

@@ -7,13 +7,13 @@ using Crestron.SimplSharp.CrestronSockets;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// An incoming communication stream
/// </summary>
public interface ICommunicationReceiver : IKeyed
{ {
/// <summary>
/// An incoming communication stream
/// </summary>
public interface ICommunicationReceiver : IKeyed
{
/// <summary> /// <summary>
/// Notifies of bytes received /// Notifies of bytes received
/// </summary> /// </summary>
@@ -36,12 +36,12 @@ namespace PepperDash.Core
/// Disconnect from the device /// Disconnect from the device
/// </summary> /// </summary>
void Disconnect(); void Disconnect();
} }
/// <summary> /// <summary>
/// Represents a device that uses basic connection /// Represents a device that uses basic connection
/// </summary> /// </summary>
public interface IBasicCommunication : ICommunicationReceiver public interface IBasicCommunication : ICommunicationReceiver
{ {
/// <summary> /// <summary>
/// Send text to the device /// Send text to the device
@@ -56,25 +56,25 @@ namespace PepperDash.Core
void SendBytes(byte[] bytes); void SendBytes(byte[] bytes);
} }
/// <summary> /// <summary>
/// Represents a device that implements IBasicCommunication and IStreamDebugging /// Represents a device that implements IBasicCommunication and IStreamDebugging
/// </summary> /// </summary>
public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging
{ {
} }
/// <summary> /// <summary>
/// Represents a device with stream debugging capablities /// Represents a device with stream debugging capablities
/// </summary> /// </summary>
public interface IStreamDebugging public interface IStreamDebugging
{ {
/// <summary> /// <summary>
/// Object to enable stream debugging /// Object to enable stream debugging
/// </summary> /// </summary>
[JsonProperty("streamDebugging")] [JsonProperty("streamDebugging")]
CommunicationStreamDebugging StreamDebugging { get; } CommunicationStreamDebugging StreamDebugging { get; }
} }
/// <summary> /// <summary>
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient, /// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
@@ -95,17 +95,17 @@ namespace PepperDash.Core
SocketStatus ClientStatus { get; } SocketStatus ClientStatus { get; }
} }
/// <summary> /// <summary>
/// Describes a device that implements ISocketStatus and IStreamDebugging /// Describes a device that implements ISocketStatus and IStreamDebugging
/// </summary> /// </summary>
public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging
{ {
} }
/// <summary> /// <summary>
/// Describes a device that can automatically attempt to reconnect /// Describes a device that can automatically attempt to reconnect
/// </summary> /// </summary>
public interface IAutoReconnect public interface IAutoReconnect
{ {
/// <summary> /// <summary>
@@ -244,4 +244,3 @@ namespace PepperDash.Core
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value)); return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
} }
} }
}

View File

@@ -7,11 +7,11 @@ using Newtonsoft.Json.Linq;
using PepperDash.Core; using PepperDash.Core;
using Serilog.Events; using Serilog.Events;
namespace PepperDash.Core.Config namespace PepperDash.Core.Config;
{
/// <summary> /// <summary>
/// Reads a Portal formatted config file /// Reads a Portal formatted config file
/// </summary> /// </summary>
public class PortalConfigReader public class PortalConfigReader
{ {
/// <summary> /// <summary>
@@ -232,4 +232,3 @@ namespace PepperDash.Core.Config
return o1; return o1;
} }
} }
}

View File

@@ -4,10 +4,10 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core namespace PepperDash.Core;
public class EncodingHelper
{ {
public class EncodingHelper
{
public static string ConvertUtf8ToAscii(string utf8String) public static string ConvertUtf8ToAscii(string utf8String)
{ {
return Encoding.ASCII.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); return Encoding.ASCII.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length);
@@ -18,5 +18,4 @@ namespace PepperDash.Core
return Encoding.Unicode.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); return Encoding.Unicode.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length);
} }
}
} }

View File

@@ -6,30 +6,28 @@ using Crestron.SimplSharp;
using Newtonsoft.Json; using Newtonsoft.Json;
using Serilog; using Serilog;
namespace PepperDash.Core namespace PepperDash.Core;
{
/// <summary> /// <summary>
/// Unique key interface to require a unique key for the class /// Unique key interface to require a unique key for the class
/// </summary> /// </summary>
public interface IKeyed public interface IKeyed
{ {
/// <summary> /// <summary>
/// Unique Key /// Gets the unique key associated with the object.
/// </summary> /// </summary>
[JsonProperty("key")] [JsonProperty("key")]
string Key { get; } string Key { get; }
} }
/// <summary> /// <summary>
/// Named Keyed device interface. Forces the device to have a Unique Key and a name. /// Named Keyed device interface. Forces the device to have a Unique Key and a name.
/// </summary> /// </summary>
public interface IKeyName : IKeyed public interface IKeyName : IKeyed
{ {
/// <summary> /// <summary>
/// Isn't it obvious :) /// Gets the name associated with the current object.
/// </summary> /// </summary>
[JsonProperty("name")] [JsonProperty("name")]
string Name { get; } string Name { get; }
}
} }

View File

@@ -2,8 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using Serilog.Events; using Serilog.Events;
namespace PepperDash.Core namespace PepperDash.Core;
{
//********************************************************************************************************* //*********************************************************************************************************
/// <summary> /// <summary>
/// The core event and status-bearing class that most if not all device and connectors can derive from. /// The core event and status-bearing class that most if not all device and connectors can derive from.
@@ -189,4 +189,3 @@ namespace PepperDash.Core
return string.Format("{0} - {1}", Key, string.IsNullOrEmpty(Name) ? "---" : Name); return string.Format("{0} - {1}", Key, string.IsNullOrEmpty(Name) ? "---" : Name);
} }
} }
}

View File

@@ -2,11 +2,11 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Serilog.Events; using Serilog.Events;
namespace PepperDash.Core namespace PepperDash.Core;
{
/// <summary> /// <summary>
/// Class to help with accessing values from the CrestronEthernetHelper class /// Class to help with accessing values from the CrestronEthernetHelper class
/// </summary> /// </summary>
public class EthernetHelper public class EthernetHelper
{ {
/// <summary> /// <summary>
@@ -114,4 +114,3 @@ namespace PepperDash.Core
} }
} }
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core namespace PepperDash.Core;
{
/// <summary> /// <summary>
/// Bool change event args /// Bool change event args
/// </summary> /// </summary>
@@ -169,4 +169,3 @@ namespace PepperDash.Core
Index = index; Index = index;
} }
} }
}

View File

@@ -4,13 +4,13 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.GenericRESTfulCommunications namespace PepperDash.Core.GenericRESTfulCommunications;
{
/// <summary> /// <summary>
/// Constants /// Constants
/// </summary> /// </summary>
public class GenericRESTfulConstants public class GenericRESTfulConstants
{ {
/// <summary> /// <summary>
/// Generic boolean change /// Generic boolean change
/// </summary> /// </summary>
@@ -35,5 +35,4 @@ namespace PepperDash.Core.GenericRESTfulCommunications
/// Error string change /// Error string change
/// </summary> /// </summary>
public const ushort ErrorStringChange = 203; public const ushort ErrorStringChange = 203;
}
} }

View File

@@ -6,8 +6,8 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.Net.Http;
using Crestron.SimplSharp.Net.Https; using Crestron.SimplSharp.Net.Https;
namespace PepperDash.Core.GenericRESTfulCommunications namespace PepperDash.Core.GenericRESTfulCommunications;
{
/// <summary> /// <summary>
/// Generic RESTful communication class /// Generic RESTful communication class
/// </summary> /// </summary>
@@ -253,4 +253,3 @@ namespace PepperDash.Core.GenericRESTfulCommunications
} }
} }
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.JsonStandardObjects namespace PepperDash.Core.JsonStandardObjects;
{
/// <summary> /// <summary>
/// Constants for simpl modules /// Constants for simpl modules
/// </summary> /// </summary>
@@ -74,4 +74,3 @@ namespace PepperDash.Core.JsonStandardObjects
Index = index; Index = index;
} }
} }
}

View File

@@ -4,8 +4,8 @@ using Crestron.SimplSharp;
using PepperDash.Core.JsonToSimpl; using PepperDash.Core.JsonToSimpl;
using Serilog.Events; using Serilog.Events;
namespace PepperDash.Core.JsonStandardObjects namespace PepperDash.Core.JsonStandardObjects;
{
/// <summary> /// <summary>
/// Device class /// Device class
/// </summary> /// </summary>
@@ -180,4 +180,3 @@ namespace PepperDash.Core.JsonStandardObjects
#endregion EventHandler Helpers #endregion EventHandler Helpers
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.JsonStandardObjects namespace PepperDash.Core.JsonStandardObjects;
{
/* /*
Convert JSON snippt to C#: http://json2csharp.com/# Convert JSON snippt to C#: http://json2csharp.com/#
@@ -254,4 +254,3 @@ namespace PepperDash.Core.JsonStandardObjects
/// </summary> /// </summary>
public List<DeviceConfig> devices { get; set; } public List<DeviceConfig> devices { get; set; }
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
{
/// <summary> /// <summary>
/// Constants for Simpl modules /// Constants for Simpl modules
/// </summary> /// </summary>
@@ -140,4 +140,3 @@ namespace PepperDash.Core.JsonToSimpl
/// </summary> /// </summary>
String String
} }
}

View File

@@ -7,11 +7,11 @@ using Serilog.Events;
//using PepperDash.Core; //using PepperDash.Core;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
{
/// <summary> /// <summary>
/// The global class to manage all the instances of JsonToSimplMaster /// The global class to manage all the instances of JsonToSimplMaster
/// </summary> /// </summary>
public class J2SGlobal public class J2SGlobal
{ {
static List<JsonToSimplMaster> Masters = new List<JsonToSimplMaster>(); static List<JsonToSimplMaster> Masters = new List<JsonToSimplMaster>();
@@ -57,4 +57,3 @@ namespace PepperDash.Core.JsonToSimpl
return Masters.FirstOrDefault(m => m.UniqueID.Equals(file, StringComparison.OrdinalIgnoreCase)); return Masters.FirstOrDefault(m => m.UniqueID.Equals(file, StringComparison.OrdinalIgnoreCase));
} }
} }
}

View File

@@ -3,11 +3,11 @@ using System.Linq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Serilog.Events; using Serilog.Events;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
{
/// <summary> /// <summary>
/// Used to interact with an array of values with the S+ modules /// Used to interact with an array of values with the S+ modules
/// </summary> /// </summary>
public class JsonToSimplArrayLookupChild : JsonToSimplChildObjectBase public class JsonToSimplArrayLookupChild : JsonToSimplChildObjectBase
{ {
/// <summary> /// <summary>
@@ -159,4 +159,3 @@ namespace PepperDash.Core.JsonToSimpl
return false; return false;
} }
} }
}

View File

@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
{
/// <summary> /// <summary>
/// Base class for JSON objects /// Base class for JSON objects
/// </summary> /// </summary>
public abstract class JsonToSimplChildObjectBase : IKeyed public abstract class JsonToSimplChildObjectBase : IKeyed
{ {
/// <summary> /// <summary>
@@ -401,4 +401,3 @@ namespace PepperDash.Core.JsonToSimpl
} }
} }
} }
}

View File

@@ -7,13 +7,13 @@ using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// Represents a JSON file that can be read and written to
/// </summary>
public class JsonToSimplFileMaster : JsonToSimplMaster
{ {
/// <summary>
/// Represents a JSON file that can be read and written to
/// </summary>
public class JsonToSimplFileMaster : JsonToSimplMaster
{
/// <summary> /// <summary>
/// Sets the filepath as well as registers this with the Global.Masters list /// Sets the filepath as well as registers this with the Global.Masters list
/// </summary> /// </summary>
@@ -285,5 +285,4 @@ namespace PepperDash.Core.JsonToSimpl
} }
} }
} }
}
} }

View File

@@ -1,10 +1,10 @@
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
{
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class JsonToSimplFixedPathObject : JsonToSimplChildObjectBase public class JsonToSimplFixedPathObject : JsonToSimplChildObjectBase
{ {
/// <summary> /// <summary>
@@ -15,4 +15,3 @@ namespace PepperDash.Core.JsonToSimpl
this.LinkedToObject = true; this.LinkedToObject = true;
} }
} }
}

View File

@@ -3,13 +3,13 @@ using System.Collections.Generic;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
{
/// <summary> /// <summary>
/// Generic Master /// Generic Master
/// </summary> /// </summary>
public class JsonToSimplGenericMaster : JsonToSimplMaster public class JsonToSimplGenericMaster : JsonToSimplMaster
{ {
/*****************************************************************************************/ /*****************************************************************************************/
/** Privates **/ /** Privates **/
@@ -115,4 +115,3 @@ namespace PepperDash.Core.JsonToSimpl
Debug.Console(0, this, "WARNING: No save callback defined."); Debug.Console(0, this, "WARNING: No save callback defined.");
} }
} }
}

View File

@@ -2,15 +2,14 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
{
/// <summary> /// <summary>
/// Abstract base class for JsonToSimpl interactions /// Abstract base class for JsonToSimpl interactions
/// </summary> /// </summary>
public abstract class JsonToSimplMaster : IKeyed public abstract class JsonToSimplMaster : IKeyed
{ {
/// <summary> /// <summary>
@@ -160,11 +159,7 @@ namespace PepperDash.Core.JsonToSimpl
/// <returns></returns> /// <returns></returns>
public static JObject ParseObject(string json) public static JObject ParseObject(string json)
{ {
#if NET6_0 using (var reader = new JsonTextReader(new StringReader(json)))
using (var reader = new JsonTextReader(new System.IO.StringReader(json)))
#else
using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json)))
#endif
{ {
var startDepth = reader.Depth; var startDepth = reader.Depth;
var obj = JObject.Load(reader); var obj = JObject.Load(reader);
@@ -181,11 +176,8 @@ namespace PepperDash.Core.JsonToSimpl
/// <returns></returns> /// <returns></returns>
public static JArray ParseArray(string json) public static JArray ParseArray(string json)
{ {
#if NET6_0
using (var reader = new JsonTextReader(new System.IO.StringReader(json))) using (var reader = new JsonTextReader(new StringReader(json)))
#else
using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json)))
#endif
{ {
var startDepth = reader.Depth; var startDepth = reader.Depth;
var obj = JArray.Load(reader); var obj = JArray.Load(reader);
@@ -244,4 +236,3 @@ namespace PepperDash.Core.JsonToSimpl
} }
} }
} }
}

View File

@@ -6,13 +6,13 @@ using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PepperDash.Core.Config; using PepperDash.Core.Config;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl;
/// <summary>
/// Portal File Master
/// </summary>
public class JsonToSimplPortalFileMaster : JsonToSimplMaster
{ {
/// <summary>
/// Portal File Master
/// </summary>
public class JsonToSimplPortalFileMaster : JsonToSimplMaster
{
/// <summary> /// <summary>
/// Sets the filepath as well as registers this with the Global.Masters list /// Sets the filepath as well as registers this with the Global.Masters list
/// </summary> /// </summary>
@@ -188,4 +188,3 @@ namespace PepperDash.Core.JsonToSimpl
} }
} }
} }
}

View File

@@ -7,10 +7,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PepperDash.Core.Logging namespace PepperDash.Core.Logging;
public class CrestronEnricher : ILogEventEnricher
{ {
public class CrestronEnricher : ILogEventEnricher
{
static readonly string _appName; static readonly string _appName;
static CrestronEnricher() static CrestronEnricher()
@@ -33,5 +33,4 @@ namespace PepperDash.Core.Logging
logEvent.AddOrUpdateProperty(property); logEvent.AddOrUpdateProperty(property);
} }
}
} }

View File

@@ -1,4 +1,8 @@
using Crestron.SimplSharp; using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronDataStore; using Crestron.SimplSharp.CrestronDataStore;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.CrestronLogger; using Crestron.SimplSharp.CrestronLogger;
@@ -11,22 +15,19 @@ using Serilog.Events;
using Serilog.Formatting.Compact; using Serilog.Formatting.Compact;
using Serilog.Formatting.Json; using Serilog.Formatting.Json;
using Serilog.Templates; using Serilog.Templates;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Contains debug commands for use in various situations
/// </summary>
public static class Debug
{ {
/// <summary>
/// Contains debug commands for use in various situations
/// </summary>
public static class Debug
{
private static readonly string LevelStoreKey = "ConsoleDebugLevel"; private static readonly string LevelStoreKey = "ConsoleDebugLevel";
private static readonly string WebSocketLevelStoreKey = "WebsocketDebugLevel"; private static readonly string WebSocketLevelStoreKey = "WebsocketDebugLevel";
private static readonly string ErrorLogLevelStoreKey = "ErrorLogDebugLevel"; private static readonly string ErrorLogLevelStoreKey = "ErrorLogDebugLevel";
private static readonly string FileLevelStoreKey = "FileDebugLevel"; private static readonly string FileLevelStoreKey = "FileDebugLevel";
private static readonly string DoNotLoadOnNextBootKey = "DoNotLoadOnNextBoot";
private static readonly Dictionary<uint, LogEventLevel> _logLevels = new Dictionary<uint, LogEventLevel>() private static readonly Dictionary<uint, LogEventLevel> _logLevels = new Dictionary<uint, LogEventLevel>()
{ {
@@ -117,6 +118,8 @@ namespace PepperDash.Core
public static LoggerConfiguration LoggerConfiguration => _loggerConfiguration; public static LoggerConfiguration LoggerConfiguration => _loggerConfiguration;
static Debug() static Debug()
{
try
{ {
CrestronDataStoreStatic.InitCrestronDataStore(); CrestronDataStoreStatic.InitCrestronDataStore();
@@ -162,21 +165,6 @@ namespace PepperDash.Core
levelSwitch: _fileLevelSwitch levelSwitch: _fileLevelSwitch
); );
try
{
if (InitialParametersClass.NumberOfRemovableDrives > 0)
{
CrestronConsole.PrintLine("{0} RM Drive(s) Present. Initializing CrestronLogger", InitialParametersClass.NumberOfRemovableDrives);
_defaultLoggerConfiguration.WriteTo.Sink(new DebugCrestronLoggerSink());
}
else
CrestronConsole.PrintLine("No RM Drive(s) Present. Not using Crestron Logger");
}
catch (Exception e)
{
CrestronConsole.PrintLine("Initializing of CrestronLogger failed: {0}", e);
}
// Instantiate the root logger // Instantiate the root logger
_loggerConfiguration = _defaultLoggerConfiguration; _loggerConfiguration = _defaultLoggerConfiguration;
@@ -193,7 +181,7 @@ namespace PepperDash.Core
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
LogMessage(LogEventLevel.Information,msg); LogMessage(LogEventLevel.Information, msg);
IncludedExcludedKeys = new Dictionary<string, object>(); IncludedExcludedKeys = new Dictionary<string, object>();
@@ -218,13 +206,9 @@ namespace PepperDash.Core
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
LoadMemory(); DoNotLoadConfigOnNextBoot = GetDoNotLoadOnNextBoot();
var context = _contexts.GetOrCreateItem("DEFAULT"); if (DoNotLoadConfigOnNextBoot)
Level = context.Level;
DoNotLoadConfigOnNextBoot = context.DoNotLoadOnNextBoot;
if(DoNotLoadConfigOnNextBoot)
CrestronConsole.PrintLine(string.Format("Program {0} will not load config after next boot. Use console command go:{0} to load the config manually", InitialParametersClass.ApplicationNumber)); CrestronConsole.PrintLine(string.Format("Program {0} will not load config after next boot. Use console command go:{0} to load the config manually", InitialParametersClass.ApplicationNumber));
_consoleLoggingLevelSwitch.MinimumLevelChanged += (sender, args) => _consoleLoggingLevelSwitch.MinimumLevelChanged += (sender, args) =>
@@ -232,6 +216,24 @@ namespace PepperDash.Core
LogMessage(LogEventLevel.Information, "Console debug level set to {minimumLevel}", _consoleLoggingLevelSwitch.MinimumLevel); LogMessage(LogEventLevel.Information, "Console debug level set to {minimumLevel}", _consoleLoggingLevelSwitch.MinimumLevel);
}; };
} }
catch (Exception ex)
{
LogError(ex, "Exception in Debug static constructor: {message}", ex.Message);
}
}
private static bool GetDoNotLoadOnNextBoot()
{
var err = CrestronDataStoreStatic.GetLocalBoolValue(DoNotLoadOnNextBootKey, out var doNotLoad);
if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
LogError("Error retrieving DoNotLoadOnNextBoot value: {err}", err);
doNotLoad = false;
}
return doNotLoad;
}
public static void UpdateLoggerConfiguration(LoggerConfiguration config) public static void UpdateLoggerConfiguration(LoggerConfiguration config)
{ {
@@ -259,14 +261,15 @@ namespace PepperDash.Core
return LogEventLevel.Information; return LogEventLevel.Information;
} }
if(logLevel < 0 || logLevel > 5) if (logLevel < 0 || logLevel > 5)
{ {
CrestronConsole.PrintLine($"Stored Log level not valid for {levelStoreKey}: {logLevel}. Setting level to {LogEventLevel.Information}"); CrestronConsole.PrintLine($"Stored Log level not valid for {levelStoreKey}: {logLevel}. Setting level to {LogEventLevel.Information}");
return LogEventLevel.Information; return LogEventLevel.Information;
} }
return (LogEventLevel)logLevel; return (LogEventLevel)logLevel;
} catch (Exception ex) }
catch (Exception ex)
{ {
CrestronConsole.PrintLine($"Exception retrieving log level for {levelStoreKey}: {ex.Message}"); CrestronConsole.PrintLine($"Exception retrieving log level for {levelStoreKey}: {ex.Message}");
return LogEventLevel.Information; return LogEventLevel.Information;
@@ -278,7 +281,7 @@ namespace PepperDash.Core
var assembly = Assembly.GetExecutingAssembly(); var assembly = Assembly.GetExecutingAssembly();
var ver = var ver =
assembly assembly
.GetCustomAttributes(typeof (AssemblyInformationalVersionAttribute), false); .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false);
if (ver != null && ver.Length > 0) if (ver != null && ver.Length > 0)
{ {
@@ -326,13 +329,13 @@ namespace PepperDash.Core
if (levelString.Trim() == "?") if (levelString.Trim() == "?")
{ {
CrestronConsole.ConsoleCommandResponse( CrestronConsole.ConsoleCommandResponse(
$@"Used to set the minimum level of debug messages to be printed to the console: "Used to set the minimum level of debug messages to be printed to the console:\r\n" +
{_logLevels[0]} = 0 $"{_logLevels[0]} = 0\r\n" +
{_logLevels[1]} = 1 $"{_logLevels[1]} = 1\r\n" +
{_logLevels[2]} = 2 $"{_logLevels[2]} = 2\r\n" +
{_logLevels[3]} = 3 $"{_logLevels[3]} = 3\r\n" +
{_logLevels[4]} = 4 $"{_logLevels[4]} = 4\r\n" +
{_logLevels[5]} = 5"); $"{_logLevels[5]} = 5");
return; return;
} }
@@ -342,18 +345,18 @@ namespace PepperDash.Core
return; return;
} }
if(int.TryParse(levelString, out var levelInt)) if (int.TryParse(levelString, out var levelInt))
{ {
if(levelInt < 0 || levelInt > 5) if (levelInt < 0 || levelInt > 5)
{ {
CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelString} to valid log level. If using a number, value must be between 0-5"); CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelString} to valid log level. If using a number, value must be between 0-5");
return; return;
} }
SetDebugLevel((uint) levelInt); SetDebugLevel((uint)levelInt);
return; return;
} }
if(Enum.TryParse<LogEventLevel>(levelString, out var levelEnum)) if (Enum.TryParse<LogEventLevel>(levelString, out var levelEnum))
{ {
SetDebugLevel(levelEnum); SetDebugLevel(levelEnum);
return; return;
@@ -373,7 +376,7 @@ namespace PepperDash.Core
/// <param name="level"> Valid values 0-5</param> /// <param name="level"> Valid values 0-5</param>
public static void SetDebugLevel(uint level) public static void SetDebugLevel(uint level)
{ {
if(!_logLevels.TryGetValue(level, out var logLevel)) if (!_logLevels.TryGetValue(level, out var logLevel))
{ {
logLevel = LogEventLevel.Information; logLevel = LogEventLevel.Information;
@@ -392,9 +395,9 @@ namespace PepperDash.Core
CrestronConsole.ConsoleCommandResponse("[Application {0}], Debug level set to {1}\r\n", CrestronConsole.ConsoleCommandResponse("[Application {0}], Debug level set to {1}\r\n",
InitialParametersClass.ApplicationNumber, _consoleLoggingLevelSwitch.MinimumLevel); InitialParametersClass.ApplicationNumber, _consoleLoggingLevelSwitch.MinimumLevel);
CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int) level}"); CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int)level}");
var err = CrestronDataStoreStatic.SetLocalIntValue(LevelStoreKey, (int) level); var err = CrestronDataStoreStatic.SetLocalIntValue(LevelStoreKey, (int)level);
CrestronConsole.ConsoleCommandResponse($"Store result: {err}:{(int)level}"); CrestronConsole.ConsoleCommandResponse($"Store result: {err}:{(int)level}");
@@ -406,7 +409,7 @@ namespace PepperDash.Core
{ {
_websocketLoggingLevelSwitch.MinimumLevel = level; _websocketLoggingLevelSwitch.MinimumLevel = level;
var err = CrestronDataStoreStatic.SetLocalUintValue(WebSocketLevelStoreKey, (uint) level); var err = CrestronDataStoreStatic.SetLocalUintValue(WebSocketLevelStoreKey, (uint)level);
if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
LogMessage(LogEventLevel.Information, "Error saving websocket debug level setting: {erro}", err); LogMessage(LogEventLevel.Information, "Error saving websocket debug level setting: {erro}", err);
@@ -571,11 +574,13 @@ namespace PepperDash.Core
public static void SetDoNotLoadConfigOnNextBoot(bool state) public static void SetDoNotLoadConfigOnNextBoot(bool state)
{ {
DoNotLoadConfigOnNextBoot = state; DoNotLoadConfigOnNextBoot = state;
_contexts.GetOrCreateItem("DEFAULT").DoNotLoadOnNextBoot = state;
SaveMemoryOnTimeout();
CrestronConsole.ConsoleCommandResponse("[Application {0}], Do Not Load Config on Next Boot set to {1}", var err = CrestronDataStoreStatic.SetLocalBoolValue(DoNotLoadOnNextBootKey, state);
InitialParametersClass.ApplicationNumber, DoNotLoadConfigOnNextBoot);
if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
LogError("Error saving console debug level setting: {err}", err);
LogInformation("Do Not Load Config on Next Boot set to {state}", DoNotLoadConfigOnNextBoot);
} }
/// <summary> /// <summary>
@@ -644,7 +649,7 @@ namespace PepperDash.Core
#region Explicit methods for logging levels #region Explicit methods for logging levels
public static void LogVerbose(IKeyed keyed, string message, params object[] args) public static void LogVerbose(IKeyed keyed, string message, params object[] args)
{ {
using(LogContext.PushProperty("Key", keyed?.Key)) using (LogContext.PushProperty("Key", keyed?.Key))
{ {
_logger.Write(LogEventLevel.Verbose, message, args); _logger.Write(LogEventLevel.Verbose, message, args);
} }
@@ -652,7 +657,7 @@ namespace PepperDash.Core
public static void LogVerbose(Exception ex, IKeyed keyed, string message, params object[] args) public static void LogVerbose(Exception ex, IKeyed keyed, string message, params object[] args)
{ {
using(LogContext.PushProperty("Key", keyed?.Key)) using (LogContext.PushProperty("Key", keyed?.Key))
{ {
_logger.Write(LogEventLevel.Verbose, ex, message, args); _logger.Write(LogEventLevel.Verbose, ex, message, args);
} }
@@ -999,7 +1004,7 @@ namespace PepperDash.Core
return string.Format(@"\user\debugSettings\program{0}", InitialParametersClass.ApplicationNumber); return string.Format(@"\user\debugSettings\program{0}", InitialParametersClass.ApplicationNumber);
} }
return string.Format("{0}{1}user{1}debugSettings{1}{2}.json",Directory.GetApplicationRootDirectory(), Path.DirectorySeparatorChar, InitialParametersClass.RoomId); return string.Format("{0}{1}user{1}debugSettings{1}{2}.json", Directory.GetApplicationRootDirectory(), Path.DirectorySeparatorChar, InitialParametersClass.RoomId);
} }
/// <summary> /// <summary>
@@ -1024,5 +1029,4 @@ namespace PepperDash.Core
/// </summary> /// </summary>
None, None,
} }
}
} }

View File

@@ -9,10 +9,10 @@ using System.IO;
using System.Text; using System.Text;
namespace PepperDash.Core namespace PepperDash.Core;
public class DebugConsoleSink : ILogEventSink
{ {
public class DebugConsoleSink : ILogEventSink
{
private readonly ITextFormatter _textFormatter; private readonly ITextFormatter _textFormatter;
public void Emit(LogEvent logEvent) public void Emit(LogEvent logEvent)
@@ -40,16 +40,14 @@ namespace PepperDash.Core
_textFormatter = formatProvider ?? new JsonFormatter(); _textFormatter = formatProvider ?? new JsonFormatter();
} }
} }
public static class DebugConsoleSinkExtensions public static class DebugConsoleSinkExtensions
{ {
public static LoggerConfiguration DebugConsoleSink( public static LoggerConfiguration DebugConsoleSink(
this LoggerSinkConfiguration loggerConfiguration, this LoggerSinkConfiguration loggerConfiguration,
ITextFormatter formatProvider = null) ITextFormatter formatProvider = null)
{ {
return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider)); return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider));
} }
}
} }

View File

@@ -6,13 +6,13 @@ using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Represents a debugging context
/// </summary>
public class DebugContext
{ {
/// <summary>
/// Represents a debugging context
/// </summary>
public class DebugContext
{
/// <summary> /// <summary>
/// Describes the folder location where a given program stores it's debug level memory. By default, the /// Describes the folder location where a given program stores it's debug level memory. By default, the
/// file written will be named appNdebug where N is 1-10. /// file written will be named appNdebug where N is 1-10.
@@ -266,16 +266,15 @@ namespace PepperDash.Core
{ {
return string.Format(@"\NVRAM\debugSettings\program{0}-{1}", InitialParametersClass.ApplicationNumber, Key); return string.Format(@"\NVRAM\debugSettings\program{0}-{1}", InitialParametersClass.ApplicationNumber, Key);
} }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class DebugContextSaveData public class DebugContextSaveData
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int Level { get; set; } public int Level { get; set; }
}
} }

View File

@@ -3,10 +3,10 @@ using Crestron.SimplSharp.CrestronLogger;
using Serilog.Core; using Serilog.Core;
using Serilog.Events; using Serilog.Events;
namespace PepperDash.Core.Logging namespace PepperDash.Core.Logging;
public class DebugCrestronLoggerSink : ILogEventSink
{ {
public class DebugCrestronLoggerSink : ILogEventSink
{
public void Emit(LogEvent logEvent) public void Emit(LogEvent logEvent)
{ {
if (!Debug.IsRunningOnAppliance) return; if (!Debug.IsRunningOnAppliance) return;
@@ -25,5 +25,4 @@ namespace PepperDash.Core.Logging
{ {
CrestronLogger.Initialize(1, LoggerModeEnum.RM); CrestronLogger.Initialize(1, LoggerModeEnum.RM);
} }
}
} }

View File

@@ -9,10 +9,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PepperDash.Core.Logging namespace PepperDash.Core.Logging;
public class DebugErrorLogSink : ILogEventSink
{ {
public class DebugErrorLogSink : ILogEventSink
{
private ITextFormatter _formatter; private ITextFormatter _formatter;
private Dictionary<LogEventLevel, Action<string>> _errorLogMap = new Dictionary<LogEventLevel, Action<string>> private Dictionary<LogEventLevel, Action<string>> _errorLogMap = new Dictionary<LogEventLevel, Action<string>>
@@ -61,5 +61,4 @@ namespace PepperDash.Core.Logging
{ {
_formatter = formatter; _formatter = formatter;
} }
}
} }

View File

@@ -2,10 +2,10 @@
using System; using System;
using Log = PepperDash.Core.Debug; using Log = PepperDash.Core.Debug;
namespace PepperDash.Core.Logging namespace PepperDash.Core.Logging;
public static class DebugExtensions
{ {
public static class DebugExtensions
{
public static void LogException(this IKeyed device, Exception ex, string message, params object[] args) public static void LogException(this IKeyed device, Exception ex, string message, params object[] args)
{ {
Log.LogMessage(ex, message, device, args); Log.LogMessage(ex, message, device, args);
@@ -70,5 +70,4 @@ namespace PepperDash.Core.Logging
{ {
Log.LogMessage(LogEventLevel.Fatal, device, message, args); Log.LogMessage(LogEventLevel.Fatal, device, message, args);
} }
}
} }

View File

@@ -2,11 +2,11 @@
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace PepperDash.Core.Logging namespace PepperDash.Core.Logging;
{
/// <summary> /// <summary>
/// Class to persist current Debug settings across program restarts /// Class to persist current Debug settings across program restarts
/// </summary> /// </summary>
public class DebugContextCollection public class DebugContextCollection
{ {
/// <summary> /// <summary>
@@ -112,4 +112,3 @@ namespace PepperDash.Core.Logging
[JsonProperty("doNotLoadOnNextBoot")] [JsonProperty("doNotLoadOnNextBoot")]
public bool DoNotLoadOnNextBoot { get; set; } public bool DoNotLoadOnNextBoot { get; set; }
} }
}

View File

@@ -1,34 +1,38 @@
using System; using Crestron.SimplSharp;
using System.Collections.Generic; using Org.BouncyCastle.Asn1.X509;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Serilog; using Serilog;
using Serilog.Configuration;
using Serilog.Core; using Serilog.Core;
using Serilog.Events; using Serilog.Events;
using Serilog.Configuration;
using WebSocketSharp.Server;
using Crestron.SimplSharp;
using WebSocketSharp;
using System.Security.Authentication;
using WebSocketSharp.Net;
using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2;
using System.IO;
using Org.BouncyCastle.Asn1.X509;
using Serilog.Formatting; using Serilog.Formatting;
using Newtonsoft.Json.Linq;
using Serilog.Formatting.Json; using Serilog.Formatting.Json;
using System;
using System.IO;
using System.Security.Authentication;
using WebSocketSharp;
using WebSocketSharp.Server;
using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Provides a WebSocket-based logging sink for debugging purposes, allowing log events to be broadcast to connected
/// WebSocket clients.
/// </summary>
/// <remarks>This class implements the <see cref="ILogEventSink"/> interface and is designed to send
/// formatted log events to WebSocket clients connected to a secure WebSocket server. The server is hosted locally
/// and uses a self-signed certificate for SSL/TLS encryption.</remarks>
public class DebugWebsocketSink : ILogEventSink, IKeyed
{ {
public class DebugWebsocketSink : ILogEventSink
{
private HttpServer _httpsServer; private HttpServer _httpsServer;
private string _path = "/debug/join/"; private readonly string _path = "/debug/join/";
private const string _certificateName = "selfCres"; private const string _certificateName = "selfCres";
private const string _certificatePassword = "cres12345"; private const string _certificatePassword = "cres12345";
/// <summary>
/// Gets the port number on which the HTTPS server is currently running.
/// </summary>
public int Port public int Port
{ get { get
{ {
@@ -38,6 +42,11 @@ namespace PepperDash.Core
} }
} }
/// <summary>
/// Gets the WebSocket URL for the current server instance.
/// </summary>
/// <remarks>The URL is dynamically constructed based on the server's current IP address, port,
/// and WebSocket path.</remarks>
public string Url public string Url
{ {
get get
@@ -47,18 +56,31 @@ namespace PepperDash.Core
} }
} }
/// <summary>
/// Gets a value indicating whether the HTTPS server is currently listening for incoming connections.
/// </summary>
public bool IsRunning { get => _httpsServer?.IsListening ?? false; } public bool IsRunning { get => _httpsServer?.IsListening ?? false; }
/// <inheritdoc/>
public string Key => "DebugWebsocketSink";
private readonly ITextFormatter _textFormatter; private readonly ITextFormatter _textFormatter;
/// <summary>
/// Initializes a new instance of the <see cref="DebugWebsocketSink"/> class with the specified text formatter.
/// </summary>
/// <remarks>This constructor initializes the WebSocket sink and ensures that a certificate is
/// available for secure communication. If the required certificate does not exist, it will be created
/// automatically. Additionally, the sink is configured to stop the server when the program is
/// stopping.</remarks>
/// <param name="formatProvider">The text formatter used to format log messages. If null, a default JSON formatter is used.</param>
public DebugWebsocketSink(ITextFormatter formatProvider) public DebugWebsocketSink(ITextFormatter formatProvider)
{ {
_textFormatter = formatProvider ?? new JsonFormatter(); _textFormatter = formatProvider ?? new JsonFormatter();
if (!File.Exists($"\\user\\{_certificateName}.pfx")) if (!File.Exists($"\\user\\{_certificateName}.pfx"))
CreateCert(null); CreateCert();
CrestronEnvironment.ProgramStatusEventHandler += type => CrestronEnvironment.ProgramStatusEventHandler += type =>
{ {
@@ -69,42 +91,41 @@ namespace PepperDash.Core
}; };
} }
private void CreateCert(string[] args) private static void CreateCert()
{ {
try try
{ {
//Debug.Console(0,"CreateCert Creating Utility");
CrestronConsole.PrintLine("CreateCert Creating Utility");
//var utility = new CertificateUtility();
var utility = new BouncyCertificate(); var utility = new BouncyCertificate();
//Debug.Console(0, "CreateCert Calling CreateCert");
CrestronConsole.PrintLine("CreateCert Calling CreateCert");
//utility.CreateCert();
var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0); var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0);
//Debug.Console(0, "DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress);
CrestronConsole.PrintLine(string.Format("DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress)); CrestronConsole.PrintLine(string.Format("DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress));
var certificate = utility.CreateSelfSignedCertificate(string.Format("CN={0}.{1}", hostName, domainName), new[] { string.Format("{0}.{1}", hostName, domainName), ipAddress }, new[] { KeyPurposeID.id_kp_serverAuth, KeyPurposeID.id_kp_clientAuth }); var certificate = utility.CreateSelfSignedCertificate(string.Format("CN={0}.{1}", hostName, domainName), [string.Format("{0}.{1}", hostName, domainName), ipAddress], [KeyPurposeID.id_kp_serverAuth, KeyPurposeID.id_kp_clientAuth]);
//Crestron fails to let us do this...perhaps it should be done through their Dll's but haven't tested //Crestron fails to let us do this...perhaps it should be done through their Dll's but haven't tested
//Debug.Print($"CreateCert Storing Certificate To My.LocalMachine");
//utility.AddCertToStore(certificate, StoreName.My, StoreLocation.LocalMachine); var separator = Path.DirectorySeparatorChar;
//Debug.Console(0, "CreateCert Saving Cert to \\user\\");
CrestronConsole.PrintLine("CreateCert Saving Cert to \\user\\");
utility.CertificatePassword = _certificatePassword; utility.CertificatePassword = _certificatePassword;
utility.WriteCertificate(certificate, @"\user\", _certificateName); utility.WriteCertificate(certificate, @$"{separator}user{separator}", _certificateName);
//Debug.Console(0, "CreateCert Ending CreateCert");
CrestronConsole.PrintLine("CreateCert Ending CreateCert");
} }
catch (Exception ex) catch (Exception ex)
{ {
//Debug.Console(0, "WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace); //Debug.Console(0, "WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
CrestronConsole.PrintLine(string.Format("WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace)); CrestronConsole.PrintLine("WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
} }
} }
/// <summary>
/// Sends a log event to all connected WebSocket clients.
/// </summary>
/// <remarks>The log event is formatted using the configured text formatter and then broadcasted
/// to all clients connected to the WebSocket server. If the WebSocket server is not initialized or not
/// listening, the method exits without performing any action.</remarks>
/// <param name="logEvent">The log event to be formatted and broadcasted. Cannot be null.</param>
public void Emit(LogEvent logEvent) public void Emit(LogEvent logEvent)
{ {
if (_httpsServer == null || !_httpsServer.IsListening) return; if (_httpsServer == null || !_httpsServer.IsListening) return;
@@ -112,10 +133,16 @@ namespace PepperDash.Core
var sw = new StringWriter(); var sw = new StringWriter();
_textFormatter.Format(logEvent, sw); _textFormatter.Format(logEvent, sw);
_httpsServer.WebSocketServices.Broadcast(sw.ToString()); _httpsServer.WebSocketServices[_path].Sessions.Broadcast(sw.ToString());
} }
/// <summary>
/// Starts the WebSocket server on the specified port and configures it with the appropriate certificate.
/// </summary>
/// <remarks>This method initializes the WebSocket server and binds it to the specified port. It
/// also applies the server's certificate for secure communication. Ensure that the port is not already in use
/// and that the certificate file is accessible.</remarks>
/// <param name="port">The port number on which the WebSocket server will listen. Must be a valid, non-negative port number.</param>
public void StartServerAndSetPort(int port) public void StartServerAndSetPort(int port)
{ {
Debug.Console(0, "Starting Websocket Server on port: {0}", port); Debug.Console(0, "Starting Websocket Server on port: {0}", port);
@@ -130,21 +157,19 @@ namespace PepperDash.Core
{ {
_httpsServer = new HttpServer(port, true); _httpsServer = new HttpServer(port, true);
if (!string.IsNullOrWhiteSpace(certPath)) if (!string.IsNullOrWhiteSpace(certPath))
{ {
Debug.Console(0, "Assigning SSL Configuration"); Debug.Console(0, "Assigning SSL Configuration");
_httpsServer.SslConfiguration = new ServerSslConfiguration(new X509Certificate2(certPath, certPassword))
{ _httpsServer.SslConfiguration.ServerCertificate = new X509Certificate2(certPath, certPassword);
ClientCertificateRequired = false, _httpsServer.SslConfiguration.ClientCertificateRequired = false;
CheckCertificateRevocation = false, _httpsServer.SslConfiguration.CheckCertificateRevocation = false;
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, _httpsServer.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12;
//this is just to test, you might want to actually validate //this is just to test, you might want to actually validate
ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => _httpsServer.SslConfiguration.ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{ {
Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered"); Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered");
return true; return true;
}
}; };
} }
Debug.Console(0, "Adding Debug Client Service"); Debug.Console(0, "Adding Debug Client Service");
@@ -193,6 +218,11 @@ namespace PepperDash.Core
} }
} }
/// <summary>
/// Stops the WebSocket server if it is currently running.
/// </summary>
/// <remarks>This method halts the WebSocket server and releases any associated resources. After
/// calling this method, the server will no longer accept or process incoming connections.</remarks>
public void StopServer() public void StopServer()
{ {
Debug.Console(0, "Stopping Websocket Server"); Debug.Console(0, "Stopping Websocket Server");
@@ -200,22 +230,45 @@ namespace PepperDash.Core
_httpsServer = null; _httpsServer = null;
} }
} }
public static class DebugWebsocketSinkExtensions /// <summary>
{ /// Configures the logger to write log events to a debug WebSocket sink.
/// </summary>
/// <remarks>This extension method allows you to direct log events to a WebSocket sink for debugging
/// purposes.</remarks>
public static class DebugWebsocketSinkExtensions
{
/// <summary>
/// Configures a logger to write log events to a debug WebSocket sink.
/// </summary>
/// <remarks>This method adds a sink that writes log events to a WebSocket for debugging purposes.
/// It is typically used during development to stream log events in real-time.</remarks>
/// <param name="loggerConfiguration">The logger sink configuration to apply the WebSocket sink to.</param>
/// <param name="formatProvider">An optional text formatter to format the log events. If not provided, a default formatter will be used.</param>
/// <returns>A <see cref="LoggerConfiguration"/> object that can be used to further configure the logger.</returns>
public static LoggerConfiguration DebugWebsocketSink( public static LoggerConfiguration DebugWebsocketSink(
this LoggerSinkConfiguration loggerConfiguration, this LoggerSinkConfiguration loggerConfiguration,
ITextFormatter formatProvider = null) ITextFormatter formatProvider = null)
{ {
return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider)); return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider));
} }
} }
public class DebugClient : WebSocketBehavior /// <summary>
{ /// Represents a WebSocket client for debugging purposes, providing connection lifecycle management and message
/// handling functionality.
/// </summary>
/// <remarks>The <see cref="DebugClient"/> class extends <see cref="WebSocketBehavior"/> to handle
/// WebSocket connections, including events for opening, closing, receiving messages, and errors. It tracks the
/// duration of the connection and logs relevant events for debugging.</remarks>
public class DebugClient : WebSocketBehavior
{
private DateTime _connectionTime; private DateTime _connectionTime;
/// <summary>
/// Gets the duration of time the WebSocket connection has been active.
/// </summary>
public TimeSpan ConnectedDuration public TimeSpan ConnectedDuration
{ {
get get
@@ -231,11 +284,17 @@ namespace PepperDash.Core
} }
} }
/// <summary>
/// Initializes a new instance of the <see cref="DebugClient"/> class.
/// </summary>
/// <remarks>This constructor creates a new <see cref="DebugClient"/> instance and logs its
/// creation using the <see cref="Debug.Console(int, string)"/> method with a debug level of 0.</remarks>
public DebugClient() public DebugClient()
{ {
Debug.Console(0, "DebugClient Created"); Debug.Console(0, "DebugClient Created");
} }
/// <inheritdoc/>
protected override void OnOpen() protected override void OnOpen()
{ {
base.OnOpen(); base.OnOpen();
@@ -246,6 +305,7 @@ namespace PepperDash.Core
_connectionTime = DateTime.Now; _connectionTime = DateTime.Now;
} }
/// <inheritdoc/>
protected override void OnMessage(MessageEventArgs e) protected override void OnMessage(MessageEventArgs e)
{ {
base.OnMessage(e); base.OnMessage(e);
@@ -253,6 +313,7 @@ namespace PepperDash.Core
Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data); Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data);
} }
/// <inheritdoc/>
protected override void OnClose(CloseEventArgs e) protected override void OnClose(CloseEventArgs e)
{ {
base.OnClose(e); base.OnClose(e);
@@ -261,11 +322,11 @@ namespace PepperDash.Core
} }
/// <inheritdoc/>
protected override void OnError(WebSocketSharp.ErrorEventArgs e) protected override void OnError(WebSocketSharp.ErrorEventArgs e)
{ {
base.OnError(e); base.OnError(e);
Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message); Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message);
} }
}
} }

View File

@@ -4,11 +4,11 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core namespace PepperDash.Core;
{
/// <summary> /// <summary>
/// Not in use /// Not in use
/// </summary> /// </summary>
public static class NetworkComm public static class NetworkComm
{ {
/// <summary> /// <summary>
@@ -18,5 +18,3 @@ namespace PepperDash.Core
{ {
} }
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement;
{
/// <summary> /// <summary>
/// JSON password configuration /// JSON password configuration
/// </summary> /// </summary>
@@ -23,4 +23,3 @@ namespace PepperDash.Core.PasswordManagement
} }
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement;
{
/// <summary> /// <summary>
/// Constants /// Constants
/// </summary> /// </summary>
@@ -54,4 +54,3 @@ namespace PepperDash.Core.PasswordManagement
/// </summary> /// </summary>
public const ushort StringValueChange = 201; public const ushort StringValueChange = 201;
} }
}

View File

@@ -1,10 +1,10 @@
using System; using System;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement;
{
/// <summary> /// <summary>
/// A class to allow user interaction with the PasswordManager /// A class to allow user interaction with the PasswordManager
/// </summary> /// </summary>
public class PasswordClient public class PasswordClient
{ {
/// <summary> /// <summary>
@@ -184,4 +184,3 @@ namespace PepperDash.Core.PasswordManagement
} }
} }
} }
}

View File

@@ -2,11 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement;
{
/// <summary> /// <summary>
/// Allows passwords to be stored and managed /// Allows passwords to be stored and managed
/// </summary> /// </summary>
public class PasswordManager public class PasswordManager
{ {
/// <summary> /// <summary>
@@ -238,4 +238,3 @@ namespace PepperDash.Core.PasswordManagement
} }
} }
} }
}

View File

@@ -5,7 +5,7 @@
<PropertyGroup> <PropertyGroup>
<RootNamespace>PepperDash.Core</RootNamespace> <RootNamespace>PepperDash.Core</RootNamespace>
<AssemblyName>PepperDashCore</AssemblyName> <AssemblyName>PepperDashCore</AssemblyName>
<TargetFramework>net472</TargetFramework> <TargetFramework>net8</TargetFramework>
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
<NeutralLanguage>en</NeutralLanguage> <NeutralLanguage>en</NeutralLanguage>
<OutputPath>bin\$(Configuration)\</OutputPath> <OutputPath>bin\$(Configuration)\</OutputPath>
@@ -42,15 +42,16 @@
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" /> <PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" />
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.21.90" /> <PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.21.128" />
<PackageReference Include="Serilog" Version="3.1.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog.Expressions" Version="4.0.0" /> <PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" /> <PackageReference Include="Serilog.Expressions" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" /> <PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="SSH.NET" Version="2024.2.0" /> <PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageReference Include="WebSocketSharp" Version="1.0.3-rc11" /> <PackageReference Include="SSH.NET" Version="2025.0.0" />
<PackageReference Include="WebSocketSharp-netstandard" Version="1.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net6'"> <ItemGroup Condition="'$(TargetFramework)' == 'net6'">
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo namespace PepperDash.Core.SystemInfo;
{
/// <summary> /// <summary>
/// Constants /// Constants
/// </summary> /// </summary>
@@ -261,4 +261,3 @@ namespace PepperDash.Core.SystemInfo
Index = index; Index = index;
} }
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo namespace PepperDash.Core.SystemInfo;
{
/// <summary> /// <summary>
/// Processor info class /// Processor info class
/// </summary> /// </summary>
@@ -201,4 +201,3 @@ namespace PepperDash.Core.SystemInfo
} }
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo namespace PepperDash.Core.SystemInfo;
{
/// <summary> /// <summary>
/// System Info class /// System Info class
/// </summary> /// </summary>
@@ -459,4 +459,3 @@ namespace PepperDash.Core.SystemInfo
} }
} }
} }
}

View File

@@ -20,13 +20,13 @@ using Org.BouncyCastle.Crypto.Operators;
using BigInteger = Org.BouncyCastle.Math.BigInteger; using BigInteger = Org.BouncyCastle.Math.BigInteger;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate; using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace PepperDash.Core namespace PepperDash.Core;
/// <summary>
/// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/
/// </summary>
internal class BouncyCertificate
{ {
/// <summary>
/// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/
/// </summary>
internal class BouncyCertificate
{
public string CertificatePassword { get; set; } = "password"; public string CertificatePassword { get; set; } = "password";
public X509Certificate2 LoadCertificate(string issuerFileName, string password) public X509Certificate2 LoadCertificate(string issuerFileName, string password)
{ {
@@ -352,5 +352,4 @@ namespace PepperDash.Core
return bRet; return bRet;
} }
}
} }

View File

@@ -1,7 +1,7 @@
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
namespace PepperDash.Core.Web.RequestHandlers namespace PepperDash.Core.Web.RequestHandlers;
{
/// <summary> /// <summary>
/// Web API default request handler /// Web API default request handler
/// </summary> /// </summary>
@@ -14,4 +14,3 @@ namespace PepperDash.Core.Web.RequestHandlers
: base(true) : base(true)
{ } { }
} }
}

View File

@@ -3,10 +3,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PepperDash.Core.Web.RequestHandlers namespace PepperDash.Core.Web.RequestHandlers;
public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler
{ {
public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler
{
private readonly Dictionary<string, Func<HttpCwsContext, Task>> _handlers; private readonly Dictionary<string, Func<HttpCwsContext, Task>> _handlers;
protected readonly bool EnableCors; protected readonly bool EnableCors;
@@ -159,5 +159,4 @@ namespace PepperDash.Core.Web.RequestHandlers
handlerTask.GetAwaiter().GetResult(); handlerTask.GetAwaiter().GetResult();
} }
}
} }

View File

@@ -2,8 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
namespace PepperDash.Core.Web.RequestHandlers namespace PepperDash.Core.Web.RequestHandlers;
{
/// <summary> /// <summary>
/// CWS Base Handler, implements IHttpCwsHandler /// CWS Base Handler, implements IHttpCwsHandler
/// </summary> /// </summary>
@@ -162,4 +162,3 @@ namespace PepperDash.Core.Web.RequestHandlers
handler(context); handler(context);
} }
} }
}

View File

@@ -7,8 +7,8 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PepperDash.Core.Web.RequestHandlers; using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Core.Web namespace PepperDash.Core.Web;
{
/// <summary> /// <summary>
/// Web API server /// Web API server
/// </summary> /// </summary>
@@ -281,4 +281,3 @@ namespace PepperDash.Core.Web
} }
} }
} }
}

View File

@@ -1,10 +1,10 @@
using System; using System;
namespace PepperDash.Core.WebApi.Presets namespace PepperDash.Core.WebApi.Presets;
{
/// <summary> /// <summary>
/// Represents a preset /// Represents a preset
/// </summary> /// </summary>
public class Preset public class Preset
{ {
/// <summary> /// <summary>
@@ -84,4 +84,3 @@ namespace PepperDash.Core.WebApi.Presets
Preset = preset; Preset = preset;
} }
} }
}

View File

@@ -4,8 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.WebApi.Presets namespace PepperDash.Core.WebApi.Presets;
{
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -90,4 +90,3 @@ namespace PepperDash.Core.WebApi.Presets
/// </summary> /// </summary>
public int PresetNumber { get; set; } public int PresetNumber { get; set; }
} }
}

View File

@@ -8,11 +8,11 @@ using Newtonsoft.Json.Linq;
using PepperDash.Core.JsonToSimpl; using PepperDash.Core.JsonToSimpl;
namespace PepperDash.Core.WebApi.Presets namespace PepperDash.Core.WebApi.Presets;
{
/// <summary> /// <summary>
/// Passcode client for the WebApi /// Passcode client for the WebApi
/// </summary> /// </summary>
public class WebApiPasscodeClient : IKeyed public class WebApiPasscodeClient : IKeyed
{ {
/// <summary> /// <summary>
@@ -270,4 +270,3 @@ namespace PepperDash.Core.WebApi.Presets
} }
} }
} }
}

View File

@@ -1,13 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using PepperDash.Core.Intersystem.Tokens; using PepperDash.Core.Intersystem.Tokens;
namespace PepperDash.Core.Intersystem.Serialization namespace PepperDash.Core.Intersystem.Serialization;
/// <summary>
/// Interface to determine XSig serialization for an object.
/// </summary>
public interface IXSigSerialization
{ {
/// <summary>
/// Interface to determine XSig serialization for an object.
/// </summary>
public interface IXSigSerialization
{
/// <summary> /// <summary>
/// Serialize the sig data /// Serialize the sig data
/// </summary> /// </summary>
@@ -21,5 +21,4 @@ namespace PepperDash.Core.Intersystem.Serialization
/// <param name="tokens"></param> /// <param name="tokens"></param>
/// <returns></returns> /// <returns></returns>
T Deserialize<T>(IEnumerable<XSigToken> tokens) where T : class, IXSigSerialization; T Deserialize<T>(IEnumerable<XSigToken> tokens) where T : class, IXSigSerialization;
}
} }

View File

@@ -1,12 +1,12 @@
using System; using System;
namespace PepperDash.Core.Intersystem.Serialization namespace PepperDash.Core.Intersystem.Serialization;
/// <summary>
/// Class to handle this specific exception type
/// </summary>
public class XSigSerializationException : Exception
{ {
/// <summary>
/// Class to handle this specific exception type
/// </summary>
public class XSigSerializationException : Exception
{
/// <summary> /// <summary>
/// default constructor /// default constructor
/// </summary> /// </summary>
@@ -24,5 +24,4 @@ namespace PepperDash.Core.Intersystem.Serialization
/// <param name="message"></param> /// <param name="message"></param>
/// <param name="inner"></param> /// <param name="inner"></param>
public XSigSerializationException(string message, Exception inner) : base(message, inner) { } public XSigSerializationException(string message, Exception inner) : base(message, inner) { }
}
} }

View File

@@ -1,12 +1,12 @@
using System; using System;
namespace PepperDash.Core.Intersystem.Tokens namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// Represents an XSigAnalogToken
/// </summary>
public sealed class XSigAnalogToken : XSigToken, IFormattable
{ {
/// <summary>
/// Represents an XSigAnalogToken
/// </summary>
public sealed class XSigAnalogToken : XSigToken, IFormattable
{
private readonly ushort _value; private readonly ushort _value;
/// <summary> /// <summary>
@@ -84,5 +84,4 @@ namespace PepperDash.Core.Intersystem.Tokens
{ {
return Value.ToString(format, formatProvider); return Value.ToString(format, formatProvider);
} }
}
} }

View File

@@ -1,12 +1,12 @@
using System; using System;
namespace PepperDash.Core.Intersystem.Tokens namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// Represents an XSigDigitalToken
/// </summary>
public sealed class XSigDigitalToken : XSigToken
{ {
/// <summary>
/// Represents an XSigDigitalToken
/// </summary>
public sealed class XSigDigitalToken : XSigToken
{
private readonly bool _value; private readonly bool _value;
/// <summary> /// <summary>
@@ -81,5 +81,4 @@ namespace PepperDash.Core.Intersystem.Tokens
{ {
return Value.ToString(formatProvider); return Value.ToString(formatProvider);
} }
}
} }

View File

@@ -1,13 +1,13 @@
using System; using System;
using System.Text; using System.Text;
namespace PepperDash.Core.Intersystem.Tokens namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// Represents an XSigSerialToken
/// </summary>
public sealed class XSigSerialToken : XSigToken
{ {
/// <summary>
/// Represents an XSigSerialToken
/// </summary>
public sealed class XSigSerialToken : XSigToken
{
private readonly string _value; private readonly string _value;
/// <summary> /// <summary>
@@ -77,5 +77,4 @@ namespace PepperDash.Core.Intersystem.Tokens
{ {
return Index + " = \"" + Value + "\""; return Index + " = \"" + Value + "\"";
} }
}
} }

View File

@@ -1,10 +1,10 @@
namespace PepperDash.Core.Intersystem.Tokens namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// Represents the base class for all XSig datatypes.
/// </summary>
public abstract class XSigToken
{ {
/// <summary>
/// Represents the base class for all XSig datatypes.
/// </summary>
public abstract class XSigToken
{
private readonly int _index; private readonly int _index;
/// <summary> /// <summary>
@@ -41,5 +41,4 @@ namespace PepperDash.Core.Intersystem.Tokens
/// <param name="offset">Offset to adjust the index with.</param> /// <param name="offset">Offset to adjust the index with.</param>
/// <returns>XSigToken</returns> /// <returns>XSigToken</returns>
public abstract XSigToken GetTokenWithOffset(int offset); public abstract XSigToken GetTokenWithOffset(int offset);
}
} }

View File

@@ -1,10 +1,10 @@
namespace PepperDash.Core.Intersystem.Tokens namespace PepperDash.Core.Intersystem.Tokens;
/// <summary>
/// XSig token types.
/// </summary>
public enum XSigTokenType
{ {
/// <summary>
/// XSig token types.
/// </summary>
public enum XSigTokenType
{
/// <summary> /// <summary>
/// Digital signal datatype. /// Digital signal datatype.
/// </summary> /// </summary>
@@ -19,5 +19,4 @@ namespace PepperDash.Core.Intersystem.Tokens
/// Serial signal datatype. /// Serial signal datatype.
/// </summary> /// </summary>
Serial Serial
}
} }

View File

@@ -18,17 +18,17 @@ using PepperDash.Core.Intersystem.Tokens;
11111111 <- denotes end of data 11111111 <- denotes end of data
*/ */
namespace PepperDash.Core.Intersystem namespace PepperDash.Core.Intersystem;
/// <summary>
/// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol.
/// </summary>
/// <remarks>
/// Indexing is not from the start of each signal type but rather from the beginning of the first defined signal
/// the Intersystem Communications (ISC) symbol.
/// </remarks>
public static class XSigHelpers
{ {
/// <summary>
/// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol.
/// </summary>
/// <remarks>
/// Indexing is not from the start of each signal type but rather from the beginning of the first defined signal
/// the Intersystem Communications (ISC) symbol.
/// </remarks>
public static class XSigHelpers
{
/// <summary> /// <summary>
/// Forces all outputs to 0. /// Forces all outputs to 0.
/// </summary> /// </summary>
@@ -235,5 +235,4 @@ namespace PepperDash.Core.Intersystem
return bytes; return bytes;
} }
}
} }

View File

@@ -4,13 +4,13 @@ using Crestron.SimplSharp.CrestronIO;
using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Serialization;
using PepperDash.Core.Intersystem.Tokens; using PepperDash.Core.Intersystem.Tokens;
namespace PepperDash.Core.Intersystem namespace PepperDash.Core.Intersystem;
/// <summary>
/// XSigToken stream reader.
/// </summary>
public sealed class XSigTokenStreamReader : IDisposable
{ {
/// <summary>
/// XSigToken stream reader.
/// </summary>
public sealed class XSigTokenStreamReader : IDisposable
{
private readonly Stream _stream; private readonly Stream _stream;
private readonly bool _leaveOpen; private readonly bool _leaveOpen;
@@ -143,5 +143,4 @@ namespace PepperDash.Core.Intersystem
if (!_leaveOpen) if (!_leaveOpen)
_stream.Dispose(); _stream.Dispose();
} }
}
} }

View File

@@ -5,13 +5,13 @@ using Crestron.SimplSharp.CrestronIO;
using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Serialization;
using PepperDash.Core.Intersystem.Tokens; using PepperDash.Core.Intersystem.Tokens;
namespace PepperDash.Core.Intersystem namespace PepperDash.Core.Intersystem;
/// <summary>
/// XSigToken stream writer.
/// </summary>
public sealed class XSigTokenStreamWriter : IDisposable
{ {
/// <summary>
/// XSigToken stream writer.
/// </summary>
public sealed class XSigTokenStreamWriter : IDisposable
{
private readonly Stream _stream; private readonly Stream _stream;
private readonly bool _leaveOpen; private readonly bool _leaveOpen;
@@ -132,5 +132,4 @@ namespace PepperDash.Core.Intersystem
if (!_leaveOpen) if (!_leaveOpen)
_stream.Dispose(); _stream.Dispose();
} }
}
} }

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharpPro;
namespace PepperDash.Essentials.Core.Abstractions
{
/// <summary>
/// Adapter that wraps actual Crestron Control System for production use
/// </summary>
public class CrestronControlSystemAdapter : ICrestronControlSystem
{
private readonly CrestronControlSystem _controlSystem;
private readonly Dictionary<uint, IRelayPort> _relayPorts;
public CrestronControlSystemAdapter(CrestronControlSystem controlSystem)
{
_controlSystem = controlSystem ?? throw new ArgumentNullException(nameof(controlSystem));
_relayPorts = new Dictionary<uint, IRelayPort>();
if (_controlSystem.SupportsRelay)
{
for (uint i = 1; i <= (uint)_controlSystem.NumberOfRelayPorts; i++)
{
_relayPorts[i] = new RelayPortAdapter(_controlSystem.RelayPorts[i]);
}
}
}
public bool SupportsRelay => _controlSystem.SupportsRelay;
public uint NumberOfRelayPorts => (uint)_controlSystem.NumberOfRelayPorts;
public Dictionary<uint, IRelayPort> RelayPorts => _relayPorts;
public string ProgramIdTag => "TestProgram"; // Simplified for now
public string ControllerPrompt => _controlSystem.ControllerPrompt;
public bool SupportsEthernet => _controlSystem.SupportsEthernet;
public bool SupportsDigitalInput => _controlSystem.SupportsDigitalInput;
public uint NumberOfDigitalInputPorts => (uint)_controlSystem.NumberOfDigitalInputPorts;
public bool SupportsVersiPort => _controlSystem.SupportsVersiport;
public uint NumberOfVersiPorts => (uint)_controlSystem.NumberOfVersiPorts;
}
/// <summary>
/// Adapter for Crestron relay port
/// </summary>
public class RelayPortAdapter : IRelayPort
{
private readonly Crestron.SimplSharpPro.Relay _relay;
public RelayPortAdapter(Crestron.SimplSharpPro.Relay relay)
{
_relay = relay ?? throw new ArgumentNullException(nameof(relay));
}
public void Open() => _relay.Open();
public void Close() => _relay.Close();
public void Pulse(int delayMs)
{
// Crestron Relay.Pulse() doesn't take parameters
// We'll just call the basic Pulse method
_relay.Close();
System.Threading.Thread.Sleep(delayMs);
_relay.Open();
}
public bool State => _relay.State;
}
/// <summary>
/// Adapter for Crestron digital input
/// </summary>
public class DigitalInputAdapter : IDigitalInput
{
private readonly Crestron.SimplSharpPro.DigitalInput _digitalInput;
public DigitalInputAdapter(Crestron.SimplSharpPro.DigitalInput digitalInput)
{
_digitalInput = digitalInput ?? throw new ArgumentNullException(nameof(digitalInput));
_digitalInput.StateChange += OnStateChange;
}
public bool State => _digitalInput.State;
public event EventHandler<DigitalInputEventArgs> StateChange;
private void OnStateChange(DigitalInput digitalInput, Crestron.SimplSharpPro.DigitalInputEventArgs args)
{
StateChange?.Invoke(this, new Abstractions.DigitalInputEventArgs(args.State));
}
}
/// <summary>
/// Adapter for Crestron VersiPort
/// </summary>
public class VersiPortAdapter : IVersiPort
{
private readonly Crestron.SimplSharpPro.Versiport _versiPort;
public VersiPortAdapter(Crestron.SimplSharpPro.Versiport versiPort)
{
_versiPort = versiPort ?? throw new ArgumentNullException(nameof(versiPort));
_versiPort.VersiportChange += OnVersiportChange;
}
public bool DigitalIn => _versiPort.DigitalIn;
public void SetDigitalOut(bool value) => _versiPort.DigitalOut = value;
public ushort AnalogIn => _versiPort.AnalogIn;
public event EventHandler<VersiPortEventArgs> VersiportChange;
private void OnVersiportChange(Versiport port, VersiportEventArgs args)
{
var eventType = args.Event == eVersiportEvent.DigitalInChange
? VersiPortEventType.DigitalInChange
: VersiPortEventType.AnalogInChange;
VersiportChange?.Invoke(this, new Abstractions.VersiPortEventArgs
{
EventType = eventType,
Value = args.Event == eVersiportEvent.DigitalInChange ? (object)port.DigitalIn : port.AnalogIn
});
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.Core.Abstractions
{
/// <summary>
/// Abstraction for Crestron Control System to enable unit testing
/// </summary>
public interface ICrestronControlSystem
{
bool SupportsRelay { get; }
uint NumberOfRelayPorts { get; }
Dictionary<uint, IRelayPort> RelayPorts { get; }
string ProgramIdTag { get; }
string ControllerPrompt { get; }
bool SupportsEthernet { get; }
bool SupportsDigitalInput { get; }
uint NumberOfDigitalInputPorts { get; }
bool SupportsVersiPort { get; }
uint NumberOfVersiPorts { get; }
}
/// <summary>
/// Abstraction for relay port
/// </summary>
public interface IRelayPort
{
void Open();
void Close();
void Pulse(int delayMs);
bool State { get; }
}
/// <summary>
/// Abstraction for digital input
/// </summary>
public interface IDigitalInput
{
bool State { get; }
event EventHandler<DigitalInputEventArgs> StateChange;
}
public class DigitalInputEventArgs : EventArgs
{
public bool State { get; set; }
public DigitalInputEventArgs(bool state)
{
State = state;
}
}
/// <summary>
/// Abstraction for VersiPort
/// </summary>
public interface IVersiPort
{
bool DigitalIn { get; }
void SetDigitalOut(bool value);
ushort AnalogIn { get; }
event EventHandler<VersiPortEventArgs> VersiportChange;
}
public class VersiPortEventArgs : EventArgs
{
public VersiPortEventType EventType { get; set; }
public object Value { get; set; }
}
public enum VersiPortEventType
{
DigitalInChange,
AnalogInChange
}
}

View File

@@ -16,25 +16,25 @@ using Serilog.Events;
//using PepperDash.Essentials.Devices.Common.Cameras; //using PepperDash.Essentials.Devices.Common.Cameras;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
/// <summary>
/// Base class for bridge API variants
/// </summary>
public abstract class BridgeApi : EssentialsDevice
{ {
/// <summary>
/// Base class for bridge API variants
/// </summary>
public abstract class BridgeApi : EssentialsDevice
{
protected BridgeApi(string key) : protected BridgeApi(string key) :
base(key) base(key)
{ {
} }
} }
/// <summary> /// <summary>
/// Bridge API using EISC /// Bridge API using EISC
/// </summary> /// </summary>
public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor
{ {
public EiscApiPropertiesConfig PropertiesConfig { get; private set; } public EiscApiPropertiesConfig PropertiesConfig { get; private set; }
public Dictionary<string, JoinMapBaseAdvanced> JoinMaps { get; private set; } public Dictionary<string, JoinMapBaseAdvanced> JoinMaps { get; private set; }
@@ -321,10 +321,10 @@ namespace PepperDash.Essentials.Core.Bridges
public StatusMonitorBase CommunicationMonitor { get; private set; } public StatusMonitorBase CommunicationMonitor { get; private set; }
#endregion #endregion
} }
public class EiscApiPropertiesConfig public class EiscApiPropertiesConfig
{ {
[JsonProperty("control")] [JsonProperty("control")]
public EssentialsControlPropertiesConfig Control { get; set; } public EssentialsControlPropertiesConfig Control { get; set; }
@@ -359,10 +359,10 @@ namespace PepperDash.Essentials.Core.Bridges
public string JoinMapKey { get; set; } public string JoinMapKey { get; set; }
} }
} }
public class EiscApiAdvancedFactory : EssentialsDeviceFactory<EiscApiAdvanced> public class EiscApiAdvancedFactory : EssentialsDeviceFactory<EiscApiAdvanced>
{ {
public EiscApiAdvancedFactory() public EiscApiAdvancedFactory()
{ {
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" }; TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" };
@@ -420,6 +420,4 @@ namespace PepperDash.Essentials.Core.Bridges
return new EiscApiAdvanced(dc, eisc); return new EiscApiAdvanced(dc, eisc);
} }
}
} }

View File

@@ -3,13 +3,13 @@ using Serilog.Events;
//using PepperDash.Essentials.Devices.Common.Cameras; //using PepperDash.Essentials.Devices.Common.Cameras;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
/// <summary>
/// Helper methods for bridges
/// </summary>
public static class BridgeHelper
{ {
/// <summary>
/// Helper methods for bridges
/// </summary>
public static class BridgeHelper
{
public static void PrintJoinMap(string command) public static void PrintJoinMap(string command)
{ {
var targets = command.Split(' '); var targets = command.Split(' ');
@@ -61,6 +61,4 @@ namespace PepperDash.Essentials.Core.Bridges
} }
} }
}
} }

View File

@@ -1,12 +1,11 @@
using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.DeviceSupport;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
/// <summary>
/// Defines a device that uses JoinMapBaseAdvanced for its join map
/// </summary>
public interface IBridgeAdvanced
{ {
/// <summary>
/// Defines a device that uses JoinMapBaseAdvanced for its join map
/// </summary>
public interface IBridgeAdvanced
{
void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class AirMediaControllerJoinMap : JoinMapBaseAdvanced
{ {
public class AirMediaControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("IsOnline")] [JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Air Media Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); new JoinMetadata { Description = "Air Media Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
@@ -67,5 +67,4 @@ namespace PepperDash.Essentials.Core.Bridges
/// <param name="joinStart">Join this join map will start at</param> /// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param> /// <param name="type">Type of the child join map</param>
protected AirMediaControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){} protected AirMediaControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){}
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class AppleTvJoinMap : JoinMapBaseAdvanced
{ {
public class AppleTvJoinMap : JoinMapBaseAdvanced
{
[JoinName("UpArrow")] [JoinName("UpArrow")]
public JoinDataComplete UpArrow = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete UpArrow = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "AppleTv Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); new JoinMetadata { Description = "AppleTv Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital });
@@ -49,5 +49,4 @@ namespace PepperDash.Essentials.Core.Bridges
public AppleTvJoinMap(uint joinStart, Type type) : base(joinStart, type) public AppleTvJoinMap(uint joinStart, Type type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class C2nRthsControllerJoinMap : JoinMapBaseAdvanced
{ {
public class C2nRthsControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("IsOnline")] [JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Temp Sensor Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); new JoinMetadata { Description = "Temp Sensor Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
@@ -41,5 +41,4 @@ namespace PepperDash.Essentials.Core.Bridges
protected C2nRthsControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) protected C2nRthsControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,12 +1,12 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
/// <summary>
/// Join map for CameraBase devices
/// </summary>
public class CameraControllerJoinMap : JoinMapBaseAdvanced
{ {
/// <summary>
/// Join map for CameraBase devices
/// </summary>
public class CameraControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("TiltUp")] [JoinName("TiltUp")]
public JoinDataComplete TiltUp = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); public JoinDataComplete TiltUp = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital });
[JoinName("TiltDown")] [JoinName("TiltDown")]
@@ -65,5 +65,4 @@ namespace PepperDash.Essentials.Core.Bridges
/// <param name="joinStart">Join this join map will start at</param> /// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param> /// <param name="type">Type of the child join map</param>
protected CameraControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){} protected CameraControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){}
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class CenOdtOccupancySensorBaseJoinMap : JoinMapBaseAdvanced
{ {
public class CenOdtOccupancySensorBaseJoinMap : JoinMapBaseAdvanced
{
#region Digitals #region Digitals
[JoinName("Online")] [JoinName("Online")]
@@ -193,6 +193,4 @@ namespace PepperDash.Essentials.Core.Bridges
protected CenOdtOccupancySensorBaseJoinMap(uint joinStart, Type type) : base(joinStart, type) protected CenOdtOccupancySensorBaseJoinMap(uint joinStart, Type type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class DisplayControllerJoinMap : JoinMapBaseAdvanced
{ {
public class DisplayControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("Name")] [JoinName("Name")]
public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });
@@ -81,5 +81,4 @@ namespace PepperDash.Essentials.Core.Bridges
protected DisplayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) protected DisplayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,7 +1,7 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges { namespace PepperDash.Essentials.Core.Bridges;
public class DmBladeChassisControllerJoinMap : JoinMapBaseAdvanced { public class DmBladeChassisControllerJoinMap : JoinMapBaseAdvanced {
[JoinName("IsOnline")] [JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 },
@@ -70,5 +70,4 @@ namespace PepperDash.Essentials.Core.Bridges {
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class DmChassisControllerJoinMap : JoinMapBaseAdvanced
{ {
public class DmChassisControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("EnableAudioBreakaway")] [JoinName("EnableAudioBreakaway")]
public JoinDataComplete EnableAudioBreakaway = new JoinDataComplete( public JoinDataComplete EnableAudioBreakaway = new JoinDataComplete(
new JoinData {JoinNumber = 4, JoinSpan = 1}, new JoinData {JoinNumber = 4, JoinSpan = 1},
@@ -166,5 +166,4 @@ namespace PepperDash.Essentials.Core.Bridges
protected DmChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) protected DmChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class DmRmcControllerJoinMap : JoinMapBaseAdvanced
{ {
public class DmRmcControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("IsOnline")] [JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); new JoinMetadata { Description = "DM RMC Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
@@ -88,5 +88,4 @@ namespace PepperDash.Essentials.Core.Bridges
: base(joinStart, type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class DmTxControllerJoinMap : JoinMapBaseAdvanced
{ {
public class DmTxControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("IsOnline")] [JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
@@ -92,5 +92,4 @@ namespace PepperDash.Essentials.Core.Bridges
: base(joinStart, type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced
{ {
public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("MasterVolumeLevel")] [JoinName("MasterVolumeLevel")]
public JoinDataComplete MasterVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete MasterVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
@@ -170,5 +170,4 @@ namespace PepperDash.Essentials.Core.Bridges
protected DmpsAudioOutputControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) protected DmpsAudioOutputControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class DmpsMicrophoneControllerJoinMap : JoinMapBaseAdvanced
{ {
public class DmpsMicrophoneControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("MicGain")] [JoinName("MicGain")]
public JoinDataComplete MicGain = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete MicGain = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Mic Gain dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); new JoinMetadata { Description = "Mic Gain dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
@@ -46,5 +46,4 @@ namespace PepperDash.Essentials.Core.Bridges
: base(joinStart, type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced
{ {
public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("EnableRouting")] [JoinName("EnableRouting")]
public JoinDataComplete EnableRouting = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete EnableRouting = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "DMPS Enable Audio and Video Routing", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); new JoinMetadata { Description = "DMPS Enable Audio and Video Routing", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital });
@@ -119,5 +119,4 @@ namespace PepperDash.Essentials.Core.Bridges
protected DmpsRoutingControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) protected DmpsRoutingControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,7 +1,7 @@
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Bridges.JoinMaps namespace PepperDash.Essentials.Core.Bridges.JoinMaps;
{
public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced
{ {
[JoinName("PLAY")] [JoinName("PLAY")]
@@ -824,4 +824,3 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
{ {
} }
} }
}

View File

@@ -1,10 +1,10 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class GenericLightingJoinMap : JoinMapBaseAdvanced
{ {
public class GenericLightingJoinMap : JoinMapBaseAdvanced
{
[JoinName("IsOnline")] [JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
@@ -45,5 +45,4 @@ namespace PepperDash.Essentials.Core.Bridges
protected GenericLightingJoinMap(uint joinStart, Type type) : base(joinStart, type) protected GenericLightingJoinMap(uint joinStart, Type type) : base(joinStart, type)
{ {
} }
}
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
namespace PepperDash.Essentials.Core.Bridges namespace PepperDash.Essentials.Core.Bridges;
public class GenericRelayControllerJoinMap : JoinMapBaseAdvanced
{ {
public class GenericRelayControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("Relay")] [JoinName("Relay")]
public JoinDataComplete Relay = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, public JoinDataComplete Relay = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
@@ -27,5 +27,4 @@ namespace PepperDash.Essentials.Core.Bridges
{ {
} }
}
} }

Some files were not shown because too many files have changed in this diff Show More