mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-01-22 08:55:21 +00:00
Compare commits
228 Commits
2.0.0-alph
...
v2.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5df7b57c43 | ||
|
|
7631c7a8a1 | ||
|
|
16e2529378 | ||
|
|
8f485071c6 | ||
|
|
4eabd82878 | ||
|
|
edfe77cd02 | ||
|
|
fd593d7117 | ||
|
|
a141b365ab | ||
|
|
68ddd76ba5 | ||
|
|
9330ebeae2 | ||
|
|
b398e73024 | ||
|
|
7a2b2eece6 | ||
|
|
543176bb08 | ||
|
|
237fff5398 | ||
|
|
b2eab21fbd | ||
|
|
f2545fb1cf | ||
|
|
27072e3475 | ||
|
|
e4755ed9df | ||
|
|
316867caf8 | ||
|
|
d8fd774324 | ||
|
|
e0058d8cfe | ||
|
|
a055d06bc6 | ||
|
|
66cb592c70 | ||
|
|
d53a5607e2 | ||
|
|
34f59f1410 | ||
|
|
261779d4c4 | ||
|
|
30d5e2b081 | ||
|
|
5516ed16c3 | ||
|
|
8108b9dfdb | ||
|
|
fb4f1482c7 | ||
|
|
54dcb5de08 | ||
|
|
4ef481375c | ||
|
|
d8a88b2a07 | ||
|
|
cc724ddf19 | ||
|
|
e29e800d9d | ||
|
|
134e8ba02e | ||
|
|
a83ba444d3 | ||
|
|
f4c5e6fbeb | ||
|
|
35d7994cc8 | ||
|
|
c3e9d654c9 | ||
|
|
f68b1e9e49 | ||
|
|
cd81b8af73 | ||
|
|
cd52c245a6 | ||
|
|
0b60f53d0e | ||
|
|
ffed2dea8a | ||
|
|
936dce2046 | ||
|
|
b33704eabe | ||
|
|
aca6fe9af5 | ||
|
|
332faaa9cc | ||
|
|
4449077a39 | ||
|
|
86ba9e0f16 | ||
|
|
db2d8a213d | ||
|
|
590e16298c | ||
|
|
1a11e9019c | ||
|
|
0e16dff90c | ||
|
|
d11827bc7b | ||
|
|
631dd2b00d | ||
|
|
639cd2abfb | ||
|
|
f04f70495f | ||
|
|
fa38e8a9a8 | ||
|
|
f351c036ed | ||
|
|
0a7da79356 | ||
|
|
82ebf45921 | ||
|
|
d0dbe986f3 | ||
|
|
aa503f3b29 | ||
|
|
90251d92df | ||
|
|
778af651d0 | ||
|
|
2e31719a84 | ||
|
|
a96fb21898 | ||
|
|
3f45372e1e | ||
|
|
60dbaf547d | ||
|
|
941e537d53 | ||
|
|
f7c5e18af8 | ||
|
|
ab73bbf979 | ||
|
|
1fb1947158 | ||
|
|
e374f7b50f | ||
|
|
7a263a644a | ||
|
|
97bd30e9c9 | ||
|
|
63c653b21f | ||
|
|
c56841d95b | ||
|
|
64d6df70b0 | ||
|
|
d970d806c9 | ||
|
|
5a9b876d80 | ||
|
|
fb60683af6 | ||
|
|
e7d7b8638e | ||
|
|
0eb2436fa0 | ||
|
|
192991cc65 | ||
|
|
421f87db5e | ||
|
|
b63996b9e6 | ||
|
|
bc217a2008 | ||
|
|
fec6b0d385 | ||
|
|
f3b4c0aa02 | ||
|
|
a3351812cd | ||
|
|
71815eff17 | ||
|
|
c7f4bf1fb2 | ||
|
|
bec3ab8e73 | ||
|
|
c499d2a2eb | ||
|
|
d9721a362e | ||
|
|
5fb6f3e117 | ||
|
|
c2fb44a662 | ||
|
|
0f9bddf4dd | ||
|
|
ddc2491664 | ||
|
|
9a6209f50a | ||
|
|
49852d25e8 | ||
|
|
ba4ca20936 | ||
|
|
c50726f813 | ||
|
|
0aafe8a62e | ||
|
|
71005940ac | ||
|
|
e5e79316a6 | ||
|
|
eb388d28db | ||
|
|
5aa1f85df5 | ||
|
|
7bac65002d | ||
|
|
ed0141a536 | ||
|
|
25ebcdfb5d | ||
|
|
b326ccf6c3 | ||
|
|
3a56e47c48 | ||
|
|
171bd6b1ec | ||
|
|
e61fd7777a | ||
|
|
027bdd5bf4 | ||
|
|
b876b8123d | ||
|
|
6e05653c6c | ||
|
|
16d32bc720 | ||
|
|
0bef5d4b77 | ||
|
|
a3c1572a77 | ||
|
|
cc06c7bfd8 | ||
|
|
00a7b25026 | ||
|
|
edc916c9d3 | ||
|
|
c755ecb16c | ||
|
|
a8c36ba243 | ||
|
|
f630d3f410 | ||
|
|
35e0662b27 | ||
|
|
effefc939c | ||
|
|
5afdc2effa | ||
|
|
448cc273ec | ||
|
|
0a2aaa693f | ||
|
|
1ebee58ad6 | ||
|
|
3c5fe88e5a | ||
|
|
8255328be1 | ||
|
|
4bf026601f | ||
|
|
888f1b3888 | ||
|
|
19bd5723c8 | ||
|
|
e3e7add5b9 | ||
|
|
dd66de0463 | ||
|
|
3823943cd9 | ||
|
|
577e111f26 | ||
|
|
528fff569d | ||
|
|
06a6b1caa2 | ||
|
|
621d848418 | ||
|
|
2f9038a501 | ||
|
|
983b18d25a | ||
|
|
048004d441 | ||
|
|
e7e448f02c | ||
|
|
2e61d8d709 | ||
|
|
d8d2c5b340 | ||
|
|
7e736ae519 | ||
|
|
0067e11d3d | ||
|
|
7942c91f73 | ||
|
|
e1638762a1 | ||
|
|
3566400379 | ||
|
|
dde85f39a2 | ||
|
|
735433f660 | ||
|
|
734149960b | ||
|
|
cb16f2a505 | ||
|
|
a2b7a39082 | ||
|
|
428f9f34bd | ||
|
|
78e49871c6 | ||
|
|
a95d44e405 | ||
|
|
12e81af9e6 | ||
|
|
5820c9d282 | ||
|
|
4d19ecde00 | ||
|
|
826b7fd6d5 | ||
|
|
cb9eb5dafa | ||
|
|
eb955aa014 | ||
|
|
2d9ffca78e | ||
|
|
98f1a09c25 | ||
|
|
a11ad421f0 | ||
|
|
8878ff7ddd | ||
|
|
7e4b5f984f | ||
|
|
64ab315142 | ||
|
|
c47a93f4d0 | ||
|
|
5a55a701d6 | ||
|
|
01862ab9aa | ||
|
|
8ec6fa785e | ||
|
|
e37c675da1 | ||
|
|
3ee8cb7ea3 | ||
|
|
e9954b3081 | ||
|
|
544a7a2d73 | ||
|
|
1d843c6c89 | ||
|
|
e1b50649fd | ||
|
|
5e69ea1947 | ||
|
|
c72db72e7e | ||
|
|
fd1b92a6c0 | ||
|
|
06d806687d | ||
|
|
d8e2f8cd51 | ||
|
|
9e588f4da5 | ||
|
|
4c466b425c | ||
|
|
d0aed1c1c5 | ||
|
|
bf966121f9 | ||
|
|
ecadb439b2 | ||
|
|
8c1553a026 | ||
|
|
9755724342 | ||
|
|
4d25c420e5 | ||
|
|
3190dacdf8 | ||
|
|
44add9aac6 | ||
|
|
5bb6405874 | ||
|
|
fed3d7e13a | ||
|
|
af848b9ca4 | ||
|
|
b52c13d8e8 | ||
|
|
26f9118154 | ||
|
|
bba3c347c6 | ||
|
|
be96adcc06 | ||
|
|
b245016420 | ||
|
|
19f2c6aa79 | ||
|
|
533ca05ac2 | ||
|
|
9c7777fbaa | ||
|
|
5530c91b75 | ||
|
|
67e0378806 | ||
|
|
1c5aca03d2 | ||
|
|
6f5fa2c3b8 | ||
|
|
3d760cbedc | ||
|
|
d713abf614 | ||
|
|
a64b5240ad | ||
|
|
c528fecb9a | ||
|
|
355e9cde12 | ||
|
|
1df8d3f617 | ||
|
|
2f1caff815 | ||
|
|
4da2f25c3d | ||
|
|
d6334538c0 |
21
.github/workflows/EssentialsPlugins-builds-4-series-caller.yml
vendored
Normal file
21
.github/workflows/EssentialsPlugins-builds-4-series-caller.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Build PepperDash Essentials
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
getVersion:
|
||||
uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-getversion.yml@main
|
||||
secrets: inherit
|
||||
build-4Series:
|
||||
uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-4Series-builds.yml@main
|
||||
secrets: inherit
|
||||
needs: getVersion
|
||||
if: needs.getVersion.outputs.newVersion == 'true'
|
||||
with:
|
||||
newVersion: ${{ needs.getVersion.outputs.newVersion }}
|
||||
version: ${{ needs.getVersion.outputs.version }}
|
||||
tag: ${{ needs.getVersion.outputs.tag }}
|
||||
channel: ${{ needs.getVersion.outputs.channel }}
|
||||
94
.github/workflows/docker.yml
vendored
94
.github/workflows/docker.yml
vendored
@@ -1,94 +0,0 @@
|
||||
name: Branch Build Using Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- feature-2.0.0/*
|
||||
- hotfix-2.0.0/*
|
||||
- release-2.0.0/*
|
||||
- development-2.0.0
|
||||
|
||||
env:
|
||||
# solution path doesn't need slashes unless there it is multiple folders deep
|
||||
# solution name does not include extension. .sln is assumed
|
||||
SOLUTION_PATH: .
|
||||
SOLUTION_FILE: PepperDash.Essentials
|
||||
# Do not edit this, we're just creating it here
|
||||
VERSION: 0.0.0-buildtype-buildnumber
|
||||
# Defaults to debug for build type
|
||||
BUILD_TYPE: Debug
|
||||
# Defaults to main as the release branch. Change as necessary
|
||||
RELEASE_BRANCH: main
|
||||
jobs:
|
||||
Build_Project_4-Series:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set Version Number
|
||||
id: setVersion
|
||||
shell: powershell
|
||||
run: |
|
||||
$latestVersion = [version]"2.0.0"
|
||||
|
||||
$newVersion = [version]$latestVersion
|
||||
$phase = ""
|
||||
$newVersionString = ""
|
||||
|
||||
switch -regex ($Env:GITHUB_REF) {
|
||||
'^refs\/pull\/*.' {
|
||||
$phase = 'beta';
|
||||
$newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER
|
||||
}
|
||||
'^refs\/heads\/hotfix-2.0.0\/*.' {
|
||||
$phase = 'hotfix'
|
||||
$newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER
|
||||
}
|
||||
'^refs\/heads\/release-2.0.0\/*.' {
|
||||
$splitRef = $Env:GITHUB_REF -split "/"
|
||||
$version = [version]($splitRef[-1] -replace "v", "")
|
||||
$phase = 'rc'
|
||||
$newVersionString = "{0}-{1}-{2}" -f $version, $phase, $Env:GITHUB_RUN_NUMBER
|
||||
}
|
||||
'^refs\/heads\/feature-2.0.0\/*.' {
|
||||
$phase = 'alpha'
|
||||
$newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER
|
||||
}
|
||||
'development-2.0.0' {
|
||||
$phase = 'beta'
|
||||
$newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER
|
||||
}
|
||||
}
|
||||
echo "version=$newVersionString" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
|
||||
- name: Setup MS Build
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
- name: restore Nuget Packages
|
||||
run: nuget restore .\$($Env:SOLUTION_FILE).sln
|
||||
# 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: Create tag for non-rc builds
|
||||
if: contains(steps.setVersion.outputs.version, 'alpha')
|
||||
run: |
|
||||
git tag ${{ steps.setVersion.outputs.version }}
|
||||
git push --tags origin
|
||||
# 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)'
|
||||
generateReleaseNotes: true
|
||||
prerelease: ${{contains('debug', env.BUILD_TYPE)}}
|
||||
tag: ${{ steps.setVersion.outputs.version }}
|
||||
- name: Setup Nuget
|
||||
run: |
|
||||
nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username pepperdash -password ${{ secrets.GITHUB_TOKEN }}
|
||||
nuget setApiKey ${{ secrets.GITHUB_TOKEN }} -Source github
|
||||
nuget setApiKey ${{ secrets.NUGET_API_KEY }} -Source https://api.nuget.org/v3/index.json
|
||||
- name: Publish to Nuget
|
||||
run: nuget push .\output\*.nupkg -Source https://api.nuget.org/v3/index.json
|
||||
- name: Publish to Github Nuget
|
||||
run: nuget push .\output\*.nupkg -Source github
|
||||
55
.github/workflows/main.yml
vendored
55
.github/workflows/main.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: main Build using Docker
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
branches:
|
||||
- main-2.0.0
|
||||
env:
|
||||
# solution path doesn't need slashes unless there it is multiple folders deep
|
||||
# solution name does not include extension. .sln is assumed
|
||||
SOLUTION_PATH: PepperDashEssentials
|
||||
SOLUTION_FILE: PepperDashEssentials
|
||||
# Do not edit this, we're just creating it here
|
||||
VERSION: 0.0.0-buildtype-buildnumber
|
||||
# Defaults to debug for build type
|
||||
BUILD_TYPE: Release
|
||||
# Defaults to main as the release branch. Change as necessary
|
||||
RELEASE_BRANCH: main
|
||||
jobs:
|
||||
Build_Project:
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
# First we checkout the source repo
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
# Generate the appropriate version number
|
||||
- name: Set Version Number
|
||||
shell: powershell
|
||||
id: setVersion
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: echo "VERSION=$($Env:TAG_NAME)" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
|
||||
- name: Setup MS Build
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
- name: restore Nuget Packages
|
||||
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: Upload Release
|
||||
id: create_release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
updateRelease: true
|
||||
artifacts: 'output\**\*.*(cpz|cplz)'
|
||||
tag: ${{ steps.setVersion.outputs.version }}
|
||||
- name: Setup Nuget
|
||||
run: |
|
||||
nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username pepperdash -password ${{ secrets.GITHUB_TOKEN }}
|
||||
nuget setApiKey ${{ secrets.GITHUB_TOKEN }} -Source github
|
||||
nuget setApiKey ${{ secrets.NUGET_API_KEY }} -Source https://api.nuget.org/v3/index.json
|
||||
- name: Publish to Nuget
|
||||
run: nuget push .\output\*.nupkg -Source https://api.nuget.org/v3/index.json
|
||||
- name: Publish to Github Nuget
|
||||
run: nuget push .\output\*.nupkg -Source github
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -391,3 +391,4 @@ FodyWeavers.xsd
|
||||
essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/PepperDash_Essentials_Interfaces.csproj
|
||||
.DS_Store
|
||||
/._PepperDash.Essentials.sln
|
||||
.vscode/settings.json
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "Essentials-Template-UI"]
|
||||
path = Essentials-Template-UI
|
||||
url = https://github.com/PepperDash/Essentials-Template-UI.git
|
||||
|
||||
36
.releaserc.json
Normal file
36
.releaserc.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"@semantic-release/commit-analyzer",
|
||||
{
|
||||
"releaseRules": [
|
||||
{ "scope": "force-patch", "release": "patch" },
|
||||
{ "scope": "no-release", "release": false }
|
||||
]
|
||||
}
|
||||
],
|
||||
"@semantic-release/release-notes-generator",
|
||||
["@semantic-release/changelog",
|
||||
{
|
||||
"changelogFile": "CHANGELOG.md"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/exec",
|
||||
{
|
||||
"verifyReleaseCmd": "echo \"newVersion=true\" >> $GITHUB_OUTPUT",
|
||||
"publishCmd": "echo \"version=${nextRelease.version}\" >> $GITHUB_OUTPUT && echo \"tag=${nextRelease.gitTag}\" >> $GITHUB_OUTPUT && echo \"type=${nextRelease.type}\" >> $GITHUB_OUTPUT && echo \"channel=${nextRelease.channel}\" >> $GITHUB_OUTPUT"
|
||||
}
|
||||
]
|
||||
],
|
||||
"branches": [
|
||||
"main",
|
||||
{"name": "development", "prerelease": "beta", "channel": "beta"},
|
||||
{"name": "release", "prerelease": "rc", "channel": "rc"},
|
||||
{
|
||||
"name": "replace-me-feature-branch",
|
||||
"prerelease": "replace-me-prerelease",
|
||||
"channel": "replace-me-prerelease"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -91,8 +91,8 @@ we receive and the availability of resources to evaluate contributions, we antic
|
||||
project remains dynamic and relevant. This may affect our responsiveness and ability to accept pull requests
|
||||
quickly. This does not mean we are ignoring them.
|
||||
- Not all innovative ideas need to be accepted as pull requests into this GitHub project to be valuable to the community.
|
||||
There may be times when we recommend that you just share your code for some enhancement to Ghidra from your own
|
||||
repository. As we identify and recognize extensions that are of general interest to the reverse engineering community, we
|
||||
There may be times when we recommend that you just share your code for some enhancement to Essentials from your own
|
||||
repository. As we identify and recognize extensions that are of general interest to Essentials, we
|
||||
may seek to incorporate them with our baseline.
|
||||
|
||||
## Legal
|
||||
|
||||
Submodule Essentials-Template-UI deleted from 8eaf88791b
@@ -0,0 +1,85 @@
|
||||
using System.Collections.Generic;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.GeneralIO;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
|
||||
namespace PepperDash.Essentials.Core.CrestronIO
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper class for CEN-IO-COM-Xxx expander module
|
||||
/// </summary>
|
||||
[Description("Wrapper class for the CEN-IO-COM-102 & CEN-IO-COM-202 expander module")]
|
||||
public class CenIoComController : CrestronGenericBaseDevice, IComPorts
|
||||
{
|
||||
private readonly CenIoCom _cenIoCom;
|
||||
|
||||
public CenIoComController(string key, string name, CenIoCom cenIo)
|
||||
:base(key, name, cenIo)
|
||||
{
|
||||
_cenIoCom = cenIo;
|
||||
}
|
||||
|
||||
#region Implementation of IComPorts
|
||||
|
||||
public CrestronCollection<ComPort> ComPorts
|
||||
{
|
||||
get { return _cenIoCom.ComPorts; }
|
||||
}
|
||||
|
||||
public int NumberOfComPorts
|
||||
{
|
||||
get { return _cenIoCom.NumberOfComPorts; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
public class CenIoCom102ControllerFactory : EssentialsDeviceFactory<CenIoComController>
|
||||
{
|
||||
private const string CenIoCom102Type = "ceniocom102";
|
||||
private const string CenIoCom202Type = "ceniocom202";
|
||||
|
||||
public CenIoCom102ControllerFactory()
|
||||
{
|
||||
TypeNames = new List<string> { CenIoCom102Type, CenIoCom202Type };
|
||||
}
|
||||
|
||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||
{
|
||||
Debug.Console(1, "Factory Attempting to create new CEN-IO-COM-Xxx Device");
|
||||
|
||||
var control = CommFactory.GetControlPropertiesConfig(dc);
|
||||
if (control == null)
|
||||
{
|
||||
Debug.Console(1, "Factory failed to create a new CEN-IO-COM-Xxx Device, control properties not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
var ipid = control.IpIdInt;
|
||||
if (ipid < 2)
|
||||
{
|
||||
Debug.Console(1, "Factory failed to create a new CEN-IO-COM-Xxx Device, invalid IP-ID found");
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (dc.Type)
|
||||
{
|
||||
case CenIoCom102Type:
|
||||
{
|
||||
return new CenIoComController(dc.Key, dc.Name, new CenIoCom102(ipid, Global.ControlSystem));
|
||||
}
|
||||
case CenIoCom202Type:
|
||||
{
|
||||
return new CenIoComController(dc.Key, dc.Name, new CenIoCom202(ipid, Global.ControlSystem));
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug.Console(1, "Factory failed to create a new CEN-IO-COM-Xxx Device, invalid type '{0}'", dc.Type);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
using Crestron.SimplSharpPro.DM;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
|
||||
namespace PepperDash_Essentials_DM.Chassis
|
||||
{
|
||||
public class HdPsXxxAnalogAuxMixerController : IKeyed,
|
||||
IHasVolumeControlWithFeedback, IHasMuteControlWithFeedback
|
||||
{
|
||||
public string Key { get; private set; }
|
||||
|
||||
private readonly HdPsXxxAnalogAuxMixer _mixer;
|
||||
|
||||
public HdPsXxxAnalogAuxMixerController(string parent, uint mixer, HdPsXxx chassis)
|
||||
{
|
||||
Key = string.Format("{0}-analogMixer{1}", parent, mixer);
|
||||
|
||||
_mixer = chassis.AnalogAuxiliaryMixer[mixer];
|
||||
|
||||
_mixer.AuxMixerPropertyChange += OnAuxMixerPropertyChange;
|
||||
_mixer.AuxiliaryMuteControl.MuteAndVolumeControlPropertyChange += OnMuteAndVolumeControlPropertyChange;
|
||||
|
||||
VolumeLevelFeedback = new IntFeedback(() => VolumeLevel);
|
||||
MuteFeedback = new BoolFeedback(() => IsMuted);
|
||||
}
|
||||
|
||||
#region Volume
|
||||
|
||||
private void OnAuxMixerPropertyChange(object sender, GenericEventArgs args)
|
||||
{
|
||||
Debug.Console(2, this, "OnAuxMixerPropertyChange: {0} > Index-{1}, EventId-{2}", sender.ToString(), args.Index, args.EventId);
|
||||
|
||||
switch (args.EventId)
|
||||
{
|
||||
case MuteAndVolumeContorlEventIds.VolumeFeedbackEventId:
|
||||
{
|
||||
VolumeLevel = _mixer.VolumeFeedback.ShortValue;
|
||||
break;
|
||||
}
|
||||
case MuteAndVolumeContorlEventIds.MuteOnEventId:
|
||||
case MuteAndVolumeContorlEventIds.MuteOffEventId:
|
||||
{
|
||||
IsMuted = _mixer.AuxiliaryMuteControl.MuteOnFeedback.BoolValue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug.Console(1, this, "OnAuxMixerPropertyChange: {0} > Index-{1}, EventId-{2} - unhandled eventId", sender.ToString(), args.Index, args.EventId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const ushort CrestronLevelMin = 0;
|
||||
private const ushort CrestronLevelMax = 65535;
|
||||
|
||||
private const int DeviceLevelMin = -800;
|
||||
private const int DeviceLevelMax = 200;
|
||||
|
||||
private const int RampTime = 5000;
|
||||
|
||||
private int _volumeLevel;
|
||||
|
||||
public int VolumeLevel
|
||||
{
|
||||
get { return _volumeLevel; }
|
||||
private set
|
||||
{
|
||||
var level = value;
|
||||
|
||||
_volumeLevel = CrestronEnvironment.ScaleWithLimits(level, DeviceLevelMax, DeviceLevelMin, CrestronLevelMax, CrestronLevelMin);
|
||||
|
||||
Debug.Console(1, this, "VolumeFeedback: level-'{0}', scaled-'{1}'", level, _volumeLevel);
|
||||
|
||||
VolumeLevelFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public IntFeedback VolumeLevelFeedback { get; private set; }
|
||||
|
||||
public void SetVolume(ushort level)
|
||||
{
|
||||
var levelScaled = CrestronEnvironment.ScaleWithLimits(level, CrestronLevelMax, CrestronLevelMin, DeviceLevelMax, DeviceLevelMin);
|
||||
|
||||
Debug.Console(1, this, "SetVolume: level-'{0}', levelScaled-'{1}'", level, levelScaled);
|
||||
|
||||
_mixer.Volume.ShortValue = (short)levelScaled;
|
||||
}
|
||||
|
||||
public void VolumeUp(bool pressRelease)
|
||||
{
|
||||
if (pressRelease)
|
||||
{
|
||||
_mixer.Volume.CreateSignedRamp(DeviceLevelMax, RampTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
_mixer.Volume.StopRamp();
|
||||
}
|
||||
}
|
||||
|
||||
public void VolumeDown(bool pressRelease)
|
||||
{
|
||||
if (pressRelease)
|
||||
{
|
||||
_mixer.Volume.CreateSignedRamp(DeviceLevelMin, RampTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
_mixer.Volume.StopRamp();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
#region Mute
|
||||
|
||||
private void OnMuteAndVolumeControlPropertyChange(MuteControl device, GenericEventArgs args)
|
||||
{
|
||||
Debug.Console(2, this, "OnMuteAndVolumeControlPropertyChange: {0} > Index-{1}, EventId-{2}", device.ToString(), args.Index, args.EventId);
|
||||
|
||||
switch (args.EventId)
|
||||
{
|
||||
case MuteAndVolumeContorlEventIds.VolumeFeedbackEventId:
|
||||
{
|
||||
VolumeLevel = _mixer.VolumeFeedback.ShortValue;
|
||||
break;
|
||||
}
|
||||
case MuteAndVolumeContorlEventIds.MuteOnEventId:
|
||||
case MuteAndVolumeContorlEventIds.MuteOffEventId:
|
||||
{
|
||||
IsMuted = _mixer.AuxiliaryMuteControl.MuteOnFeedback.BoolValue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug.Console(1, this, "OnMuteAndVolumeControlPropertyChange: {0} > Index-{1}, EventId-{2} - unhandled eventId", device.ToString(), args.Index, args.EventId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isMuted;
|
||||
|
||||
public bool IsMuted
|
||||
{
|
||||
get { return _isMuted; }
|
||||
set
|
||||
{
|
||||
_isMuted = value;
|
||||
|
||||
Debug.Console(1, this, "IsMuted: _isMuted-'{0}'", _isMuted);
|
||||
|
||||
MuteFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public BoolFeedback MuteFeedback { get; private set; }
|
||||
|
||||
public void MuteOn()
|
||||
{
|
||||
_mixer.AuxiliaryMuteControl.MuteOn();
|
||||
}
|
||||
|
||||
public void MuteOff()
|
||||
{
|
||||
_mixer.AuxiliaryMuteControl.MuteOff();
|
||||
}
|
||||
|
||||
public void MuteToggle()
|
||||
{
|
||||
if (IsMuted)
|
||||
MuteOff();
|
||||
else
|
||||
MuteOn();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro.DM;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
|
||||
namespace PepperDash_Essentials_DM.Chassis
|
||||
{
|
||||
public class HdPsXxxOutputAudioController : IKeyed,
|
||||
IHasVolumeControlWithFeedback, IHasMuteControlWithFeedback
|
||||
{
|
||||
public string Key { get; private set; }
|
||||
|
||||
private readonly HdPsXxxHdmiDmLiteOutputMixer _mixer; // volume/volumeFeedback
|
||||
private readonly HdPsXxxOutputPort _port; // mute/muteFeedback
|
||||
|
||||
public HdPsXxxOutputAudioController(string parent, uint output, HdPsXxx chassis)
|
||||
{
|
||||
Key = string.Format("{0}-audioOut{1}", parent, output);
|
||||
|
||||
_port = chassis.HdmiDmLiteOutputs[output].OutputPort;
|
||||
_mixer = chassis.HdmiDmLiteOutputs[output].Mixer;
|
||||
|
||||
chassis.DMOutputChange += ChassisOnDmOutputChange;
|
||||
|
||||
VolumeLevelFeedback = new IntFeedback(() => VolumeLevel);
|
||||
MuteFeedback = new BoolFeedback(() => IsMuted);
|
||||
}
|
||||
|
||||
private void ChassisOnDmOutputChange(Switch device, DMOutputEventArgs args)
|
||||
{
|
||||
switch (args.EventId)
|
||||
{
|
||||
case (DMOutputEventIds.VolumeEventId):
|
||||
{
|
||||
Debug.Console(2, this, "HdPsXxxOutputAudioController: {0} > Index-{1}, Number-{3}, EventId-{2} - AudioMute/UnmuteEventId",
|
||||
device.ToString(), args.Index, args.EventId, args.Number);
|
||||
|
||||
VolumeLevel = _mixer.VolumeFeedback.ShortValue;
|
||||
|
||||
break;
|
||||
}
|
||||
case DMOutputEventIds.MuteOnEventId:
|
||||
case DMOutputEventIds.MuteOffEventId:
|
||||
{
|
||||
Debug.Console(2, this, "HdPsXxxOutputAudioController: {0} > Index-{1}, Number-{3}, EventId-{2} - MuteOnEventId/MuteOffEventId",
|
||||
device.ToString(), args.Index, args.EventId, args.Number);
|
||||
|
||||
IsMuted = _port.MuteOnFeedback.BoolValue;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug.Console(1, this, "HdPsXxxOutputAudioController: {0} > Index-{1}, Number-{3}, EventId-{2} - unhandled eventId",
|
||||
device.ToString(), args.Index, args.EventId, args.Number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Volume
|
||||
|
||||
private const ushort CrestronLevelMin = 0;
|
||||
private const ushort CrestronLevelMax = 65535;
|
||||
|
||||
private const int DeviceLevelMin = -800;
|
||||
private const int DeviceLevelMax = 200;
|
||||
|
||||
private const int RampTime = 5000;
|
||||
|
||||
private int _volumeLevel;
|
||||
|
||||
public int VolumeLevel
|
||||
{
|
||||
get { return _volumeLevel; }
|
||||
private set
|
||||
{
|
||||
var level = value;
|
||||
|
||||
_volumeLevel = CrestronEnvironment.ScaleWithLimits(level, DeviceLevelMax, DeviceLevelMin, CrestronLevelMax, CrestronLevelMin);
|
||||
|
||||
Debug.Console(2, this, "VolumeFeedback: level-'{0}', scaled-'{1}'", level, _volumeLevel);
|
||||
|
||||
VolumeLevelFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public IntFeedback VolumeLevelFeedback { get; private set; }
|
||||
|
||||
public void SetVolume(ushort level)
|
||||
{
|
||||
var levelScaled = CrestronEnvironment.ScaleWithLimits(level, CrestronLevelMax, CrestronLevelMin, DeviceLevelMax, DeviceLevelMin);
|
||||
|
||||
Debug.Console(1, this, "SetVolume: level-'{0}', levelScaled-'{1}'", level, levelScaled);
|
||||
|
||||
_mixer.Volume.ShortValue = (short)levelScaled;
|
||||
}
|
||||
|
||||
public void VolumeUp(bool pressRelease)
|
||||
{
|
||||
if (pressRelease)
|
||||
{
|
||||
_mixer.Volume.CreateSignedRamp(DeviceLevelMax, RampTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
_mixer.Volume.StopRamp();
|
||||
}
|
||||
}
|
||||
|
||||
public void VolumeDown(bool pressRelease)
|
||||
{
|
||||
if (pressRelease)
|
||||
{
|
||||
_mixer.Volume.CreateSignedRamp(DeviceLevelMin, RampTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
_mixer.Volume.StopRamp();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
#region Mute
|
||||
|
||||
private bool _isMuted;
|
||||
|
||||
public bool IsMuted
|
||||
{
|
||||
get { return _isMuted; }
|
||||
set
|
||||
{
|
||||
_isMuted = value;
|
||||
|
||||
Debug.Console(1, this, "IsMuted: _isMuted-'{0}'", _isMuted);
|
||||
|
||||
MuteFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public BoolFeedback MuteFeedback { get; private set; }
|
||||
|
||||
public void MuteOn()
|
||||
{
|
||||
_port.MuteOn();
|
||||
}
|
||||
|
||||
public void MuteOff()
|
||||
{
|
||||
_port.MuteOff();
|
||||
}
|
||||
|
||||
public void MuteToggle()
|
||||
{
|
||||
if (IsMuted)
|
||||
MuteOff();
|
||||
else
|
||||
MuteOn();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,41 @@
|
||||
<Project>
|
||||
<ItemGroup>
|
||||
<None Include="$(PackageOutputPath)\$(AssemblyName)\*.cpz" Condition="$(ProjectType) == 'Program'">
|
||||
<None Include="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz" Condition="$(ProjectType) == 'Program'">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>build;</PackagePath>
|
||||
</None>
|
||||
<None Include="$(PackageOutputPath)\$(AssemblyName)\*.cplz" Condition="$(ProjectType) == 'ProgramLibrary'">
|
||||
<None Include="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz" Condition="$(ProjectType) == 'ProgramLibrary'">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>build;</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Target Name="Create CPLZ" AfterTargets="Build; AfterRebuild" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''">
|
||||
<PropertyGroup Condition="$(ProjectType) == 'ProgramLibrary'">
|
||||
<FileName>$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz</FileName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(ProjectType) == 'Program'">
|
||||
<FileName>$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz</FileName>
|
||||
</PropertyGroup>
|
||||
<Target Name="DeleteCPLZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != '' And Exists($(FileName))">
|
||||
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz">
|
||||
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
|
||||
</Delete>
|
||||
<Message Text="Deleted files: '@(DeletedList)'" />
|
||||
</Target>
|
||||
<Target Name="CreateCPLZ" AfterTargets="Build" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''" DependsOnTargets="DeleteCPLZ">
|
||||
<Message Text="Creating CPLZ $(TargetDir)"></Message>
|
||||
<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"/>
|
||||
<MakeDir Directories="$(PackageOutputPath)" Condition="!Exists($(PackageOutputPath))" />
|
||||
<ZipDirectory SourceDirectory="$(TargetDir)" DestinationFile="$(PackageOutputPath)\$(TargetName).$(Version).$(TargetFramework).cplz" Overwrite="true"/>
|
||||
<Copy SourceFiles="$(PackageOutputPath)\$(TargetName).$(Version).$(TargetFramework).cplz" DestinationFiles="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz" />
|
||||
</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="DeleteCPZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'Program' And $(TargetDir) != '' And Exists($(FileName))">
|
||||
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz">
|
||||
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
|
||||
</Delete>
|
||||
<Message Text="Deleted files: '@(DeletedList)'" />
|
||||
</Target>
|
||||
<Target Name="Copy CPZ NET47" AfterTargets="SimplSharpPostProcess47" Condition="($(ProjectType) == 'Program' And ( '$(TargetFramework)' != 'net6.0' ) And ( '$(TargetFramework)' != 'net8.0' ))">
|
||||
<Target Name="Copy CPZ" AfterTargets="SimplSharpPostProcess" 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" />
|
||||
<Move SourceFiles="$(TargetDir)$(TargetName).cpz" DestinationFiles="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz" />
|
||||
<Copy SourceFiles="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz" DestinationFiles="$(PackageOutputPath)\$(TargetName).$(Version).$(TargetFramework).cpz" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
using System.Reflection;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
using Crestron.SimplSharpPro.EthernetCommunication;
|
||||
@@ -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().GetCType()))
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
66
src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs
Normal file
66
src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs
Normal 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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Bridges
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Bridges
|
||||
{
|
||||
|
||||
@@ -93,6 +93,7 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
void OnDataReceived(string s)
|
||||
{
|
||||
var eventSubscribed = false;
|
||||
|
||||
var bytesHandler = BytesReceived;
|
||||
if (bytesHandler != null)
|
||||
@@ -101,6 +102,7 @@ namespace PepperDash.Essentials.Core
|
||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes));
|
||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||
eventSubscribed = true;
|
||||
}
|
||||
var textHandler = TextReceived;
|
||||
if (textHandler != null)
|
||||
@@ -108,7 +110,10 @@ namespace PepperDash.Essentials.Core
|
||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s);
|
||||
textHandler(this, new GenericCommMethodReceiveTextArgs(s));
|
||||
eventSubscribed = true;
|
||||
}
|
||||
|
||||
if(!eventSubscribed) Debug.LogMessage(LogEventLevel.Warning, this, "Received data but no handler is registered");
|
||||
}
|
||||
|
||||
public override bool Deactivate()
|
||||
|
||||
@@ -23,12 +23,12 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (objectType == typeof(ComPort.ComPortSpec))
|
||||
if (objectType == typeof(ComPort.ComPortSpec?))
|
||||
{
|
||||
var newSer = new JsonSerializer();
|
||||
newSer.Converters.Add(new ComSpecPropsJsonConverter());
|
||||
newSer.ObjectCreationHandling = ObjectCreationHandling.Replace;
|
||||
return newSer.Deserialize<ComPort.ComPortSpec>(reader);
|
||||
return newSer.Deserialize<ComPort.ComPortSpec?>(reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ namespace PepperDash.Essentials.Core
|
||||
/// </summary>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(ComPort.ComPortSpec);
|
||||
return objectType == typeof(ComPort.ComPortSpec?);
|
||||
}
|
||||
|
||||
public override bool CanRead { get { return true; } }
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace PepperDash.Essentials.Core
|
||||
switch (controlConfig.Method)
|
||||
{
|
||||
case eControlMethod.Com:
|
||||
comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams, controlConfig);
|
||||
comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams.Value, controlConfig);
|
||||
break;
|
||||
case eControlMethod.Cec:
|
||||
comm = new CecPortController(deviceConfig.Key + "-cec", GetCecPort, controlConfig);
|
||||
@@ -115,7 +115,7 @@ namespace PepperDash.Essentials.Core
|
||||
var comPar = config.ComParams;
|
||||
var dev = GetIComPortsDeviceFromManagedDevice(config.ControlPortDevKey);
|
||||
if (dev != null && config.ControlPortNumber <= dev.NumberOfComPorts)
|
||||
return dev.ComPorts[config.ControlPortNumber];
|
||||
return dev.ComPorts[config.ControlPortNumber.Value];
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber);
|
||||
return null;
|
||||
}
|
||||
@@ -201,23 +201,26 @@ namespace PepperDash.Essentials.Core
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class EssentialsControlPropertiesConfig :
|
||||
PepperDash.Core.ControlPropertiesConfig
|
||||
public class EssentialsControlPropertiesConfig :
|
||||
ControlPropertiesConfig
|
||||
{
|
||||
|
||||
[JsonProperty("comParams", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonConverter(typeof(ComSpecJsonConverter))]
|
||||
public ComPort.ComPortSpec ComParams { get; set; }
|
||||
public ComPort.ComPortSpec? ComParams { get; set; }
|
||||
|
||||
public string CresnetId { get; set; }
|
||||
[JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string CresnetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to provide uint conversion of string CresnetId
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint CresnetIdInt
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
return Convert.ToUInt32(CresnetId, 16);
|
||||
}
|
||||
@@ -228,11 +231,13 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string InfinetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Attepmts to provide uiont conversion of string InifinetId
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint InfinetIdInt
|
||||
{
|
||||
get
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.Net.Http;
|
||||
using Crestron.SimplSharp.Net.Http;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.DebugThings;
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
[Obsolete("Please use the builtin HttpClient class instead: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines")]
|
||||
[Obsolete("Please use the builtin HttpClient class instead: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines")]
|
||||
public class GenericHttpClient : Device, IBasicCommunication
|
||||
{
|
||||
public HttpClient Client;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Crestron.SimplSharpPro;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Config
|
||||
{
|
||||
public class AudioControlPointListItem
|
||||
{
|
||||
[JsonProperty("levelControls")]
|
||||
public Dictionary<string, LevelControlListItem> LevelControls { get; set; } = new Dictionary<string, LevelControlListItem>();
|
||||
|
||||
[JsonProperty("presets")]
|
||||
public Dictionary<string, PresetListItem> Presets { get; set; } = new Dictionary<string, PresetListItem>();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Essentials.Core.Devices;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Config
|
||||
{
|
||||
@@ -23,7 +24,13 @@ namespace PepperDash.Essentials.Core.Config
|
||||
public Dictionary<string, Dictionary<string, SourceListItem>> SourceLists { get; set; }
|
||||
|
||||
[JsonProperty("destinationLists")]
|
||||
public Dictionary<string, Dictionary<string,DestinationListItem>> DestinationLists { get; set; }
|
||||
public Dictionary<string, Dictionary<string, DestinationListItem>> DestinationLists { get; set; }
|
||||
|
||||
[JsonProperty("audioControlPointLists")]
|
||||
public Dictionary<string, AudioControlPointListItem> AudioControlPointLists { get; set; }
|
||||
|
||||
[JsonProperty("cameraLists")]
|
||||
public Dictionary<string, Dictionary<string, CameraListItem>> CameraLists { get; set; }
|
||||
|
||||
[JsonProperty("tieLines")]
|
||||
public List<TieLineConfig> TieLines { get; set; }
|
||||
@@ -37,6 +44,8 @@ namespace PepperDash.Essentials.Core.Config
|
||||
Devices = new List<DeviceConfig>();
|
||||
SourceLists = new Dictionary<string, Dictionary<string, SourceListItem>>();
|
||||
DestinationLists = new Dictionary<string, Dictionary<string, DestinationListItem>>();
|
||||
AudioControlPointLists = new Dictionary<string, AudioControlPointListItem>();
|
||||
CameraLists = new Dictionary<string, Dictionary<string, CameraListItem>>();
|
||||
TieLines = new List<TieLineConfig>();
|
||||
JoinMaps = new Dictionary<string, JObject>();
|
||||
}
|
||||
@@ -46,7 +55,7 @@ namespace PepperDash.Essentials.Core.Config
|
||||
/// </summary>
|
||||
public Dictionary<string, SourceListItem> GetSourceListForKey(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key) || !SourceLists.ContainsKey(key))
|
||||
if (SourceLists == null || string.IsNullOrEmpty(key) || !SourceLists.ContainsKey(key))
|
||||
return null;
|
||||
|
||||
return SourceLists[key];
|
||||
@@ -55,17 +64,41 @@ namespace PepperDash.Essentials.Core.Config
|
||||
/// <summary>
|
||||
/// Retrieves a DestinationListItem based on the key
|
||||
/// </summary>
|
||||
/// <param name="key">key of the item to retrieve</param>
|
||||
/// <returns>DestinationListItem if the key exists, null otherwise</returns>
|
||||
/// <param name="key">key of the list to retrieve</param>
|
||||
/// <returns>DestinationList if the key exists, null otherwise</returns>
|
||||
public Dictionary<string, DestinationListItem> GetDestinationListForKey(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key) || !DestinationLists.ContainsKey(key))
|
||||
if (DestinationLists == null || string.IsNullOrEmpty(key) || !DestinationLists.ContainsKey(key))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return DestinationLists[key];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a AudioControlPointList based on the key
|
||||
/// </summary>
|
||||
/// <param name="key">key of the list to retrieve</param>
|
||||
/// <returns>AudioControlPointList if the key exists, null otherwise</returns>
|
||||
public AudioControlPointListItem GetAudioControlPointListForKey(string key)
|
||||
{
|
||||
if (AudioControlPointLists == null || string.IsNullOrEmpty(key) || !AudioControlPointLists.ContainsKey(key))
|
||||
return null;
|
||||
|
||||
return AudioControlPointLists[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks CameraLists for a given list and returns it if found. Otherwise, returns null
|
||||
/// </summary>
|
||||
public Dictionary<string, CameraListItem> GetCameraListForKey(string key)
|
||||
{
|
||||
if (CameraLists == null || string.IsNullOrEmpty(key) || !CameraLists.ContainsKey(key))
|
||||
return null;
|
||||
|
||||
return CameraLists[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks Devices for an item with a Key that matches and returns it if found. Otherwise, retunes null
|
||||
|
||||
@@ -31,9 +31,17 @@ namespace PepperDash.Essentials.Core.Config
|
||||
if (string.IsNullOrEmpty(SystemUrl))
|
||||
return "missing url";
|
||||
|
||||
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*");
|
||||
string uuid = result.Groups[1].Value;
|
||||
return uuid;
|
||||
if (SystemUrl.Contains("#"))
|
||||
{
|
||||
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*");
|
||||
string uuid = result.Groups[1].Value;
|
||||
return uuid;
|
||||
} else
|
||||
{
|
||||
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/.*");
|
||||
string uuid = result.Groups[1].Value;
|
||||
return uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,10 +52,18 @@ namespace PepperDash.Essentials.Core.Config
|
||||
{
|
||||
if (string.IsNullOrEmpty(TemplateUrl))
|
||||
return "missing template url";
|
||||
|
||||
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/templates\/(.*)\/#.*");
|
||||
string uuid = result.Groups[1].Value;
|
||||
return uuid;
|
||||
|
||||
if (TemplateUrl.Contains("#"))
|
||||
{
|
||||
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/templates\/(.*)\/#.*");
|
||||
string uuid = result.Groups[1].Value;
|
||||
return uuid;
|
||||
} else
|
||||
{
|
||||
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/(.*)\/system-template-versions\/(.*)\/.*");
|
||||
string uuid = result.Groups[2].Value;
|
||||
return uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
|
||||
|
||||
using Crestron.SimplSharp;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the info section of a Config file
|
||||
/// </summary>
|
||||
public class InfoConfig
|
||||
/// <summary>
|
||||
/// Represents the info section of a Config file
|
||||
/// </summary>
|
||||
public class InfoConfig
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,22 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
/// <example>
|
||||
/// See MockDisplay for example implemntation
|
||||
/// </example>
|
||||
public interface IHasInputs<TKey, TSelector>: IKeyName
|
||||
[Obsolete("Use IHasInputs<T> instead. Will be removed for 2.0 release")]
|
||||
public interface IHasInputs<T, TSelector>: IKeyName
|
||||
{
|
||||
ISelectableItems<TKey> Inputs { get; }
|
||||
ISelectableItems<T> Inputs { get; }
|
||||
}
|
||||
|
||||
void SetInput(TSelector selector);
|
||||
|
||||
/// <summary>
|
||||
/// Describes a device that has selectable inputs
|
||||
/// </summary>
|
||||
/// <typeparam name="T">the type to use as the key for each input item. Most likely an enum or string</typeparam>\
|
||||
/// <example>
|
||||
/// See MockDisplay for example implemntation
|
||||
/// </example>
|
||||
public interface IHasInputs<T> : IKeyName
|
||||
{
|
||||
ISelectableItems<T> Inputs { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
public interface IHumiditySensor
|
||||
{
|
||||
/// <summary>
|
||||
/// Reports the relative humidity level. Level ranging from 0 to 100 (for 0% to 100%
|
||||
/// RH). EventIds: HumidityFeedbackFeedbackEventId will trigger to indicate change.
|
||||
/// </summary>
|
||||
IntFeedback HumidityFeedback { get; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,10 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
void AddDeviceMessenger(IMobileControlMessenger messenger);
|
||||
|
||||
bool CheckForDeviceMessenger(string key);
|
||||
}
|
||||
|
||||
IMobileControlRoomMessenger GetRoomMessenger(string key);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a mobile control messenger
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a class that has warm up and cool down
|
||||
/// </summary>
|
||||
public interface IProjectorScreenLiftControl
|
||||
{
|
||||
void Raise();
|
||||
void Lower();
|
||||
BoolFeedback IsInUpPosition { get; }
|
||||
bool InUpPosition { get; }
|
||||
event EventHandler<EventArgs> PositionChanged;
|
||||
string DisplayDeviceKey { get; }
|
||||
eScreenLiftControlType Type { get; } // screen/lift
|
||||
}
|
||||
|
||||
public enum eScreenLiftControlType
|
||||
{
|
||||
lift,
|
||||
screen
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,6 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
Dictionary<TKey, ISelectableItem> Items { get; set; }
|
||||
|
||||
[JsonProperty("currentItem")]
|
||||
string CurrentItem { get; set; }
|
||||
TKey CurrentItem { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
public interface ITemperatureSensor
|
||||
{
|
||||
/// <summary>
|
||||
/// The values will range from -400 to +1760 (for -40° to +176° F) or -400 to +800
|
||||
/// (for -40° to +80° C)in tenths of a degree.
|
||||
/// </summary>
|
||||
IntFeedback TemperatureFeedback { get; }
|
||||
|
||||
|
||||
BoolFeedback TemperatureInCFeedback { get; }
|
||||
|
||||
void SetTemperatureFormat(bool setToC);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public abstract class AudioControlListItemBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Key of the parent device in the DeviceManager
|
||||
/// </summary>
|
||||
[JsonProperty("parentDeviceKey")]
|
||||
public string ParentDeviceKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional key of the item in the parent device
|
||||
/// </summary>
|
||||
[JsonProperty("itemKey")]
|
||||
public string ItemKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A name that will override the items's name on the UI
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the item should be included in the user accessible list
|
||||
/// </summary>
|
||||
[JsonProperty("includeInUserList")]
|
||||
public bool IncludeInUserList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to specify the order of the items in the source list when displayed
|
||||
/// </summary>
|
||||
[JsonProperty("order")]
|
||||
public int Order { get; set; }
|
||||
}
|
||||
}
|
||||
76
src/PepperDash.Essentials.Core/Devices/CameraListItem.cs
Normal file
76
src/PepperDash.Essentials.Core/Devices/CameraListItem.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class CameraListItem
|
||||
{
|
||||
[JsonProperty("deviceKey")]
|
||||
public string DeviceKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the source Device for this, if it exists in DeviceManager
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Device CameraDevice
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_cameraDevice == null)
|
||||
_cameraDevice = DeviceManager.GetDeviceForKey(DeviceKey) as Device;
|
||||
return _cameraDevice;
|
||||
}
|
||||
}
|
||||
Device _cameraDevice;
|
||||
|
||||
/// <summary>
|
||||
/// Gets either the source's Name or this AlternateName property, if
|
||||
/// defined. If source doesn't exist, returns "Missing source"
|
||||
/// </summary>
|
||||
[JsonProperty("preferredName")]
|
||||
public string PreferredName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(Name))
|
||||
{
|
||||
if (CameraDevice == null)
|
||||
return "---";
|
||||
return CameraDevice.Name;
|
||||
}
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A name that will override the source's name on the UI
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Specifies and icon for the source list item
|
||||
/// </summary>
|
||||
[JsonProperty("icon")]
|
||||
public string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Alternate icon
|
||||
/// </summary>
|
||||
[JsonProperty("altIcon", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string AltIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the item should be included in the user facing list
|
||||
/// </summary>
|
||||
[JsonProperty("includeInUserList")]
|
||||
public bool IncludeInUserList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to specify the order of the items in the source list when displayed
|
||||
/// </summary>
|
||||
[JsonProperty("order")]
|
||||
public int Order { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,131 +1,203 @@
|
||||
|
||||
|
||||
using Crestron.SimplSharp;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class DeviceJsonApi
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="json"></param>
|
||||
public static void DoDeviceActionWithJson(string json)
|
||||
{
|
||||
if (String.IsNullOrEmpty(json))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
"Please provide a JSON object matching the format {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}.\r\nIf the method has no parameters, the \"params\" object may be omitted.");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var action = JsonConvert.DeserializeObject<DeviceActionWrapper>(json);
|
||||
public class DeviceJsonApi
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="json"></param>
|
||||
public static void DoDeviceActionWithJson(string json)
|
||||
{
|
||||
if (String.IsNullOrEmpty(json))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
"Please provide a JSON object matching the format {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}.\r\nIf the method has no parameters, the \"params\" object may be omitted.");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var action = JsonConvert.DeserializeObject<DeviceActionWrapper>(json);
|
||||
|
||||
DoDeviceAction(action);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Incorrect format for JSON. Please check that the format matches {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}");
|
||||
}
|
||||
|
||||
}
|
||||
DoDeviceAction(action);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Incorrect format for JSON. Please check that the format matches {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
public static void DoDeviceAction(DeviceActionWrapper action)
|
||||
{
|
||||
var key = action.DeviceKey;
|
||||
var obj = FindObjectOnPath(key);
|
||||
if (obj == null)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to find object at path {0}", key);
|
||||
return;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
public static void DoDeviceAction(DeviceActionWrapper action)
|
||||
{
|
||||
var key = action.DeviceKey;
|
||||
var obj = FindObjectOnPath(key);
|
||||
if (obj == null)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to find object at path {0}", key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action.Params == null)
|
||||
{
|
||||
if (action.Params == null)
|
||||
{
|
||||
//no params, so setting action.Params to empty array
|
||||
action.Params = new object[0];
|
||||
}
|
||||
action.Params = new object[0];
|
||||
}
|
||||
|
||||
CType t = obj.GetType();
|
||||
try
|
||||
{
|
||||
var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList();
|
||||
Type t = obj.GetType();
|
||||
try
|
||||
{
|
||||
var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList();
|
||||
|
||||
var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length);
|
||||
var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length);
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
"Unable to find method with name {0} and that matches parameters {1}", action.MethodName,
|
||||
action.Params);
|
||||
return;
|
||||
}
|
||||
if (method == null)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
"Unable to find method with name {0} and that matches parameters {1}", action.MethodName,
|
||||
action.Params);
|
||||
return;
|
||||
}
|
||||
var mParams = method.GetParameters();
|
||||
|
||||
var convertedParams = mParams
|
||||
.Select((p, i) => ConvertType(action.Params[i], p.ParameterType))
|
||||
.ToArray();
|
||||
method.Invoke(obj, convertedParams);
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name,
|
||||
action.DeviceKey);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to call method with name {0}. {1}", action.MethodName,
|
||||
ex.Message);}
|
||||
}
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey);
|
||||
method.Invoke(obj, convertedParams);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey);
|
||||
}
|
||||
});
|
||||
|
||||
private static object ConvertType(object value, Type conversionType)
|
||||
{
|
||||
if (!conversionType.IsEnum)
|
||||
{
|
||||
return Convert.ChangeType(value, conversionType, System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name,
|
||||
action.DeviceKey);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to call method with name {0}. {1}", action.MethodName,
|
||||
ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
var stringValue = Convert.ToString(value);
|
||||
public static async Task DoDeviceActionAsync(DeviceActionWrapper action)
|
||||
{
|
||||
var key = action.DeviceKey;
|
||||
var obj = FindObjectOnPath(key);
|
||||
if (obj == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Warning, "Unable to find object at path {deviceKey}", null, key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(stringValue))
|
||||
{
|
||||
throw new InvalidCastException(
|
||||
String.Format("{0} cannot be converted to a string prior to conversion to enum"));
|
||||
}
|
||||
return Enum.Parse(conversionType, stringValue, true);
|
||||
}
|
||||
if (action.Params == null)
|
||||
{
|
||||
//no params, so setting action.Params to empty array
|
||||
action.Params = new object[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the properties on a device
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetProperties(string deviceObjectPath)
|
||||
{
|
||||
var obj = FindObjectOnPath(deviceObjectPath);
|
||||
if (obj == null)
|
||||
return "{ \"error\":\"No Device\"}";
|
||||
Type t = obj.GetType();
|
||||
try
|
||||
{
|
||||
var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList();
|
||||
|
||||
CType t = obj.GetType();
|
||||
// get the properties and set them into a new collection of NameType wrappers
|
||||
var props = t.GetProperties().Select(p => new PropertyNameType(p, obj));
|
||||
return JsonConvert.SerializeObject(props, Formatting.Indented);
|
||||
}
|
||||
var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length);
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Warning,
|
||||
"Unable to find method with name {methodName} and that matches parameters {@parameters}", null, action.MethodName,
|
||||
action.Params);
|
||||
return;
|
||||
}
|
||||
var mParams = method.GetParameters();
|
||||
|
||||
var convertedParams = mParams
|
||||
.Select((p, i) => ConvertType(action.Params[i], p.ParameterType))
|
||||
.ToArray();
|
||||
|
||||
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)
|
||||
{
|
||||
await task;
|
||||
}
|
||||
// If the method returns a Task<T>, await it
|
||||
else if (result != null && result.GetType().IsGenericType && result.GetType().GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
await (Task)result;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Unable to call method with name {methodName} with {@parameters}", null, action.MethodName, action.Params);
|
||||
}
|
||||
}
|
||||
|
||||
private static object ConvertType(object value, Type conversionType)
|
||||
{
|
||||
if (!conversionType.IsEnum)
|
||||
{
|
||||
return Convert.ChangeType(value, conversionType, System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
var stringValue = Convert.ToString(value);
|
||||
|
||||
if (String.IsNullOrEmpty(stringValue))
|
||||
{
|
||||
throw new InvalidCastException(
|
||||
String.Format("{0} cannot be converted to a string prior to conversion to enum"));
|
||||
}
|
||||
return Enum.Parse(conversionType, stringValue, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the properties on a device
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetProperties(string deviceObjectPath)
|
||||
{
|
||||
var obj = FindObjectOnPath(deviceObjectPath);
|
||||
if (obj == null)
|
||||
return "{ \"error\":\"No Device\"}";
|
||||
|
||||
Type t = obj.GetType();
|
||||
// get the properties and set them into a new collection of NameType wrappers
|
||||
var props = t.GetProperties().Select(p => new PropertyNameType(p, obj));
|
||||
return JsonConvert.SerializeObject(props, Formatting.Indented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property from a device path by name
|
||||
@@ -136,10 +208,10 @@ namespace PepperDash.Essentials.Core
|
||||
public static object GetPropertyByName(string deviceObjectPath, string propertyName)
|
||||
{
|
||||
var dev = FindObjectOnPath(deviceObjectPath);
|
||||
if(dev == null)
|
||||
if (dev == null)
|
||||
return "{ \"error\":\"No Device\"}";
|
||||
|
||||
object prop = dev.GetType().GetCType().GetProperty(propertyName).GetValue(dev, null);
|
||||
|
||||
object prop = dev.GetType().GetProperty(propertyName).GetValue(dev, null);
|
||||
|
||||
// var prop = t.GetProperty(propertyName);
|
||||
if (prop != null)
|
||||
@@ -153,126 +225,126 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the methods on a device
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMethods(string deviceObjectPath)
|
||||
{
|
||||
var obj = FindObjectOnPath(deviceObjectPath);
|
||||
if (obj == null)
|
||||
return "{ \"error\":\"No Device\"}";
|
||||
/// <summary>
|
||||
/// Gets the methods on a device
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMethods(string deviceObjectPath)
|
||||
{
|
||||
var obj = FindObjectOnPath(deviceObjectPath);
|
||||
if (obj == null)
|
||||
return "{ \"error\":\"No Device\"}";
|
||||
|
||||
// Package up method names using helper objects
|
||||
CType t = obj.GetType();
|
||||
var methods = t.GetMethods()
|
||||
.Where(m => !m.IsSpecialName)
|
||||
.Select(p => new MethodNameParams(p));
|
||||
return JsonConvert.SerializeObject(methods, Formatting.Indented);
|
||||
}
|
||||
// Package up method names using helper objects
|
||||
Type t = obj.GetType();
|
||||
var methods = t.GetMethods()
|
||||
.Where(m => !m.IsSpecialName)
|
||||
.Select(p => new MethodNameParams(p));
|
||||
return JsonConvert.SerializeObject(methods, Formatting.Indented);
|
||||
}
|
||||
|
||||
public static string GetApiMethods(string deviceObjectPath)
|
||||
{
|
||||
var obj = FindObjectOnPath(deviceObjectPath);
|
||||
if (obj == null)
|
||||
return "{ \"error\":\"No Device\"}";
|
||||
public static string GetApiMethods(string deviceObjectPath)
|
||||
{
|
||||
var obj = FindObjectOnPath(deviceObjectPath);
|
||||
if (obj == null)
|
||||
return "{ \"error\":\"No Device\"}";
|
||||
|
||||
// Package up method names using helper objects
|
||||
CType t = obj.GetType();
|
||||
var methods = t.GetMethods()
|
||||
.Where(m => !m.IsSpecialName)
|
||||
.Where(m => m.GetCustomAttributes(typeof(ApiAttribute), true).Any())
|
||||
.Select(p => new MethodNameParams(p));
|
||||
return JsonConvert.SerializeObject(methods, Formatting.Indented);
|
||||
}
|
||||
|
||||
// Package up method names using helper objects
|
||||
Type t = obj.GetType();
|
||||
var methods = t.GetMethods()
|
||||
.Where(m => !m.IsSpecialName)
|
||||
.Where(m => m.GetCustomAttributes(typeof(ApiAttribute), true).Any())
|
||||
.Select(p => new MethodNameParams(p));
|
||||
return JsonConvert.SerializeObject(methods, Formatting.Indented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Walks down a dotted object path, starting with a Device, and returns the object
|
||||
/// at the end of the path
|
||||
/// </summary>
|
||||
public static object FindObjectOnPath(string deviceObjectPath)
|
||||
{
|
||||
var path = deviceObjectPath.Split('.');
|
||||
|
||||
var dev = DeviceManager.GetDeviceForKey(path[0]);
|
||||
if (dev == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device {0} not found", path[0]);
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Walks down a dotted object path, starting with a Device, and returns the object
|
||||
/// at the end of the path
|
||||
/// </summary>
|
||||
public static object FindObjectOnPath(string deviceObjectPath)
|
||||
{
|
||||
var path = deviceObjectPath.Split('.');
|
||||
|
||||
// loop through any dotted properties
|
||||
object obj = dev;
|
||||
if (path.Length > 1)
|
||||
{
|
||||
for (int i = 1; i < path.Length; i++)
|
||||
{
|
||||
var objName = path[i];
|
||||
string indexStr = null;
|
||||
var indexOpen = objName.IndexOf('[');
|
||||
if (indexOpen != -1)
|
||||
{
|
||||
var indexClose = objName.IndexOf(']');
|
||||
if (indexClose == -1)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, dev, "ERROR Unmatched index brackets");
|
||||
return null;
|
||||
}
|
||||
// Get the index and strip quotes if any
|
||||
indexStr = objName.Substring(indexOpen + 1, indexClose - indexOpen - 1).Replace("\"", "");
|
||||
objName = objName.Substring(0, indexOpen);
|
||||
Debug.LogMessage(LogEventLevel.Information, dev, " Checking for collection '{0}', index '{1}'", objName, indexStr);
|
||||
}
|
||||
var dev = DeviceManager.GetDeviceForKey(path[0]);
|
||||
if (dev == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device {0} not found", path[0]);
|
||||
return null;
|
||||
}
|
||||
|
||||
CType oType = obj.GetType();
|
||||
var prop = oType.GetProperty(objName);
|
||||
if (prop == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} not found on {1}", objName, path[i - 1]);
|
||||
return null;
|
||||
}
|
||||
// if there's an index, try to get the property
|
||||
if (indexStr != null)
|
||||
{
|
||||
if (!typeof(ICollection).IsAssignableFrom(prop.PropertyType))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} is not collection", objName);
|
||||
return null;
|
||||
}
|
||||
var collection = prop.GetValue(obj, null) as ICollection;
|
||||
// Get the indexed items "property"
|
||||
var indexedPropInfo = prop.PropertyType.GetProperty("Item");
|
||||
// These are the parameters for the indexing. Only care about one
|
||||
var indexParams = indexedPropInfo.GetIndexParameters();
|
||||
if (indexParams.Length > 0)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, " Indexed, param type: {0}", indexParams[0].ParameterType.Name);
|
||||
var properParam = Convert.ChangeType(indexStr, indexParams[0].ParameterType,
|
||||
System.Globalization.CultureInfo.InvariantCulture);
|
||||
try
|
||||
{
|
||||
obj = indexedPropInfo.GetValue(collection, new object[] { properParam });
|
||||
}
|
||||
// if the index is bad, catch it here.
|
||||
catch (Crestron.SimplSharp.Reflection.TargetInvocationException e)
|
||||
{
|
||||
if (e.InnerException is ArgumentOutOfRangeException)
|
||||
Debug.LogMessage(LogEventLevel.Information, " Index Out of range");
|
||||
else if (e.InnerException is KeyNotFoundException)
|
||||
Debug.LogMessage(LogEventLevel.Information, " Key not found");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// loop through any dotted properties
|
||||
object obj = dev;
|
||||
if (path.Length > 1)
|
||||
{
|
||||
for (int i = 1; i < path.Length; i++)
|
||||
{
|
||||
var objName = path[i];
|
||||
string indexStr = null;
|
||||
var indexOpen = objName.IndexOf('[');
|
||||
if (indexOpen != -1)
|
||||
{
|
||||
var indexClose = objName.IndexOf(']');
|
||||
if (indexClose == -1)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, dev, "ERROR Unmatched index brackets");
|
||||
return null;
|
||||
}
|
||||
// Get the index and strip quotes if any
|
||||
indexStr = objName.Substring(indexOpen + 1, indexClose - indexOpen - 1).Replace("\"", "");
|
||||
objName = objName.Substring(0, indexOpen);
|
||||
Debug.LogMessage(LogEventLevel.Information, dev, " Checking for collection '{0}', index '{1}'", objName, indexStr);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
obj = prop.GetValue(obj, null);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
Type oType = obj.GetType();
|
||||
var prop = oType.GetProperty(objName);
|
||||
if (prop == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} not found on {1}", objName, path[i - 1]);
|
||||
return null;
|
||||
}
|
||||
// if there's an index, try to get the property
|
||||
if (indexStr != null)
|
||||
{
|
||||
if (!typeof(ICollection).IsAssignableFrom(prop.PropertyType))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} is not collection", objName);
|
||||
return null;
|
||||
}
|
||||
var collection = prop.GetValue(obj, null) as ICollection;
|
||||
// Get the indexed items "property"
|
||||
var indexedPropInfo = prop.PropertyType.GetProperty("Item");
|
||||
// These are the parameters for the indexing. Only care about one
|
||||
var indexParams = indexedPropInfo.GetIndexParameters();
|
||||
if (indexParams.Length > 0)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, " Indexed, param type: {0}", indexParams[0].ParameterType.Name);
|
||||
var properParam = Convert.ChangeType(indexStr, indexParams[0].ParameterType,
|
||||
System.Globalization.CultureInfo.InvariantCulture);
|
||||
try
|
||||
{
|
||||
obj = indexedPropInfo.GetValue(collection, new object[] { properParam });
|
||||
}
|
||||
// if the index is bad, catch it here.
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
if (e.InnerException is ArgumentOutOfRangeException)
|
||||
Debug.LogMessage(LogEventLevel.Information, " Index Out of range");
|
||||
else if (e.InnerException is KeyNotFoundException)
|
||||
Debug.LogMessage(LogEventLevel.Information, " Key not found");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
obj = prop.GetValue(obj, null);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a property on an object.
|
||||
@@ -287,7 +359,7 @@ namespace PepperDash.Essentials.Core
|
||||
//if (obj == null)
|
||||
// return "{\"error\":\"No object found\"}";
|
||||
|
||||
//CType t = obj.GetType();
|
||||
//Type t = obj.GetType();
|
||||
|
||||
|
||||
//// get the properties and set them into a new collection of NameType wrappers
|
||||
@@ -295,78 +367,85 @@ namespace PepperDash.Essentials.Core
|
||||
//return JsonConvert.SerializeObject(props, Formatting.Indented);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class DeviceActionWrapper
|
||||
{
|
||||
public string DeviceKey { get; set; }
|
||||
public string MethodName { get; set; }
|
||||
public object[] Params { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public class PropertyNameType
|
||||
{
|
||||
object Parent;
|
||||
public class DeviceActionWrapper
|
||||
{
|
||||
public string DeviceKey { get; set; }
|
||||
public string MethodName { get; set; }
|
||||
public object[] Params { get; set; }
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public PropertyInfo PropInfo { get; private set; }
|
||||
public string Name { get { return PropInfo.Name; } }
|
||||
public string Type { get { return PropInfo.PropertyType.Name; } }
|
||||
public string Value { get
|
||||
public class PropertyNameType
|
||||
{
|
||||
private object Parent;
|
||||
|
||||
[JsonIgnore]
|
||||
public PropertyInfo PropInfo { get; private set; }
|
||||
public string Name { get { return PropInfo.Name; } }
|
||||
public string Type { get { return PropInfo.PropertyType.Name; } }
|
||||
public string Value
|
||||
{
|
||||
if (PropInfo.CanRead)
|
||||
get
|
||||
{
|
||||
try
|
||||
if (PropInfo.CanRead)
|
||||
{
|
||||
return PropInfo.GetValue(Parent, null).ToString();
|
||||
try
|
||||
{
|
||||
return PropInfo.GetValue(Parent, null).ToString();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
return null;
|
||||
} }
|
||||
}
|
||||
|
||||
public bool CanRead { get { return PropInfo.CanRead; } }
|
||||
public bool CanWrite { get { return PropInfo.CanWrite; } }
|
||||
|
||||
|
||||
public PropertyNameType(PropertyInfo info, object parent)
|
||||
{
|
||||
PropInfo = info;
|
||||
public PropertyNameType(PropertyInfo info, object parent)
|
||||
{
|
||||
PropInfo = info;
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodNameParams
|
||||
{
|
||||
[JsonIgnore]
|
||||
public MethodInfo MethodInfo { get; private set; }
|
||||
public class MethodNameParams
|
||||
{
|
||||
[JsonIgnore]
|
||||
public MethodInfo MethodInfo { get; private set; }
|
||||
|
||||
public string Name { get { return MethodInfo.Name; } }
|
||||
public IEnumerable<NameType> Params { get {
|
||||
return MethodInfo.GetParameters().Select(p =>
|
||||
new NameType { Name = p.Name, Type = p.ParameterType.Name });
|
||||
} }
|
||||
public string Name { get { return MethodInfo.Name; } }
|
||||
public IEnumerable<NameType> Params
|
||||
{
|
||||
get
|
||||
{
|
||||
return MethodInfo.GetParameters().Select(p =>
|
||||
new NameType { Name = p.Name, Type = p.ParameterType.Name });
|
||||
}
|
||||
}
|
||||
|
||||
public MethodNameParams(MethodInfo info)
|
||||
{
|
||||
MethodInfo = info;
|
||||
}
|
||||
}
|
||||
public MethodNameParams(MethodInfo info)
|
||||
{
|
||||
MethodInfo = info;
|
||||
}
|
||||
}
|
||||
|
||||
public class NameType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
public class NameType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public class ApiAttribute : CAttribute
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public class ApiAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public static class DeviceManager
|
||||
{
|
||||
public static class DeviceManager
|
||||
{
|
||||
public static event EventHandler<EventArgs> AllDevicesActivated;
|
||||
public static event EventHandler<EventArgs> AllDevicesRegistered;
|
||||
public static event EventHandler<EventArgs> AllDevicesInitialized;
|
||||
|
||||
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
|
||||
private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
|
||||
//public static List<Device> Devices { get { return _Devices; } }
|
||||
//static List<Device> _Devices = new List<Device>();
|
||||
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
|
||||
private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
|
||||
|
||||
static readonly Dictionary<string, IKeyed> Devices = new Dictionary<string, IKeyed>(StringComparer.OrdinalIgnoreCase);
|
||||
//public static List<Device> Devices { get { return _Devices; } }
|
||||
//static List<Device> _Devices = new List<Device>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of all the devices in a list
|
||||
/// </summary>
|
||||
public static List<IKeyed> AllDevices { get { return new List<IKeyed>(Devices.Values); } }
|
||||
private static readonly Dictionary<string, IKeyed> Devices = new Dictionary<string, IKeyed>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static bool AddDeviceEnabled;
|
||||
/// <summary>
|
||||
/// Returns a copy of all the devices in a list
|
||||
/// </summary>
|
||||
public static List<IKeyed> AllDevices { get { return new List<IKeyed>(Devices.Values); } }
|
||||
|
||||
public static void Initialize(CrestronControlSystem cs)
|
||||
{
|
||||
AddDeviceEnabled = true;
|
||||
CrestronConsole.AddNewConsoleCommand(ListDeviceCommStatuses, "devcommstatus", "Lists the communication status of all devices",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDeviceFeedbacks, "devfb", "Lists current feedbacks",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDevices, "devlist", "Lists current managed devices",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(DeviceJsonApi.DoDeviceActionWithJson, "devjson", "",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetProperties(s)), "devprops", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetMethods(s)), "devmethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetApiMethods(s)), "apimethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
public static bool AddDeviceEnabled;
|
||||
|
||||
public static void Initialize(CrestronControlSystem cs)
|
||||
{
|
||||
AddDeviceEnabled = true;
|
||||
CrestronConsole.AddNewConsoleCommand(ListDeviceCommStatuses, "devcommstatus", "Lists the communication status of all devices",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDeviceFeedbacks, "devfb", "Lists current feedbacks",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(ListDevices, "devlist", "Lists current managed devices",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(DeviceJsonApi.DoDeviceActionWithJson, "devjson", "",
|
||||
ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetProperties(s)), "devprops", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetMethods(s)), "devmethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetApiMethods(s)), "apimethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||
CrestronConsole.AddNewConsoleCommand(SimulateComReceiveOnDevice, "devsimreceive",
|
||||
"Simulates incoming data on a com device", ConsoleAccessLevelEnum.AccessOperator);
|
||||
|
||||
@@ -52,77 +52,89 @@ namespace PepperDash.Essentials.Core
|
||||
CrestronConsole.AddNewConsoleCommand(s => DisableAllDeviceStreamDebugging(), "disableallstreamdebug", "disables stream debugging on all devices", ConsoleAccessLevelEnum.AccessOperator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls activate steps on all Device class items
|
||||
/// </summary>
|
||||
public static void ActivateAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
/// <summary>
|
||||
/// Calls activate steps on all Device class items
|
||||
/// </summary>
|
||||
public static void ActivateAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnAllDevicesRegistered();
|
||||
|
||||
DeviceCriticalSection.Enter();
|
||||
DeviceCriticalSection.Enter();
|
||||
AddDeviceEnabled = false;
|
||||
// PreActivate all devices
|
||||
Debug.LogMessage(LogEventLevel.Information,"****PreActivation starting...****");
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).PreActivate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// PreActivate all devices
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PreActivation starting...****");
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).PreActivate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PreActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PreActivation complete****");
|
||||
Debug.LogMessage(LogEventLevel.Information, "****Activation starting...****");
|
||||
Debug.LogMessage(LogEventLevel.Information, "****Activation starting...****");
|
||||
|
||||
// Activate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).Activate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Activate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).Activate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} Activation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "****Activation complete****");
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PostActivation starting...****");
|
||||
|
||||
// PostActivate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).PostActivate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PostActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
// PostActivate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (d is Device)
|
||||
(d as Device).PostActivate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PostActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PostActivation complete****");
|
||||
|
||||
OnAllDevicesActivated();
|
||||
}
|
||||
finally
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeviceManager_Initialized(object sender, EventArgs e)
|
||||
{
|
||||
var allInitialized = Devices.Values.OfType<EssentialsDevice>().All(d => d.IsInitialized);
|
||||
|
||||
if (allInitialized)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "****All Devices Initalized****");
|
||||
|
||||
OnAllDevicesInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesActivated()
|
||||
{
|
||||
@@ -142,77 +154,85 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls activate on all Device class items
|
||||
/// </summary>
|
||||
public static void DeactivateAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
DeviceCriticalSection.Enter();
|
||||
foreach (var d in Devices.Values.OfType<Device>())
|
||||
{
|
||||
d.Deactivate();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
private static void OnAllDevicesInitialized()
|
||||
{
|
||||
var handler = AllDevicesInitialized;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
//static void ListMethods(string devKey)
|
||||
//{
|
||||
// var dev = GetDeviceForKey(devKey);
|
||||
// if(dev != null)
|
||||
// {
|
||||
// var type = dev.GetType().GetCType();
|
||||
// var methods = type.GetMethods(BindingFlags.Public|BindingFlags.Instance);
|
||||
// var sb = new StringBuilder();
|
||||
// sb.AppendLine(string.Format("{2} methods on [{0}] ({1}):", dev.Key, type.Name, methods.Length));
|
||||
// foreach (var m in methods)
|
||||
// {
|
||||
// sb.Append(string.Format("{0}(", m.Name));
|
||||
// var pars = m.GetParameters();
|
||||
// foreach (var p in pars)
|
||||
// sb.Append(string.Format("({1}){0} ", p.Name, p.ParameterType.Name));
|
||||
// sb.AppendLine(")");
|
||||
// }
|
||||
// CrestronConsole.ConsoleCommandResponse(sb.ToString());
|
||||
// }
|
||||
//}
|
||||
/// <summary>
|
||||
/// Calls activate on all Device class items
|
||||
/// </summary>
|
||||
public static void DeactivateAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
DeviceCriticalSection.Enter();
|
||||
foreach (var d in Devices.Values.OfType<Device>())
|
||||
{
|
||||
d.Deactivate();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ListDevices(string s)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "{0} Devices registered with Device Manager:", Devices.Count);
|
||||
var sorted = Devices.Values.ToList();
|
||||
sorted.Sort((a, b) => a.Key.CompareTo(b.Key));
|
||||
//static void ListMethods(string devKey)
|
||||
//{
|
||||
// var dev = GetDeviceForKey(devKey);
|
||||
// if(dev != null)
|
||||
// {
|
||||
// var type = dev.GetType().GetType();
|
||||
// var methods = type.GetMethods(BindingFlags.Public|BindingFlags.Instance);
|
||||
// var sb = new StringBuilder();
|
||||
// sb.AppendLine(string.Format("{2} methods on [{0}] ({1}):", dev.Key, type.Name, methods.Length));
|
||||
// foreach (var m in methods)
|
||||
// {
|
||||
// sb.Append(string.Format("{0}(", m.Name));
|
||||
// var pars = m.GetParameters();
|
||||
// foreach (var p in pars)
|
||||
// sb.Append(string.Format("({1}){0} ", p.Name, p.ParameterType.Name));
|
||||
// sb.AppendLine(")");
|
||||
// }
|
||||
// CrestronConsole.ConsoleCommandResponse(sb.ToString());
|
||||
// }
|
||||
//}
|
||||
|
||||
foreach (var d in sorted)
|
||||
{
|
||||
var name = d is IKeyName ? (d as IKeyName).Name : "---";
|
||||
Debug.LogMessage(LogEventLevel.Information, " [{0}] {1}", d.Key, name);
|
||||
}
|
||||
}
|
||||
private static void ListDevices(string s)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "{0} Devices registered with Device Manager:", Devices.Count);
|
||||
var sorted = Devices.Values.ToList();
|
||||
sorted.Sort((a, b) => a.Key.CompareTo(b.Key));
|
||||
|
||||
private static void ListDeviceFeedbacks(string devKey)
|
||||
{
|
||||
var dev = GetDeviceForKey(devKey);
|
||||
if (dev == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey);
|
||||
return;
|
||||
}
|
||||
var statusDev = dev as IHasFeedback;
|
||||
if (statusDev == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device '{0}' does not have visible feedbacks", devKey);
|
||||
return;
|
||||
}
|
||||
statusDev.DumpFeedbacksToConsole(true);
|
||||
}
|
||||
foreach (var d in sorted)
|
||||
{
|
||||
var name = d is IKeyName ? (d as IKeyName).Name : "---";
|
||||
Debug.LogMessage(LogEventLevel.Information, " [{0}] {1}", d.Key, name);
|
||||
}
|
||||
}
|
||||
|
||||
//static void ListDeviceCommands(string devKey)
|
||||
private static void ListDeviceFeedbacks(string devKey)
|
||||
{
|
||||
var dev = GetDeviceForKey(devKey);
|
||||
if (dev == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey);
|
||||
return;
|
||||
}
|
||||
if (!(dev is IHasFeedback statusDev))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device '{0}' does not have visible feedbacks", devKey);
|
||||
return;
|
||||
}
|
||||
statusDev.DumpFeedbacksToConsole(true);
|
||||
}
|
||||
|
||||
//static void ListDeviceCommands(string devKey)
|
||||
//{
|
||||
// var dev = GetDeviceForKey(devKey);
|
||||
// if (dev == null)
|
||||
@@ -223,134 +243,135 @@ namespace PepperDash.Essentials.Core
|
||||
// Debug.LogMessage(LogEventLevel.Information, "This needs to be reworked. Stay tuned.", devKey);
|
||||
//}
|
||||
|
||||
private static void ListDeviceCommStatuses(string input)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var dev in Devices.Values.OfType<ICommunicationMonitor>())
|
||||
{
|
||||
sb.Append(string.Format("{0}: {1}\r", dev,
|
||||
dev.CommunicationMonitor.Status));
|
||||
}
|
||||
CrestronConsole.ConsoleCommandResponse(sb.ToString());
|
||||
}
|
||||
private static void ListDeviceCommStatuses(string input)
|
||||
{
|
||||
|
||||
foreach (var dev in Devices.Values.OfType<ICommunicationMonitor>())
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse($"{dev}: {dev.CommunicationMonitor.Status}{Environment.NewLine}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//static void DoDeviceCommand(string command)
|
||||
//static void DoDeviceCommand(string command)
|
||||
//{
|
||||
// Debug.LogMessage(LogEventLevel.Information, "Not yet implemented. Stay tuned");
|
||||
//}
|
||||
|
||||
public static void AddDevice(IKeyed newDev)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceCriticalSection.TryEnter())
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Currently unable to add devices to Device Manager. Please try again");
|
||||
return;
|
||||
}
|
||||
// Check for device with same key
|
||||
//var existingDevice = _Devices.FirstOrDefault(d => d.Key.Equals(newDev.Key, StringComparison.OrdinalIgnoreCase));
|
||||
////// If it exists, remove or warn??
|
||||
//if (existingDevice != null)
|
||||
public static void AddDevice(IKeyed newDev)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceCriticalSection.TryEnter())
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Currently unable to add devices to Device Manager. Please try again");
|
||||
return;
|
||||
}
|
||||
// Check for device with same key
|
||||
//var existingDevice = _Devices.FirstOrDefault(d => d.Key.Equals(newDev.Key, StringComparison.OrdinalIgnoreCase));
|
||||
////// If it exists, remove or warn??
|
||||
//if (existingDevice != null)
|
||||
|
||||
if (!AddDeviceEnabled)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "All devices have been activated. Adding new devices is not allowed.");
|
||||
return;
|
||||
}
|
||||
if (!AddDeviceEnabled)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "All devices have been activated. Adding new devices is not allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Devices.ContainsKey(newDev.Key))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, newDev, "WARNING: A device with this key already exists. Not added to manager");
|
||||
return;
|
||||
}
|
||||
Devices.Add(newDev.Key, newDev);
|
||||
//if (!(_Devices.Contains(newDev)))
|
||||
// _Devices.Add(newDev);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
if (Devices.ContainsKey(newDev.Key))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, newDev, "WARNING: A device with this key already exists. Not added to manager");
|
||||
return;
|
||||
}
|
||||
Devices.Add(newDev.Key, newDev);
|
||||
//if (!(_Devices.Contains(newDev)))
|
||||
// _Devices.Add(newDev);
|
||||
|
||||
public static void AddDevice(IEnumerable<IKeyed> devicesToAdd)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceCriticalSection.TryEnter())
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"Currently unable to add devices to Device Manager. Please try again");
|
||||
return;
|
||||
}
|
||||
if (!AddDeviceEnabled)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"All devices have been activated. Adding new devices is not allowed.");
|
||||
return;
|
||||
}
|
||||
if (newDev is EssentialsDevice essentialsDev)
|
||||
essentialsDev.Initialized += DeviceManager_Initialized;
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dev in devicesToAdd)
|
||||
{
|
||||
try
|
||||
{
|
||||
Devices.Add(dev.Key, dev);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Error adding device with key {0} to Device Manager: {1}\r\nStack Trace: {2}",
|
||||
dev.Key, ex.Message, ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
public static void AddDevice(IEnumerable<IKeyed> devicesToAdd)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceCriticalSection.TryEnter())
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"Currently unable to add devices to Device Manager. Please try again");
|
||||
return;
|
||||
}
|
||||
if (!AddDeviceEnabled)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information,
|
||||
"All devices have been activated. Adding new devices is not allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
public static void RemoveDevice(IKeyed newDev)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var dev in devicesToAdd)
|
||||
{
|
||||
try
|
||||
{
|
||||
Devices.Add(dev.Key, dev);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Error adding device with key {0} to Device Manager: {1}\r\nStack Trace: {2}",
|
||||
dev.Key, ex.Message, ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveDevice(IKeyed newDev)
|
||||
{
|
||||
try
|
||||
{
|
||||
DeviceCriticalSection.Enter();
|
||||
if (newDev == null)
|
||||
return;
|
||||
if (Devices.ContainsKey(newDev.Key))
|
||||
Devices.Remove(newDev.Key);
|
||||
//if (_Devices.Contains(newDev))
|
||||
// _Devices.Remove(newDev);
|
||||
else
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device manager: Device '{0}' does not exist in manager. Cannot remove", newDev.Key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
if (newDev == null)
|
||||
return;
|
||||
if (Devices.ContainsKey(newDev.Key))
|
||||
Devices.Remove(newDev.Key);
|
||||
//if (_Devices.Contains(newDev))
|
||||
// _Devices.Remove(newDev);
|
||||
else
|
||||
Debug.LogMessage(LogEventLevel.Information, "Device manager: Device '{0}' does not exist in manager. Cannot remove", newDev.Key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeviceCriticalSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetDeviceKeys()
|
||||
{
|
||||
//return _Devices.Select(d => d.Key).ToList();
|
||||
return Devices.Keys;
|
||||
}
|
||||
public static IEnumerable<string> GetDeviceKeys()
|
||||
{
|
||||
//return _Devices.Select(d => d.Key).ToList();
|
||||
return Devices.Keys;
|
||||
}
|
||||
|
||||
public static IEnumerable<IKeyed> GetDevices()
|
||||
{
|
||||
//return _Devices.Select(d => d.Key).ToList();
|
||||
return Devices.Values;
|
||||
}
|
||||
public static IEnumerable<IKeyed> GetDevices()
|
||||
{
|
||||
//return _Devices.Select(d => d.Key).ToList();
|
||||
return Devices.Values;
|
||||
}
|
||||
|
||||
public static IKeyed GetDeviceForKey(string key)
|
||||
{
|
||||
//return _Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
if (key != null && Devices.ContainsKey(key))
|
||||
return Devices[key];
|
||||
public static IKeyed GetDeviceForKey(string key)
|
||||
{
|
||||
//return _Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
if (key != null && Devices.ContainsKey(key))
|
||||
return Devices[key];
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Console handler that simulates com port data receive
|
||||
@@ -367,8 +388,7 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "**** {0} - {1} ****", match.Groups[1].Value, match.Groups[2].Value);
|
||||
|
||||
var com = GetDeviceForKey(match.Groups[1].Value) as ComPortController;
|
||||
if (com == null)
|
||||
if (!(GetDeviceForKey(match.Groups[1].Value) is ComPortController com))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("'{0}' is not a comm port device", match.Groups[1].Value);
|
||||
return;
|
||||
@@ -423,16 +443,15 @@ namespace PepperDash.Essentials.Core
|
||||
var deviceKey = args[0];
|
||||
var setting = args[1];
|
||||
|
||||
var timeout= String.Empty;
|
||||
var timeout = String.Empty;
|
||||
|
||||
if (args.Length >= 3)
|
||||
{
|
||||
timeout = args[2];
|
||||
}
|
||||
|
||||
var device = GetDeviceForKey(deviceKey) as IStreamDebugging;
|
||||
|
||||
if (device == null)
|
||||
if (!(GetDeviceForKey(deviceKey) is IStreamDebugging device))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to get device with key: {0}", deviceKey);
|
||||
return;
|
||||
@@ -479,13 +498,11 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
foreach (var device in AllDevices)
|
||||
{
|
||||
var streamDevice = device as IStreamDebugging;
|
||||
|
||||
if (streamDevice != null)
|
||||
if (device is IStreamDebugging streamDevice)
|
||||
{
|
||||
streamDevice.StreamDebugging.SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting.Off);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
using System.Reflection;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
@@ -17,6 +17,24 @@ namespace PepperDash.Essentials.Core
|
||||
[Description("The base Essentials Device Class")]
|
||||
public abstract class EssentialsDevice : Device
|
||||
{
|
||||
public event EventHandler Initialized;
|
||||
|
||||
private bool _isInitialized;
|
||||
public bool IsInitialized {
|
||||
get { return _isInitialized; }
|
||||
private set
|
||||
{
|
||||
if (_isInitialized == value) return;
|
||||
|
||||
_isInitialized = value;
|
||||
|
||||
if (_isInitialized)
|
||||
{
|
||||
Initialized?.Invoke(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected EssentialsDevice(string key)
|
||||
: base(key)
|
||||
{
|
||||
@@ -41,6 +59,8 @@ namespace PepperDash.Essentials.Core
|
||||
try
|
||||
{
|
||||
Initialize();
|
||||
|
||||
IsInitialized = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface IHasDspPresets
|
||||
{
|
||||
List<IDspPreset> Presets { get; }
|
||||
|
||||
void RecallPreset(IDspPreset preset);
|
||||
|
||||
}
|
||||
|
||||
public interface IDspPreset
|
||||
{
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
||||
12
src/PepperDash.Essentials.Core/Devices/IDspPresets.cs
Normal file
12
src/PepperDash.Essentials.Core/Devices/IDspPresets.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using PepperDash.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface IDspPresets
|
||||
{
|
||||
Dictionary<string, IKeyName> Presets { get; }
|
||||
|
||||
void RecallPreset(string key);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
@@ -23,7 +21,7 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public static void DumpFeedbacksToConsole(this IHasFeedback source, bool getCurrentStates)
|
||||
{
|
||||
CType t = source.GetType();
|
||||
Type t = source.GetType();
|
||||
// get the properties and set them into a new collection of NameType wrappers
|
||||
var props = t.GetProperties().Select(p => new PropertyNameType(p, t));
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Devices;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class LevelControlListItem : AudioControlListItemBase
|
||||
{
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public IBasicVolumeWithFeedback LevelControl
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_levelControl == null)
|
||||
_levelControl = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IBasicVolumeWithFeedback;
|
||||
return _levelControl;
|
||||
}
|
||||
}
|
||||
IBasicVolumeWithFeedback _levelControl;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name from the device if it implements IKeyName or else returns the Name property
|
||||
/// </summary>
|
||||
[JsonProperty("preferredName")]
|
||||
public string PreferredName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Name)) return Name;
|
||||
else
|
||||
{
|
||||
if (LevelControl is IKeyName namedLevelControl)
|
||||
{
|
||||
if (namedLevelControl == null)
|
||||
return "---";
|
||||
return namedLevelControl.Name;
|
||||
}
|
||||
else return "---";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key of the device in the DeviceManager for control
|
||||
/// </summary>
|
||||
[JsonProperty("deviceKey")]
|
||||
public string DeviceKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if(string.IsNullOrEmpty(ItemKey)) return ParentDeviceKey;
|
||||
else
|
||||
{
|
||||
return DeviceManager.AllDevices.
|
||||
Where(d => d.Key.Contains(ParentDeviceKey) && d.Key.Contains(ItemKey)).FirstOrDefault()?.Key ?? $"{ParentDeviceKey}--{ItemKey}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the item is a level, mute , or both
|
||||
/// </summary>
|
||||
[JsonProperty("type")]
|
||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public eLevelControlType Type { get; set; }
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum eLevelControlType
|
||||
{
|
||||
Level = 1,
|
||||
Mute = 2,
|
||||
LevelAndMute = Level | Mute,
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using Crestron.SimplSharpPro;
|
||||
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using Crestron.SimplSharpPro;
|
||||
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
@@ -70,7 +69,7 @@ namespace PepperDash.Essentials.Core.Devices
|
||||
{
|
||||
public LaptopFactory()
|
||||
{
|
||||
TypeNames = new List<string>() { "laptop" };
|
||||
TypeNames = new List<string>() { "deprecated" };
|
||||
}
|
||||
|
||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||
|
||||
45
src/PepperDash.Essentials.Core/Devices/PresetListItem.cs
Normal file
45
src/PepperDash.Essentials.Core/Devices/PresetListItem.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class PresetListItem : AudioControlListItemBase
|
||||
{
|
||||
[JsonIgnore]
|
||||
public IKeyName Preset
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_preset == null)
|
||||
{
|
||||
var parent = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IDspPresets;
|
||||
if (parent == null || !parent.Presets.ContainsKey(ItemKey))
|
||||
return null;
|
||||
_preset = parent.Presets[ItemKey];
|
||||
}
|
||||
return _preset;
|
||||
}
|
||||
}
|
||||
private IKeyName _preset;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name from the device if it implements IKeyName or else returns the Name property
|
||||
/// </summary>
|
||||
[JsonProperty("preferredName")]
|
||||
public string PreferredName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Name)) return Name;
|
||||
|
||||
else return Preset.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +1,121 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Crestron.SimplSharpPro;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum eSourceListItemType
|
||||
{
|
||||
Route, Off, Other, SomethingAwesomerThanThese
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum eSourceListItemType
|
||||
{
|
||||
Route, Off, Other, SomethingAwesomerThanThese
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an item in a source list - can be deserialized into.
|
||||
/// </summary>
|
||||
public class SourceListItem
|
||||
{
|
||||
[JsonProperty("sourceKey")]
|
||||
public string SourceKey { get; set; }
|
||||
/// <summary>
|
||||
/// Represents an item in a source list - can be deserialized into.
|
||||
/// </summary>
|
||||
public class SourceListItem
|
||||
{
|
||||
[JsonProperty("sourceKey")]
|
||||
public string SourceKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the source Device for this, if it exists in DeviceManager
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Device SourceDevice
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_SourceDevice == null)
|
||||
_SourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as Device;
|
||||
return _SourceDevice;
|
||||
}
|
||||
}
|
||||
Device _SourceDevice;
|
||||
/// <summary>
|
||||
/// Returns the source Device for this, if it exists in DeviceManager
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Device SourceDevice
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_SourceDevice == null)
|
||||
_SourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as Device;
|
||||
return _SourceDevice;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets either the source's Name or this AlternateName property, if
|
||||
/// defined. If source doesn't exist, returns "Missing source"
|
||||
/// </summary>
|
||||
[JsonProperty("preferredName")]
|
||||
public string PreferredName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(Name))
|
||||
{
|
||||
if (SourceDevice == null)
|
||||
return "---";
|
||||
return SourceDevice.Name;
|
||||
}
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
private Device _SourceDevice;
|
||||
|
||||
/// <summary>
|
||||
/// A name that will override the source's name on the UI
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Gets either the source's Name or this AlternateName property, if
|
||||
/// defined. If source doesn't exist, returns "Missing source"
|
||||
/// </summary>
|
||||
[JsonProperty("preferredName")]
|
||||
public string PreferredName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(Name))
|
||||
{
|
||||
if (SourceDevice == null)
|
||||
return "---";
|
||||
return SourceDevice.Name;
|
||||
}
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A name that will override the source's name on the UI
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies and icon for the source list item
|
||||
/// </summary>
|
||||
[JsonProperty("icon")]
|
||||
public string Icon { get; set; }
|
||||
public string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Alternate icon
|
||||
/// </summary>
|
||||
[JsonProperty("altIcon")]
|
||||
public string AltIcon { get; set; }
|
||||
public string AltIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the item should be included in the source list
|
||||
/// </summary>
|
||||
[JsonProperty("includeInSourceList")]
|
||||
public bool IncludeInSourceList { get; set; }
|
||||
public bool IncludeInSourceList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to specify the order of the items in the source list when displayed
|
||||
/// </summary>
|
||||
[JsonProperty("order")]
|
||||
public int Order { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key of the device for volume control
|
||||
/// </summary>
|
||||
[JsonProperty("volumeControlKey")]
|
||||
public string VolumeControlKey { get; set; }
|
||||
public string VolumeControlKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of source list item
|
||||
/// </summary>
|
||||
[JsonProperty("type")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public eSourceListItemType Type { get; set; }
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public eSourceListItemType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of routes to execute for this source list item
|
||||
/// </summary>
|
||||
[JsonProperty("routeList")]
|
||||
public List<SourceRouteListItem> RouteList { get; set; }
|
||||
public List<SourceRouteListItem> RouteList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if this source should be disabled for sharing to the far end call participants via codec content
|
||||
/// </summary>
|
||||
[JsonProperty("disableCodecSharing")]
|
||||
public bool DisableCodecSharing { get; set; }
|
||||
public bool DisableCodecSharing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if this source should be disabled for routing to a shared output
|
||||
/// </summary>
|
||||
[JsonProperty("disableRoutedSharing")]
|
||||
public bool DisableRoutedSharing { get; set; }
|
||||
public bool DisableRoutedSharing { get; set; }
|
||||
|
||||
[JsonProperty("destinations")]
|
||||
public List<eSourceListItemDestinationTypes> Destinations { get; set; }
|
||||
@@ -144,25 +137,46 @@ namespace PepperDash.Essentials.Core
|
||||
[JsonProperty("isAudioSource")]
|
||||
public bool IsAudioSource { get; set; }
|
||||
|
||||
public SourceListItem()
|
||||
{
|
||||
Icon = "Blank";
|
||||
}
|
||||
/// <summary>
|
||||
/// Hide source on UI when Avanced Sharing is enabled
|
||||
/// </summary>
|
||||
[JsonProperty("disableAdvancedRouting")]
|
||||
public bool DisableAdvancedRouting { get; set; }
|
||||
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Hide source on UI when Simpl Sharing is enabled
|
||||
/// </summary>
|
||||
[JsonProperty("disableSimpleRouting")]
|
||||
public bool DisableSimpleRouting { get; set; }
|
||||
|
||||
public class SourceRouteListItem
|
||||
{
|
||||
[JsonProperty("sourceKey")]
|
||||
public string SourceKey { get; set; }
|
||||
public SourceListItem()
|
||||
{
|
||||
Icon = "Blank";
|
||||
}
|
||||
|
||||
[JsonProperty("destinationKey")]
|
||||
public string DestinationKey { get; set; }
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{SourceKey}:{Name}";
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("type")]
|
||||
public eRoutingSignalType Type { get; set; }
|
||||
}
|
||||
public class SourceRouteListItem
|
||||
{
|
||||
[JsonProperty("sourceKey")]
|
||||
public string SourceKey { get; set; }
|
||||
|
||||
[JsonProperty("sourcePortKey")]
|
||||
public string SourcePortKey { get; set; }
|
||||
|
||||
[JsonProperty("destinationKey")]
|
||||
public string DestinationKey { get; set; }
|
||||
|
||||
[JsonProperty("destinationPortKey")]
|
||||
public string DestinationPortKey { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public eRoutingSignalType Type { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the valid destination types for SourceListItems in a room
|
||||
@@ -172,7 +186,12 @@ namespace PepperDash.Essentials.Core
|
||||
defaultDisplay,
|
||||
leftDisplay,
|
||||
rightDisplay,
|
||||
centerDisplay,
|
||||
programAudio,
|
||||
codecContent
|
||||
codecContent,
|
||||
frontLeftDisplay,
|
||||
frontRightDisplay,
|
||||
rearLeftDisplay,
|
||||
rearRightDisplay,
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.Bridges;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
using Crestron.SimplSharpPro.DM;
|
||||
using Crestron.SimplSharpPro.DM.Endpoints;
|
||||
using Crestron.SimplSharpPro.DM.Endpoints.Transmitters;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Bridges;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
|
||||
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
|
||||
public abstract class DisplayBase : EssentialsDevice, IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking
|
||||
{
|
||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
||||
public event InputChangedEventHandler InputChanged;
|
||||
|
||||
public string CurrentSourceInfoKey { get; set; }
|
||||
public SourceListItem CurrentSourceInfo
|
||||
@@ -96,7 +94,9 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void ExecuteSwitch(object selector);
|
||||
public RoutingInputPort CurrentInputPort => throw new NotImplementedException();
|
||||
|
||||
public abstract void ExecuteSwitch(object selector);
|
||||
|
||||
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey,
|
||||
EiscApiAdvanced bridge)
|
||||
@@ -266,16 +266,16 @@ namespace PepperDash.Essentials.Core
|
||||
abstract protected Func<bool> PowerIsOnFeedbackFunc { get; }
|
||||
|
||||
|
||||
public static MockDisplay DefaultDisplay
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_DefaultDisplay == null)
|
||||
_DefaultDisplay = new MockDisplay("default", "Default Display");
|
||||
return _DefaultDisplay;
|
||||
}
|
||||
}
|
||||
static MockDisplay _DefaultDisplay;
|
||||
// public static MockDisplay DefaultDisplay
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// if (_DefaultDisplay == null)
|
||||
// _DefaultDisplay = new MockDisplay("default", "Default Display");
|
||||
// return _DefaultDisplay;
|
||||
// }
|
||||
//}
|
||||
//static MockDisplay _DefaultDisplay;
|
||||
|
||||
public TwoWayDisplayBase(string key, string name)
|
||||
: base(key, name)
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
using Crestron.SimplSharpPro.DM;
|
||||
using Crestron.SimplSharpPro.DM.Endpoints;
|
||||
using Crestron.SimplSharpPro.DM.Endpoints.Transmitters;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Bridges;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
|
||||
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced
|
||||
|
||||
{
|
||||
public RoutingInputPort HdmiIn1 { get; private set; }
|
||||
public RoutingInputPort HdmiIn2 { get; private set; }
|
||||
public RoutingInputPort HdmiIn3 { get; private set; }
|
||||
public RoutingInputPort ComponentIn1 { get; private set; }
|
||||
public RoutingInputPort VgaIn1 { get; private set; }
|
||||
|
||||
bool _PowerIsOn;
|
||||
bool _IsWarmingUp;
|
||||
bool _IsCoolingDown;
|
||||
|
||||
protected override Func<bool> PowerIsOnFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "*************************************************** Display Power is {0}", _PowerIsOn ? "on" : "off");
|
||||
return _PowerIsOn;
|
||||
};
|
||||
} }
|
||||
protected override Func<bool> IsCoolingDownFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "*************************************************** {0}", _IsCoolingDown ? "Display is cooling down" : "Display has finished cooling down");
|
||||
return _IsCoolingDown;
|
||||
};
|
||||
}
|
||||
}
|
||||
protected override Func<bool> IsWarmingUpFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "*************************************************** {0}", _IsWarmingUp ? "Display is warming up" : "Display has finished warming up");
|
||||
return _IsWarmingUp;
|
||||
};
|
||||
}
|
||||
}
|
||||
protected override Func<string> CurrentInputFeedbackFunc { get { return () => "Not Implemented"; } }
|
||||
|
||||
int VolumeHeldRepeatInterval = 200;
|
||||
ushort VolumeInterval = 655;
|
||||
ushort _FakeVolumeLevel = 31768;
|
||||
bool _IsMuted;
|
||||
|
||||
public MockDisplay(string key, string name)
|
||||
: base(key, name)
|
||||
{
|
||||
HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
||||
eRoutingPortConnectionType.Hdmi, null, this);
|
||||
HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
||||
eRoutingPortConnectionType.Hdmi, null, this);
|
||||
HdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
||||
eRoutingPortConnectionType.Hdmi, null, this);
|
||||
ComponentIn1 = new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Video,
|
||||
eRoutingPortConnectionType.Component, null, this);
|
||||
VgaIn1 = new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Video,
|
||||
eRoutingPortConnectionType.Composite, null, this);
|
||||
InputPorts.AddRange(new[] { HdmiIn1, HdmiIn2, HdmiIn3, ComponentIn1, VgaIn1 });
|
||||
|
||||
VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; });
|
||||
MuteFeedback = new BoolFeedback("MuteOn", () => _IsMuted);
|
||||
|
||||
WarmupTime = 10000;
|
||||
CooldownTime = 10000;
|
||||
}
|
||||
|
||||
public override void PowerOn()
|
||||
{
|
||||
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
|
||||
{
|
||||
_IsWarmingUp = true;
|
||||
IsWarmingUpFeedback.InvokeFireUpdate();
|
||||
// Fake power-up cycle
|
||||
WarmupTimer = new CTimer(o =>
|
||||
{
|
||||
_IsWarmingUp = false;
|
||||
_PowerIsOn = true;
|
||||
IsWarmingUpFeedback.InvokeFireUpdate();
|
||||
PowerIsOnFeedback.InvokeFireUpdate();
|
||||
}, WarmupTime);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PowerOff()
|
||||
{
|
||||
// If a display has unreliable-power off feedback, just override this and
|
||||
// remove this check.
|
||||
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
|
||||
{
|
||||
_IsCoolingDown = true;
|
||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
||||
// Fake cool-down cycle
|
||||
CooldownTimer = new CTimer(o =>
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Cooldown timer ending");
|
||||
_IsCoolingDown = false;
|
||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
||||
_PowerIsOn = false;
|
||||
PowerIsOnFeedback.InvokeFireUpdate();
|
||||
}, CooldownTime);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PowerToggle()
|
||||
{
|
||||
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
|
||||
PowerOff();
|
||||
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
|
||||
PowerOn();
|
||||
}
|
||||
|
||||
public override void ExecuteSwitch(object selector)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "ExecuteSwitch: {0}", selector);
|
||||
|
||||
if (!_PowerIsOn)
|
||||
{
|
||||
PowerOn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region IBasicVolumeWithFeedback Members
|
||||
|
||||
public IntFeedback VolumeLevelFeedback { get; private set; }
|
||||
|
||||
public void SetVolume(ushort level)
|
||||
{
|
||||
_FakeVolumeLevel = level;
|
||||
VolumeLevelFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
public void MuteOn()
|
||||
{
|
||||
_IsMuted = true;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
public void MuteOff()
|
||||
{
|
||||
_IsMuted = false;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
public BoolFeedback MuteFeedback { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBasicVolumeControls Members
|
||||
|
||||
public void VolumeUp(bool pressRelease)
|
||||
{
|
||||
//while (pressRelease)
|
||||
//{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease);
|
||||
if (pressRelease)
|
||||
{
|
||||
var newLevel = _FakeVolumeLevel + VolumeInterval;
|
||||
SetVolume((ushort)newLevel);
|
||||
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
public void VolumeDown(bool pressRelease)
|
||||
{
|
||||
//while (pressRelease)
|
||||
//{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease);
|
||||
if (pressRelease)
|
||||
{
|
||||
var newLevel = _FakeVolumeLevel - VolumeInterval;
|
||||
SetVolume((ushort)newLevel);
|
||||
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
public void MuteToggle()
|
||||
{
|
||||
_IsMuted = !_IsMuted;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
||||
{
|
||||
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
|
||||
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
|
||||
{
|
||||
public MockDisplayFactory()
|
||||
{
|
||||
TypeNames = new List<string>() { "mockdisplay" };
|
||||
}
|
||||
|
||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device");
|
||||
return new MockDisplay(dc.Key, dc.Name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
@@ -14,13 +14,13 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class DeviceFactoryWrapper
|
||||
{
|
||||
public CType CType { get; set; }
|
||||
public Type Type { get; set; }
|
||||
public string Description { get; set; }
|
||||
public Func<DeviceConfig, IKeyed> FactoryMethod { get; set; }
|
||||
|
||||
public DeviceFactoryWrapper()
|
||||
{
|
||||
CType = null;
|
||||
Type = null;
|
||||
Description = "Not Available";
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
var factory = (IDeviceFactory)Crestron.SimplSharp.Reflection.Activator.CreateInstance(type);
|
||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||
factory.LoadTypeFactories();
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -69,7 +69,7 @@ namespace PepperDash.Essentials.Core
|
||||
DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
|
||||
}
|
||||
|
||||
public static void AddFactoryForType(string typeName, string description, CType cType, Func<DeviceConfig, IKeyed> method)
|
||||
public static void AddFactoryForType(string typeName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace PepperDash.Essentials.Core
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = new DeviceFactoryWrapper() { CType = cType, Description = description, FactoryMethod = method };
|
||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||
DeviceFactory.FactoryMethods.Add(typeName, wrapper);
|
||||
}
|
||||
|
||||
@@ -149,18 +149,7 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Error, "Exception occurred while creating device {0}: {1}", dc.Key, ex.Message);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.StackTrace);
|
||||
|
||||
if (ex.InnerException == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Error, "Inner exception while creating device {0}: {1}", dc.Key,
|
||||
ex.InnerException.Message);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.InnerException.StackTrace);
|
||||
Debug.LogMessage(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -180,17 +169,17 @@ namespace PepperDash.Essentials.Core
|
||||
foreach (var type in types.OrderBy(t => t.Key))
|
||||
{
|
||||
var description = type.Value.Description;
|
||||
var cType = "Not Specified by Plugin";
|
||||
var Type = "Not Specified by Plugin";
|
||||
|
||||
if (type.Value.CType != null)
|
||||
if (type.Value.Type != null)
|
||||
{
|
||||
cType = type.Value.CType.FullName;
|
||||
Type = type.Value.Type.FullName;
|
||||
}
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
@"Type: '{0}'
|
||||
CType: '{1}'
|
||||
Description: {2}{3}", type.Key, cType, description, CrestronEnvironment.NewLine);
|
||||
Type: '{1}'
|
||||
Description: {2}{3}", type.Key, Type, description, CrestronEnvironment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a class that is capable of loading device types
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
using System.Reflection;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using Serilog.Events;
|
||||
@@ -25,7 +25,7 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
var factory = (IProcessorExtensionDeviceFactory)Crestron.SimplSharp.Reflection.Activator.CreateInstance(extension);
|
||||
var factory = (IProcessorExtensionDeviceFactory)Activator.CreateInstance(extension);
|
||||
factory.LoadFactories();
|
||||
}
|
||||
catch( Exception e )
|
||||
@@ -55,7 +55,7 @@ namespace PepperDash.Essentials.Core
|
||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, new DeviceFactoryWrapper() { FactoryMethod = method });
|
||||
}
|
||||
|
||||
public static void AddFactoryForType(string extensionName, string description, CType cType, Func<DeviceConfig, IKeyed> method)
|
||||
public static void AddFactoryForType(string extensionName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace PepperDash.Essentials.Core
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = new DeviceFactoryWrapper() { CType = cType, Description = description, FactoryMethod = method };
|
||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, wrapper);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Crestron.SimplSharp.CrestronXml;
|
||||
@@ -14,6 +10,10 @@ using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Fusion
|
||||
{
|
||||
|
||||
@@ -137,6 +137,7 @@ namespace PepperDash.Essentials.Core
|
||||
public static void SetFilePathPrefix(string prefix)
|
||||
{
|
||||
FilePathPrefix = prefix;
|
||||
Debug.LogMessage(LogEventLevel.Information, "File Path Prefix set to '{0}'", FilePathPrefix);
|
||||
}
|
||||
|
||||
static string _AssemblyVersion;
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
using System.Reflection;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
@@ -107,19 +107,20 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
|
||||
protected void AddJoins(Type type)
|
||||
{
|
||||
{
|
||||
var fields =
|
||||
type.GetCType()
|
||||
.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"],
|
||||
@@ -501,7 +510,7 @@ namespace PepperDash.Essentials.Core
|
||||
public string GetNameAttribute(MemberInfo memberInfo)
|
||||
{
|
||||
var name = string.Empty;
|
||||
var attribute = (JoinNameAttribute)CAttribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute));
|
||||
var attribute = (JoinNameAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute));
|
||||
|
||||
if (attribute == null) return name;
|
||||
|
||||
@@ -514,13 +523,13 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public class JoinNameAttribute : CAttribute
|
||||
public class JoinNameAttribute : Attribute
|
||||
{
|
||||
private string _Name;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace PepperDash.Essentials.Core.Monitoring
|
||||
_uptimePollTimer = null;
|
||||
}
|
||||
|
||||
private void PollUptime(object obj)
|
||||
public void PollUptime(object obj)
|
||||
{
|
||||
var consoleResponse = string.Empty;
|
||||
|
||||
@@ -142,19 +142,22 @@ namespace PepperDash.Essentials.Core.Monitoring
|
||||
_uptime = uptimeRaw.Substring(forIndex + 4);
|
||||
}
|
||||
|
||||
private static void ProcessorReboot()
|
||||
public static void ProcessorReboot()
|
||||
{
|
||||
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return;
|
||||
Debug.LogMessage(LogEventLevel.Information, "Rebooting...");
|
||||
|
||||
var response = string.Empty;
|
||||
|
||||
var response = string.Empty;
|
||||
CrestronConsole.SendControlSystemCommand("reboot", ref response);
|
||||
}
|
||||
|
||||
private static void ProgramReset(uint index)
|
||||
public static void ProgramReset(uint index)
|
||||
{
|
||||
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return;
|
||||
Debug.LogMessage(LogEventLevel.Information, "Resetting Program {0}...", index);
|
||||
|
||||
if (index <= 0 || index > 10) return;
|
||||
if (index <= 0 || index > 10) return;
|
||||
|
||||
var cmd = string.Format("progreset -p:{0}", index);
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using PepperDash.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
@@ -17,7 +14,7 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
private IPartitionStateProvider _partitionSensor;
|
||||
|
||||
private bool isInAutoMode;
|
||||
public bool IsInAutoMode { get; private set; }
|
||||
|
||||
private bool _partitionPresent;
|
||||
|
||||
@@ -25,6 +22,11 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsInAutoMode)
|
||||
{
|
||||
return _partitionSensor.PartitionPresentFeedback.BoolValue;
|
||||
}
|
||||
|
||||
return _partitionPresent;
|
||||
}
|
||||
set
|
||||
@@ -72,11 +74,11 @@ namespace PepperDash.Essentials.Core
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||
private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||
{
|
||||
if (isInAutoMode)
|
||||
if (IsInAutoMode)
|
||||
{
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
PartitionPresent = e.BoolValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +88,9 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public void SetAutoMode()
|
||||
{
|
||||
isInAutoMode = true;
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting {Key} to Auto Mode", this);
|
||||
|
||||
IsInAutoMode = true;
|
||||
if (PartitionPresentFeedback != null)
|
||||
{
|
||||
PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue);
|
||||
@@ -98,13 +102,19 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
if (_partitionSensor != null)
|
||||
{
|
||||
_partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange;
|
||||
_partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange;
|
||||
PartitionPresent = _partitionSensor.PartitionPresentFeedback.BoolValue;
|
||||
}
|
||||
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
public void SetManualMode()
|
||||
{
|
||||
isInAutoMode = false;
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting {Key} to Manual Mode", this);
|
||||
|
||||
IsInAutoMode = false;
|
||||
if (PartitionPresentFeedback != null)
|
||||
{
|
||||
PartitionPresentFeedback.SetValueFunc(() => _partitionPresent);
|
||||
@@ -117,13 +127,16 @@ namespace PepperDash.Essentials.Core
|
||||
if (_partitionSensor != null)
|
||||
{
|
||||
_partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange;
|
||||
PartitionPresent = _partitionSensor.PartitionPresentFeedback.BoolValue;
|
||||
}
|
||||
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
|
||||
public void SetPartitionStatePresent()
|
||||
{
|
||||
if (!isInAutoMode)
|
||||
if (!IsInAutoMode)
|
||||
{
|
||||
PartitionPresent = true;
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
@@ -132,7 +145,7 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public void SetPartitionStateNotPresent()
|
||||
{
|
||||
if (!isInAutoMode)
|
||||
if (!IsInAutoMode)
|
||||
{
|
||||
PartitionPresent = false;
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
@@ -141,7 +154,10 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public void ToggglePartitionState()
|
||||
{
|
||||
if (!isInAutoMode)
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Toggling Partition State for {Key}", this);
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"IsInAutoMode: {IsInAutoMode}", this);
|
||||
|
||||
if (!IsInAutoMode)
|
||||
{
|
||||
PartitionPresent = !PartitionPresent;
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace PepperDash.Essentials.Core
|
||||
[JsonProperty("adjacentRoomKeys")]
|
||||
List<string> AdjacentRoomKeys { get; }
|
||||
|
||||
[JsonProperty("isInAutoMode")]
|
||||
bool IsInAutoMode { get; }
|
||||
|
||||
void SetPartitionStatePresent();
|
||||
|
||||
void SetPartitionStateNotPresent();
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
<Configurations>Debug;Release;Debug 4.7.2</Configurations>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6</TargetFrameworks>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<AssemblyName>PepperDash_Essentials_Core</AssemblyName>
|
||||
<RootNamespace>PepperDash.Essentials.Core</RootNamespace>
|
||||
<Title>PepperDash Essentials Core</Title>
|
||||
<PackageId>PepperDash.Essentials.Core</PackageId>
|
||||
<InformationalVersion>$(Version)</InformationalVersion>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<Version>2.0.0-local</Version>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
@@ -22,8 +25,8 @@
|
||||
<DebugType>pdbonly</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.42" />
|
||||
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-402" />
|
||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.90" />
|
||||
<PackageReference Include="PepperDashCore" Version="2.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />
|
||||
|
||||
@@ -1,432 +0,0 @@
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>PepperDash.Essentials.Core</RootNamespace>
|
||||
<AssemblyName>PepperDash_Essentials_Core</AssemblyName>
|
||||
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92300};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
|
||||
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
|
||||
<OSVersion>5.0</OSVersion>
|
||||
<DeployDirSuffix>SmartDeviceProject1</DeployDirSuffix>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<NativePlatformName>Windows CE</NativePlatformName>
|
||||
<FormFactorID>
|
||||
</FormFactorID>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NoStdLib>true</NoStdLib>
|
||||
<NoConfig>true</NoConfig>
|
||||
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NoStdLib>true</NoStdLib>
|
||||
<NoConfig>true</NoConfig>
|
||||
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Crestron.SimplSharpPro.DeviceSupport, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DeviceSupport.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.DM, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DM.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.EthernetCommunications, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.EthernetCommunications.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.Fusion, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Fusion.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.Gateways, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Gateways.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.GeneralIO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.GeneralIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.Remotes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Remotes.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.ThreeSeriesCards, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.ThreeSeriesCards.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="PepperDash_Core, Version=1.2.1.30543, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="SimplSharpCWSHelperInterface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SimplSharpPro, Version=1.5.3.17, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SimplSharpTimerEventInterface, Version=1.0.6197.20052, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpTimerEventInterface.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Bridges\BridgeBase.cs" />
|
||||
<Compile Include="Bridges\IBridge.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\AirMediaControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\AppleTvJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\GenericIrControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\HdPsXxxControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\IAnalogInputJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\IDigitalOutputJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\PduJoinMapBase.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\C2nRthsControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\CameraControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\CenOdtOccupancySensorBaseJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DigitalLoggerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DisplayControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DmBladeChassisControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DmChassisControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DmpsAudioOutputControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DmpsMicrophoneControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DmpsRoutingControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DmRmcControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\DmTxControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\GenericLightingJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\GenericRelayControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\GlsOccupancySensorBaseJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\GlsPartitionSensorJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\HdMdNxM4kEControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\HdMdxxxCEControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\Hrxxx0WirelessRemoteControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\IBasicCommunicationJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\IDigitalInputJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\IRBlurayBaseJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\SetTopBoxControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\StatusSignControllerJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\SystemMonitorJoinMap.cs" />
|
||||
<Compile Include="Bridges\JoinMaps\VideoCodecControllerJoinMap.cs" />
|
||||
<Compile Include="Comm and IR\CecPortController.cs" />
|
||||
<Compile Include="Comm and IR\CommFactory.cs" />
|
||||
<Compile Include="Comm and IR\CommunicationExtras.cs" />
|
||||
<Compile Include="Comm and IR\ComPortController.cs" />
|
||||
<Compile Include="Comm and IR\ComSpecJsonConverter.cs" />
|
||||
<Compile Include="Comm and IR\ConsoleCommMockDevice.cs" />
|
||||
<Compile Include="Comm and IR\GenericComm.cs" />
|
||||
<Compile Include="Comm and IR\GenericHttpClient.cs" />
|
||||
<Compile Include="Comm and IR\IRPortHelper.cs" />
|
||||
<Compile Include="Config\Essentials\ConfigUpdater.cs" />
|
||||
<Compile Include="Config\Essentials\ConfigReader.cs" />
|
||||
<Compile Include="Config\Essentials\ConfigWriter.cs" />
|
||||
<Compile Include="Config\Essentials\EssentialsConfig.cs" />
|
||||
<Compile Include="Config\SourceDevicePropertiesConfigBase.cs" />
|
||||
<Compile Include="Crestron IO\C2nIo\C2nIoController.cs" />
|
||||
<Compile Include="Crestron IO\C2nRts\C2nRthsController.cs" />
|
||||
<Compile Include="Crestron IO\Cards\C3CardControllerBase.cs" />
|
||||
<Compile Include="Crestron IO\Cards\C3Com3Controller.cs" />
|
||||
<Compile Include="Crestron IO\Cards\C3Io16Controller.cs" />
|
||||
<Compile Include="Crestron IO\Cards\C3Ir8Controller.cs" />
|
||||
<Compile Include="Crestron IO\Cards\C3Ry16Controller.cs" />
|
||||
<Compile Include="Crestron IO\Cards\C3Ry8Controller.cs" />
|
||||
<Compile Include="Crestron IO\Cards\CenCi31Controller.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Crestron IO\Cards\CenCi33Controller.cs" />
|
||||
<Compile Include="Crestron IO\Cards\InternalCardCageController.cs" />
|
||||
<Compile Include="Crestron IO\DinCenCn\DinCenCnController.cs" />
|
||||
<Compile Include="Crestron IO\DinCenCn\IHasCresnetBranches.cs" />
|
||||
<Compile Include="Crestron IO\DinIo8\DinIo8Controller.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\CenIoDigIn104Controller.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\GenericVersiportAnalogInputDevice.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\GenericDigitalInputDevice.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\GenericVersiportInputDevice.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\IAnalogInput.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\IDigitalInput.cs" />
|
||||
<Compile Include="Crestron IO\IOPortConfig.cs" />
|
||||
<Compile Include="Crestron IO\Ir\CenIoIr104Controller.cs" />
|
||||
<Compile Include="Crestron IO\Outputs\GenericVersiportOutputDevice.cs" />
|
||||
<Compile Include="Crestron IO\Outputs\IDigitalOutput.cs" />
|
||||
<Compile Include="Crestron IO\Relay\CenIoRy104Controller.cs" />
|
||||
<Compile Include="Crestron IO\Relay\GenericRelayDevice.cs" />
|
||||
<Compile Include="Crestron IO\Relay\ISwitchedOutput.cs" />
|
||||
<Compile Include="Crestron IO\StatusSign\StatusSignController.cs" />
|
||||
<Compile Include="Device Info\NetworkDeviceHelpers.cs" />
|
||||
<Compile Include="Devices\PowerInterfaces.cs" />
|
||||
<Compile Include="Web\RequestHandlers\AppDebugRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\GetFeedbacksForDeviceRequestHandler.cs" />
|
||||
<Compile Include="Web\EssentialsWebApiHelpers.cs" />
|
||||
<Compile Include="Web\RequestHandlers\GetTypesByFilterRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\GetJoinMapForDeviceKeyRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\DefaultRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\DevListRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\DevPropsRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\DevJsonRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\SetDeviceStreamDebugRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\DisableAllStreamDebugRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\ShowConfigRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\GetTypesRequestHandler.cs" />
|
||||
<Compile Include="Web\RequestHandlers\GetJoinMapForBridgeKeyRequestHandler.cs" />
|
||||
<Compile Include="Web\EssemtialsWebApi.cs" />
|
||||
<Compile Include="Web\EssentialsWebApiFactory.cs" />
|
||||
<Compile Include="Web\EssentialsWebApiPropertiesConfig.cs" />
|
||||
<Compile Include="Web\RequestHandlers\ReportVersionsRequestHandler.cs" />
|
||||
<Compile Include="Device Info\DeviceInfo.cs" />
|
||||
<Compile Include="Device Info\DeviceInfoEventArgs.cs" />
|
||||
<Compile Include="Device Info\IDeviceInfoProvider.cs" />
|
||||
<Compile Include="Devices\CodecInterfaces.cs" />
|
||||
<Compile Include="Devices\CrestronProcessor.cs" />
|
||||
<Compile Include="Devices\DestinationListItem.cs" />
|
||||
<Compile Include="Devices\DeviceApiBase.cs" />
|
||||
<Compile Include="Devices\DeviceFeedbackExtensions.cs" />
|
||||
<Compile Include="Devices\EssentialsBridgeableDevice.cs" />
|
||||
<Compile Include="Devices\EssentialsDevice.cs" />
|
||||
<Compile Include="Devices\GenericIRController.cs" />
|
||||
<Compile Include="Devices\IDspPreset.cs" />
|
||||
<Compile Include="Devices\IProjectorInterfaces.cs" />
|
||||
<Compile Include="Devices\IReconfigurableDevice.cs" />
|
||||
<Compile Include="Devices\PC\InRoomPc.cs" />
|
||||
<Compile Include="Devices\PC\Laptop.cs" />
|
||||
<Compile Include="Devices\PduInterfaces.cs" />
|
||||
<Compile Include="Devices\ReconfigurableDevice.cs" />
|
||||
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IPasswordPrompt.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\ITvPresetsProvider.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IHasBranding.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\ILanguageDefinition.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IHasFarEndContentStatus.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IHasPhoneDialing.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IMobileControl.cs" />
|
||||
<Compile Include="Extensions\JsonExtensions.cs" />
|
||||
<Compile Include="Extensions\StringExtensions.cs" />
|
||||
<Compile Include="Factory\DeviceFactory.cs" />
|
||||
<Compile Include="Factory\IDeviceFactory.cs" />
|
||||
<Compile Include="Factory\ReadyEventArgs.cs" />
|
||||
<Compile Include="Feedbacks\BoolFeedback.cs" />
|
||||
<Compile Include="Feedbacks\FeedbackCollection.cs" />
|
||||
<Compile Include="Feedbacks\FeedbackEventArgs.cs" />
|
||||
<Compile Include="Feedbacks\IntFeedback.cs" />
|
||||
<Compile Include="Feedbacks\SerialFeedback.cs" />
|
||||
<Compile Include="Feedbacks\StringFeedback.cs" />
|
||||
<Compile Include="File\FileIO.cs" />
|
||||
<Compile Include="Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs" />
|
||||
<Compile Include="Fusion\FusionCustomPropertiesBridge.cs" />
|
||||
<Compile Include="Fusion\FusionEventHandlers.cs" />
|
||||
<Compile Include="Fusion\FusionProcessorQueries.cs" />
|
||||
<Compile Include="Fusion\EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs" />
|
||||
<Compile Include="Fusion\FusionRviDataClasses.cs" />
|
||||
<Compile Include="Gateways\CenRfgwController.cs" />
|
||||
<Compile Include="Gateways\EssentialsRfGatewayConfig.cs" />
|
||||
<Compile Include="Global\EthernetAdapterInfo.cs" />
|
||||
<Compile Include="Interfaces\ILogStrings.cs" />
|
||||
<Compile Include="Interfaces\ILogStringsWithLevel.cs" />
|
||||
<Compile Include="Occupancy\GlsOccupancySensorPropertiesConfig.cs" />
|
||||
<Compile Include="Occupancy\GlsOirOccupancySensorController.cs" />
|
||||
<Compile Include="PartitionSensor\EssentialsPartitionController.cs" />
|
||||
<Compile Include="PartitionSensor\GlsPartitionSensorPropertiesConfig.cs" />
|
||||
<Compile Include="PartitionSensor\IPartitionStateProvider.cs" />
|
||||
<Compile Include="Occupancy\OccupancyAggregatorConfig.cs" />
|
||||
<Compile Include="Queues\ComsMessage.cs" />
|
||||
<Compile Include="Queues\ProcessStringMessage.cs" />
|
||||
<Compile Include="Queues\GenericQueue.cs" />
|
||||
<Compile Include="Global\JobTimer.cs" />
|
||||
<Compile Include="Global\Scheduler.cs" />
|
||||
<Compile Include="Queues\IQueue.cs" />
|
||||
<Compile Include="JoinMaps\JoinMapBase.cs" />
|
||||
<Compile Include="Lighting\Lighting Interfaces.cs" />
|
||||
<Compile Include="Lighting\LightingBase.cs" />
|
||||
<Compile Include="Monitoring\SystemMonitorController.cs" />
|
||||
<Compile Include="Microphone Privacy\MicrophonePrivacyController.cs" />
|
||||
<Compile Include="Microphone Privacy\MicrophonePrivacyControllerConfig.cs" />
|
||||
<Compile Include="Occupancy\CenOdtOccupancySensorBaseController.cs" />
|
||||
<Compile Include="Occupancy\GlsOccupancySensorBaseController.cs" />
|
||||
<Compile Include="Occupancy\GlsOdtOccupancySensorController.cs" />
|
||||
<Compile Include="Occupancy\IOccupancyStatusProviderAggregator.cs" />
|
||||
<Compile Include="PartitionSensor\GlsPartitionSensorController.cs" />
|
||||
<Compile Include="Plugins\PluginLoader.cs" />
|
||||
<Compile Include="Presets\PresetBase.cs" />
|
||||
<Compile Include="Plugins\IPluginDeviceFactory.cs" />
|
||||
<Compile Include="Queues\IQueueMessage.cs" />
|
||||
<Compile Include="Ramps and Increments\ActionIncrementer.cs" />
|
||||
<Compile Include="Config\BasicConfig.cs" />
|
||||
<Compile Include="Config\ConfigPropertiesHelpers.cs" />
|
||||
<Compile Include="Config\InfoConfig.cs" />
|
||||
<Compile Include="Config\DeviceConfig.cs" />
|
||||
<Compile Include="Devices\DisplayUiConstants.cs" />
|
||||
<Compile Include="Devices\IUsageTracking.cs" />
|
||||
<Compile Include="Devices\DeviceJsonApi.cs" />
|
||||
<Compile Include="Devices\SourceListItem.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IDisplayBasic.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IDumbSource.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IWarmingCooling.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IDiscPlayerControls.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IPower.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IUiDisplayInfo.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\ISetTopBoxControls.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IChannel.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IColorFunctions.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IDPad.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\IDvr.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\Template.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\ITransport.cs" />
|
||||
<Compile Include="Devices\GenericMonitoredTcpDevice.cs" />
|
||||
<Compile Include="DeviceTypeInterfaces\INumeric.cs" />
|
||||
<Compile Include="Devices\IVolumeAndAudioInterfaces.cs" />
|
||||
<Compile Include="Display\BasicIrDisplay.cs" />
|
||||
<Compile Include="Feedbacks\BoolFeedbackOneShot.cs" />
|
||||
<Compile Include="Ramps and Increments\NumericalHelpers.cs" />
|
||||
<Compile Include="Ramps and Increments\UshortSigIncrementer.cs" />
|
||||
<Compile Include="Remotes\ButtonExtensions.cs" />
|
||||
<Compile Include="Remotes\CrestronRemotePropertiesConfig.cs" />
|
||||
<Compile Include="Remotes\Hrxx0WirelessRemoteController.cs" />
|
||||
<Compile Include="Room\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" />
|
||||
<Compile Include="Room\Combining\EssentialsRoomCombiner.cs" />
|
||||
<Compile Include="Room\Combining\EssentialsRoomCombinerPropertiesConfig.cs" />
|
||||
<Compile Include="Room\Combining\IEssentialsRoomCombiner.cs" />
|
||||
<Compile Include="Room\Combining\RoomCombinationScenario.cs" />
|
||||
<Compile Include="Room\EssentialsRoomBase.cs" />
|
||||
<Compile Include="Room\Config\EssentialsRoomScheduledEventsConfig.cs" />
|
||||
<Compile Include="Room\IEssentialsRoom.cs" />
|
||||
<Compile Include="Room\Interfaces.cs" />
|
||||
<Compile Include="Room\iOccupancyStatusProvider.cs" />
|
||||
<Compile Include="Routing\DummyRoutingInputsDevice.cs" />
|
||||
<Compile Include="Routing\ICardPortsDevice.cs" />
|
||||
<Compile Include="InUseTracking\IInUseTracking.cs" />
|
||||
<Compile Include="InUseTracking\InUseTracking.cs" />
|
||||
<Compile Include="Routing\IRoutingInputsExtensions.cs" />
|
||||
<Compile Include="Monitoring\StatusMonitorCollection.cs" />
|
||||
<Compile Include="Monitoring\CrestronGenericBaseCommunicationMonitor.cs" />
|
||||
<Compile Include="Monitoring\StatusMonitorBase.cs" />
|
||||
<Compile Include="Monitoring\Interfaces.cs" />
|
||||
<Compile Include="Monitoring\GenericCommunicationMonitor.cs" />
|
||||
<Compile Include="Devices\AudioInterfaces.cs" />
|
||||
<Compile Include="Devices\IAttachVideoStatusExtensions.cs" />
|
||||
<Compile Include="Devices\IHasFeedbacks.cs" />
|
||||
<Compile Include="Devices\SmartObjectBaseTypes.cs" />
|
||||
<Compile Include="Devices\PresentationDeviceType.cs" />
|
||||
<Compile Include="Display\MockDisplay.cs" />
|
||||
<Compile Include="Ethernet\EthernetStatistics.cs" />
|
||||
<Compile Include="Global\Global.cs" />
|
||||
<Compile Include="License\EssentialsLicenseManager.cs" />
|
||||
<Compile Include="Feedbacks\BoolOutputLogicals.cs" />
|
||||
<Compile Include="Presets\Interfaces.cs" />
|
||||
<Compile Include="Presets\PresetsListSubpageReferenceListItem.cs" />
|
||||
<Compile Include="Presets\DevicePresetsView.cs" />
|
||||
<Compile Include="Presets\PresetChannel.cs" />
|
||||
<Compile Include="Presets\DevicePresets.cs" />
|
||||
<Compile Include="Routing\RoutingInterfaces.cs" />
|
||||
<Compile Include="Routing\RoutingPort.cs" />
|
||||
<Compile Include="Routing\RoutingPortCollection.cs" />
|
||||
<Compile Include="Feedbacks\BoolFeedbackPulseExtender.cs" />
|
||||
<Compile Include="Routing\RoutingPortNames.cs" />
|
||||
<Compile Include="Routing\TieLineConfig.cs" />
|
||||
<Compile Include="Secrets\CrestronGlobalSecretsProvider.cs" />
|
||||
<Compile Include="Secrets\CrestronLocalSecretsProvider.cs" />
|
||||
<Compile Include="Secrets\CrestronSecret.cs" />
|
||||
<Compile Include="Secrets\Interfaces.cs" />
|
||||
<Compile Include="Secrets\SecretsManager.cs" />
|
||||
<Compile Include="Secrets\SecretsPropertiesConfig.cs" />
|
||||
<Compile Include="Shades\Shade Interfaces.cs" />
|
||||
<Compile Include="Shades\ShadeBase.cs" />
|
||||
<Compile Include="Shades\ShadeController.cs" />
|
||||
<Compile Include="SmartObjects\SmartObjectNumeric.cs" />
|
||||
<Compile Include="SmartObjects\SmartObjectDynamicList.cs" />
|
||||
<Compile Include="SmartObjects\SmartObjectDPad.cs" />
|
||||
<Compile Include="SmartObjects\SmartObjectHelperBase.cs" />
|
||||
<Compile Include="Routing\TieLine.cs" />
|
||||
<Compile Include="Queues\StringResponseProcessor.cs" />
|
||||
<Compile Include="Timers\CountdownTimer.cs" />
|
||||
<Compile Include="Timers\RetriggerableTimer.cs" />
|
||||
<Compile Include="Touchpanels\CrestronTouchpanelPropertiesConfig.cs" />
|
||||
<Compile Include="Touchpanels\Interfaces.cs" />
|
||||
<Compile Include="Touchpanels\Keyboards\HabaneroKeyboardController.cs" />
|
||||
<Compile Include="Touchpanels\Mpc3Touchpanel.cs" />
|
||||
<Compile Include="Touchpanels\TriListExtensions.cs" />
|
||||
<Compile Include="UI PageManagers\BlurayPageManager.cs" />
|
||||
<Compile Include="UI PageManagers\SetTopBoxThreePanelPageManager.cs" />
|
||||
<Compile Include="UI PageManagers\SinglePageManager.cs" />
|
||||
<Compile Include="UI PageManagers\PageManager.cs" />
|
||||
<Compile Include="UI PageManagers\SetTopBoxTwoPanelPageManager.cs" />
|
||||
<Compile Include="UI\TouchpanelBase.cs" />
|
||||
<Compile Include="Utilities\ActionSequence.cs" />
|
||||
<Compile Include="VideoStatus\VideoStatusOutputs.cs" />
|
||||
<Compile Include="Crestron\CrestronGenericBaseDevice.cs" />
|
||||
<Compile Include="DeviceControlsParentInterfaces\IPresentationSource.cs" />
|
||||
<Compile Include="Devices\DeviceManager.cs" />
|
||||
<Compile Include="Devices\IrOutputPortController.cs" />
|
||||
<Compile Include="Display\DisplayBase.cs" />
|
||||
<Compile Include="Feedbacks\FeedbackBase.cs" />
|
||||
<Compile Include="Room\Room.cs" />
|
||||
<Compile Include="SmartObjects\SubpageReferencList\SourceListSubpageReferenceList.cs" />
|
||||
<Compile Include="Touchpanels\ModalDialog.cs" />
|
||||
<Compile Include="TriListBridges\HandlerBridge.cs" />
|
||||
<Compile Include="Devices\FIND HOMES Interfaces.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SigHelper.cs" />
|
||||
<Compile Include="SmartObjects\SubpageReferencList\SubpageReferenceList.cs" />
|
||||
<Compile Include="SmartObjects\SubpageReferencList\SubpageReferenceListItem.cs" />
|
||||
<None Include="app.config" />
|
||||
<None Include="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>rem S# Pro preparation will execute after these operations</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
using System.Reflection;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using Serilog.Events;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
@@ -27,24 +27,31 @@ namespace PepperDash.Essentials
|
||||
/// </summary>
|
||||
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
||||
|
||||
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
||||
|
||||
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
||||
|
||||
public static List<LoadedAssembly> EssentialsPluginAssemblies { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The directory to look in for .cplz plugin packages
|
||||
/// </summary>
|
||||
static string _pluginDirectory = Global.FilePathPrefix + "plugins";
|
||||
static string _pluginDirectory => Global.FilePathPrefix + "plugins";
|
||||
|
||||
/// <summary>
|
||||
/// The directory where plugins will be moved to and loaded from
|
||||
/// </summary>
|
||||
static string _loadedPluginsDirectoryPath = _pluginDirectory + Global.DirectorySeparator + "loadedAssemblies";
|
||||
static string _loadedPluginsDirectoryPath => _pluginDirectory + Global.DirectorySeparator + "loadedAssemblies";
|
||||
|
||||
// The temp directory where .cplz archives will be unzipped to
|
||||
static string _tempDirectory = _pluginDirectory + Global.DirectorySeparator + "temp";
|
||||
static string _tempDirectory => _pluginDirectory + Global.DirectorySeparator + "temp";
|
||||
|
||||
|
||||
static PluginLoader()
|
||||
{
|
||||
LoadedAssemblies = new List<LoadedAssembly>();
|
||||
LoadedPluginFolderAssemblies = new List<LoadedAssembly>();
|
||||
EssentialsPluginAssemblies = new List<LoadedAssembly>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -59,7 +66,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Found {0} Assemblies", assemblyFiles.Length);
|
||||
|
||||
foreach (var fi in assemblyFiles)
|
||||
foreach (var fi in assemblyFiles.Where(fi => fi.Name.Contains("Essentials") || fi.Name.Contains("PepperDash")))
|
||||
{
|
||||
string version = string.Empty;
|
||||
Assembly assembly = null;
|
||||
@@ -69,6 +76,7 @@ namespace PepperDash.Essentials
|
||||
case ("PepperDashEssentials.dll"):
|
||||
{
|
||||
version = Global.AssemblyVersion;
|
||||
EssentialsAssembly = new LoadedAssembly(fi.Name, version, assembly);
|
||||
break;
|
||||
}
|
||||
case ("PepperDash_Essentials_Core.dll"):
|
||||
@@ -81,9 +89,12 @@ namespace PepperDash.Essentials
|
||||
version = Global.AssemblyVersion;
|
||||
break;
|
||||
}
|
||||
case ("PepperDash_Core.dll"):
|
||||
case ("PepperDashCore.dll"):
|
||||
{
|
||||
version = PepperDash.Core.Debug.PepperDashCoreVersion;
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Found PepperDash_Core.dll");
|
||||
version = Debug.PepperDashCoreVersion;
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "PepperDash_Core Version: {0}", version);
|
||||
PepperDashCoreAssembly = new LoadedAssembly(fi.Name, version, assembly);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -119,24 +130,31 @@ namespace PepperDash.Essentials
|
||||
/// <param name="fileName"></param>
|
||||
static LoadedAssembly LoadAssembly(string filePath)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load {0}", filePath);
|
||||
var assembly = Assembly.LoadFrom(filePath);
|
||||
if (assembly != null)
|
||||
try
|
||||
{
|
||||
var assyVersion = GetAssemblyVersion(assembly);
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load {0}", filePath);
|
||||
var assembly = Assembly.LoadFrom(filePath);
|
||||
if (assembly != null)
|
||||
{
|
||||
var assyVersion = GetAssemblyVersion(assembly);
|
||||
|
||||
var loadedAssembly = new LoadedAssembly(assembly.GetName().Name, assyVersion, assembly);
|
||||
LoadedAssemblies.Add(loadedAssembly);
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loaded assembly '{0}', version {1}", loadedAssembly.Name, loadedAssembly.Version);
|
||||
return loadedAssembly;
|
||||
}
|
||||
else
|
||||
var loadedAssembly = new LoadedAssembly(assembly.GetName().Name, assyVersion, assembly);
|
||||
LoadedAssemblies.Add(loadedAssembly);
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loaded assembly '{0}', version {1}", loadedAssembly.Name, loadedAssembly.Version);
|
||||
return loadedAssembly;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to load assembly: '{0}'", filePath);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to load assembly: '{0}'", filePath);
|
||||
Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,7 +162,7 @@ namespace PepperDash.Essentials
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <returns></returns>
|
||||
static string GetAssemblyVersion(Assembly assembly)
|
||||
public static string GetAssemblyVersion(Assembly assembly)
|
||||
{
|
||||
var ver = assembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false);
|
||||
if (ver != null && ver.Length > 0)
|
||||
@@ -190,12 +208,19 @@ namespace PepperDash.Essentials
|
||||
/// <param name="command"></param>
|
||||
public static void ReportAssemblyVersions(string command)
|
||||
{
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse("Loaded Assemblies:" + CrestronEnvironment.NewLine);
|
||||
foreach (var assembly in LoadedAssemblies)
|
||||
CrestronConsole.ConsoleCommandResponse("Essentials Version: {0}" + CrestronEnvironment.NewLine, Global.AssemblyVersion);
|
||||
CrestronConsole.ConsoleCommandResponse("PepperDash Core Version: {0}" + CrestronEnvironment.NewLine, PepperDashCoreAssembly.Version);
|
||||
CrestronConsole.ConsoleCommandResponse("Essentials Plugin Versions:" + CrestronEnvironment.NewLine);
|
||||
foreach (var assembly in EssentialsPluginAssemblies)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
|
||||
}
|
||||
|
||||
//CrestronConsole.ConsoleCommandResponse("Loaded Assemblies:" + CrestronEnvironment.NewLine);
|
||||
//foreach (var assembly in LoadedAssemblies)
|
||||
//{
|
||||
// CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
|
||||
//}
|
||||
}
|
||||
/// <summary>
|
||||
/// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder
|
||||
@@ -354,7 +379,7 @@ namespace PepperDash.Essentials
|
||||
try
|
||||
{
|
||||
var assy = loadedAssembly.Assembly;
|
||||
CType[] types = {};
|
||||
Type[] types = {};
|
||||
try
|
||||
{
|
||||
types = assy.GetTypes();
|
||||
@@ -375,7 +400,7 @@ namespace PepperDash.Essentials
|
||||
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
|
||||
{
|
||||
var plugin =
|
||||
(IPluginDeviceFactory) Crestron.SimplSharp.Reflection.Activator.CreateInstance(type);
|
||||
(IPluginDeviceFactory)Activator.CreateInstance(type);
|
||||
LoadCustomPlugin(plugin, loadedAssembly);
|
||||
}
|
||||
}
|
||||
@@ -432,6 +457,9 @@ namespace PepperDash.Essentials
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loading plugin: {0}", loadedAssembly.Name);
|
||||
plugin.LoadTypeFactories();
|
||||
|
||||
if(!EssentialsPluginAssemblies.Contains(loadedAssembly))
|
||||
EssentialsPluginAssemblies.Add(loadedAssembly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -439,7 +467,7 @@ namespace PepperDash.Essentials
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="loadPlugin"></param>
|
||||
static void LoadCustomLegacyPlugin(CType type, MethodInfo loadPlugin, LoadedAssembly loadedAssembly)
|
||||
static void LoadCustomLegacyPlugin(Type type, MethodInfo loadPlugin, LoadedAssembly loadedAssembly)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "LoadPlugin method found in {0}", type.Name);
|
||||
|
||||
@@ -486,6 +514,8 @@ namespace PepperDash.Essentials
|
||||
/// </summary>
|
||||
public static void LoadPlugins()
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Attempting to Load Plugins from {_pluginDirectory}", _pluginDirectory);
|
||||
|
||||
if (Directory.Exists(_pluginDirectory))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Plugins directory found, checking for plugins");
|
||||
@@ -514,8 +544,11 @@ namespace PepperDash.Essentials
|
||||
/// </summary>
|
||||
public class LoadedAssembly
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; private set; }
|
||||
[JsonProperty("version")]
|
||||
public string Version { get; private set; }
|
||||
[JsonIgnore]
|
||||
public Assembly Assembly { get; private set; }
|
||||
|
||||
public LoadedAssembly(string name, string version, Assembly assembly)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using Crestron.SimplSharp;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Logging;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
using Newtonsoft.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
@@ -35,7 +36,7 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
set
|
||||
{
|
||||
if(value == _isInAutoMode)
|
||||
if (value == _isInAutoMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -49,6 +50,8 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
private int _scenarioChangeDebounceTimeSeconds = 10; // default to 10s
|
||||
|
||||
private Mutex _scenarioChange = new Mutex();
|
||||
|
||||
public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props)
|
||||
: base(key)
|
||||
{
|
||||
@@ -81,7 +84,15 @@ namespace PepperDash.Essentials.Core
|
||||
SetupPartitionStateProviders();
|
||||
|
||||
SetRooms();
|
||||
});
|
||||
|
||||
|
||||
// Subscribe to the AllDevicesInitialized event
|
||||
// We need to wait until all devices are initialized in case
|
||||
// any actions are dependent on 3rd party devices already being
|
||||
// connected and initialized
|
||||
DeviceManager.AllDevicesInitialized += (o, a) =>
|
||||
{
|
||||
if (IsInAutoMode)
|
||||
{
|
||||
DetermineRoomCombinationScenario();
|
||||
@@ -90,10 +101,10 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
SetRoomCombinationScenario(_propertiesConfig.defaultScenarioKey);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
void CreateScenarios()
|
||||
private void CreateScenarios()
|
||||
{
|
||||
foreach (var scenarioConfig in _propertiesConfig.Scenarios)
|
||||
{
|
||||
@@ -102,21 +113,29 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
void SetRooms()
|
||||
private void SetRooms()
|
||||
{
|
||||
_rooms = new List<IEssentialsRoom>();
|
||||
|
||||
foreach (var roomKey in _propertiesConfig.RoomKeys)
|
||||
{
|
||||
var room = DeviceManager.GetDeviceForKey(roomKey) as IEssentialsRoom;
|
||||
if (room != null)
|
||||
var room = DeviceManager.GetDeviceForKey(roomKey);
|
||||
|
||||
if (DeviceManager.GetDeviceForKey(roomKey) is IEssentialsRoom essentialsRoom)
|
||||
{
|
||||
_rooms.Add(room);
|
||||
_rooms.Add(essentialsRoom);
|
||||
}
|
||||
}
|
||||
|
||||
var rooms = DeviceManager.AllDevices.OfType<IEssentialsRoom>().Cast<Device>();
|
||||
|
||||
foreach (var room in rooms)
|
||||
{
|
||||
room.Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void SetupPartitionStateProviders()
|
||||
private void SetupPartitionStateProviders()
|
||||
{
|
||||
foreach (var pConfig in _propertiesConfig.Partitions)
|
||||
{
|
||||
@@ -130,14 +149,18 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||
private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||
{
|
||||
StartDebounceTimer();
|
||||
}
|
||||
|
||||
void StartDebounceTimer()
|
||||
private void StartDebounceTimer()
|
||||
{
|
||||
var time = _scenarioChangeDebounceTimeSeconds * 1000;
|
||||
// default to 500ms for manual mode
|
||||
var time = 500;
|
||||
|
||||
// if in auto mode, debounce the scenario change
|
||||
if (IsInAutoMode) time = _scenarioChangeDebounceTimeSeconds * 1000;
|
||||
|
||||
if (_scenarioChangeDebounceTimer == null)
|
||||
{
|
||||
@@ -152,7 +175,7 @@ namespace PepperDash.Essentials.Core
|
||||
/// <summary>
|
||||
/// Determines the current room combination scenario based on the state of the partition sensors
|
||||
/// </summary>
|
||||
void DetermineRoomCombinationScenario()
|
||||
private void DetermineRoomCombinationScenario()
|
||||
{
|
||||
if (_scenarioChangeDebounceTimer != null)
|
||||
{
|
||||
@@ -160,14 +183,20 @@ namespace PepperDash.Essentials.Core
|
||||
_scenarioChangeDebounceTimer = null;
|
||||
}
|
||||
|
||||
this.LogInformation("Determining Combination Scenario");
|
||||
|
||||
var currentScenario = RoomCombinationScenarios.FirstOrDefault((s) =>
|
||||
{
|
||||
this.LogDebug("Checking scenario {scenarioKey}", s.Key);
|
||||
// iterate the partition states
|
||||
foreach (var partitionState in s.PartitionStates)
|
||||
{
|
||||
this.LogDebug("checking PartitionState {partitionStateKey}", partitionState.PartitionKey);
|
||||
// get the partition by key
|
||||
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey));
|
||||
|
||||
this.LogDebug("Expected State: {partitionPresent} Actual State: {partitionState}", partitionState.PartitionPresent, partition.PartitionPresentFeedback.BoolValue);
|
||||
|
||||
if (partition != null && partitionState.PartitionPresent != partition.PartitionPresentFeedback.BoolValue)
|
||||
{
|
||||
// the partition can't be found or the state doesn't match
|
||||
@@ -180,10 +209,41 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
if (currentScenario != null)
|
||||
{
|
||||
CurrentScenario = currentScenario;
|
||||
this.LogInformation("Found combination Scenario {scenarioKey}", currentScenario.Key);
|
||||
ChangeScenario(currentScenario);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ChangeScenario(IRoomCombinationScenario newScenario)
|
||||
{
|
||||
|
||||
|
||||
if (newScenario == _currentScenario)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Deactivate the old scenario first
|
||||
if (_currentScenario != null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Deactivating scenario {currentScenario}", this, _currentScenario.Name);
|
||||
await _currentScenario.Deactivate();
|
||||
}
|
||||
|
||||
_currentScenario = newScenario;
|
||||
|
||||
// Activate the new scenario
|
||||
if (_currentScenario != null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, $"Current Scenario: {_currentScenario.Name}", this);
|
||||
await _currentScenario.Activate();
|
||||
}
|
||||
|
||||
RoomCombinationScenarioChanged?.Invoke(this, new EventArgs());
|
||||
|
||||
|
||||
}
|
||||
|
||||
#region IEssentialsRoomCombiner Members
|
||||
|
||||
public event EventHandler<EventArgs> RoomCombinationScenarioChanged;
|
||||
@@ -194,33 +254,6 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
return _currentScenario;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (value != _currentScenario)
|
||||
{
|
||||
// Deactivate the old scenario first
|
||||
if (_currentScenario != null)
|
||||
{
|
||||
_currentScenario.Deactivate();
|
||||
}
|
||||
|
||||
_currentScenario = value;
|
||||
|
||||
// Activate the new scenario
|
||||
if (_currentScenario != null)
|
||||
{
|
||||
_currentScenario.Activate();
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Debug, this, "Current Scenario: {0}", _currentScenario.Name);
|
||||
}
|
||||
|
||||
var handler = RoomCombinationScenarioChanged;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BoolFeedback IsInAutoModeFeedback { get; private set; }
|
||||
@@ -228,16 +261,35 @@ namespace PepperDash.Essentials.Core
|
||||
public void SetAutoMode()
|
||||
{
|
||||
IsInAutoMode = true;
|
||||
|
||||
foreach (var partition in Partitions)
|
||||
{
|
||||
partition.SetAutoMode();
|
||||
}
|
||||
|
||||
DetermineRoomCombinationScenario();
|
||||
}
|
||||
|
||||
public void SetManualMode()
|
||||
{
|
||||
IsInAutoMode = false;
|
||||
|
||||
foreach (var partition in Partitions)
|
||||
{
|
||||
partition.SetManualMode();
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleMode()
|
||||
{
|
||||
IsInAutoMode = !IsInAutoMode;
|
||||
if (IsInAutoMode)
|
||||
{
|
||||
SetManualMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAutoMode();
|
||||
}
|
||||
}
|
||||
|
||||
public List<IRoomCombinationScenario> RoomCombinationScenarios { get; private set; }
|
||||
@@ -246,7 +298,7 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public void TogglePartitionState(string partitionKey)
|
||||
{
|
||||
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IPartitionController;
|
||||
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey));
|
||||
|
||||
if (partition != null)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
|
||||
@@ -87,12 +88,12 @@ namespace PepperDash.Essentials.Core
|
||||
/// <summary>
|
||||
/// Activates this room combination scenario
|
||||
/// </summary>
|
||||
void Activate();
|
||||
Task Activate();
|
||||
|
||||
/// <summary>
|
||||
/// Deactivates this room combination scenario
|
||||
/// </summary>
|
||||
void Deactivate();
|
||||
Task Deactivate();
|
||||
|
||||
/// <summary>
|
||||
/// The state of the partitions that would activate this scenario
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core.Logging;
|
||||
using Serilog.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a room combination scenario
|
||||
/// </summary>
|
||||
public class RoomCombinationScenario: IRoomCombinationScenario, IKeyName
|
||||
public class RoomCombinationScenario : IRoomCombinationScenario, IKeyName
|
||||
{
|
||||
private RoomCombinationScenarioConfig _config;
|
||||
|
||||
@@ -40,7 +34,7 @@ namespace PepperDash.Essentials.Core
|
||||
get { return _isActive; }
|
||||
set
|
||||
{
|
||||
if(value == _isActive)
|
||||
if (value == _isActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -76,30 +70,36 @@ namespace PepperDash.Essentials.Core
|
||||
IsActiveFeedback = new BoolFeedback(() => _isActive);
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
public async Task Activate()
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Activating Scenario: '{0}' with {1} action(s) defined", Name, activationActions.Count);
|
||||
this.LogInformation("Activating Scenario {name} with {activationActionCount} action(s) defined", Name, activationActions.Count);
|
||||
|
||||
List<Task> tasks = new List<Task>();
|
||||
|
||||
if (activationActions != null)
|
||||
{
|
||||
foreach (var action in activationActions)
|
||||
{
|
||||
DeviceJsonApi.DoDeviceAction(action);
|
||||
this.LogInformation("Running Activation action {@action}", action);
|
||||
await DeviceJsonApi.DoDeviceActionAsync(action);
|
||||
}
|
||||
}
|
||||
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
public async Task Deactivate()
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Deactivating Scenario: '{0}' with {1} action(s) defined", Name, deactivationActions.Count);
|
||||
this.LogInformation("Deactivating Scenario {name} with {deactivationActionCount} action(s) defined", Name, deactivationActions.Count);
|
||||
|
||||
List<Task> tasks = new List<Task>();
|
||||
|
||||
if (deactivationActions != null)
|
||||
{
|
||||
foreach (var action in deactivationActions)
|
||||
{
|
||||
DeviceJsonApi.DoDeviceAction(action);
|
||||
this.LogInformation("Running deactivation action {actionDeviceKey}:{actionMethod}", action.DeviceKey, action.MethodName);
|
||||
await DeviceJsonApi.DoDeviceActionAsync(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -198,6 +199,12 @@ namespace PepperDash.Essentials.Room.Config
|
||||
public string SourceListKey { get; set; }
|
||||
[JsonProperty("destinationListKey")]
|
||||
public string DestinationListKey { get; set; }
|
||||
[JsonProperty("audioControlPointListKey")]
|
||||
public string AudioControlPointListKey { get; set; }
|
||||
[JsonProperty("cameraListKey")]
|
||||
public string CameraListKey { get; set; }
|
||||
|
||||
|
||||
[JsonProperty("defaultSourceItem")]
|
||||
public string DefaultSourceItem { get; set; }
|
||||
/// <summary>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
public class EssentialsRoomEmergencyTriggerConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// contact,
|
||||
/// contact,versiport
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
/// <summary>
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -59,28 +59,102 @@ namespace PepperDash.Essentials.Core
|
||||
/// </summary>
|
||||
public IMobileControlRoomMessenger MobileControlRoomBridge { get; private set; }
|
||||
|
||||
protected const string _defaultListKey = "default";
|
||||
|
||||
/// <summary>
|
||||
/// The config name of the source list
|
||||
/// </summary>
|
||||
///
|
||||
protected string _SourceListKey;
|
||||
private string _sourceListKey;
|
||||
public string SourceListKey {
|
||||
get
|
||||
{
|
||||
return _SourceListKey;
|
||||
}
|
||||
private set
|
||||
{
|
||||
if (value != _SourceListKey)
|
||||
if(string.IsNullOrEmpty(_sourceListKey))
|
||||
{
|
||||
_SourceListKey = value;
|
||||
return _defaultListKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _sourceListKey;
|
||||
}
|
||||
}
|
||||
protected set
|
||||
{
|
||||
if (value != _sourceListKey)
|
||||
{
|
||||
_sourceListKey = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string DestinationListKey { get; private set; }
|
||||
private string _destinationListKey;
|
||||
public string DestinationListKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_destinationListKey))
|
||||
{
|
||||
return _defaultListKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _destinationListKey;
|
||||
}
|
||||
}
|
||||
protected set
|
||||
{
|
||||
if (value != _destinationListKey)
|
||||
{
|
||||
_destinationListKey = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected const string _defaultSourceListKey = "default";
|
||||
private string _audioControlPointListKey;
|
||||
public string AudioControlPointListKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_audioControlPointListKey))
|
||||
{
|
||||
return _defaultListKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _destinationListKey;
|
||||
}
|
||||
}
|
||||
protected set
|
||||
{
|
||||
if (value != _audioControlPointListKey)
|
||||
{
|
||||
_audioControlPointListKey = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _cameraListKey;
|
||||
public string CameraListKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_cameraListKey))
|
||||
{
|
||||
return _defaultListKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _cameraListKey;
|
||||
}
|
||||
}
|
||||
protected set
|
||||
{
|
||||
if (value != _cameraListKey)
|
||||
{
|
||||
_cameraListKey = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timer used for informing the UIs of a shutdown
|
||||
@@ -141,6 +215,7 @@ namespace PepperDash.Essentials.Core
|
||||
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
|
||||
ShutdownType = eShutdownType.None;
|
||||
};
|
||||
|
||||
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
|
||||
|
||||
ShutdownPromptSeconds = 60;
|
||||
@@ -191,7 +266,7 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceListKey = _defaultSourceListKey;
|
||||
sourceListKey = _defaultListKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
string DestinationListKey { get; }
|
||||
|
||||
string AudioControlPointListKey { get; }
|
||||
|
||||
string CameraListKey { get; }
|
||||
|
||||
SecondsCountdownTimer ShutdownPromptTimer { get; }
|
||||
int ShutdownPromptSeconds { get; }
|
||||
int ShutdownVacancySeconds { get; }
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
void RunRouteAction(string routeKey, string sourceListKey);
|
||||
|
||||
void RunRouteAction(string routeKey, string sourceListKey, Action successCallback);
|
||||
void RunRouteAction(string routeKey, string sourceListKey, Action successCallback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -159,4 +159,13 @@ namespace PepperDash.Essentials.Core
|
||||
Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; }
|
||||
}
|
||||
|
||||
public interface IHasAccessoryDevices : IKeyName
|
||||
{
|
||||
List<string> AccessoryDeviceKeys { get; }
|
||||
}
|
||||
|
||||
public interface IHasCiscoNavigatorTouchpanel
|
||||
{
|
||||
string CiscoNavigatorTouchpanelKey { get; }
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
public class DummyRoutingInputsDevice : Device, IRoutingSource
|
||||
public class DummyRoutingInputsDevice : Device, IRoutingSource, IRoutingOutputs
|
||||
{
|
||||
/// <summary>
|
||||
/// A single output port, backplane, audioVideo
|
||||
|
||||
373
src/PepperDash.Essentials.Core/Routing/Extensions.cs
Normal file
373
src/PepperDash.Essentials.Core/Routing/Extensions.cs
Normal file
@@ -0,0 +1,373 @@
|
||||
using PepperDash.Essentials.Core.Queues;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Debug = PepperDash.Core.Debug;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Extensions added to any IRoutingInputs classes to provide discovery-based routing
|
||||
/// on those destinations.
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
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
|
||||
/// in RouteDescriptorCollection.DefaultCollection
|
||||
/// </summary>
|
||||
public static void ReleaseAndMakeRoute(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, string destinationPortKey = "", string sourcePortKey = "")
|
||||
{
|
||||
// Remove this line before committing!!!!!
|
||||
var frame = new StackFrame(1, true);
|
||||
Debug.LogMessage(LogEventLevel.Information, "ReleaseAndMakeRoute Called from {method} with params {destinationKey}:{sourceKey}:{signalType}:{destinationPortKey}:{sourcePortKey}", frame.GetMethod().Name, destination.Key, source.Key, signalType.ToString(), destinationPortKey, sourcePortKey);
|
||||
|
||||
var inputPort = string.IsNullOrEmpty(destinationPortKey) ? null : destination.InputPorts.FirstOrDefault(p => p.Key == destinationPortKey);
|
||||
var outputPort = string.IsNullOrEmpty(sourcePortKey) ? null : source.OutputPorts.FirstOrDefault(p => p.Key == sourcePortKey);
|
||||
|
||||
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)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Removing route request for {destination}", null, destinationKey);
|
||||
|
||||
var result = RouteRequests.Remove(destinationKey);
|
||||
|
||||
var messageTemplate = result ? "Route Request for {destination} removed" : "Route Request for {destination} not found";
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, messageTemplate, null, destinationKey);
|
||||
}
|
||||
|
||||
/// <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
|
||||
/// a route is discovered, a new RouteDescriptor is returned. If one or both parts
|
||||
/// of an audio/video route are discovered a route descriptor is returned. If no route is
|
||||
/// discovered, then null is returned
|
||||
/// </summary>
|
||||
public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort)
|
||||
{
|
||||
// if it's a single signal type, find the route
|
||||
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo))
|
||||
{
|
||||
var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType);
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType);
|
||||
|
||||
if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort))
|
||||
singleTypeRouteDescriptor = null;
|
||||
|
||||
var routes = singleTypeRouteDescriptor?.Routes ?? new List<RouteSwitchDescriptor>();
|
||||
foreach (var route in routes)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString());
|
||||
}
|
||||
|
||||
return (singleTypeRouteDescriptor, null);
|
||||
}
|
||||
// otherwise, audioVideo needs to be handled as two steps.
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key);
|
||||
|
||||
var audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio);
|
||||
|
||||
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort);
|
||||
|
||||
if (!audioSuccess)
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key);
|
||||
|
||||
var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Video);
|
||||
|
||||
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort);
|
||||
|
||||
if (!videoSuccess)
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key);
|
||||
|
||||
foreach (var route in audioRouteDescriptor.Routes)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString());
|
||||
}
|
||||
|
||||
foreach (var route in videoRouteDescriptor.Routes)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString());
|
||||
}
|
||||
|
||||
|
||||
if (!audioSuccess && !videoSuccess)
|
||||
return (null, null);
|
||||
|
||||
|
||||
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
|
||||
/// hoping to find the source.
|
||||
/// </summary>
|
||||
/// <param name="destination"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="destinationPort">The RoutingOutputPort whose link is being checked for a route</param>
|
||||
/// <param name="alreadyCheckedDevices">Prevents Devices from being twice-checked</param>
|
||||
/// <param name="signalType">This recursive function should not be called with AudioVideo</param>
|
||||
/// <param name="cycle">Just an informational counter</param>
|
||||
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
|
||||
/// <returns>true if source is hit</returns>
|
||||
private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
|
||||
RoutingOutputPort outputPortToUse, List<IRoutingInputsOutputs> alreadyCheckedDevices,
|
||||
eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable, RoutingInputPort destinationPort, RoutingOutputPort sourcePort)
|
||||
{
|
||||
cycle++;
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString());
|
||||
|
||||
RoutingInputPort goodInputPort = null;
|
||||
|
||||
IEnumerable<TieLine> destinationTieLines;
|
||||
TieLine directTie = null;
|
||||
|
||||
if (destinationPort == null)
|
||||
{
|
||||
|
||||
destinationTieLines = TieLineCollection.Default.Where(t =>
|
||||
t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo)));
|
||||
}
|
||||
else
|
||||
{
|
||||
destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo)));
|
||||
}
|
||||
|
||||
// find the TieLine without a port
|
||||
if (destinationPort == null && sourcePort == null)
|
||||
{
|
||||
directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.SourcePort.ParentDevice.Key == source.Key);
|
||||
}
|
||||
// find a tieLine to a specific destination port without a specific source port
|
||||
else if (destinationPort != null && sourcePort == null)
|
||||
{
|
||||
directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key);
|
||||
}
|
||||
// find a tieline to a specific source port without a specific destination port
|
||||
else if (destinationPort == null & sourcePort != null)
|
||||
{
|
||||
directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key);
|
||||
}
|
||||
// find a tieline to a specific source port and destination port
|
||||
else if (destinationPort != null && sourcePort != null)
|
||||
{
|
||||
directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key);
|
||||
}
|
||||
|
||||
if (directTie != null) // Found a tie directly to the source
|
||||
{
|
||||
goodInputPort = directTie.DestinationPort;
|
||||
}
|
||||
else // no direct-connect. Walk back devices.
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {sourceKey}. Walking down tie lines", destination, source.Key);
|
||||
|
||||
// No direct tie? Run back out on the inputs' attached devices...
|
||||
// Only the ones that are routing devices
|
||||
var midpointTieLines = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
|
||||
|
||||
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
|
||||
if (alreadyCheckedDevices == null)
|
||||
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
|
||||
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
|
||||
|
||||
foreach (var tieLine in midpointTieLines)
|
||||
{
|
||||
var midpointDevice = tieLine.SourcePort.ParentDevice as IRoutingInputsOutputs;
|
||||
|
||||
// Check if this previous device has already been walked
|
||||
if (alreadyCheckedDevices.Contains(midpointDevice))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", destination, midpointDevice.Key, destination.Key);
|
||||
continue;
|
||||
}
|
||||
|
||||
var midpointOutputPort = tieLine.SourcePort;
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {midpointDeviceKey}", destination, midpointDevice.Key);
|
||||
|
||||
// haven't seen this device yet. Do it. Pass the output port to the next
|
||||
// level to enable switching on success
|
||||
var upstreamRoutingSuccess = midpointDevice.GetRouteToSource(source, midpointOutputPort,
|
||||
alreadyCheckedDevices, signalType, cycle, routeTable, null, sourcePort);
|
||||
|
||||
if (upstreamRoutingSuccess)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Route found on {midpointDeviceKey}", destination, midpointDevice.Key);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", destination, tieLine.SourcePort, tieLine.DestinationPort);
|
||||
goodInputPort = tieLine.DestinationPort;
|
||||
break; // Stop looping the inputs in this cycle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (goodInputPort == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key);
|
||||
return false;
|
||||
}
|
||||
|
||||
// we have a route on corresponding inputPort. *** Do the route ***
|
||||
|
||||
if (destination is IRoutingSink)
|
||||
{
|
||||
// it's a sink device
|
||||
routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
|
||||
}
|
||||
else if (destination is IRouting)
|
||||
{
|
||||
routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort));
|
||||
}
|
||||
else // device is merely IRoutingInputOutputs
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Unmerged change from project 'PepperDash.Essentials.Core (net6)'
|
||||
Before:
|
||||
namespace PepperDash.Essentials.Core.Routing.Interfaces
|
||||
After:
|
||||
using PepperDash;
|
||||
using PepperDash.Essentials;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using PepperDash.Essentials.Core.Routing.Interfaces
|
||||
*/
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// The handler type for a Room's SourceInfoChange
|
||||
/// </summary>
|
||||
public delegate void SourceInfoChangeHandler(SourceListItem info, ChangeType type);
|
||||
//*******************************************************************************************
|
||||
// Interfaces
|
||||
|
||||
/// <summary>
|
||||
/// For rooms with a single presentation source, change event
|
||||
/// </summary>
|
||||
public interface IHasCurrentSourceInfoChange
|
||||
{
|
||||
string CurrentSourceInfoKey { get; set; }
|
||||
SourceListItem CurrentSourceInfo { get; set; }
|
||||
event SourceInfoChangeHandler CurrentSourceChange;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
public interface IVideoSync: IKeyed
|
||||
public interface IVideoSync : IKeyed
|
||||
{
|
||||
bool VideoSyncDetected { get; }
|
||||
|
||||
|
||||
10
src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs
Normal file
10
src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a receiver that has internal routing (DM-RMC-4K-Z-SCALER-C)
|
||||
/// </summary>
|
||||
public interface IRmcRouting : IRoutingNumeric
|
||||
{
|
||||
IntFeedback AudioVideoSourceNumericFeedback { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an IRmcRouting with a feedback event
|
||||
/// </summary>
|
||||
public interface IRmcRoutingWithFeedback : IRmcRouting
|
||||
{
|
||||
}
|
||||
}
|
||||
21
src/PepperDash.Essentials.Core/Routing/IRouting.cs
Normal file
21
src/PepperDash.Essentials.Core/Routing/IRouting.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a midpoint device as have internal routing. Any devices in the middle of the
|
||||
/// signal chain, that do switching, must implement this for routing to work otherwise
|
||||
/// the routing algorithm will treat the IRoutingInputsOutputs device as a passthrough
|
||||
/// device.
|
||||
/// </summary>
|
||||
public interface IRouting : IRoutingInputsOutputs
|
||||
{
|
||||
void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType);
|
||||
}
|
||||
|
||||
/*public interface IRouting<TInputSelector,TOutputSelector> : IRoutingInputsOutputs
|
||||
{
|
||||
void ExecuteSwitch(TInputSelector inputSelector, TOutputSelector outputSelector, eRoutingSignalType signalType);
|
||||
}*/
|
||||
}
|
||||
16
src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs
Normal file
16
src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an event structure for reporting output route data
|
||||
/// </summary>
|
||||
public interface IRoutingFeedback : IKeyName
|
||||
{
|
||||
event EventHandler<RoutingNumericEventArgs> NumericSwitchChange;
|
||||
//void OnSwitchChange(RoutingNumericEventArgs e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.DM;
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
|
||||
public interface IRoutingHasVideoInputSyncFeedbacks
|
||||
{
|
||||
FeedbackCollection<BoolFeedback> VideoInputSyncFeedbacks { get; }
|
||||
}
|
||||
}
|
||||
18
src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs
Normal file
18
src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a class that has a collection of RoutingInputPorts
|
||||
/// </summary>
|
||||
public interface IRoutingInputs : IKeyed
|
||||
{
|
||||
RoutingPortCollection<RoutingInputPort> InputPorts { get; }
|
||||
}
|
||||
|
||||
/* public interface IRoutingInputs<TSelector> : IKeyed
|
||||
{
|
||||
RoutingPortCollection<RoutingInputPort<TSelector>, TSelector> InputPorts { get; }
|
||||
}*/
|
||||
}
|
||||
@@ -1,426 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.DM;
|
||||
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class RouteRequest
|
||||
{
|
||||
public IRoutingSink Destination {get; set;}
|
||||
public IRoutingOutputs Source {get; set;}
|
||||
public eRoutingSignalType SignalType {get; set;}
|
||||
|
||||
public void HandleCooldown(object sender, FeedbackEventArgs args)
|
||||
{
|
||||
var coolingDevice = sender as IWarmingCooling;
|
||||
|
||||
if(args.BoolValue == false)
|
||||
{
|
||||
Destination.ReleaseAndMakeRoute(Source, SignalType);
|
||||
|
||||
if(sender == null) return;
|
||||
|
||||
coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extensions added to any IRoutingInputs classes to provide discovery-based routing
|
||||
/// on those destinations.
|
||||
/// </summary>
|
||||
public static class IRoutingInputsExtensions
|
||||
{
|
||||
private static Dictionary<string, RouteRequest> RouteRequests = new Dictionary<string, RouteRequest>();
|
||||
/// <summary>
|
||||
/// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
|
||||
/// and then attempts a new Route and if sucessful, stores that RouteDescriptor
|
||||
/// in RouteDescriptorCollection.DefaultCollection
|
||||
/// </summary>
|
||||
public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
|
||||
{
|
||||
var routeRequest = new RouteRequest {
|
||||
Destination = destination,
|
||||
Source = source,
|
||||
SignalType = signalType
|
||||
};
|
||||
|
||||
var coolingDevice = destination as IWarmingCooling;
|
||||
|
||||
RouteRequest existingRouteRequest;
|
||||
|
||||
//We already have a route request for this device, and it's a cooling device and is cooling
|
||||
if (RouteRequests.TryGetValue(destination.Key, out existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
|
||||
{
|
||||
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
|
||||
|
||||
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
|
||||
|
||||
RouteRequests[destination.Key] = routeRequest;
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "******************************************************** Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", 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.Verbose, "******************************************************** Device: {0} is cooling down. Storing route request to route to source key: {1}", destination.Key, routeRequest.Source.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false)
|
||||
{
|
||||
RouteRequests.Remove(destination.Key);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "******************************************************** Device: {0} is NOT cooling down. Removing stored route request and routing to source key: {1}", destination.Key, routeRequest.Source.Key);
|
||||
}
|
||||
|
||||
destination.ReleaseRoute();
|
||||
|
||||
RunRouteRequest(routeRequest);
|
||||
}
|
||||
|
||||
public static void RunRouteRequest(RouteRequest request)
|
||||
{
|
||||
if (request.Source == null) return;
|
||||
var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType);
|
||||
if (newRoute == null) return;
|
||||
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, request.Destination, "Executing full route");
|
||||
newRoute.ExecuteRoutes();
|
||||
}
|
||||
|
||||
/// <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 IRoutingSink destination)
|
||||
{
|
||||
RouteRequest existingRequest;
|
||||
|
||||
if (RouteRequests.TryGetValue(destination.Key, out existingRequest) && destination is IWarmingCooling)
|
||||
{
|
||||
var coolingDevice = destination as IWarmingCooling;
|
||||
|
||||
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown;
|
||||
}
|
||||
|
||||
RouteRequests.Remove(destination.Key);
|
||||
|
||||
var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination);
|
||||
if (current != null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, destination, "Releasing current route: {0}", 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
|
||||
/// a route is discovered, a new RouteDescriptor is returned. If one or both parts
|
||||
/// of an audio/video route are discovered a route descriptor is returned. If no route is
|
||||
/// discovered, then null is returned
|
||||
/// </summary>
|
||||
public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
|
||||
{
|
||||
var routeDescr = new RouteDescriptor(source, destination, signalType);
|
||||
// if it's a single signal type, find the route
|
||||
if ((signalType & (eRoutingSignalType.Audio & eRoutingSignalType.Video)) == (eRoutingSignalType.Audio & eRoutingSignalType.Video))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, destination, "Attempting to build source route from {0}", source.Key);
|
||||
if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescr))
|
||||
routeDescr = null;
|
||||
}
|
||||
// otherwise, audioVideo needs to be handled as two steps.
|
||||
else
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, destination, "Attempting to build audio and video routes from {0}", source.Key);
|
||||
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescr);
|
||||
if (!audioSuccess)
|
||||
Debug.LogMessage(LogEventLevel.Debug, destination, "Cannot find audio route to {0}", source.Key);
|
||||
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescr);
|
||||
if (!videoSuccess)
|
||||
Debug.LogMessage(LogEventLevel.Debug, destination, "Cannot find video route to {0}", source.Key);
|
||||
if (!audioSuccess && !videoSuccess)
|
||||
routeDescr = null;
|
||||
}
|
||||
|
||||
//Debug.LogMessage(LogEventLevel.Debug, destination, "Route{0} discovered", routeDescr == null ? " NOT" : "");
|
||||
return routeDescr;
|
||||
}
|
||||
|
||||
/// <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
|
||||
/// hoping to find the source.
|
||||
/// </summary>
|
||||
/// <param name="destination"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="outputPortToUse">The RoutingOutputPort whose link is being checked for a route</param>
|
||||
/// <param name="alreadyCheckedDevices">Prevents Devices from being twice-checked</param>
|
||||
/// <param name="signalType">This recursive function should not be called with AudioVideo</param>
|
||||
/// <param name="cycle">Just an informational counter</param>
|
||||
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
|
||||
/// <returns>true if source is hit</returns>
|
||||
static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
|
||||
RoutingOutputPort outputPortToUse, List<IRoutingInputsOutputs> alreadyCheckedDevices,
|
||||
eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable)
|
||||
{
|
||||
cycle++;
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {0} {1}--> {2}", cycle, source.Key, destination.Key);
|
||||
|
||||
RoutingInputPort goodInputPort = null;
|
||||
var destDevInputTies = TieLineCollection.Default.Where(t =>
|
||||
t.DestinationPort.ParentDevice == destination && (t.Type == signalType || (t.Type & (eRoutingSignalType.Audio | eRoutingSignalType.Video)) == (eRoutingSignalType.Audio | eRoutingSignalType.Video)));
|
||||
|
||||
// find a direct tie
|
||||
var directTie = destDevInputTies.FirstOrDefault(
|
||||
t => t.DestinationPort.ParentDevice == destination
|
||||
&& t.SourcePort.ParentDevice == source);
|
||||
if (directTie != null) // Found a tie directly to the source
|
||||
{
|
||||
goodInputPort = directTie.DestinationPort;
|
||||
}
|
||||
else // no direct-connect. Walk back devices.
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, destination, "is not directly connected to {0}. Walking down tie lines", source.Key);
|
||||
|
||||
// No direct tie? Run back out on the inputs' attached devices...
|
||||
// Only the ones that are routing devices
|
||||
var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
|
||||
|
||||
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
|
||||
if (alreadyCheckedDevices == null)
|
||||
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
|
||||
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
|
||||
|
||||
foreach (var inputTieToTry in attachedMidpoints)
|
||||
{
|
||||
var upstreamDeviceOutputPort = inputTieToTry.SourcePort;
|
||||
var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs;
|
||||
Debug.LogMessage(LogEventLevel.Verbose, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key);
|
||||
|
||||
// Check if this previous device has already been walked
|
||||
if (alreadyCheckedDevices.Contains(upstreamRoutingDevice))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key);
|
||||
continue;
|
||||
}
|
||||
// haven't seen this device yet. Do it. Pass the output port to the next
|
||||
// level to enable switching on success
|
||||
var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
|
||||
alreadyCheckedDevices, signalType, cycle, routeTable);
|
||||
if (upstreamRoutingSuccess)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, destination, "Upstream device route found");
|
||||
goodInputPort = inputTieToTry.DestinationPort;
|
||||
break; // Stop looping the inputs in this cycle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we have a route on corresponding inputPort. *** Do the route ***
|
||||
if (goodInputPort != null)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, destination, "adding RouteDescriptor");
|
||||
if (outputPortToUse == null)
|
||||
{
|
||||
// it's a sink device
|
||||
routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
|
||||
}
|
||||
else if (destination is IRouting)
|
||||
{
|
||||
routeTable.Routes.Add(new RouteSwitchDescriptor (outputPortToUse, goodInputPort));
|
||||
}
|
||||
else // device is merely IRoutingInputOutputs
|
||||
Debug.LogMessage(LogEventLevel.Verbose, destination, " No routing. Passthrough device");
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, destination, "Exiting cycle {0}", cycle);
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, destination, "No route found to {0}", source.Key);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A collection of RouteDescriptors - typically the static DefaultCollection is used
|
||||
/// </summary>
|
||||
public class RouteDescriptorCollection
|
||||
{
|
||||
public static RouteDescriptorCollection DefaultCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_DefaultCollection == null)
|
||||
_DefaultCollection = new RouteDescriptorCollection();
|
||||
return _DefaultCollection;
|
||||
}
|
||||
}
|
||||
static RouteDescriptorCollection _DefaultCollection;
|
||||
|
||||
List<RouteDescriptor> RouteDescriptors = new List<RouteDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the
|
||||
/// destination exists already, it will not be added - in order to preserve
|
||||
/// proper route releasing.
|
||||
/// </summary>
|
||||
/// <param name="descriptor"></param>
|
||||
public void AddRouteDescriptor(RouteDescriptor descriptor)
|
||||
{
|
||||
if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination,
|
||||
"Route to [{0}] already exists in global routes table", descriptor.Source.Key);
|
||||
return;
|
||||
}
|
||||
RouteDescriptors.Add(descriptor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RouteDescriptor for a destination
|
||||
/// </summary>
|
||||
/// <returns>null if no RouteDescriptor for a destination exists</returns>
|
||||
public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination)
|
||||
{
|
||||
return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the RouteDescriptor for a given destination AND removes it from collection.
|
||||
/// Returns null if no route with the provided destination exists.
|
||||
/// </summary>
|
||||
public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination)
|
||||
{
|
||||
var descr = GetRouteDescriptorForDestination(destination);
|
||||
if (descr != null)
|
||||
RouteDescriptors.Remove(descr);
|
||||
return descr;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an collection of individual route steps between Source and Destination
|
||||
/// </summary>
|
||||
public class RouteDescriptor
|
||||
{
|
||||
public IRoutingInputs Destination { 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)
|
||||
{
|
||||
Destination = destination;
|
||||
Source = source;
|
||||
SignalType = signalType;
|
||||
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}", route.ToString());
|
||||
if (route.SwitchingDevice is IRoutingSink)
|
||||
{
|
||||
var device = route.SwitchingDevice as IRoutingSinkWithSwitching;
|
||||
if (device == null)
|
||||
continue;
|
||||
|
||||
device.ExecuteSwitch(route.InputPort.Selector);
|
||||
}
|
||||
else if (route.SwitchingDevice is IRouting)
|
||||
{
|
||||
(route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
|
||||
route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Output port {0} routing. Count={1}", 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)
|
||||
{
|
||||
if (route.SwitchingDevice is IRouting)
|
||||
{
|
||||
// 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}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 individual link for a route
|
||||
/// </summary>
|
||||
public class RouteSwitchDescriptor
|
||||
{
|
||||
public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } }
|
||||
public RoutingOutputPort OutputPort { get; set; }
|
||||
public RoutingInputPort InputPort { get; set; }
|
||||
|
||||
public RouteSwitchDescriptor(RoutingInputPort inputPort)
|
||||
{
|
||||
InputPort = inputPort;
|
||||
}
|
||||
|
||||
public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort)
|
||||
{
|
||||
InputPort = inputPort;
|
||||
OutputPort = outputPort;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if(SwitchingDevice is IRouting)
|
||||
return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector);
|
||||
else
|
||||
return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// For devices like RMCs, baluns, other devices with no switching.
|
||||
/// </summary>
|
||||
public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs
|
||||
{
|
||||
}
|
||||
|
||||
/* /// <summary>
|
||||
/// For devices like RMCs, baluns, other devices with no switching.
|
||||
/// </summary>
|
||||
public interface IRoutingInputsOutputs<TInputSelector, TOutputSelector> : IRoutingInputs<TInputSelector>, IRoutingOutputs<TOutputSelector>
|
||||
{
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface IRoutingNumeric : IRouting
|
||||
{
|
||||
void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an IRoutingNumeric with a feedback event
|
||||
/// </summary>
|
||||
public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback
|
||||
{
|
||||
}
|
||||
}
|
||||
19
src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs
Normal file
19
src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a class that has a collection of RoutingOutputPorts
|
||||
/// </summary>
|
||||
|
||||
public interface IRoutingOutputs : IKeyed
|
||||
{
|
||||
RoutingPortCollection<RoutingOutputPort> OutputPorts { get; }
|
||||
}
|
||||
|
||||
/* public interface IRoutingOutputs<TSelector> : IKeyed
|
||||
{
|
||||
RoutingPortCollection<RoutingOutputPort<TSelector>, TSelector> OutputPorts { get; }
|
||||
}*/
|
||||
}
|
||||
23
src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs
Normal file
23
src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// For fixed-source endpoint devices
|
||||
/// </summary>
|
||||
public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange
|
||||
{
|
||||
}
|
||||
|
||||
public interface IRoutingSinkWithInputPort :IRoutingSink
|
||||
{
|
||||
RoutingInputPort CurrentInputPort { get; }
|
||||
}
|
||||
/*/// <summary>
|
||||
/// For fixed-source endpoint devices
|
||||
/// </summary>
|
||||
public interface IRoutingSink<TSelector> : IRoutingInputs<TSelector>, IHasCurrentSourceInfoChange
|
||||
{
|
||||
void UpdateRouteRequest<TOutputSelector>(RouteRequest<TSelector, TOutputSelector> request);
|
||||
|
||||
RouteRequest<TSelector, TOutputSelector> GetRouteRequest<TOutputSelector>();
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using PepperDash.Essentials.Core.Routing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// For fixed-source endpoint devices
|
||||
/// </summary>
|
||||
public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* /// <summary>
|
||||
/// For fixed-source endpoint devices
|
||||
/// </summary>
|
||||
public interface IRoutingSinkWithFeedback<TSelector> : IRoutingSinkWithSwitching<TSelector>
|
||||
{
|
||||
RouteSwitchDescriptor CurrentRoute { get; }
|
||||
|
||||
event EventHandler InputChanged;
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public delegate void InputChangedEventHandler(IRoutingSinkWithSwitching destination, RoutingInputPort currentPort);
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint device like a display, that selects inputs
|
||||
/// </summary>
|
||||
public interface IRoutingSinkWithSwitching : IRoutingSink
|
||||
{
|
||||
void ExecuteSwitch(object inputSelector);
|
||||
}
|
||||
|
||||
public interface IRoutingSinkWithSwitchingWithInputPort:IRoutingSinkWithSwitching, IRoutingSinkWithInputPort
|
||||
{
|
||||
event InputChangedEventHandler InputChanged;
|
||||
}
|
||||
|
||||
/* /// <summary>
|
||||
/// Endpoint device like a display, that selects inputs
|
||||
/// </summary>
|
||||
public interface IRoutingSinkWithSwitching<TSelector> : IRoutingSink<TSelector>
|
||||
{
|
||||
void ExecuteSwitch(TSelector inputSelector);
|
||||
}*/
|
||||
}
|
||||
9
src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs
Normal file
9
src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an IRoutingOutputs devices as being a source - the start of the chain
|
||||
/// </summary>
|
||||
public interface IRoutingSource : IRoutingOutputs
|
||||
{
|
||||
}
|
||||
}
|
||||
12
src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs
Normal file
12
src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface IRoutingWithClear : IRouting
|
||||
{
|
||||
/// <summary>
|
||||
/// Clears a route to an output, however a device needs to do that
|
||||
/// </summary>
|
||||
/// <param name="outputSelector">Output to clear</param>
|
||||
/// <param name="signalType">signal type to clear</param>
|
||||
void ClearRoute(object outputSelector, eRoutingSignalType signalType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public delegate void RouteChangedEventHandler(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute);
|
||||
/// <summary>
|
||||
/// Defines an IRouting with a feedback event
|
||||
/// </summary>
|
||||
public interface IRoutingWithFeedback : IRouting
|
||||
{
|
||||
List<RouteSwitchDescriptor> CurrentRoutes { get; }
|
||||
|
||||
event RouteChangedEventHandler RouteChanged;
|
||||
}
|
||||
}
|
||||
8
src/PepperDash.Essentials.Core/Routing/ITxRouting.cs
Normal file
8
src/PepperDash.Essentials.Core/Routing/ITxRouting.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface ITxRouting : IRoutingNumeric
|
||||
{
|
||||
IntFeedback VideoSourceNumericFeedback { get; }
|
||||
IntFeedback AudioSourceNumericFeedback { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an IRmcRouting with a feedback event
|
||||
/// </summary>
|
||||
public interface ITxRoutingWithFeedback : ITxRouting
|
||||
{
|
||||
}
|
||||
}
|
||||
170
src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs
Normal file
170
src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Crestron.SimplSharpPro;
|
||||
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an collection of individual route steps between Source and Destination
|
||||
/// </summary>
|
||||
public class RouteDescriptor
|
||||
{
|
||||
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 RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) : this(source, destination, null, signalType)
|
||||
{
|
||||
}
|
||||
|
||||
public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType)
|
||||
{
|
||||
Destination = destination;
|
||||
Source = source;
|
||||
SignalType = signalType;
|
||||
InputPort = inputPort;
|
||||
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());
|
||||
|
||||
if (route.SwitchingDevice is IRoutingSinkWithSwitching sink)
|
||||
{
|
||||
sink.ExecuteSwitch(route.InputPort.Selector);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (route.SwitchingDevice is IRouting switchingDevice)
|
||||
{
|
||||
switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
|
||||
|
||||
route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
|
||||
|
||||
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)
|
||||
{
|
||||
if (route.OutputPort == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// Represents an collection of individual route steps between Source and Destination
|
||||
/// </summary>
|
||||
public class RouteDescriptor<TInputSelector, TOutputSelector>
|
||||
{
|
||||
public IRoutingInputs<TInputSelector> Destination { get; private set; }
|
||||
public IRoutingOutputs<TOutputSelector> Source { get; private set; }
|
||||
public eRoutingSignalType SignalType { get; private set; }
|
||||
public List<RouteSwitchDescriptor<TInputSelector, TOutputSelector>> Routes { get; private set; }
|
||||
|
||||
|
||||
public RouteDescriptor(IRoutingOutputs<TOutputSelector> source, IRoutingInputs<TInputSelector> destination, eRoutingSignalType signalType)
|
||||
{
|
||||
Destination = destination;
|
||||
Source = source;
|
||||
SignalType = signalType;
|
||||
Routes = new List<RouteSwitchDescriptor<TInputSelector, TOutputSelector>>();
|
||||
}
|
||||
|
||||
/// <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<TInputSelector> sink)
|
||||
{
|
||||
sink.ExecuteSwitch(route.InputPort.Selector);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (route.SwitchingDevice is IRouting switchingDevice)
|
||||
{
|
||||
switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
|
||||
|
||||
route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
|
||||
|
||||
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)
|
||||
{
|
||||
if (route.SwitchingDevice is IRouting<TInputSelector, TOutputSelector>)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of RouteDescriptors - typically the static DefaultCollection is used
|
||||
/// </summary>
|
||||
public class RouteDescriptorCollection
|
||||
{
|
||||
public static RouteDescriptorCollection DefaultCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_DefaultCollection == null)
|
||||
_DefaultCollection = new RouteDescriptorCollection();
|
||||
return _DefaultCollection;
|
||||
}
|
||||
}
|
||||
private static RouteDescriptorCollection _DefaultCollection;
|
||||
|
||||
private readonly List<RouteDescriptor> RouteDescriptors = new List<RouteDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the
|
||||
/// destination exists already, it will not be added - in order to preserve
|
||||
/// proper route releasing.
|
||||
/// </summary>
|
||||
/// <param name="descriptor"></param>
|
||||
public void AddRouteDescriptor(RouteDescriptor descriptor)
|
||||
{
|
||||
if (descriptor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination)
|
||||
&& 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);
|
||||
return;
|
||||
}
|
||||
RouteDescriptors.Add(descriptor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RouteDescriptor for a destination
|
||||
/// </summary>
|
||||
/// <returns>null if no RouteDescriptor for a destination exists</returns>
|
||||
public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs 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.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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the RouteDescriptor for a given destination AND removes it from collection.
|
||||
/// Returns null if no route with the provided destination exists.
|
||||
/// </summary>
|
||||
public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination, string 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)
|
||||
: GetRouteDescriptorForDestinationAndInputPort(destination, inputPortKey);
|
||||
if (descr != null)
|
||||
RouteDescriptors.Remove(descr);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Found route descriptor {routeDescriptor}", destination, descr);
|
||||
|
||||
return descr;
|
||||
}
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// A collection of RouteDescriptors - typically the static DefaultCollection is used
|
||||
/// </summary>
|
||||
public class RouteDescriptorCollection<TInputSelector, TOutputSelector>
|
||||
{
|
||||
public static RouteDescriptorCollection<TInputSelector, TOutputSelector> DefaultCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_DefaultCollection == null)
|
||||
_DefaultCollection = new RouteDescriptorCollection<TInputSelector, TOutputSelector>();
|
||||
return _DefaultCollection;
|
||||
}
|
||||
}
|
||||
private static RouteDescriptorCollection<TInputSelector, TOutputSelector> _DefaultCollection;
|
||||
|
||||
private readonly List<RouteDescriptor> RouteDescriptors = new List<RouteDescriptor>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the
|
||||
/// destination exists already, it will not be added - in order to preserve
|
||||
/// proper route releasing.
|
||||
/// </summary>
|
||||
/// <param name="descriptor"></param>
|
||||
public void AddRouteDescriptor(RouteDescriptor descriptor)
|
||||
{
|
||||
if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination,
|
||||
"Route to [{0}] already exists in global routes table", descriptor.Source.Key);
|
||||
return;
|
||||
}
|
||||
RouteDescriptors.Add(descriptor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RouteDescriptor for a destination
|
||||
/// </summary>
|
||||
/// <returns>null if no RouteDescriptor for a destination exists</returns>
|
||||
public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs<TInputSelector> destination)
|
||||
{
|
||||
return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the RouteDescriptor for a given destination AND removes it from collection.
|
||||
/// Returns null if no route with the provided destination exists.
|
||||
/// </summary>
|
||||
public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs<TInputSelector> destination)
|
||||
{
|
||||
var descr = GetRouteDescriptorForDestination(destination);
|
||||
if (descr != null)
|
||||
RouteDescriptors.Remove(descr);
|
||||
return descr;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
47
src/PepperDash.Essentials.Core/Routing/RouteRequest.cs
Normal file
47
src/PepperDash.Essentials.Core/Routing/RouteRequest.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class RouteRequest
|
||||
{
|
||||
public RoutingInputPort DestinationPort { get; set; }
|
||||
|
||||
public RoutingOutputPort SourcePort { get; set; }
|
||||
public IRoutingInputs Destination { get; set; }
|
||||
public IRoutingOutputs Source { get; set; }
|
||||
public eRoutingSignalType SignalType { get; set; }
|
||||
|
||||
public void HandleCooldown(object sender, FeedbackEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
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());
|
||||
|
||||
if (args.BoolValue == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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(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"}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an individual link for a route
|
||||
/// </summary>
|
||||
public class RouteSwitchDescriptor
|
||||
{
|
||||
public IRoutingInputs SwitchingDevice { get { return InputPort?.ParentDevice; } }
|
||||
public RoutingOutputPort OutputPort { get; set; }
|
||||
public RoutingInputPort InputPort { get; set; }
|
||||
|
||||
public RouteSwitchDescriptor(RoutingInputPort inputPort)
|
||||
{
|
||||
InputPort = inputPort;
|
||||
}
|
||||
|
||||
public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort)
|
||||
{
|
||||
InputPort = inputPort;
|
||||
OutputPort = outputPort;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (SwitchingDevice is IRouting)
|
||||
return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches output {(OutputPort != null ? OutputPort.Key : "No output port")} to input {(InputPort != null ? InputPort.Key : "No input port")}";
|
||||
else
|
||||
return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches to input {(InputPort != null ? InputPort.Key : "No input port")}";
|
||||
}
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// Represents an individual link for a route
|
||||
/// </summary>
|
||||
public class RouteSwitchDescriptor<TInputSelector, TOutputSelector>
|
||||
{
|
||||
public IRoutingInputs<TInputSelector> SwitchingDevice { get { return InputPort.ParentDevice; } }
|
||||
public RoutingOutputPort<TOutputSelector> OutputPort { get; set; }
|
||||
public RoutingInputPort<TInputSelector> InputPort { get; set; }
|
||||
|
||||
public RouteSwitchDescriptor(RoutingInputPort<TInputSelector> inputPort)
|
||||
{
|
||||
InputPort = inputPort;
|
||||
}
|
||||
|
||||
public RouteSwitchDescriptor(RoutingOutputPort<TOutputSelector> outputPort, RoutingInputPort<TInputSelector> inputPort)
|
||||
{
|
||||
InputPort = inputPort;
|
||||
OutputPort = outputPort;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (SwitchingDevice is IRouting)
|
||||
return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector);
|
||||
else
|
||||
return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
271
src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs
Normal file
271
src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
public class RoutingFeedbackManager:EssentialsDevice
|
||||
{
|
||||
public RoutingFeedbackManager(string key, string name): base(key, name)
|
||||
{
|
||||
AddPreActivationAction(SubscribeForMidpointFeedback);
|
||||
AddPreActivationAction(SubscribeForSinkFeedback);
|
||||
}
|
||||
|
||||
|
||||
private void SubscribeForMidpointFeedback()
|
||||
{
|
||||
var midpointDevices = DeviceManager.AllDevices.OfType<IRoutingWithFeedback>();
|
||||
|
||||
foreach (var device in midpointDevices)
|
||||
{
|
||||
device.RouteChanged += HandleMidpointUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
private void SubscribeForSinkFeedback()
|
||||
{
|
||||
var sinkDevices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
|
||||
foreach (var device in sinkDevices)
|
||||
{
|
||||
device.InputChanged += HandleSinkUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMidpointUpdate(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute)
|
||||
{
|
||||
try
|
||||
{
|
||||
var devices = DeviceManager.AllDevices.OfType<IRoutingSinkWithSwitchingWithInputPort>();
|
||||
|
||||
foreach (var device in devices)
|
||||
{
|
||||
UpdateDestination(device, device.CurrentInputPort);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error handling midpoint update from {midpointKey}:{Exception}", this, midpoint.Key, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSinkUpdate(IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort)
|
||||
{
|
||||
try
|
||||
{
|
||||
UpdateDestination(sender, currentInputPort);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error handling Sink update from {senderKey}:{Exception}", this, sender.Key, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort)
|
||||
{
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this,destination?.Key, inputPort?.Key);
|
||||
|
||||
if(inputPort == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "Destination {destination} has not reported an input port yet", this,destination.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
TieLine firstTieLine;
|
||||
try
|
||||
{
|
||||
var tieLines = TieLineCollection.Default;
|
||||
|
||||
firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key);
|
||||
|
||||
if (firstTieLine == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
SourceKey = "$transient",
|
||||
Name = inputPort.Key,
|
||||
};
|
||||
|
||||
|
||||
destination.CurrentSourceInfo = tempSourceListItem; ;
|
||||
destination.CurrentSourceInfoKey = "$transient";
|
||||
return;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine);
|
||||
|
||||
TieLine sourceTieLine;
|
||||
try
|
||||
{
|
||||
sourceTieLine = GetRootTieLine(firstTieLine);
|
||||
|
||||
if (sourceTieLine == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
SourceKey = "$transient",
|
||||
Name = "None",
|
||||
};
|
||||
|
||||
destination.CurrentSourceInfo = tempSourceListItem;
|
||||
destination.CurrentSourceInfoKey = string.Empty;
|
||||
return;
|
||||
}
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error getting sourceTieLine: {Exception}", this, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine);
|
||||
|
||||
// Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet.
|
||||
var room = DeviceManager.AllDevices.OfType<IEssentialsRoom>().FirstOrDefault((r) => {
|
||||
if(r is IHasMultipleDisplays roomMultipleDisplays)
|
||||
{
|
||||
return roomMultipleDisplays.Displays.Any(d => d.Value.Key == destination.Key);
|
||||
}
|
||||
|
||||
if(r is IHasDefaultDisplay roomDefaultDisplay)
|
||||
{
|
||||
return roomDefaultDisplay.DefaultDisplay.Key == destination.Key;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if(room == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No room found for display {destination}", this, destination.Key);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found room {room} for destination {destination}", this, room.Key, destination.Key);
|
||||
|
||||
var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey);
|
||||
|
||||
if (sourceList == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}", this, room.SourceListKey, sourceTieLine);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found sourceList for room {room}", this, room.Key);
|
||||
|
||||
var sourceListItem = sourceList.FirstOrDefault(sli => {
|
||||
//// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose,
|
||||
// "SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}",
|
||||
// this,
|
||||
// sli.Key,
|
||||
// sli.Value.SourceKey,
|
||||
// sourceTieLine.SourcePort.ParentDevice.Key);
|
||||
|
||||
return sli.Value.SourceKey.Equals(sourceTieLine.SourcePort.ParentDevice.Key,StringComparison.InvariantCultureIgnoreCase);
|
||||
});
|
||||
|
||||
var source = sourceListItem.Value;
|
||||
var sourceKey = sourceListItem.Key;
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No source found for device {key}. Creating transient source for {destination}", this, sourceTieLine.SourcePort.ParentDevice.Key, destination);
|
||||
|
||||
var tempSourceListItem = new SourceListItem
|
||||
{
|
||||
SourceKey = "$transient",
|
||||
Name = sourceTieLine.SourcePort.Key,
|
||||
};
|
||||
|
||||
destination.CurrentSourceInfoKey = "$transient";
|
||||
destination.CurrentSourceInfo = tempSourceListItem;
|
||||
return;
|
||||
}
|
||||
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {@source} with key {sourceKey}", this, source, sourceKey);
|
||||
|
||||
destination.CurrentSourceInfoKey = sourceKey;
|
||||
destination.CurrentSourceInfo = source;
|
||||
|
||||
}
|
||||
|
||||
private TieLine GetRootTieLine(TieLine tieLine)
|
||||
{
|
||||
TieLine nextTieLine = null;
|
||||
try
|
||||
{
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "**Following tieLine {tieLine}**", this, tieLine);
|
||||
|
||||
if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint)
|
||||
{
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device {sourceDevice} is midpoint", this, midpoint);
|
||||
|
||||
if(midpoint.CurrentRoutes == null || midpoint.CurrentRoutes.Count == 0)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Midpoint {midpointKey} has no routes",this, midpoint.Key);
|
||||
return null;
|
||||
}
|
||||
|
||||
var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => {
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", this, route, tieLine);
|
||||
|
||||
return route.OutputPort != null && route.InputPort != null && route.OutputPort?.Key == tieLine.SourcePort.Key && route.OutputPort?.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key;
|
||||
});
|
||||
|
||||
if (currentRoute == null)
|
||||
{
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "No route through midpoint {midpoint} for outputPort {outputPort}", this, midpoint.Key, tieLine.SourcePort);
|
||||
return null;
|
||||
}
|
||||
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found currentRoute {currentRoute} through {midpoint}", this, currentRoute, midpoint);
|
||||
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => {
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Checking {route} against {tieLine}", tl.DestinationPort.Key, currentRoute.InputPort.Key);
|
||||
return tl.DestinationPort.Key == currentRoute.InputPort.Key && tl.DestinationPort.ParentDevice.Key == currentRoute.InputPort.ParentDevice.Key; });
|
||||
|
||||
if (nextTieLine != null)
|
||||
{
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found next tieLine {tieLine}. Walking the chain", this, nextTieLine);
|
||||
return GetRootTieLine(nextTieLine);
|
||||
}
|
||||
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root tieLine {tieLine}", this,nextTieLine);
|
||||
return nextTieLine;
|
||||
}
|
||||
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this, tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource);
|
||||
//Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}", this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name));
|
||||
|
||||
if (tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain
|
||||
{
|
||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine);
|
||||
return tieLine;
|
||||
}
|
||||
|
||||
nextTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == tieLine.SourcePort.Key && tl.DestinationPort.ParentDevice.Key == tieLine.SourcePort.ParentDevice.Key );
|
||||
|
||||
if (nextTieLine != null)
|
||||
{
|
||||
return GetRootTieLine(nextTieLine);
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error walking tieLines: {Exception}", this, ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user