Compare commits

...

61 Commits

Author SHA1 Message Date
jtalborough
ccf86df64a Merge branch 'feature-2.0.0/builds-with-cpz' into feature-2.0.0/creslib-version-update 2025-02-27 19:14:51 -05:00
jtalborough
afc37f5426 fix: remove unnecessary IncludeSymbols and IncludeSource parameters from dotnet pack command in Docker workflow 2025-02-27 19:07:48 -05:00
jtalborough
4ed5bb7ada build: trigger 2025-02-27 18:59:29 -05:00
jtalborough
4360e7f992 refactor: clean up Directory.Build.targets by removing unnecessary closing tag 2025-02-27 18:51:39 -05:00
jtalborough
f926db418d feat: improve CPZ file handling in Docker workflow and update build targets for better output management 2025-02-27 18:46:59 -05:00
jtalborough
0944be2a70 feat: add CPZ file handling and logging in Docker workflow and build targets 2025-02-27 18:30:26 -05:00
jtalborough
bacc0a4f57 fix: update artifact path syntax in docker workflow for release action 2025-02-27 18:12:16 -05:00
jtalborough
1d49ea67ad feat: enhance build process with detailed logging and new target for CPZ creation 2025-02-27 17:51:07 -05:00
Colin Denig
d8b328d066 Merge tag '2.0.0-alpha-2636' into feature-2.0.0/creslib-version-update 2025-02-27 15:03:02 -05:00
jtalborough
35018b3572 fix: update docker workflow for version tagging and build steps 2025-02-27 14:35:59 -05:00
Andrew Knous
01d9b3e851 feat: updates crestron libraries to 2.21.90, adds Newtonsoft.Json for net6 2025-02-20 22:43:40 -05:00
Jason T Alborough
237fff5398 Merge pull request #1214 from PepperDash/feature-2.0.0/concurrent-routing-issues
Fix issues with concurrent routing actions
2025-02-20 13:19:56 -05:00
Andrew Welker
b2eab21fbd Merge pull request #1211 from PepperDash/hotfix-2.0.0/room-combiner-syncronous-events
fix: improve error handling and await device actions in RoomCombinati…
2025-02-19 17:20:59 -06:00
Andrew Welker
f2545fb1cf Merge pull request #1212 from PepperDash/feature-2.0.0/versiport-room-combiner
Enable using Versiports with Room Combiner
2025-02-19 17:20:40 -06:00
Andrew Welker
27072e3475 fix: #1213 remove key from GenericSoftCodec routing port keys 2025-02-19 17:10:18 -06:00
Andrew Welker
e4755ed9df Merge branch 'feature-2.0.0/concurrent-routing-issues' of https://github.com/PepperDash/Essentials into feature-2.0.0/concurrent-routing-issues 2025-02-19 17:00:45 -06:00
Andrew Welker
316867caf8 chore: update to PD Core 2.0.0-alpha-451
Catch the `SshOperationTimeoutException` and handle it differently.
2025-02-19 16:49:22 -06:00
jtalborough
d8fd774324 Merge branch 'hotfix-2.0.0/room-combiner-syncronous-events' into feature-2.0.0/concurrent-routing-issues 2025-02-19 15:11:46 -05:00
Andrew Welker
e0058d8cfe chore: update PD Core to 2.0.0-alpha-450
Updated to Renci for SSH
2025-02-19 13:24:52 -06:00
Andrew Welker
a055d06bc6 chore: add some logging for route queue processing 2025-02-19 11:18:00 -06:00
Andrew Welker
66cb592c70 chore: add missing curly brace 2025-02-19 11:10:35 -06:00
Andrew Welker
d53a5607e2 chore: reorg methos in routing Extensions class 2025-02-19 11:07:41 -06:00
Andrew Welker
34f59f1410 fix: move ReleaseRoute & RunRouteRequests to use a queue 2025-02-19 11:06:56 -06:00
Andrew Welker
261779d4c4 fix: actually log exception correctly 2025-02-18 14:04:30 -06:00
Andrew Welker
30d5e2b081 fix: add more exception handling
Also add null check for `AddRouteDescriptor` method
2025-02-18 14:00:53 -06:00
Andrew Welker
5516ed16c3 fix: use null instead of empty string to make it clearer what's happening 2025-02-18 12:02:52 -06:00
Andrew Welker
8108b9dfdb fix: attempt to get better logging for exception
Fixed some issues with log messages that were not formatted correctly for Serilog.
2025-02-18 11:59:26 -06:00
Nick Genovese
fb4f1482c7 fix: small null check in the release and make route method 2025-01-31 19:33:31 -05:00
Nick Genovese
54dcb5de08 feat: implement IPartitionStateProvider to Generic VersaPortInput 2025-01-30 15:21:12 -05:00
jtalborough
4ef481375c fix: improve error handling and await device actions in RoomCombinationScenario 2025-01-28 09:00:21 -05:00
Nick Genovese
d8a88b2a07 Merge branch 'development-2.0.0' into feature-2.0.0/emergencyOSD 2025-01-10 07:31:35 -05:00
Andrew Welker
cc724ddf19 Merge pull request #1210 from PepperDash/hotfix-2.0.0/release-routes-clears-the-routes
Hotfix 2.0.0/release routes clears the routes
2024-12-30 13:33:54 -06:00
Nick Genovese
e29e800d9d fix: now pushes the tag whenever not rc 2024-12-10 07:52:43 -05:00
Nick Genovese
134e8ba02e fix: remove null route when releasing route 2024-12-10 07:44:10 -05:00
Neil Dorin
a83ba444d3 Merge pull request #1209 from PepperDash/feature-2.0.0/more-cooldown-fixes 2024-11-22 08:34:13 -07:00
Andrew Welker
f4c5e6fbeb fix: remove event sub for route request
When route requests made during a destination's cooldown cycle were handled, the event subscription was *NOT* being removed, resulting in the request being run on *EVERY* subsequent cooldown complete event.
2024-11-22 09:14:07 -06:00
Andrew Welker
35d7994cc8 Merge pull request #1208 from PepperDash/feature-2.0.0/cooldown-exception
fix: add try/catch for routing cooldown handler
2024-11-20 15:52:24 -06:00
Andrew Welker
c3e9d654c9 fix: add try/catch for routing cooldown handler
Fixed log statement to handle when a value is null
2024-11-20 15:47:33 -06:00
Andrew Knous
f68b1e9e49 feat: cleans up code, adds versiport comment, changes ShowEmergencyMessage arg name to "url" 2024-11-19 09:19:48 -08:00
Andrew Knous
cd81b8af73 feat: adds roomKey to ShowEmergencyMessage 2024-11-14 17:00:21 -05:00
Andrew Knous
cd52c245a6 feat: adds emergency OSD support 2024-11-14 16:23:31 -05:00
Neil Dorin
0b60f53d0e feat: Adds IEssentialsRoomEmergency interface and implements on contact closure device to provide state 2024-11-13 12:15:25 -07:00
Andrew Welker
ffed2dea8a Merge pull request #1206 from PepperDash/feature-2.0.0/catv-presets
docs: adds debug statement to print preset count
2024-10-31 09:54:47 -05:00
Andrew Welker
936dce2046 Merge pull request #1204 from PepperDash/feature-2.0.0/fix-version-info
feat: adds sdi in/out port names
2024-10-31 09:53:46 -05:00
Andrew Welker
b33704eabe Merge pull request #1203 from PepperDash/feature-2.0.0/bridge-issues
fix: joins in join maps get added correctly to a bridge
2024-10-30 13:27:25 -05:00
Andrew Welker
aca6fe9af5 chore: remove extraneous call 2024-10-30 13:20:43 -05:00
Andrew Welker
332faaa9cc fix: joins in join maps get added correctly to a bridge
When Essentials moved to using `System.Reflection` instead of the Crestron classes, there were some leftover `GetType` calls that were no longer necessary. These extra calls were preventing things from getting the correct type.

Join Map printing was also fixed to print out in an actual readable fashion.
2024-10-30 13:18:36 -05:00
Nick Genovese
4449077a39 Merge pull request #1202 from PepperDash/feature-2.0.0/display-feedback-fix
Set CurrentSourceKey correctly & in the correct order
2024-10-30 11:32:29 -04:00
Andrew Welker
86ba9e0f16 fix: set currentSourceKey & currentSource in order 2024-10-30 10:19:55 -05:00
Andrew Welker
db2d8a213d fix: get order of source & source key correct 2024-10-29 10:59:26 -05:00
Andrew Welker
590e16298c fix: use correct key for destination CurrentSourceInfoKey 2024-10-28 16:41:30 -05:00
Andrew Welker
1a11e9019c Merge pull request #1201 from PepperDash/feature-2.0.0/routing-feedback-manager-nullref
Feature 2.0.0/routing feedback manager nullref
2024-10-25 08:33:46 -05:00
Nick Genovese
0e16dff90c fix: checks the routing output port for null 2024-10-24 20:52:24 -04:00
Andrew Welker
639cd2abfb Merge pull request #1197 from PepperDash/feature-2.0.0/add-cpz-to-builds
Feature 2.0.0/add cpz to builds
2024-10-18 10:46:05 -05:00
jtalborough
778af651d0 feature: adds pack for release builds 2024-08-05 10:40:33 -04:00
jtalborough
2e31719a84 fix: artifact path 2024-08-05 10:39:04 -04:00
jtalborough
a96fb21898 feature: add dotnet pack 2024-08-05 09:52:57 -04:00
jtalborough
3f45372e1e feature: add cpz test 2024-08-02 15:55:38 -04:00
jtalborough
60dbaf547d fix: artifact path 2024-08-02 11:00:07 -04:00
Neil Dorin
63c653b21f docs: adds debug statement to print preset count 2024-07-24 10:39:52 -06:00
Neil Dorin
b326ccf6c3 feat: adds sdi in/out port names 2024-06-19 13:08:55 -06:00
28 changed files with 730 additions and 420 deletions

View File

@@ -66,6 +66,55 @@ jobs:
# Build the solutions in the docker image
- name: Build Solution
run: msbuild .\$($Env:SOLUTION_FILE).sln /p:Platform="Any CPU" /p:Configuration="Debug" /p:Version="${{ steps.setVersion.outputs.version }}" -m
- name: Debug CPZ Files
shell: powershell
run: |
Write-Host "Checking for CPZ files..."
# First, let's find out the actual directory structure
Write-Host "Current directory: $(Get-Location)"
Write-Host "Directory structure:"
Get-ChildItem -Path . -Directory -Recurse -Depth 2 | ForEach-Object { Write-Host $_.FullName }
# Look for all CPZ files in the repository
Write-Host "Searching for all CPZ files in the repository:"
$cpzFiles = Get-ChildItem -Path . -Recurse -Filter "*.cpz"
if ($cpzFiles.Count -eq 0) {
Write-Host "No CPZ files found in the repository."
} else {
Write-Host "Found $($cpzFiles.Count) CPZ files:"
foreach ($file in $cpzFiles) {
Write-Host " $($file.FullName)"
}
# Create output directory if it doesn't exist
$outputDir = ".\output\build"
if (-not (Test-Path $outputDir)) {
New-Item -ItemType Directory -Path $outputDir -Force
Write-Host "Created output directory: $outputDir"
}
# Copy all CPZ files to the output directory
foreach ($file in $cpzFiles) {
$destPath = Join-Path $outputDir $file.Name
Write-Host "Copying $($file.FullName) to $destPath"
Copy-Item -Path $file.FullName -Destination $destPath -Force
}
}
- name: Pack Solution
run: |
dotnet pack .\$($Env:SOLUTION_FILE).sln --configuration $env:BUILD_TYPE --output ./output /p:Version="${{ steps.setVersion.outputs.version }}"
# Ensure CPZ files are included in the package
$cpzFiles = Get-ChildItem -Path . -Recurse | Where-Object { $_.Extension -eq ".cpz" }
if ($cpzFiles.Count -eq 0) {
Write-Host "WARNING: No CPZ files found!"
} else {
Write-Host "Found $($cpzFiles.Count) CPZ files"
foreach ($file in $cpzFiles) {
Write-Host "CPZ file: $($file.FullName)"
}
}
- name: Create tag for non-rc builds
if: contains(steps.setVersion.outputs.version, 'alpha')
run: |
@@ -74,9 +123,6 @@ jobs:
# Create the release on the source repo
- name: Create Release
id: create_release
# if: contains(steps.setVersion.outputs.version,'-rc-') ||
# contains(steps.setVersion.outputs.version,'-hotfix-') ||
# contains(steps.setVersion.outputs.version, '-beta-')
uses: ncipollo/release-action@v1
with:
artifacts: 'output\**\*.*(cpz|cplz)'

View File

@@ -37,6 +37,8 @@ jobs:
run: nuget restore .\$($Env:SOLUTION_FILE).sln
- name: Build Solution
run: msbuild .\$($Env:SOLUTION_FILE).sln /p:Platform="Any CPU" /p:Configuration="Debug" /p:Version="${{ steps.setVersion.outputs.version }}" -m
- name: Pack Solution
run: dotnet pack .\$($Env:SOLUTION_FILE).sln --configuration $env:BUILD_TYPE --output ./output /p:Version="${{ steps.setVersion.outputs.version }}"
- name: Upload Release
id: create_release
uses: ncipollo/release-action@v1

View File

@@ -6,6 +6,7 @@
Provided under MIT license
## Overview
PepperDash Essentials is an open source Crestron framework that can be configured as a standalone program capable of running a wide variety of system designs and can also be utilized as a plug-in architecture to augment other Simpl# Pro and Simpl Windows programs.

View File

@@ -1,6 +1,19 @@
<Project>
<ItemGroup>
<None Include="$(PackageOutputPath)\$(AssemblyName)\*.cpz" Condition="$(ProjectType) == 'Program'">
<!-- Include CPZ files from multiple possible locations -->
<None Include="$(TargetDir)*.cpz" Condition="$(ProjectType) == 'Program'">
<Pack>true</Pack>
<PackagePath>build;</PackagePath>
</None>
<None Include="$(OutputPath)*.cpz" Condition="$(ProjectType) == 'Program'">
<Pack>true</Pack>
<PackagePath>build;</PackagePath>
</None>
<None Include="$(MSBuildProjectDirectory)\bin\$(Configuration)\**\*.cpz" Condition="$(ProjectType) == 'Program'">
<Pack>true</Pack>
<PackagePath>build;</PackagePath>
</None>
<None Include="$(PackageOutputPath)\build\*.cpz" Condition="$(ProjectType) == 'Program'">
<Pack>true</Pack>
<PackagePath>build;</PackagePath>
</None>
@@ -10,17 +23,94 @@
</None>
</ItemGroup>
<Target Name="Create CPLZ" AfterTargets="Build; AfterRebuild" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''">
<Message Text="Creating CPLZ $(TargetDir)"></Message>
<Message Text="Creating CPLZ $(TargetDir)" Importance="high" />
<Message Text="PackageOutputPath: $(PackageOutputPath)" Importance="high" />
<Message Text="AssemblyName: $(AssemblyName)" Importance="high" />
<Message Text="TargetName: $(TargetName)" Importance="high" />
<Message Text="Version: $(Version)" Importance="high" />
<Message Text="TargetFramework: $(TargetFramework)" Importance="high" />
<MakeDir Directories="$(PackageOutputPath)" Condition="!Exists($(PackageOutputPath))" />
<MakeDir Directories="$(PackageOutputPath)\$(AssemblyName)" Condition="!Exists('$(PackageOutputPath)\$(AssemblyName)')" />
<ZipDirectory SourceDirectory="$(TargetDir)" DestinationFile="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cplz" Overwrite="true"/>
</Target>
<Target Name="Copy CPZ NET6" AfterTargets="SimplSharpPostProcess" Condition="($(ProjectType) == 'Program' And ( '$(TargetFramework)' == 'net6.0' ) Or ( '$(TargetFramework)' == 'net8.0' ))">
<Message Text="Copying CPZ"></Message>
<Move SourceFiles="$(TargetDir)$(TargetName).cpz" DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz" />
<Target Name="Debug Variables" BeforeTargets="Build">
<Message Text="================ Debug Variables ================" Importance="high" />
<Message Text="ProjectType: '$(ProjectType)'" Importance="high" />
<Message Text="TargetFramework: '$(TargetFramework)'" Importance="high" />
<Message Text="TargetDir: '$(TargetDir)'" Importance="high" />
<Message Text="===============================================" Importance="high" />
</Target>
<Target Name="Copy CPZ NET47" AfterTargets="SimplSharpPostProcess47" Condition="($(ProjectType) == 'Program' And ( '$(TargetFramework)' != 'net6.0' ) And ( '$(TargetFramework)' != 'net8.0' ))">
<Message Text="Copying CPZ"></Message>
<Move SourceFiles="$(TargetDir)$(TargetName).cpz" DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz" />
<Target Name="Copy CPZ NET472"
AfterTargets="Build"
DependsOnTargets="BuildDependencies"
Condition="'$(ProjectType)' == 'Program' And '$(TargetFramework)' == 'net472'">
<Message Text="========================================" Importance="high" />
<Message Text="Starting CPZ Build Process for NET472" Importance="high" />
<Message Text="ProjectType: '$(ProjectType)'" Importance="high" />
<Message Text="TargetFramework: '$(TargetFramework)'" Importance="high" />
<Message Text="========================================" Importance="high" />
<!-- Create output directory -->
<MakeDir Directories="$(PackageOutputPath)\$(AssemblyName)"
Condition="!Exists('$(PackageOutputPath)\$(AssemblyName)')" />
<!-- Copy the CPZ file -->
<Copy SourceFiles="$(TargetDir)$(TargetName).cpz"
DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz"
Condition="Exists('$(TargetDir)$(TargetName).cpz')" />
<Message Text="CPZ Build completed for NET472"
Condition="Exists('$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz')"
Importance="high" />
</Target>
</Project>
<Target Name="Copy CPZ NET6"
AfterTargets="Build"
DependsOnTargets="BuildDependencies"
Condition="'$(ProjectType)' == 'Program' And ('$(TargetFramework)' == 'net6.0' Or '$(TargetFramework)' == 'net8.0')">
<Message Text="========================================" Importance="high" />
<Message Text="Starting CPZ Build Process" Importance="high" />
<Message Text="ProjectType: '$(ProjectType)'" Importance="high" />
<Message Text="TargetFramework: '$(TargetFramework)'" Importance="high" />
<Message Text="MSBuildProjectDirectory: '$(MSBuildProjectDirectory)'" Importance="high" />
<Message Text="PATH: '$(PATH)'" Importance="high" />
<Message Text="========================================" Importance="high" />
<!-- Check for SimplSharp compiler -->
<PropertyGroup>
<SimplSharpCompilerPath>$(HOME)/.crestron/SimplSharpPro/SimplSharpCompiler</SimplSharpCompilerPath>
</PropertyGroup>
<Warning Text="SimplSharpCompiler not found at: $(SimplSharpCompilerPath)"
Condition="!Exists('$(SimplSharpCompilerPath)')" />
<!-- Run the SimplSharp compiler to create CPZ -->
<Exec Command="&quot;$(SimplSharpCompilerPath)&quot; &quot;$(MSBuildProjectDirectory)&quot; &quot;$(TargetDir)&quot;"
IgnoreExitCode="false"
WorkingDirectory="$(MSBuildProjectDirectory)"
ConsoleToMSBuild="true"
Condition="Exists('$(SimplSharpCompilerPath)')">
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
</Exec>
<Message Text="SimplSharp Output: $(OutputOfExec)" Importance="high" />
<!-- Create output directory -->
<MakeDir Directories="$(PackageOutputPath)\$(AssemblyName)"
Condition="!Exists('$(PackageOutputPath)\$(AssemblyName)')" />
<!-- Copy the CPZ file -->
<Copy SourceFiles="$(TargetDir)$(TargetName).cpz"
DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz"
Condition="Exists('$(TargetDir)$(TargetName).cpz')" />
<Message Text="CPZ Build completed"
Condition="Exists('$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz')"
Importance="high" />
</Target>
<Target Name="BuildDependencies">
<MSBuild Projects="@(ProjectReference)"
Targets="Build"
BuildInParallel="true" />
</Target>
</Project>

View File

@@ -18,81 +18,6 @@ using Serilog.Events;
namespace PepperDash.Essentials.Core.Bridges
{
/// <summary>
/// Helper methods for bridges
/// </summary>
public static class BridgeHelper
{
public static void PrintJoinMap(string command)
{
var targets = command.Split(' ');
var bridgeKey = targets[0].Trim();
var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced;
if (bridge == null)
{
Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey);
return;
}
if (targets.Length > 1)
{
var deviceKey = targets[1].Trim();
if (string.IsNullOrEmpty(deviceKey)) return;
bridge.PrintJoinMapForDevice(deviceKey);
}
else
{
bridge.PrintJoinMaps();
}
}
public static void JoinmapMarkdown(string command)
{
var targets = command.Split(' ');
var bridgeKey = targets[0].Trim();
var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced;
if (bridge == null)
{
Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey);
return;
}
if (targets.Length > 1)
{
var deviceKey = targets[1].Trim();
if (string.IsNullOrEmpty(deviceKey)) return;
bridge.MarkdownJoinMapForDevice(deviceKey, bridgeKey);
}
else
{
bridge.MarkdownForBridge(bridgeKey);
}
}
}
/// <summary>
/// Base class for all bridge class variants
/// </summary>
public class BridgeBase : EssentialsDevice
{
public BridgeApi Api { get; protected set; }
public BridgeBase(string key) :
base(key)
{
}
}
/// <summary>
/// Base class for bridge API variants
/// </summary>
@@ -168,19 +93,15 @@ namespace PepperDash.Essentials.Core.Bridges
Debug.LogMessage(LogEventLevel.Debug, this, "Linking Device: '{0}'", device.Key);
if (!typeof(IBridgeAdvanced).IsAssignableFrom(device.GetType().GetType()))
if (device is IBridgeAdvanced bridge)
{
Debug.LogMessage(LogEventLevel.Information, this,
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
device.Key);
bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this);
continue;
}
var bridge = device as IBridgeAdvanced;
if (bridge != null)
{
bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this);
}
Debug.LogMessage(LogEventLevel.Information, this,
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
device.Key);
}
}
@@ -249,11 +170,11 @@ namespace PepperDash.Essentials.Core.Bridges
/// </summary>
public virtual void PrintJoinMaps()
{
Debug.LogMessage(LogEventLevel.Information, this, "Join Maps for EISC IPID: {0}", Eisc.ID.ToString("X"));
CrestronConsole.ConsoleCommandResponse("Join Maps for EISC IPID: {0}\r\n", Eisc.ID.ToString("X"));
foreach (var joinMap in JoinMaps)
{
Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}':", joinMap.Key);
CrestronConsole.ConsoleCommandResponse("Join map for device '{0}':", joinMap.Key);
joinMap.Value.PrintJoinMapInfo();
}
}

View File

@@ -0,0 +1,66 @@
using PepperDash.Core;
using Serilog.Events;
//using PepperDash.Essentials.Devices.Common.Cameras;
namespace PepperDash.Essentials.Core.Bridges
{
/// <summary>
/// Helper methods for bridges
/// </summary>
public static class BridgeHelper
{
public static void PrintJoinMap(string command)
{
var targets = command.Split(' ');
var bridgeKey = targets[0].Trim();
if (!(DeviceManager.GetDeviceForKey(bridgeKey) is EiscApiAdvanced bridge))
{
Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey);
return;
}
if (targets.Length > 1)
{
var deviceKey = targets[1].Trim();
if (string.IsNullOrEmpty(deviceKey)) return;
bridge.PrintJoinMapForDevice(deviceKey);
}
else
{
bridge.PrintJoinMaps();
}
}
public static void JoinmapMarkdown(string command)
{
var targets = command.Split(' ');
var bridgeKey = targets[0].Trim();
var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced;
if (bridge == null)
{
Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey);
return;
}
if (targets.Length > 1)
{
var deviceKey = targets[1].Trim();
if (string.IsNullOrEmpty(deviceKey)) return;
bridge.MarkdownJoinMapForDevice(deviceKey, bridgeKey);
}
else
{
bridge.MarkdownForBridge(bridgeKey);
}
}
}
}

View File

@@ -21,7 +21,7 @@ namespace PepperDash.Essentials.Core.CrestronIO
/// <summary>
/// Represents a generic digital input deviced tied to a versiport
/// </summary>
public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput
public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IPartitionStateProvider
{
public Versiport InputPort { get; private set; }
@@ -35,10 +35,15 @@ namespace PepperDash.Essentials.Core.CrestronIO
}
}
public BoolFeedback PartitionPresentFeedback { get; }
public bool PartitionPresent => !InputStateFeedbackFunc();
public GenericVersiportDigitalInputDevice(string key, string name, Func<IOPortConfig, Versiport> postActivationFunc, IOPortConfig config) :
base(key, name)
{
InputStateFeedback = new BoolFeedback(InputStateFeedbackFunc);
PartitionPresentFeedback = new BoolFeedback(() => !InputStateFeedbackFunc());
AddPostActivationAction(() =>
{
@@ -52,7 +57,8 @@ namespace PepperDash.Essentials.Core.CrestronIO
InputPort.VersiportChange += InputPort_VersiportChange;
InputStateFeedback.FireUpdate();
PartitionPresentFeedback.FireUpdate();
Debug.LogMessage(LogEventLevel.Debug, this, "Created GenericVersiportDigitalInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor);
@@ -65,7 +71,10 @@ namespace PepperDash.Essentials.Core.CrestronIO
Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event);
if(args.Event == eVersiportEvent.DigitalInChange)
{
InputStateFeedback.FireUpdate();
PartitionPresentFeedback.FireUpdate();
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IEmergencyOSD
{
void ShowEmergencyMessage(string url);
void HideEmergencyMessage();
}
}

View File

@@ -1,5 +1,3 @@
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
@@ -11,7 +9,6 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace PepperDash.Essentials.Core
{
public class DeviceJsonApi
@@ -141,18 +138,26 @@ namespace PepperDash.Essentials.Core
.Select((p, i) => ConvertType(action.Params[i], p.ParameterType))
.ToArray();
await Task.Run(() =>
try
{
try
Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey} with {@params}", null, method.Name, action.DeviceKey, action.Params);
var result = method.Invoke(obj, convertedParams);
// If the method returns a Task, await it
if (result is Task task)
{
Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey} with {@params}", null, method.Name, action.DeviceKey, action.Params);
method.Invoke(obj, convertedParams);
await task;
}
catch (Exception e)
// If the method returns a Task<T>, await it
else if (result != null && result.GetType().IsGenericType && result.GetType().GetGenericTypeDefinition() == typeof(Task<>))
{
Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey);
await (Task)result;
}
});
}
catch (Exception e)
{
Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey);
}
}
catch (Exception ex)
{
@@ -206,7 +211,7 @@ namespace PepperDash.Essentials.Core
if (dev == null)
return "{ \"error\":\"No Device\"}";
object prop = dev.GetType().GetType().GetProperty(propertyName).GetValue(dev, null);
object prop = dev.GetType().GetProperty(propertyName).GetValue(dev, null);
// var prop = t.GetProperty(propertyName);
if (prop != null)

View File

@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Reflection;
//using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharp.Scheduler;
using PepperDash.Core;

View File

@@ -107,19 +107,20 @@ namespace PepperDash.Essentials.Core
}
protected void AddJoins(Type type)
{
{
var fields =
type.GetType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(f => f.IsDefined(typeof (JoinNameAttribute), true));
type.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(f => f.IsDefined(typeof (JoinNameAttribute), true)).ToList();
Debug.LogMessage(LogEventLevel.Debug, "Got {fields} with JoinNameAttribute", fields.Count);
foreach (var field in fields)
{
var childClass = Convert.ChangeType(this, type, null);
var value = field.GetValue(childClass) as JoinDataComplete; //this here is JoinMapBaseAdvanced, not the child class. JoinMapBaseAdvanced has no fields.
//this here is JoinMapBaseAdvanced, not the child class. JoinMapBaseAdvanced has no fields.
if (value == null)
if (!(field.GetValue(childClass) is JoinDataComplete value))
{
Debug.LogMessage(LogEventLevel.Information, "Unable to cast base class to {0}", type.Name);
continue;
@@ -129,7 +130,7 @@ namespace PepperDash.Essentials.Core
var joinName = value.GetNameAttribute(field);
if (String.IsNullOrEmpty(joinName)) continue;
if (string.IsNullOrEmpty(joinName)) continue;
Joins.Add(joinName, value);
}
@@ -155,29 +156,37 @@ namespace PepperDash.Essentials.Core
{
var sb = new StringBuilder();
// Get the joins of each type and print them
sb.AppendLine(String.Format("# {0}", GetType().Name));
sb.AppendLine();
sb.AppendLine("## Digitals");
sb.AppendLine();
// Get the joins of each type and print them
var digitals =
Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital)
.ToDictionary(j => j.Key, j => j.Value);
var digitalSb = AppendJoinList(GetSortedJoins(digitals));
digitalSb.AppendLine("## Analogs");
digitalSb.AppendLine();
var lineEnding = "\r\n";
var analogs =
Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog)
var digitals =
Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Digital))
.ToDictionary(j => j.Key, j => j.Value);
var analogs = Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Analog))
.ToDictionary(j => j.Key, j => j.Value);
var analogSb = AppendJoinList(GetSortedJoins(analogs));
analogSb.AppendLine("## Serials");
analogSb.AppendLine();
var serials =
Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial)
Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Serial))
.ToDictionary(j => j.Key, j => j.Value);
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Digital join count {digitalCount} Analog join count {analogCount} Serial join count {serialCount}", null, digitals.Count, analogs.Count, serials.Count);
// Get the joins of each type and print them
sb.Append($"# {GetType().Name}\r\n");
sb.Append(lineEnding);
sb.Append($"## Digitals{lineEnding}");
sb.Append(lineEnding);
// Get the joins of each type and print them
var digitalSb = AppendJoinList(GetSortedJoins(digitals));
digitalSb.Append($"## Analogs{lineEnding}");
digitalSb.Append(lineEnding);
var analogSb = AppendJoinList(GetSortedJoins(analogs));
analogSb.Append($"## Serials{lineEnding}");
analogSb.Append(lineEnding);
var serialSb = AppendJoinList(GetSortedJoins(serials));
sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length);
@@ -202,7 +211,7 @@ namespace PepperDash.Essentials.Core
private static void WriteJoinmapMarkdown(StringBuilder stringBuilder, string pluginType, string bridgeKey, string deviceKey)
{
var fileName = String.Format("{0}{1}{2}__{3}__{4}.md", Global.FilePathPrefix, "joinMaps/", pluginType, bridgeKey, deviceKey);
var fileName = string.Format("{0}{1}{2}__{3}__{4}.md", Global.FilePathPrefix, "joinMaps/", pluginType, bridgeKey, deviceKey);
using (var sw = new StreamWriter(fileName))
{
@@ -230,7 +239,7 @@ namespace PepperDash.Essentials.Core
static StringBuilder AppendJoinList(List<KeyValuePair<string, JoinDataComplete>> joins)
{
var sb = new StringBuilder();
const string stringFormatter = "| {0} | {1} | {2} | {3} | {4} |";
const string stringFormatter = "| {0} | {1} | {2} | {3} | {4} |\r\n";
const int joinNumberLen = 11;
const int joinSpanLen = 9;
const int typeLen = 19;
@@ -238,25 +247,25 @@ namespace PepperDash.Essentials.Core
var descriptionLen = (from @join in joins select @join.Value into j select j.Metadata.Description.Length).Concat(new[] {11}).Max();
//build header
sb.AppendLine(String.Format(stringFormatter,
String.Format("Join Number").PadRight(joinNumberLen, ' '),
String.Format("Join Span").PadRight(joinSpanLen, ' '),
String.Format("Description").PadRight(descriptionLen, ' '),
String.Format("Type").PadRight(typeLen, ' '),
String.Format("Capabilities").PadRight(capabilitiesLen, ' ')));
sb.Append(string.Format(stringFormatter,
string.Format("Join Number").PadRight(joinNumberLen, ' '),
string.Format("Join Span").PadRight(joinSpanLen, ' '),
string.Format("Description").PadRight(descriptionLen, ' '),
string.Format("Type").PadRight(typeLen, ' '),
string.Format("Capabilities").PadRight(capabilitiesLen, ' ')));
//build table seperator
sb.AppendLine(String.Format(stringFormatter,
new String('-', joinNumberLen),
new String('-', joinSpanLen),
new String('-', descriptionLen),
new String('-', typeLen),
new String('-', capabilitiesLen)));
sb.Append(string.Format(stringFormatter,
new string('-', joinNumberLen),
new string('-', joinSpanLen),
new string('-', descriptionLen),
new string('-', typeLen),
new string('-', capabilitiesLen)));
foreach (var join in joins)
{
sb.AppendLine(join.Value.GetMarkdownFormattedData(stringFormatter, descriptionLen));
sb.Append(join.Value.GetMarkdownFormattedData(stringFormatter, descriptionLen));
}
sb.AppendLine();
sb.Append("\r\n");
return sb;
}
@@ -411,10 +420,10 @@ namespace PepperDash.Essentials.Core
{
//Fixed Width Headers
var joinNumberLen = String.Format("Join Number").Length;
var joinSpanLen = String.Format("Join Span").Length;
var typeLen = String.Format("AnalogDigitalSerial").Length;
var capabilitiesLen = String.Format("ToFromFusion").Length;
var joinNumberLen = string.Format("Join Number").Length;
var joinSpanLen = string.Format("Join Span").Length;
var typeLen = string.Format("AnalogDigitalSerial").Length;
var capabilitiesLen = string.Format("ToFromFusion").Length;
//Track which one failed, if it did
const string placeholder = "unknown";
@@ -430,13 +439,13 @@ namespace PepperDash.Essentials.Core
try
{
dataArray["joinNumber"] = String.Format("{0}", JoinNumber.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinNumberLen, ' ');
dataArray["joinSpan"] = String.Format("{0}", JoinSpan.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinSpanLen, ' ');
dataArray["description"] = String.Format("{0}", Metadata.Description.ReplaceIfNullOrEmpty(placeholder)).PadRight(descriptionLen, ' ');
dataArray["joinType"] = String.Format("{0}", Metadata.JoinType.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(typeLen, ' ');
dataArray["capabilities"] = String.Format("{0}", Metadata.JoinCapabilities.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(capabilitiesLen, ' ');
dataArray["joinNumber"] = string.Format("{0}", JoinNumber.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinNumberLen, ' ');
dataArray["joinSpan"] = string.Format("{0}", JoinSpan.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinSpanLen, ' ');
dataArray["description"] = string.Format("{0}", Metadata.Description.ReplaceIfNullOrEmpty(placeholder)).PadRight(descriptionLen, ' ');
dataArray["joinType"] = string.Format("{0}", Metadata.JoinType.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(typeLen, ' ');
dataArray["capabilities"] = string.Format("{0}", Metadata.JoinCapabilities.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(capabilitiesLen, ' ');
return String.Format(stringFormatter,
return string.Format(stringFormatter,
dataArray["joinNumber"],
dataArray["joinSpan"],
dataArray["description"],
@@ -454,8 +463,8 @@ namespace PepperDash.Essentials.Core
errorKey = item.Key;
break;
}
Debug.LogMessage(LogEventLevel.Information, "Unable to decode join metadata {1}- {0}", e.Message, !String.IsNullOrEmpty(errorKey) ? (' ' + errorKey) : String.Empty);
return String.Format(stringFormatter,
Debug.LogMessage(LogEventLevel.Information, "Unable to decode join metadata {1}- {0}", e.Message, !string.IsNullOrEmpty(errorKey) ? (' ' + errorKey) : string.Empty);
return string.Format(stringFormatter,
dataArray["joinNumber"],
dataArray["joinSpan"],
dataArray["description"],
@@ -520,7 +529,7 @@ namespace PepperDash.Essentials.Core
public JoinNameAttribute(string name)
{
Debug.LogMessage(LogEventLevel.Verbose, "Setting Attribute Name: {0}", name);
Debug.LogMessage(LogEventLevel.Verbose, "Setting Attribute Name: {0}",null, name);
_Name = name;
}

View File

@@ -25,8 +25,11 @@
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-424" />
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.21.90" />
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-455" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net6'">
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />

View File

@@ -130,6 +130,8 @@ namespace PepperDash.Essentials.Core.Presets
var pl = JsonConvert.DeserializeObject<PresetsList>(File.ReadToEnd(_filePath, Encoding.ASCII));
Name = pl.Name;
PresetsList = pl.Channels;
Debug.LogMessage(LogEventLevel.Verbose, this, "Loaded {0} presets", PresetsList.Count);
}
catch (Exception e)
{

View File

@@ -81,12 +81,10 @@ namespace PepperDash.Essentials.Core
foreach (var action in activationActions)
{
this.LogInformation("Running Activation action {@action}", action);
tasks.Add(DeviceJsonApi.DoDeviceActionAsync(action));
await DeviceJsonApi.DoDeviceActionAsync(action);
}
}
await Task.WhenAll(tasks);
IsActive = true;
}
@@ -101,12 +99,10 @@ namespace PepperDash.Essentials.Core
foreach (var action in deactivationActions)
{
this.LogInformation("Running deactivation action {actionDeviceKey}:{actionMethod}", action.DeviceKey, action.MethodName);
tasks.Add( DeviceJsonApi.DoDeviceActionAsync(action));
await DeviceJsonApi.DoDeviceActionAsync(action);
}
}
await Task.WhenAll(tasks);
IsActive = false;
}

View File

@@ -24,6 +24,7 @@ namespace PepperDash.Essentials.Room.Config
//switch on emergency type here. Right now only contact and shutdown
var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room);
DeviceManager.AddDevice(e);
return e;
}
return null;
}

View File

@@ -16,7 +16,7 @@
public class EssentialsRoomEmergencyTriggerConfig
{
/// <summary>
/// contact,
/// contact,versiport
/// </summary>
public string Type { get; set; }
/// <summary>

View File

@@ -4,12 +4,16 @@ using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials.Core
{
public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase
public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase, IEssentialsRoomEmergency
{
public event EventHandler<EventArgs> EmergencyStateChange;
IEssentialsRoom Room;
string Behavior;
bool TriggerOnClose;
public bool InEmergency { get; private set; }
public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, IEssentialsRoom room) :
base(key)
{
@@ -25,14 +29,49 @@ namespace PepperDash.Essentials.Core
cs.DigitalInputPorts[portNum].StateChange += EsentialsRoomEmergencyContactClosure_StateChange;
}
}
else if (config.Trigger.Type.Equals("versiport", StringComparison.OrdinalIgnoreCase))
{
var portNum = (uint)config.Trigger.Number;
if (portNum <= cs.NumberOfVersiPorts)
{
cs.VersiPorts[portNum].Register();
cs.VersiPorts[portNum].SetVersiportConfiguration(eVersiportConfiguration.DigitalInput);
cs.VersiPorts[portNum].DisablePullUpResistor = true;
cs.VersiPorts[portNum].VersiportChange += EssentialsRoomEmergencyContactClosure_VersiportChange;
}
}
Behavior = config.Behavior;
TriggerOnClose = config.Trigger.TriggerOnClose;
}
private void EssentialsRoomEmergencyContactClosure_VersiportChange(Versiport port, VersiportEventArgs args)
{
if (args.Event == eVersiportEvent.DigitalInChange)
{
ContactClosure_StateChange(port.DigitalIn);
}
}
void EsentialsRoomEmergencyContactClosure_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args)
{
if (args.State && TriggerOnClose || !args.State && !TriggerOnClose)
ContactClosure_StateChange(args.State);
}
void ContactClosure_StateChange(bool portState)
{
if (portState && TriggerOnClose || !portState && !TriggerOnClose)
{
InEmergency = true;
if (EmergencyStateChange != null)
EmergencyStateChange(this, new EventArgs());
RunEmergencyBehavior();
}
else
{
InEmergency = false;
if (EmergencyStateChange != null)
EmergencyStateChange(this, new EventArgs());
}
}
/// <summary>
@@ -44,4 +83,14 @@ namespace PepperDash.Essentials.Core
Room.Shutdown();
}
}
/// <summary>
/// Describes the functionality of a room emergency contact closure
/// </summary>
public interface IEssentialsRoomEmergency
{
event EventHandler<EventArgs> EmergencyStateChange;
bool InEmergency { get; }
}
}

View File

@@ -1,4 +1,6 @@
using Serilog.Events;
using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -17,6 +19,8 @@ namespace PepperDash.Essentials.Core
{
private static readonly Dictionary<string, RouteRequest> RouteRequests = new Dictionary<string, RouteRequest>();
private static readonly GenericQueue routeRequestQueue = new GenericQueue("routingQueue");
/// <summary>
/// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
/// and then attempts a new Route and if sucessful, stores that RouteDescriptor
@@ -33,6 +37,15 @@ namespace PepperDash.Essentials.Core
ReleaseAndMakeRoute(destination, source, signalType, inputPort, outputPort);
}
public static void ReleaseRoute(this IRoutingInputs destination)
{
routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, string.Empty));
}
public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey)
{
routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, inputPortKey));
}
public static void RemoveRouteRequestForDestination(string destinationKey)
{
@@ -45,118 +58,6 @@ namespace PepperDash.Essentials.Core
Debug.LogMessage(LogEventLevel.Information, messageTemplate, null, destinationKey);
}
private static void ReleaseAndMakeRoute(IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort = null, RoutingOutputPort sourcePort = null)
{
if (destination == null) throw new ArgumentNullException(nameof(destination));
if (source == null) throw new ArgumentNullException(nameof(source));
if (destinationPort == null) Debug.LogMessage(LogEventLevel.Information, "Destination port is null");
if (sourcePort == null) Debug.LogMessage(LogEventLevel.Information, "Source port is null");
var routeRequest = new RouteRequest
{
Destination = destination,
DestinationPort = destinationPort,
Source = source,
SourcePort = sourcePort,
SignalType = signalType
};
var coolingDevice = destination as IWarmingCooling;
//We already have a route request for this device, and it's a cooling device and is cooling
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
RouteRequests[destination.Key] = routeRequest;
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down and already has a routing request stored. Storing new route request to route to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key);
return;
}
//New Request
if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{
coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown;
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
RouteRequests.Add(destination.Key, routeRequest);
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down. Storing route request to route to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key);
return;
}
if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false)
{
RouteRequests.Remove(destination.Key);
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key);
}
destination.ReleaseRoute(destinationPort?.Key ?? string.Empty);
RunRouteRequest(routeRequest);
}
private static void RunRouteRequest(RouteRequest request)
{
if (request.Source == null)
return;
var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort);
if (audioOrSingleRoute == null && videoRoute == null)
return;
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute);
if (videoRoute != null)
{
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute);
}
Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination);
audioOrSingleRoute.ExecuteRoutes();
videoRoute?.ExecuteRoutes();
}
public static void ReleaseRoute(this IRoutingInputs destination)
{
ReleaseRoute(destination, string.Empty);
}
/// <summary>
/// Will release the existing route on the destination, if it is found in
/// RouteDescriptorCollection.DefaultCollection
/// </summary>
/// <param name="destination"></param>
public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey)
{
Debug.LogMessage(LogEventLevel.Information, "Release route for {inputPortKey}", destination, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling)
{
var coolingDevice = destination as IWarmingCooling;
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown;
}
RouteRequests.Remove(destination.Key);
var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey);
if (current != null)
{
Debug.LogMessage(LogEventLevel.Debug, "Releasing current route: {0}", destination, current.Source.Key);
current.ReleaseRoutes();
}
}
/// <summary>
/// Builds a RouteDescriptor that contains the steps necessary to make a route between devices.
/// Routes of type AudioVideo will be built as two separate routes, audio and video. If
@@ -175,7 +76,8 @@ namespace PepperDash.Essentials.Core
if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort))
singleTypeRouteDescriptor = null;
foreach (var route in singleTypeRouteDescriptor.Routes)
var routes = singleTypeRouteDescriptor?.Routes ?? new List<RouteSwitchDescriptor>();
foreach (var route in routes)
{
Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString());
}
@@ -218,6 +120,126 @@ namespace PepperDash.Essentials.Core
return (audioRouteDescriptor, videoRouteDescriptor);
}
private static void ReleaseAndMakeRoute(IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort = null, RoutingOutputPort sourcePort = null)
{
if (destination == null) throw new ArgumentNullException(nameof(destination));
if (source == null) throw new ArgumentNullException(nameof(source));
if (destinationPort == null) Debug.LogMessage(LogEventLevel.Information, "Destination port is null");
if (sourcePort == null) Debug.LogMessage(LogEventLevel.Information, "Source port is null");
var routeRequest = new RouteRequest
{
Destination = destination,
DestinationPort = destinationPort,
Source = source,
SourcePort = sourcePort,
SignalType = signalType
};
var coolingDevice = destination as IWarmingCooling;
//We already have a route request for this device, and it's a cooling device and is cooling
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
RouteRequests[destination.Key] = routeRequest;
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down and already has a routing request stored. Storing new route request to route to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key);
return;
}
//New Request
if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
RouteRequests.Add(destination.Key, routeRequest);
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is cooling down. Storing route request to route to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key);
return;
}
if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false)
{
var handledRequest = RouteRequests[destination.Key];
coolingDevice.IsCoolingDownFeedback.OutputChange -= handledRequest.HandleCooldown;
RouteRequests.Remove(destination.Key);
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key);
}
routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination,destinationPort?.Key ?? string.Empty));
routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest));
}
private static void RunRouteRequest(RouteRequest request)
{
try
{
if (request.Source == null)
return;
var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort);
if (audioOrSingleRoute == null && videoRoute == null)
return;
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute);
if (videoRoute != null)
{
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute);
}
Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination);
audioOrSingleRoute.ExecuteRoutes();
videoRoute?.ExecuteRoutes();
} catch(Exception ex)
{
Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request);
}
}
/// <summary>
/// Will release the existing route on the destination, if it is found in
/// RouteDescriptorCollection.DefaultCollection
/// </summary>
/// <param name="destination"></param>
private static void ReleaseRouteInternal(IRoutingInputs destination, string inputPortKey)
{
try
{
Debug.LogMessage(LogEventLevel.Information, "Release route for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling)
{
var coolingDevice = destination as IWarmingCooling;
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown;
}
RouteRequests.Remove(destination.Key);
var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey);
if (current != null)
{
Debug.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key);
current.ReleaseRoutes();
}
} catch (Exception ex)
{
Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'",null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
}
}
/// <summary>
/// The recursive part of this. Will stop on each device, search its inputs for the
/// desired source and if not found, invoke this function for the each input port

View File

@@ -12,19 +12,19 @@ namespace PepperDash.Essentials.Core
/// Represents an collection of individual route steps between Source and Destination
/// </summary>
public class RouteDescriptor
{
public IRoutingInputs Destination { get; private set; }
{
public IRoutingInputs Destination { get; private set; }
public RoutingInputPort InputPort { get; private set; }
public IRoutingOutputs Source { get; private set; }
public eRoutingSignalType SignalType { get; private set; }
public List<RouteSwitchDescriptor> Routes { get; private set; }
public IRoutingOutputs Source { get; private set; }
public eRoutingSignalType SignalType { get; private set; }
public List<RouteSwitchDescriptor> Routes { get; private set; }
public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType):this(source,destination, null, signalType)
{
}
public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) : this(source, destination, null, signalType)
{
}
public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType)
{
@@ -35,20 +35,20 @@ namespace PepperDash.Essentials.Core
Routes = new List<RouteSwitchDescriptor>();
}
/// <summary>
/// Executes all routes described in this collection. Typically called via
/// extension method IRoutingInputs.ReleaseAndMakeRoute()
/// </summary>
public void ExecuteRoutes()
{
foreach (var route in Routes)
{
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}",null, route.ToString());
/// <summary>
/// Executes all routes described in this collection. Typically called via
/// extension method IRoutingInputs.ReleaseAndMakeRoute()
/// </summary>
public void ExecuteRoutes()
{
foreach (var route in Routes)
{
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteRoutes: {0}", null, route.ToString());
if (route.SwitchingDevice is IRoutingSinkWithSwitching sink)
{
{
sink.ExecuteSwitch(route.InputPort.Selector);
continue;
continue;
}
if (route.SwitchingDevice is IRouting switchingDevice)
@@ -59,35 +59,43 @@ namespace PepperDash.Essentials.Core
Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
}
}
}
}
}
/// <summary>
/// Releases all routes in this collection. Typically called via
/// extension method IRoutingInputs.ReleaseAndMakeRoute()
/// </summary>
public void ReleaseRoutes()
{
foreach (var route in Routes.Where(r => r.SwitchingDevice is IRouting))
{
if (route.SwitchingDevice is IRouting switchingDevice)
{
switchingDevice.ExecuteSwitch(null, route.OutputPort.Selector, SignalType);
/// <summary>
/// Releases all routes in this collection. Typically called via
/// extension method IRoutingInputs.ReleaseAndMakeRoute()
/// </summary>
public void ReleaseRoutes()
{
foreach (var route in Routes.Where(r => r.SwitchingDevice is IRouting))
{
if (route.SwitchingDevice is IRouting switchingDevice)
{
if (route.OutputPort == null)
{
continue;
}
// Pull the route from the port. Whatever is watching the output's in use tracker is
// responsible for responding appropriately.
route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType);
Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}",null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
}
}
}
if (route.OutputPort.InUseTracker != null)
{
route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType);
Debug.LogMessage(LogEventLevel.Verbose, "Port {0} releasing. Count={1}", null, route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
}
else
{
Debug.LogMessage(LogEventLevel.Error, "InUseTracker is null for OutputPort {0}", null, route.OutputPort.Key);
}
}
}
}
public override string ToString()
{
var routesText = Routes.Select(r => r.ToString()).ToArray();
return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText));
}
}
public override string ToString()
{
var routesText = Routes.Select(r => r.ToString()).ToArray();
return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText));
}
}
/*/// <summary>
/// Represents an collection of individual route steps between Source and Destination

View File

@@ -41,7 +41,7 @@ namespace PepperDash.Essentials.Core
&& RouteDescriptors.Any(t => t.Destination == descriptor.Destination && t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key))
{
Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination,
"Route to [{0}] already exists in global routes table", descriptor.Source.Key);
"Route to [{0}] already exists in global routes table", descriptor?.Source?.Key);
return;
}
RouteDescriptors.Add(descriptor);
@@ -53,14 +53,14 @@ namespace PepperDash.Essentials.Core
/// <returns>null if no RouteDescriptor for a destination exists</returns>
public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination)
{
Debug.LogMessage(LogEventLevel.Debug, "Getting route descriptor", destination);
Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}'", destination?.Key ?? null);
return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination);
}
public RouteDescriptor GetRouteDescriptorForDestinationAndInputPort(IRoutingInputs destination, string inputPortKey)
{
Debug.LogMessage(LogEventLevel.Debug, "Getting route descriptor for {inputPortKey}", destination, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination && rd.InputPort != null && rd.InputPort.Key == inputPortKey);
}
@@ -70,7 +70,7 @@ namespace PepperDash.Essentials.Core
/// </summary>
public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination, string inputPortKey = "")
{
Debug.LogMessage(LogEventLevel.Debug, "Removing route descriptor for {inputPortKey}", destination, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
Debug.LogMessage(LogEventLevel.Information, "Removing route descriptor for '{destination}':'{inputPortKey}'", destination.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
var descr = string.IsNullOrEmpty(inputPortKey)
? GetRouteDescriptorForDestination(destination)
@@ -78,7 +78,7 @@ namespace PepperDash.Essentials.Core
if (descr != null)
RouteDescriptors.Remove(descr);
Debug.LogMessage(LogEventLevel.Debug, "Found route descriptor {routeDescriptor}", destination, descr);
Debug.LogMessage(LogEventLevel.Information, "Found route descriptor {routeDescriptor}", destination, descr);
return descr;
}

View File

@@ -1,5 +1,6 @@
using PepperDash.Core;
using Serilog.Events;
using System;
namespace PepperDash.Essentials.Core
{
@@ -14,21 +15,33 @@ namespace PepperDash.Essentials.Core
public void HandleCooldown(object sender, FeedbackEventArgs args)
{
Debug.LogMessage(LogEventLevel.Information, "Handling cooldown route request: {destination}:{destinationPort} -> {source}:{sourcePort} {type}", null, Destination.Key, DestinationPort.Key, Source.Key, SourcePort.Key, SignalType.ToString());
if (args.BoolValue == true)
try
{
return;
}
Debug.LogMessage(LogEventLevel.Information, "Handling cooldown route request: {destination}:{destinationPort} -> {source}:{sourcePort} {type}", null, Destination?.Key ?? "empty destination", DestinationPort?.Key ?? "no destination port", Source?.Key ?? "empty source", SourcePort?.Key ?? "empty source port", SignalType.ToString());
Debug.LogMessage(LogEventLevel.Information, "Cooldown complete. Making route from {destination} to {source}", Destination.Key, Source.Key);
Destination.ReleaseAndMakeRoute(Source, SignalType, DestinationPort?.Key ?? string.Empty, SourcePort?.Key ?? string.Empty);
if (args.BoolValue == true)
{
return;
}
if (sender is IWarmingCooling coolingDevice)
Debug.LogMessage(LogEventLevel.Information, "Cooldown complete. Making route from {destination} to {source}", Destination?.Key, Source?.Key);
Destination.ReleaseAndMakeRoute(Source, SignalType, DestinationPort?.Key ?? string.Empty, SourcePort?.Key ?? string.Empty);
if (sender is IWarmingCooling coolingDevice)
{
Debug.LogMessage(LogEventLevel.Debug, "Unsubscribing from cooling feedback for {destination}", null, Destination.Key);
coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown;
}
} catch(Exception ex)
{
Debug.LogMessage(LogEventLevel.Debug, "Unsubscribing from cooling feedback for {destination}", null, Destination.Key);
coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown;
Debug.LogMessage(ex, "Exception handling cooldown", Destination);
}
}
public override string ToString()
{
return $"Route {Source?.Key ?? "No Source Device"}:{SourcePort?.Key ?? "auto"} to {Destination?.Key ?? "No Destination Device"}:{DestinationPort?.Key ?? "auto"}";
}
}
}

View File

@@ -0,0 +1,45 @@
using PepperDash.Core;
using PepperDash.Essentials.Core.Queues;
using System;
using Serilog.Events;
namespace PepperDash.Essentials.Core.Routing
{
public class RouteRequestQueueItem : IQueueMessage
{
private readonly Action<RouteRequest> action;
private readonly RouteRequest routeRequest;
public RouteRequestQueueItem(Action<RouteRequest> routeAction, RouteRequest request)
{
action = routeAction;
routeRequest = request;
}
public void Dispatch()
{
Debug.LogMessage(LogEventLevel.Information, "Dispatching route request {routeRequest}", null, routeRequest);
action(routeRequest);
}
}
public class ReleaseRouteQueueItem : IQueueMessage
{
private readonly Action<IRoutingInputs, string> action;
private readonly IRoutingInputs destination;
private readonly string inputPortKey;
public ReleaseRouteQueueItem(Action<IRoutingInputs, string> action, IRoutingInputs destination, string inputPortKey)
{
this.action = action;
this.destination = destination;
this.inputPortKey = inputPortKey;
}
public void Dispatch()
{
Debug.LogMessage(LogEventLevel.Information, "Dispatching release route request for {destination}:{inputPortKey}", null, destination?.Key ?? "no destination", string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
action(destination, inputPortKey);
}
}
}

View File

@@ -175,6 +175,7 @@ namespace PepperDash.Essentials.Core.Routing
});
var source = sourceListItem.Value;
var sourceKey = sourceListItem.Key;
if (source == null)
{
@@ -186,15 +187,16 @@ namespace PepperDash.Essentials.Core.Routing
Name = sourceTieLine.SourcePort.Key,
};
destination.CurrentSourceInfo = tempSourceListItem; ;
destination.CurrentSourceInfoKey = "$transient";
destination.CurrentSourceInfo = tempSourceListItem;
return;
}
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {source}", this, source);
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {@source} with key {sourceKey}", this, source, sourceKey);
destination.CurrentSourceInfoKey = sourceKey;
destination.CurrentSourceInfo = source;
destination.CurrentSourceInfoKey = source.SourceKey;
}
private TieLine GetRootTieLine(TieLine tieLine)

View File

@@ -28,8 +28,11 @@
<ItemGroup>
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-424" />
<ItemGroup>
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.21.90" />
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-455" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net6'">
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

View File

@@ -28,14 +28,14 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec
for(var i = 1; i <= props.OutputCount; i++)
{
var outputPort = new RoutingOutputPort($"{Key}-output{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this);
var outputPort = new RoutingOutputPort($"output{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this);
OutputPorts.Add(outputPort);
}
for(var i = 1; i<= props.ContentInputCount; i++)
{
var inputPort = new RoutingInputPort($"{Key}-contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this);
var inputPort = new RoutingInputPort($"contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this);
InputPorts.Add(inputPort);
}
@@ -47,7 +47,7 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec
for(var i = 1; i <=props.CameraInputCount; i++)
{
var cameraPort = new RoutingInputPort($"{Key}-cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this);
var cameraPort = new RoutingInputPort($"cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this);
InputPorts.Add(cameraPort);
}

View File

@@ -42,7 +42,7 @@ namespace PepperDash.Essentials.Devices.Common
public void PrintExpectedIrCommands()
{
var cmds = typeof (AppleTvIrCommands).GetType().GetFields(BindingFlags.Public | BindingFlags.Static);
var cmds = typeof (AppleTvIrCommands).GetFields(BindingFlags.Public | BindingFlags.Static);
foreach (var value in cmds.Select(cmd => cmd.GetValue(null)).OfType<string>())
{

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Reflection;
//using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharp;
using PepperDash.Core;
@@ -1214,7 +1214,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
var entryIndex = counterIndex;
Debug.LogMessage(LogEventLevel.Verbose, this, "Entry{2:0000} Name: {0}, Folder ID: {1}, Type: {3}, ParentFolderId: {4}",
entry.Name, entry.FolderId, entryIndex, entry.GetType().GetType().FullName, entry.ParentFolderId);
entry.Name, entry.FolderId, entryIndex, entry.GetType().FullName, entry.ParentFolderId);
if (entry is DirectoryFolder)
{

View File

@@ -1,58 +1,61 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectType>Program</ProjectType>
<Configurations>Debug;Release;Debug 4.7.2</Configurations>
</PropertyGroup>
<PropertyGroup>
<RootNamespace>PepperDash.Essentials</RootNamespace>
<AssemblyName>PepperDashEssentials</AssemblyName>
<TargetFrameworks>net472;net6</TargetFrameworks>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<Title>PepperDash Essentials</Title>
<PackageId>PepperDashEssentials</PackageId>
<Version>2.0.0-local</Version>
<InformationalVersion>$(Version)</InformationalVersion>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 4.7.2|AnyCPU'">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<ItemGroup>
<None Include="Example Configuration\EssentialsHuddleSpaceRoom\configurationFile-HuddleSpace-2-Source.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Example Configuration\EssentialsHuddleVtc1Room\configurationFile-mockVideoCodec_din-ap3_-_dm4x1.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Example Configuration\SIMPLBridging\configurationFile-dmps3300c-avRouting.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Example Configuration\SIMPLBridging\SIMPLBridgeExample_configurationFile.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="SGD\PepperDash Essentials iPad.sgd">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="SGD\PepperDash Essentials TSW-560.sgd">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="SGD\PepperDash Essentials TSW-760.sgd">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.20.66" />
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-424" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
<ProjectReference Include="..\PepperDash.Essentials.Devices.Common\PepperDash.Essentials.Devices.Common.csproj" />
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectType>Program</ProjectType>
<Configurations>Debug;Release;Debug 4.7.2</Configurations>
</PropertyGroup>
<PropertyGroup>
<RootNamespace>PepperDash.Essentials</RootNamespace>
<AssemblyName>PepperDashEssentials</AssemblyName>
<TargetFrameworks>net472</TargetFrameworks>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<Title>PepperDash Essentials</Title>
<PackageId>PepperDashEssentials</PackageId>
<Version>2.0.0-local</Version>
<InformationalVersion>$(Version)</InformationalVersion>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 4.7.2|AnyCPU'">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<ItemGroup>
<None Include="Example Configuration\EssentialsHuddleSpaceRoom\configurationFile-HuddleSpace-2-Source.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Example Configuration\EssentialsHuddleVtc1Room\configurationFile-mockVideoCodec_din-ap3_-_dm4x1.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Example Configuration\SIMPLBridging\configurationFile-dmps3300c-avRouting.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Example Configuration\SIMPLBridging\SIMPLBridgeExample_configurationFile.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="SGD\PepperDash Essentials iPad.sgd">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="SGD\PepperDash Essentials TSW-560.sgd">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="SGD\PepperDash Essentials TSW-760.sgd">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.21.90" />
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-455" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net6'">
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
<ProjectReference Include="..\PepperDash.Essentials.Devices.Common\PepperDash.Essentials.Devices.Common.csproj" />
</ItemGroup>
</Project>