mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-01-26 02:44:57 +00:00
Compare commits
78 Commits
2.0.0-alph
...
maintenanc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9576db76d7 | ||
|
|
fe0363ed8c | ||
|
|
e92fe5cf2c | ||
|
|
a673122e00 | ||
|
|
4854018d7b | ||
|
|
078f35a91d | ||
|
|
dba07dced8 | ||
|
|
5ad232135c | ||
|
|
3f8e72f366 | ||
|
|
307b2f54a7 | ||
|
|
f73482e8ed | ||
|
|
e5a7641564 | ||
|
|
2b845ce4cb | ||
|
|
1f095e2fb3 | ||
|
|
2a7f491f62 | ||
|
|
2af603013d | ||
|
|
9aa890d404 | ||
|
|
de714f998b | ||
|
|
bcc07fb4cf | ||
|
|
a3651eac76 | ||
|
|
645d9d7098 | ||
|
|
b731f51c5a | ||
|
|
02c2dceedc | ||
|
|
bc1e9b070a | ||
|
|
781faa0431 | ||
|
|
87602c19d7 | ||
|
|
ade5596a18 | ||
|
|
c32ffdc1a8 | ||
|
|
a8285f211d | ||
|
|
6f38f4953e | ||
|
|
8230d95746 | ||
|
|
065726ee72 | ||
|
|
33a31ab931 | ||
|
|
b85377dccf | ||
|
|
e7c5e0566a | ||
|
|
cb2c117588 | ||
|
|
be34808ef0 | ||
|
|
7a4224e52a | ||
|
|
428f9f34bd | ||
|
|
78e49871c6 | ||
|
|
12e81af9e6 | ||
|
|
544a7a2d73 | ||
|
|
1d843c6c89 | ||
|
|
c72db72e7e | ||
|
|
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 |
23
.github/scripts/GenerateVersionNumber-2.0.0.ps1
vendored
23
.github/scripts/GenerateVersionNumber-2.0.0.ps1
vendored
@@ -1,23 +0,0 @@
|
||||
$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\/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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Write-Output $newVersionString
|
||||
21
.github/workflows/EssentialsPlugins-builds-3-series-caller.yml
vendored
Normal file
21
.github/workflows/EssentialsPlugins-builds-3-series-caller.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Build Essentials 1.X
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
getVersion:
|
||||
uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-getversion.yml@main
|
||||
secrets: inherit
|
||||
build-3Series:
|
||||
uses: PepperDash/workflow-templates/.github/workflows/essentials-3Series-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: Pack Solution
|
||||
run: dotnet pack .\$($Env:SOLUTION_FILE).sln --configuration $env:BUILD_TYPE --output ./output /p:Version="${{ steps.setVersion.outputs.version }}"
|
||||
- name: Create tag for non-rc builds
|
||||
if: ${{ !contains(steps.setVersion.outputs.version, 'rc') }}
|
||||
run: |
|
||||
git tag ${{ steps.setVersion.outputs.version }}
|
||||
git push --tags origin
|
||||
# Create the release on the source repo
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
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
|
||||
57
.github/workflows/main.yml
vendored
57
.github/workflows/main.yml
vendored
@@ -1,57 +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: Pack Solution
|
||||
run: dotnet pack .\$($Env:SOLUTION_FILE).sln --configuration $env:BUILD_TYPE --output ./output /p:Version="${{ steps.setVersion.outputs.version }}"
|
||||
- name: Upload Release
|
||||
id: create_release
|
||||
uses: ncipollo/release-action@v1
|
||||
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
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -390,5 +390,3 @@ MigrationBackup/
|
||||
FodyWeavers.xsd
|
||||
essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/PepperDash_Essentials_Interfaces.csproj
|
||||
.DS_Store
|
||||
/._PepperDash.Essentials.sln
|
||||
.vscode/settings.json
|
||||
|
||||
34
.releaserc.json
Normal file
34
.releaserc.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"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": [
|
||||
"maintenance-1x",
|
||||
{
|
||||
"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
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33213.308
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Devices.Common", "src\PepperDash.Essentials.Devices.Common\PepperDash.Essentials.Devices.Common.csproj", "{53E204B7-97DD-441D-A96C-721DF014DF82}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials", "src\PepperDash.Essentials\PepperDash.Essentials.csproj", "{CB3B11BA-625C-4D35-B663-FDC5BE9A230E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Core", "src\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj", "{3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug 4.7.2|Any CPU = Debug 4.7.2|Any CPU
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{53E204B7-97DD-441D-A96C-721DF014DF82}.Debug 4.7.2|Any CPU.ActiveCfg = Debug 4.7.2|Any CPU
|
||||
{53E204B7-97DD-441D-A96C-721DF014DF82}.Debug 4.7.2|Any CPU.Build.0 = Debug 4.7.2|Any CPU
|
||||
{53E204B7-97DD-441D-A96C-721DF014DF82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{53E204B7-97DD-441D-A96C-721DF014DF82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{53E204B7-97DD-441D-A96C-721DF014DF82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{53E204B7-97DD-441D-A96C-721DF014DF82}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Debug 4.7.2|Any CPU.ActiveCfg = Debug 4.7.2|Any CPU
|
||||
{CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Debug 4.7.2|Any CPU.Build.0 = Debug 4.7.2|Any CPU
|
||||
{CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Debug 4.7.2|Any CPU.ActiveCfg = Debug 4.7.2|Any CPU
|
||||
{3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Debug 4.7.2|Any CPU.Build.0 = Debug 4.7.2|Any CPU
|
||||
{3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6907A4BF-7201-47CF-AAB1-3597F3B8E1C3}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
49
PepperDashEssentials.3Series.sln
Normal file
49
PepperDashEssentials.3Series.sln
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDashEssentials", "src\PepperDashEssentials\PepperDashEssentials.csproj", "{1BED5BA9-88C4-4365-9362-6F4B128071D3}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{892B761C-E479-44CE-BD74-243E9214AF13} = {892B761C-E479-44CE-BD74-243E9214AF13}
|
||||
{9199CE8A-0C9F-4952-8672-3EED798B284F} = {9199CE8A-0C9F-4952-8672-3EED798B284F}
|
||||
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash_Essentials_Core", "src\essentials-framework\Essentials Core\PepperDashEssentialsBase\PepperDash_Essentials_Core.csproj", "{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials Devices Common", "src\essentials-framework\Essentials Devices Common\Essentials Devices Common\Essentials Devices Common.csproj", "{892B761C-E479-44CE-BD74-243E9214AF13}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash_Essentials_DM", "src\essentials-framework\Essentials DM\Essentials_DM\PepperDash_Essentials_DM.csproj", "{9199CE8A-0C9F-4952-8672-3EED798B284F}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
3
packages.config
Normal file
3
packages.config
Normal file
@@ -0,0 +1,3 @@
|
||||
<packages>
|
||||
<package id="PepperDashCore" version="1.4.3" targetFramework="net35" allowedVersions="[1.0,2.0)"/>
|
||||
</packages>
|
||||
@@ -1,21 +0,0 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>2.0.0-local</Version>
|
||||
<InformationalVersion>$(Version)</InformationalVersion>
|
||||
<Authors>PepperDash Technologies</Authors>
|
||||
<Company>PepperDash Technologies</Company>
|
||||
<Product>PepperDash Essentials</Product>
|
||||
<Copyright>Copyright © 2023</Copyright>
|
||||
<RepositoryUrl>https://github.com/PepperDash/Essentials</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>Crestron; 4series</PackageTags>
|
||||
<PackageOutputPath>../../output</PackageOutputPath>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\LICENSE.md" Pack="true" PackagePath=""/>
|
||||
<None Include="..\..\README.md" Pack="true" PackagePath=""/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,26 +0,0 @@
|
||||
<Project>
|
||||
<ItemGroup>
|
||||
<None Include="$(PackageOutputPath)\$(AssemblyName)\*.cpz" Condition="$(ProjectType) == 'Program'">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>build;</PackagePath>
|
||||
</None>
|
||||
<None Include="$(PackageOutputPath)\$(AssemblyName)\*.cplz" Condition="$(ProjectType) == 'ProgramLibrary'">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>build;</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Target Name="Create CPLZ" AfterTargets="Build; AfterRebuild" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''">
|
||||
<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"/>
|
||||
</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>
|
||||
<Target Name="Copy CPZ NET47" AfterTargets="SimplSharpPostProcess47" Condition="($(ProjectType) == 'Program' And ( '$(TargetFramework)' != 'net6.0' ) And ( '$(TargetFramework)' != 'net8.0' ))">
|
||||
<Message Text="Copying CPZ"></Message>
|
||||
<Move SourceFiles="$(TargetDir)$(TargetName).cpz" DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,66 +0,0 @@
|
||||
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,20 +0,0 @@
|
||||
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>();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface ILoadConfig
|
||||
{
|
||||
void GoWithLoad();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
public interface IHasBranding
|
||||
{
|
||||
bool BrandingEnabled { get; }
|
||||
void InitializeBranding(string roomKey);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using PepperDash.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Describes a device that has selectable inputs
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">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>
|
||||
[Obsolete("Use IHasInputs<T> instead. Will be removed for 2.0 release")]
|
||||
public interface IHasInputs<T, TSelector>: IKeyName
|
||||
{
|
||||
ISelectableItems<T> Inputs { get; }
|
||||
}
|
||||
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using PepperDash.Essentials.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
public interface IHasPhoneDialing
|
||||
{
|
||||
BoolFeedback PhoneOffHookFeedback { get; }
|
||||
StringFeedback CallerIdNameFeedback { get; }
|
||||
StringFeedback CallerIdNumberFeedback { get; }
|
||||
void DialPhoneCall(string number);
|
||||
void EndPhoneCall();
|
||||
void SendDtmfToPhone(string digit);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using PepperDash.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a device that has selectable surround sound modes
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">the type to use as the key for each input item. Most likely an enum or string</typeparam>
|
||||
public interface IHasSurroundSoundModes<TKey, TSelector>: IKeyName
|
||||
{
|
||||
ISelectableItems<TKey> SurroundSoundModes { get; }
|
||||
|
||||
void SetSurroundSoundMode(TSelector selector);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
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; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
public interface ILanguageDefinition
|
||||
{
|
||||
string LocaleName { get; set; }
|
||||
string FriendlyName { get; set; }
|
||||
bool Enable { get; set; }
|
||||
List<LanguageLabel> UiLabels { get; set; }
|
||||
List<LanguageLabel> Sources { get; set; }
|
||||
List<LanguageLabel> Destinations { get; set; }
|
||||
List<LanguageLabel> SourceGroupNames { get; set; }
|
||||
List<LanguageLabel> DestinationGroupNames { get; set; }
|
||||
List<LanguageLabel> RoomNames { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
|
||||
public interface ILanguageProvider
|
||||
{
|
||||
ILanguageDefinition CurrentLanguage { get; set; }
|
||||
|
||||
event EventHandler CurrentLanguageChanged;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
public interface ILevelControls
|
||||
{
|
||||
Dictionary<string, IBasicVolumeWithFeedback> LevelControlPoints { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this interface on a device or room if it uses custom Mobile Control messengers
|
||||
/// </summary>
|
||||
public interface ICustomMobileControl : IKeyed
|
||||
{
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// Describes a MobileControlSystemController
|
||||
/// </summary>
|
||||
public interface IMobileControl : IKeyed
|
||||
{
|
||||
void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent);
|
||||
|
||||
void LinkSystemMonitorToAppServer();
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Describes a MobileSystemController that accepts IEssentialsRoom
|
||||
/// </summary>
|
||||
public interface IMobileControl : IKeyed
|
||||
{
|
||||
string Host { get; }
|
||||
|
||||
string ClientAppUrl { get; }
|
||||
|
||||
string SystemUuid { get; }
|
||||
|
||||
BoolFeedback ApiOnlineAndAuthorized { get;}
|
||||
|
||||
void SendMessageObject(IMobileControlMessage o);
|
||||
|
||||
void AddAction<T>(T messenger, Action<string, string, JToken> action) where T:IMobileControlMessenger;
|
||||
|
||||
void RemoveAction(string key);
|
||||
|
||||
void AddDeviceMessenger(IMobileControlMessenger messenger);
|
||||
|
||||
bool CheckForDeviceMessenger(string key);
|
||||
|
||||
IMobileControlRoomMessenger GetRoomMessenger(string key);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a mobile control messenger
|
||||
/// </summary>
|
||||
public interface IMobileControlMessenger: IKeyed
|
||||
{
|
||||
IMobileControl AppServerController { get; }
|
||||
string MessagePath { get; }
|
||||
|
||||
string DeviceKey { get; }
|
||||
void RegisterWithAppServer(IMobileControl appServerController);
|
||||
}
|
||||
|
||||
public interface IMobileControlMessage
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
string Type { get; }
|
||||
|
||||
[JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
string ClientId { get; }
|
||||
|
||||
[JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)]
|
||||
JToken Content { get; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a MobileControl Room Bridge
|
||||
/// </summary>
|
||||
public interface IMobileControlRoomMessenger : IKeyed
|
||||
{
|
||||
event EventHandler<EventArgs> UserCodeChanged;
|
||||
|
||||
event EventHandler<EventArgs> UserPromptedForCode;
|
||||
|
||||
event EventHandler<EventArgs> ClientJoined;
|
||||
|
||||
event EventHandler<EventArgs> AppUrlChanged;
|
||||
|
||||
string UserCode { get; }
|
||||
|
||||
string QrCodeUrl { get; }
|
||||
|
||||
string QrCodeChecksum { get; }
|
||||
|
||||
string McServerUrl { get; }
|
||||
|
||||
string RoomName { get; }
|
||||
|
||||
string AppUrl { get; }
|
||||
|
||||
void UpdateAppUrl(string url);
|
||||
}
|
||||
|
||||
public interface IMobileControlAction
|
||||
{
|
||||
IMobileControlMessenger Messenger { get; }
|
||||
|
||||
Action<string,string, JToken> Action { get; }
|
||||
}
|
||||
|
||||
public interface IMobileControlTouchpanelController : IKeyed
|
||||
{
|
||||
string DefaultRoomKey { get; }
|
||||
void SetAppUrl(string url);
|
||||
bool UseDirectServer { get; }
|
||||
bool ZoomRoomController { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Describes an item that can be selected
|
||||
/// </summary>
|
||||
public interface ISelectableItem : IKeyName
|
||||
{
|
||||
event EventHandler ItemUpdated;
|
||||
|
||||
[JsonProperty("isSelected")]
|
||||
bool IsSelected { get; set; }
|
||||
void Select();
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a collection of items that can be selected
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">type for the keys in the collection. Probably a string or enum</typeparam>
|
||||
public interface ISelectableItems<TKey>
|
||||
{
|
||||
event EventHandler ItemsUpdated;
|
||||
event EventHandler CurrentItemChanged;
|
||||
|
||||
[JsonProperty("items")]
|
||||
Dictionary<TKey, ISelectableItem> Items { get; set; }
|
||||
|
||||
[JsonProperty("currentItem")]
|
||||
TKey CurrentItem { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||
{
|
||||
public class LanguageLabel
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string DisplayText { get; set; }
|
||||
public uint JoinNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
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,446 +0,0 @@
|
||||
|
||||
|
||||
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.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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (action.Params == null)
|
||||
{
|
||||
//no params, so setting action.Params to empty array
|
||||
action.Params = new object[0];
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 (action.Params == null)
|
||||
{
|
||||
//no params, so setting action.Params to empty array
|
||||
action.Params = new object[0];
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey} with {@params}", null, method.Name, action.DeviceKey, action.Params);
|
||||
method.Invoke(obj, convertedParams);
|
||||
}
|
||||
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
|
||||
/// </summary>
|
||||
/// <param name="deviceObjectPath"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <returns></returns>
|
||||
public static object GetPropertyByName(string deviceObjectPath, string propertyName)
|
||||
{
|
||||
var dev = FindObjectOnPath(deviceObjectPath);
|
||||
if (dev == null)
|
||||
return "{ \"error\":\"No Device\"}";
|
||||
|
||||
object prop = dev.GetType().GetProperty(propertyName).GetValue(dev, null);
|
||||
|
||||
// var prop = t.GetProperty(propertyName);
|
||||
if (prop != null)
|
||||
{
|
||||
return prop;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Unable to find Property: {0} on Device with path: {1}", propertyName, deviceObjectPath);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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
|
||||
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\"}";
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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.
|
||||
/// </summary>
|
||||
/// <param name="deviceObjectPath"></param>
|
||||
/// <returns></returns>
|
||||
public static string SetProperty(string deviceObjectPath)
|
||||
{
|
||||
throw new NotImplementedException("This could be really useful. Finish it please");
|
||||
|
||||
//var obj = FindObjectOnPath(deviceObjectPath);
|
||||
//if (obj == null)
|
||||
// return "{\"error\":\"No object found\"}";
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class DeviceActionWrapper
|
||||
{
|
||||
public string DeviceKey { get; set; }
|
||||
public string MethodName { get; set; }
|
||||
public object[] Params { get; set; }
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PropInfo.CanRead)
|
||||
{
|
||||
try
|
||||
{
|
||||
return PropInfo.GetValue(Parent, null).ToString();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
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;
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
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 MethodNameParams(MethodInfo info)
|
||||
{
|
||||
MethodInfo = info;
|
||||
}
|
||||
}
|
||||
|
||||
public class NameType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public class ApiAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,508 +0,0 @@
|
||||
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 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 Dictionary<string, IKeyed> Devices = new Dictionary<string, IKeyed>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <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 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);
|
||||
|
||||
CrestronConsole.AddNewConsoleCommand(SetDeviceStreamDebugging, "setdevicestreamdebug", "set comm debug [deviceKey] [off/rx/tx/both] ([minutes])", ConsoleAccessLevelEnum.AccessOperator);
|
||||
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
|
||||
{
|
||||
OnAllDevicesRegistered();
|
||||
|
||||
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)
|
||||
{
|
||||
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...****");
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "****PostActivation complete****");
|
||||
|
||||
OnAllDevicesActivated();
|
||||
}
|
||||
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()
|
||||
{
|
||||
var handler = AllDevicesActivated;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesRegistered()
|
||||
{
|
||||
var handler = AllDevicesRegistered;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnAllDevicesInitialized()
|
||||
{
|
||||
var handler = AllDevicesInitialized;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(null, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/// <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();
|
||||
}
|
||||
}
|
||||
|
||||
//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());
|
||||
// }
|
||||
//}
|
||||
|
||||
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));
|
||||
|
||||
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 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)
|
||||
// {
|
||||
// Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey);
|
||||
// return;
|
||||
// }
|
||||
// Debug.LogMessage(LogEventLevel.Information, "This needs to be reworked. Stay tuned.", devKey);
|
||||
//}
|
||||
|
||||
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)
|
||||
//{
|
||||
// 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)
|
||||
|
||||
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);
|
||||
|
||||
if (newDev is EssentialsDevice essentialsDev)
|
||||
essentialsDev.Initialized += DeviceManager_Initialized;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Console handler that simulates com port data receive
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public static void SimulateComReceiveOnDevice(string s)
|
||||
{
|
||||
// devcomsim:1 xyzabc
|
||||
var match = Regex.Match(s, @"(\S*)\s*(.*)");
|
||||
if (match.Groups.Count < 3)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(" Format: devsimreceive:P <device key> <string to send>");
|
||||
return;
|
||||
}
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, "**** {0} - {1} ****", match.Groups[1].Value, match.Groups[2].Value);
|
||||
|
||||
if (!(GetDeviceForKey(match.Groups[1].Value) is ComPortController com))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("'{0}' is not a comm port device", match.Groups[1].Value);
|
||||
return;
|
||||
}
|
||||
com.SimulateReceive(match.Groups[2].Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints a list of routing inputs and outputs by device key.
|
||||
/// </summary>
|
||||
/// <param name="s">Device key from which to report data</param>
|
||||
public static void GetRoutingPorts(string s)
|
||||
{
|
||||
var device = GetDeviceForKey(s);
|
||||
|
||||
if (device == null) return;
|
||||
var inputPorts = ((device as IRoutingInputs) != null) ? (device as IRoutingInputs).InputPorts : null;
|
||||
var outputPorts = ((device as IRoutingOutputs) != null) ? (device as IRoutingOutputs).OutputPorts : null;
|
||||
if (inputPorts != null)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Input Ports:{2}", s, inputPorts.Count, CrestronEnvironment.NewLine);
|
||||
foreach (var routingInputPort in inputPorts)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("{0}{1}", routingInputPort.Key, CrestronEnvironment.NewLine);
|
||||
}
|
||||
}
|
||||
if (outputPorts == null) return;
|
||||
CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Output Ports:{2}", s, outputPorts.Count, CrestronEnvironment.NewLine);
|
||||
foreach (var routingOutputPort in outputPorts)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("{0}{1}", routingOutputPort.Key, CrestronEnvironment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to set the debug level of a device
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
public static void SetDeviceStreamDebugging(string s)
|
||||
{
|
||||
if (String.IsNullOrEmpty(s) || s.Contains("?"))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(
|
||||
@"SETDEVICESTREAMDEBUG [{deviceKey}] [OFF |TX | RX | BOTH] [timeOutInMinutes]
|
||||
{deviceKey} [OFF | TX | RX | BOTH] - Device to set stream debugging on, and which setting to use
|
||||
timeOutInMinutes - Set timeout for stream debugging. Default is 30 minutes");
|
||||
return;
|
||||
}
|
||||
|
||||
var args = s.Split(' ');
|
||||
|
||||
var deviceKey = args[0];
|
||||
var setting = args[1];
|
||||
|
||||
var timeout = String.Empty;
|
||||
|
||||
if (args.Length >= 3)
|
||||
{
|
||||
timeout = args[2];
|
||||
}
|
||||
|
||||
|
||||
if (!(GetDeviceForKey(deviceKey) is IStreamDebugging device))
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to get device with key: {0}", deviceKey);
|
||||
return;
|
||||
}
|
||||
|
||||
eStreamDebuggingSetting debugSetting;
|
||||
|
||||
try
|
||||
{
|
||||
debugSetting = (eStreamDebuggingSetting)Enum.Parse(typeof(eStreamDebuggingSetting), setting, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to convert setting value. Please use off/rx/tx/both");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(timeout))
|
||||
{
|
||||
try
|
||||
{
|
||||
var min = Convert.ToUInt32(timeout);
|
||||
|
||||
device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, min);
|
||||
CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse("Unable to convert minutes or settings value. Please use an integer value for minutes. Error: {0}", e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
device.StreamDebugging.SetDebuggingWithDefaultTimeout(debugSetting);
|
||||
CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for default time (30 minutes)", deviceKey, debugSetting);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets stream debugging settings to off for all devices
|
||||
/// </summary>
|
||||
public static void DisableAllDeviceStreamDebugging()
|
||||
{
|
||||
foreach (var device in AllDevices)
|
||||
{
|
||||
if (device is IStreamDebugging streamDevice)
|
||||
{
|
||||
streamDevice.StreamDebugging.SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting.Off);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using PepperDash.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface IDspPresets
|
||||
{
|
||||
Dictionary<string, IKeyName> Presets { get; }
|
||||
|
||||
void RecallPreset(string key);
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
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,197 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using PepperDash.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <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>
|
||||
/// 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;
|
||||
}
|
||||
}
|
||||
|
||||
private Device _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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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")]
|
||||
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; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to specify the order of the items in the source list when displayed
|
||||
/// </summary>
|
||||
[JsonProperty("order")]
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key of the device for volume control
|
||||
/// </summary>
|
||||
[JsonProperty("volumeControlKey")]
|
||||
public string VolumeControlKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of source list item
|
||||
/// </summary>
|
||||
[JsonProperty("type")]
|
||||
[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; }
|
||||
|
||||
/// <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; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if this source should be disabled for routing to a shared output
|
||||
/// </summary>
|
||||
[JsonProperty("disableRoutedSharing")]
|
||||
public bool DisableRoutedSharing { get; set; }
|
||||
|
||||
[JsonProperty("destinations")]
|
||||
public List<eSourceListItemDestinationTypes> Destinations { get; set; }
|
||||
/// <summary>
|
||||
/// A means to reference a source list for this source item, in the event that this source has an input that can have sources routed to it
|
||||
/// </summary>
|
||||
[JsonProperty("sourceListKey")]
|
||||
public string SourceListKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the device associated with this source is controllable
|
||||
/// </summary>
|
||||
[JsonProperty("isControllable")]
|
||||
public bool IsControllable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the device associated with this source has audio available
|
||||
/// </summary>
|
||||
[JsonProperty("isAudioSource")]
|
||||
public bool IsAudioSource { get; set; }
|
||||
|
||||
/// <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 SourceListItem()
|
||||
{
|
||||
Icon = "Blank";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{SourceKey}:{Name}";
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
/// </summary>
|
||||
public enum eSourceListItemDestinationTypes
|
||||
{
|
||||
defaultDisplay,
|
||||
leftDisplay,
|
||||
rightDisplay,
|
||||
centerDisplay,
|
||||
programAudio,
|
||||
codecContent,
|
||||
frontLeftDisplay,
|
||||
frontRightDisplay,
|
||||
rearLeftDisplay,
|
||||
rearRightDisplay,
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface IProcessorExtensionDeviceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads all the extension factories to the ProcessorExtensionDeviceFactory
|
||||
/// </summary>
|
||||
void LoadFactories();
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
|
||||
using System.Reflection;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
|
||||
public class ProcessorExtensionDeviceFactory
|
||||
{
|
||||
public ProcessorExtensionDeviceFactory() {
|
||||
var assy = Assembly.GetExecutingAssembly();
|
||||
PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
|
||||
|
||||
var extensions = assy.GetTypes().Where(ct => typeof(IProcessorExtensionDeviceFactory)
|
||||
.IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
|
||||
|
||||
if (extensions != null )
|
||||
{
|
||||
foreach ( var extension in extensions )
|
||||
{
|
||||
try
|
||||
{
|
||||
var factory = (IProcessorExtensionDeviceFactory)Activator.CreateInstance(extension);
|
||||
factory.LoadFactories();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to load extension device: '{1}' ProcessorExtensionDeviceFactory: {0}", e, extension.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of factory methods, keyed by config types, added by plugins.
|
||||
/// These methods are looked up and called by GetDevice in this class.
|
||||
/// </summary>
|
||||
static Dictionary<string, DeviceFactoryWrapper> ProcessorExtensionFactoryMethods =
|
||||
new Dictionary<string, DeviceFactoryWrapper>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a plugin factory method
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public static void AddFactoryForType(string extensionName, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, new DeviceFactoryWrapper() { FactoryMethod = 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);
|
||||
|
||||
if (ProcessorExtensionFactoryMethods.ContainsKey(extensionName))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Unable to add extension device: '{0}'. Already exists in ProcessorExtensionDeviceFactory", extensionName);
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, wrapper);
|
||||
}
|
||||
|
||||
private static void CheckForSecrets(IEnumerable<Newtonsoft.Json.Linq.JProperty> obj)
|
||||
{
|
||||
foreach (var prop in obj.Where(prop => prop.Value as Newtonsoft.Json.Linq.JObject != null))
|
||||
{
|
||||
if (prop.Name.ToLower() == "secret")
|
||||
{
|
||||
var secret = GetSecret(prop.Children().First().ToObject<SecretsPropertiesConfig>());
|
||||
//var secret = GetSecret(JsonConvert.DeserializeObject<SecretsPropertiesConfig>(prop.Children().First().ToString()));
|
||||
prop.Parent.Replace(secret);
|
||||
}
|
||||
var recurseProp = prop.Value as Newtonsoft.Json.Linq.JObject;
|
||||
if (recurseProp == null) return;
|
||||
CheckForSecrets(recurseProp.Properties());
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetSecret(SecretsPropertiesConfig data)
|
||||
{
|
||||
var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider);
|
||||
if (secretProvider == null) return null;
|
||||
var secret = secretProvider.GetSecret(data.Key);
|
||||
if (secret != null) return (string)secret.Value;
|
||||
Debug.LogMessage(LogEventLevel.Debug,
|
||||
"Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider",
|
||||
data.Provider, data.Key);
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The factory method for processor extension devices. Also iterates the Factory methods that have
|
||||
/// been loaded from plugins
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public static IKeyed GetExtensionDevice(DeviceConfig dc)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Loading '{0}' from Essentials Core", dc.Type);
|
||||
|
||||
var localDc = new DeviceConfig(dc);
|
||||
|
||||
var key = localDc.Key;
|
||||
var name = localDc.Name;
|
||||
var type = localDc.Type;
|
||||
var properties = localDc.Properties;
|
||||
//var propRecurse = properties;
|
||||
|
||||
var typeName = localDc.Type.ToLower();
|
||||
|
||||
var jObject = properties as Newtonsoft.Json.Linq.JObject;
|
||||
if (jObject != null)
|
||||
{
|
||||
var jProp = jObject.Properties();
|
||||
|
||||
CheckForSecrets(jProp);
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "typeName = {0}", typeName);
|
||||
// Check for types that have been added by plugin dlls.
|
||||
return !ProcessorExtensionFactoryMethods.ContainsKey(typeName) ? null : ProcessorExtensionFactoryMethods[typeName].FactoryMethod(localDc);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "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.Information, "Inner exception while creating device {0}: {1}", dc.Key,
|
||||
ex.InnerException.Message);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.InnerException.StackTrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<ProjectType>ProgramLibrary</ProjectType>
|
||||
<Configurations>Debug;Release;Debug 4.7.2</Configurations>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;net6</TargetFrameworks>
|
||||
<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>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 4.7.2|AnyCPU'">
|
||||
<DebugType>full</DebugType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
|
||||
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-424" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,73 +0,0 @@
|
||||
using System;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Queues
|
||||
{
|
||||
/// <summary>
|
||||
/// IBasicCommunication Message for IQueue
|
||||
/// </summary>
|
||||
public class ComsMessage : IQueueMessage
|
||||
{
|
||||
private readonly byte[] _bytes;
|
||||
private readonly IBasicCommunication _coms;
|
||||
private readonly string _string;
|
||||
private readonly bool _isByteMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a string message
|
||||
/// </summary>
|
||||
/// <param name="coms">IBasicCommunication to send the message</param>
|
||||
/// <param name="message">Message to send</param>
|
||||
public ComsMessage(IBasicCommunication coms, string message)
|
||||
{
|
||||
Validate(coms, message);
|
||||
_coms = coms;
|
||||
_string = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a byte message
|
||||
/// </summary>
|
||||
/// <param name="coms">IBasicCommunication to send the message</param>
|
||||
/// <param name="message">Message to send</param>
|
||||
public ComsMessage(IBasicCommunication coms, byte[] message)
|
||||
{
|
||||
Validate(coms, message);
|
||||
_coms = coms;
|
||||
_bytes = message;
|
||||
_isByteMessage = true;
|
||||
}
|
||||
|
||||
private void Validate(IBasicCommunication coms, object message)
|
||||
{
|
||||
if (coms == null)
|
||||
throw new ArgumentNullException("coms");
|
||||
|
||||
if (message == null)
|
||||
throw new ArgumentNullException("message");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatchs the string/byte[] to the IBasicCommunication specified
|
||||
/// </summary>
|
||||
public void Dispatch()
|
||||
{
|
||||
if (_isByteMessage)
|
||||
{
|
||||
_coms.SendBytes(_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
_coms.SendText(_string);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows either the byte[] or string to be sent
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return _bytes != null ? _bytes.ToString() : _string;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,270 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using Crestron.SimplSharp;
|
||||
using PepperDash.Core;
|
||||
using Serilog.Events;
|
||||
using Thread = Crestron.SimplSharpPro.CrestronThread.Thread;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Queues
|
||||
{
|
||||
/// <summary>
|
||||
/// Threadsafe processing of queued items with pacing if required
|
||||
/// </summary>
|
||||
public class GenericQueue : IQueue<IQueueMessage>
|
||||
{
|
||||
private readonly string _key;
|
||||
protected readonly ConcurrentQueue<IQueueMessage> _queue;
|
||||
protected readonly Thread _worker;
|
||||
protected readonly CEvent _waitHandle = new CEvent();
|
||||
|
||||
private bool _delayEnabled;
|
||||
private int _delayTime;
|
||||
|
||||
private const Thread.eThreadPriority _defaultPriority = Thread.eThreadPriority.MediumPriority;
|
||||
|
||||
/// <summary>
|
||||
/// If the instance has been disposed.
|
||||
/// </summary>
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the capacity of the CrestronQueue (fixed Size property)
|
||||
/// </summary>
|
||||
public int QueueCapacity
|
||||
{
|
||||
get
|
||||
{
|
||||
return int.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of elements currently in the CrestronQueue
|
||||
/// </summary>
|
||||
public int QueueCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return _queue.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with no thread priority
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public GenericQueue(string key)
|
||||
: this(key, _defaultPriority, 0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with queue size
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="capacity">Fixed size for the queue to hold</param>
|
||||
public GenericQueue(string key, int capacity)
|
||||
: this(key, _defaultPriority, capacity, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for generic queue with no pacing
|
||||
/// </summary>
|
||||
/// <param name="key">Key</param>
|
||||
/// <param name="pacing">Pacing in ms between actions</param>
|
||||
public GenericQueue(int pacing, string key)
|
||||
: this(key, _defaultPriority, 0, pacing)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with pacing and capacity
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="pacing"></param>
|
||||
/// <param name="capacity"></param>
|
||||
public GenericQueue(string key, int pacing, int capacity)
|
||||
: this(key, _defaultPriority, capacity, pacing)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with pacing and priority
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="pacing"></param>
|
||||
/// <param name="priority"></param>
|
||||
public GenericQueue(string key, int pacing, Thread.eThreadPriority priority)
|
||||
: this(key, priority, 0, pacing)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with pacing, priority and capacity
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="capacity"></param>
|
||||
public GenericQueue(string key, Thread.eThreadPriority priority, int capacity)
|
||||
: this(key, priority, capacity, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with pacing, priority and capacity
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="pacing"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="capacity"></param>
|
||||
public GenericQueue(string key, int pacing, Thread.eThreadPriority priority, int capacity)
|
||||
: this(key, priority, capacity, pacing)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for generic queue with no pacing
|
||||
/// </summary>
|
||||
/// <param name="key">Key</param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="capacity"></param>
|
||||
/// <param name="pacing"></param>
|
||||
protected GenericQueue(string key, Thread.eThreadPriority priority, int capacity, int pacing)
|
||||
{
|
||||
_key = key;
|
||||
int cap = 25; // sets default
|
||||
if (capacity > 0)
|
||||
{
|
||||
cap = capacity; // overrides default
|
||||
}
|
||||
|
||||
_queue = new ConcurrentQueue<IQueueMessage>();
|
||||
_worker = new Thread(ProcessQueue, null, Thread.eThreadStartOptions.Running)
|
||||
{
|
||||
Priority = priority,
|
||||
Name = _key
|
||||
};
|
||||
|
||||
SetDelayValues(pacing);
|
||||
}
|
||||
|
||||
private void SetDelayValues(int pacing)
|
||||
{
|
||||
_delayEnabled = pacing > 0;
|
||||
_delayTime = pacing;
|
||||
|
||||
CrestronEnvironment.ProgramStatusEventHandler += programEvent =>
|
||||
{
|
||||
if (programEvent != eProgramStatusEventType.Stopping)
|
||||
return;
|
||||
|
||||
Dispose(true);
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thread callback
|
||||
/// </summary>
|
||||
/// <param name="obj">The action used to process dequeued items</param>
|
||||
/// <returns>Null when the thread is exited</returns>
|
||||
private object ProcessQueue(object obj)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_queue.TryDequeue(out var item) && item == null)
|
||||
break;
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Debug.LogMessage(LogEventLevel.Verbose, this, "Processing queue item: '{0}'", item.ToString());
|
||||
item.Dispatch();
|
||||
|
||||
if (_delayEnabled)
|
||||
Thread.Sleep(_delayTime);
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
//swallowing this exception, as it should only happen on shut down
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "Caught an exception in the Queue: {1}:{0}", ex.Message, ex);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Stack Trace: {0}", ex.StackTrace);
|
||||
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "---\r\n{0}", ex.InnerException.Message);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Stack Trace: {0}", ex.InnerException.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
else _waitHandle.Wait();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Enqueue(IQueueMessage item)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, this, "Queue has been disposed. Enqueuing messages not allowed while program is stopping.");
|
||||
return;
|
||||
}
|
||||
|
||||
_queue.Enqueue(item);
|
||||
_waitHandle.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the thread and cleans up resources. Thread cannot be restarted once
|
||||
/// disposed.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
CrestronEnvironment.GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actually does the disposing. If you override this method, be sure to either call the base implementation
|
||||
/// or clean up all the resources yourself.
|
||||
/// </summary>
|
||||
/// <param name="disposing">set to true unless called from finalizer</param>
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
using (_waitHandle)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Disposing...");
|
||||
_queue.Enqueue(null);
|
||||
_waitHandle.Set();
|
||||
_worker.Join();
|
||||
}
|
||||
}
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
~GenericQueue()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Key
|
||||
/// </summary>
|
||||
public string Key
|
||||
{
|
||||
get { return _key; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Queues
|
||||
{
|
||||
public interface IQueue<T> : IKeyed, IDisposable where T : class
|
||||
{
|
||||
void Enqueue(T item);
|
||||
bool Disposed { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Queues
|
||||
{
|
||||
public interface IQueueMessage
|
||||
{
|
||||
void Dispatch();
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Queues
|
||||
{
|
||||
/// <summary>
|
||||
/// Message class for processing strings via an IQueue
|
||||
/// </summary>
|
||||
public class ProcessStringMessage : IQueueMessage
|
||||
{
|
||||
private readonly Action<string> _action;
|
||||
private readonly string _message;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="message">Message to be processed</param>
|
||||
/// <param name="action">Action to invoke on the message</param>
|
||||
public ProcessStringMessage(string message, Action<string> action)
|
||||
{
|
||||
_message = message;
|
||||
_action = action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the string with the given action
|
||||
/// </summary>
|
||||
public void Dispatch()
|
||||
{
|
||||
if (_action == null || String.IsNullOrEmpty(_message))
|
||||
return;
|
||||
|
||||
_action(_message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To string
|
||||
/// </summary>
|
||||
/// <returns>The current message</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return _message ?? String.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
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
|
||||
{
|
||||
private RoomCombinationScenarioConfig _config;
|
||||
|
||||
[JsonProperty("key")]
|
||||
public string Key { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("partitionStates")]
|
||||
public List<PartitionState> PartitionStates { get; private set; }
|
||||
|
||||
[JsonProperty("uiMap")]
|
||||
public Dictionary<string, string> UiMap { get; set; }
|
||||
|
||||
private bool _isActive;
|
||||
|
||||
[JsonProperty("isActive")]
|
||||
public bool IsActive
|
||||
{
|
||||
get { return _isActive; }
|
||||
set
|
||||
{
|
||||
if (value == _isActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isActive = value;
|
||||
IsActiveFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public BoolFeedback IsActiveFeedback { get; private set; }
|
||||
|
||||
private List<DeviceActionWrapper> activationActions;
|
||||
|
||||
private List<DeviceActionWrapper> deactivationActions;
|
||||
|
||||
public RoomCombinationScenario(RoomCombinationScenarioConfig config)
|
||||
{
|
||||
Key = config.Key;
|
||||
|
||||
Name = config.Name;
|
||||
|
||||
PartitionStates = config.PartitionStates;
|
||||
|
||||
UiMap = config.UiMap;
|
||||
|
||||
activationActions = config.ActivationActions;
|
||||
|
||||
deactivationActions = config.DeactivationActions;
|
||||
|
||||
_config = config;
|
||||
|
||||
IsActiveFeedback = new BoolFeedback(() => _isActive);
|
||||
}
|
||||
|
||||
public async Task Activate()
|
||||
{
|
||||
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)
|
||||
{
|
||||
this.LogInformation("Running Activation action {@action}", action);
|
||||
tasks.Add(DeviceJsonApi.DoDeviceActionAsync(action));
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public async Task Deactivate()
|
||||
{
|
||||
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)
|
||||
{
|
||||
this.LogInformation("Running deactivation action {actionDeviceKey}:{actionMethod}", action.DeviceKey, action.MethodName);
|
||||
tasks.Add( DeviceJsonApi.DoDeviceActionAsync(action));
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
IsActive = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
using System;
|
||||
using Crestron.SimplSharpPro;
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
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)
|
||||
{
|
||||
Room = room;
|
||||
var cs = Global.ControlSystem;
|
||||
|
||||
if (config.Trigger.Type.Equals("contact", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var portNum = (uint)config.Trigger.Number;
|
||||
if (portNum <= cs.NumberOfDigitalInputPorts)
|
||||
{
|
||||
cs.DigitalInputPorts[portNum].Register();
|
||||
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)
|
||||
{
|
||||
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>
|
||||
///
|
||||
/// </summary>
|
||||
public void RunEmergencyBehavior()
|
||||
{
|
||||
if (Behavior.Equals("shutdown"))
|
||||
Room.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes the functionality of a room emergency contact closure
|
||||
/// </summary>
|
||||
public interface IEssentialsRoomEmergency
|
||||
{
|
||||
event EventHandler<EventArgs> EmergencyStateChange;
|
||||
|
||||
bool InEmergency { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface IRoomEventSchedule
|
||||
{
|
||||
void AddOrUpdateScheduledEvent(ScheduledEventConfig eventConfig);
|
||||
|
||||
List<ScheduledEventConfig> GetScheduledEvents();
|
||||
|
||||
event EventHandler<ScheduledEventEventArgs> ScheduledEventsChanged;
|
||||
}
|
||||
|
||||
public class ScheduledEventEventArgs : EventArgs
|
||||
{
|
||||
public List<ScheduledEventConfig> ScheduledEvents;
|
||||
}
|
||||
}
|
||||
@@ -1,361 +0,0 @@
|
||||
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>();
|
||||
|
||||
/// <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 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
destination.ReleaseRoute(destinationPort?.Key ?? string.Empty);
|
||||
|
||||
RunRouteRequest(routeRequest);
|
||||
}
|
||||
|
||||
private static void RunRouteRequest(RouteRequest request)
|
||||
{
|
||||
if (request.Source == null)
|
||||
return;
|
||||
|
||||
var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort);
|
||||
|
||||
if (audioOrSingleRoute == null && videoRoute == null)
|
||||
return;
|
||||
|
||||
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute);
|
||||
|
||||
if (videoRoute != null)
|
||||
{
|
||||
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute);
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination);
|
||||
|
||||
audioOrSingleRoute.ExecuteRoutes();
|
||||
videoRoute?.ExecuteRoutes();
|
||||
}
|
||||
|
||||
public static void ReleaseRoute(this IRoutingInputs destination)
|
||||
{
|
||||
ReleaseRoute(destination, string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will release the existing route on the destination, if it is found in
|
||||
/// RouteDescriptorCollection.DefaultCollection
|
||||
/// </summary>
|
||||
/// <param name="destination"></param>
|
||||
public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Release route for '{destination}':'{inputPortKey}'", destination?.Key ?? "", 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 ?? "", string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using PepperDash.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
public interface IVideoSync : IKeyed
|
||||
{
|
||||
bool VideoSyncDetected { get; }
|
||||
|
||||
event EventHandler VideoSyncChanged;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
public interface IMatrixRouting
|
||||
{
|
||||
Dictionary<string, IRoutingInputSlot> InputSlots { get; }
|
||||
Dictionary<string, IRoutingOutputSlot> OutputSlots { get; }
|
||||
|
||||
void Route(string inputSlotKey, string outputSlotKey, eRoutingSignalType type);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an IRmcRouting with a feedback event
|
||||
/// </summary>
|
||||
public interface IRmcRoutingWithFeedback : IRmcRouting
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
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);
|
||||
}*/
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +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;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
|
||||
public interface IRoutingHasVideoInputSyncFeedbacks
|
||||
{
|
||||
FeedbackCollection<BoolFeedback> VideoInputSyncFeedbacks { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
public interface IRoutingInputSlot: IRoutingSlot, IOnline, IVideoSync
|
||||
{
|
||||
string TxDeviceKey { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
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,16 +0,0 @@
|
||||
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>
|
||||
{
|
||||
}*/
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface IRoutingNumeric : IRouting
|
||||
{
|
||||
void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an IRoutingNumeric with a feedback event
|
||||
/// </summary>
|
||||
public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
public interface IRoutingOutputSlot : IRoutingSlot
|
||||
{
|
||||
event EventHandler OutputSlotChanged;
|
||||
|
||||
string RxDeviceKey { get; }
|
||||
|
||||
Dictionary<eRoutingSignalType, IRoutingInputSlot> CurrentRoutes { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
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; }
|
||||
}*/
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
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>();
|
||||
}*/
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
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;
|
||||
}*/
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
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);
|
||||
}*/
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using PepperDash.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Routing
|
||||
{
|
||||
public interface IRoutingSlot:IKeyName
|
||||
{
|
||||
int SlotNumber { get; }
|
||||
|
||||
eRoutingSignalType SupportedSignalTypes { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an IRoutingOutputs devices as being a source - the start of the chain
|
||||
/// </summary>
|
||||
public interface IRoutingSource : IRoutingOutputs
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public interface ITxRouting : IRoutingNumeric
|
||||
{
|
||||
IntFeedback VideoSourceNumericFeedback { get; }
|
||||
IntFeedback AudioSourceNumericFeedback { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an IRmcRouting with a feedback event
|
||||
/// </summary>
|
||||
public interface ITxRoutingWithFeedback : ITxRouting
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
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));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
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 ?? "");
|
||||
|
||||
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 ?? "", 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 ?? "", 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;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
using System;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic RoutingInput with no statuses.
|
||||
/// </summary>
|
||||
public class RoutingInputPort : RoutingPort
|
||||
{
|
||||
/// <summary>
|
||||
/// The IRoutingInputs object this lives on
|
||||
/// </summary>
|
||||
public IRoutingInputs ParentDevice { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a basic RoutingInputPort
|
||||
/// </summary>
|
||||
/// <param name="selector">An object used to refer to this port in the IRouting device's ExecuteSwitch method.
|
||||
/// May be string, number, whatever</param>
|
||||
/// <param name="parent">The IRoutingInputs object this lives on</param>
|
||||
public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType,
|
||||
object selector, IRoutingInputs parent)
|
||||
: this (key, type, connType, selector, parent, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a virtual routing input port that lives inside a device. For example
|
||||
/// the ports that link a DM card to a DM matrix bus
|
||||
/// </summary>
|
||||
/// <param name="isInternal">true for internal ports</param>
|
||||
public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType,
|
||||
object selector, IRoutingInputs parent, bool isInternal)
|
||||
: base(key, type, connType, selector, isInternal)
|
||||
{
|
||||
if (parent == null)
|
||||
throw new ArgumentNullException(nameof(parent));
|
||||
ParentDevice = parent;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}";
|
||||
}
|
||||
}
|
||||
|
||||
/*/// <summary>
|
||||
/// Basic RoutingInput with no statuses.
|
||||
/// </summary>
|
||||
public class RoutingInputPort<TSelector> : RoutingPort<TSelector>
|
||||
{
|
||||
/// <summary>
|
||||
/// The IRoutingInputs object this lives on
|
||||
/// </summary>
|
||||
public IRoutingInputs<TSelector> ParentDevice { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a basic RoutingInputPort
|
||||
/// </summary>
|
||||
/// <param name="selector">An object used to refer to this port in the IRouting device's ExecuteSwitch method.
|
||||
/// May be string, number, whatever</param>
|
||||
/// <param name="parent">The IRoutingInputs object this lives on</param>
|
||||
public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType,
|
||||
TSelector selector, IRoutingInputs<TSelector> parent)
|
||||
: this(key, type, connType, selector, parent, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for a virtual routing input port that lives inside a device. For example
|
||||
/// the ports that link a DM card to a DM matrix bus
|
||||
/// </summary>
|
||||
/// <param name="isInternal">true for internal ports</param>
|
||||
public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType,
|
||||
TSelector selector, IRoutingInputs<TSelector> parent, bool isInternal)
|
||||
: base(key, type, connType, selector, isInternal)
|
||||
{
|
||||
ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A RoutingInputPort for devices like DM-TX and DM input cards.
|
||||
/// Will provide video statistics on connected signals
|
||||
/// </summary>
|
||||
public class RoutingInputPortWithVideoStatuses : RoutingInputPort
|
||||
{
|
||||
/// <summary>
|
||||
/// Video statuses attached to this port
|
||||
/// </summary>
|
||||
public VideoStatusOutputs VideoStatus { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="selector">An object used to refer to this port in the IRouting device's ExecuteSwitch method.
|
||||
/// May be string, number, whatever</param>
|
||||
/// <param name="parent">The IRoutingInputs object this lives on</param>
|
||||
/// <param name="funcs">A VideoStatusFuncsWrapper used to assign the callback funcs that will get
|
||||
/// the values for the various stats</param>
|
||||
public RoutingInputPortWithVideoStatuses(string key,
|
||||
eRoutingSignalType type, eRoutingPortConnectionType connType, object selector,
|
||||
IRoutingInputs parent, VideoStatusFuncsWrapper funcs) :
|
||||
base(key, type, connType, selector, parent)
|
||||
{
|
||||
VideoStatus = new VideoStatusOutputs(funcs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using System;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class RoutingNumericEventArgs : EventArgs
|
||||
{
|
||||
|
||||
public uint? Output { get; set; }
|
||||
public uint? Input { get; set; }
|
||||
|
||||
public eRoutingSignalType SigType { get; set; }
|
||||
public RoutingInputPort InputPort { get; set; }
|
||||
public RoutingOutputPort OutputPort { get; set; }
|
||||
|
||||
public RoutingNumericEventArgs(uint output, uint input, eRoutingSignalType sigType) : this(output, input, null, null, sigType)
|
||||
{
|
||||
}
|
||||
|
||||
public RoutingNumericEventArgs(RoutingOutputPort outputPort, RoutingInputPort inputPort,
|
||||
eRoutingSignalType sigType)
|
||||
: this(null, null, outputPort, inputPort, sigType)
|
||||
{
|
||||
}
|
||||
|
||||
public RoutingNumericEventArgs()
|
||||
: this(null, null, null, null, 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public RoutingNumericEventArgs(uint? output, uint? input, RoutingOutputPort outputPort,
|
||||
RoutingInputPort inputPort, eRoutingSignalType sigType)
|
||||
{
|
||||
OutputPort = outputPort;
|
||||
InputPort = inputPort;
|
||||
|
||||
Output = output;
|
||||
Input = input;
|
||||
SigType = sigType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using System;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class RoutingOutputPort : RoutingPort
|
||||
{
|
||||
/// <summary>
|
||||
/// The IRoutingOutputs object this port lives on
|
||||
/// </summary>
|
||||
public IRoutingOutputs ParentDevice { get; private set; }
|
||||
|
||||
public InUseTracking InUseTracker { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="selector">An object used to refer to this port in the IRouting device's ExecuteSwitch method.
|
||||
/// May be string, number, whatever</param>
|
||||
/// <param name="parent">The IRoutingOutputs object this port lives on</param>
|
||||
public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType,
|
||||
object selector, IRoutingOutputs parent)
|
||||
: this(key, type, connType, selector, parent, false)
|
||||
{
|
||||
}
|
||||
|
||||
public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType,
|
||||
object selector, IRoutingOutputs parent, bool isInternal)
|
||||
: base(key, type, connType, selector, isInternal)
|
||||
{
|
||||
ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent));
|
||||
InUseTracker = new InUseTracking();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}";
|
||||
}
|
||||
}
|
||||
|
||||
/*public class RoutingOutputPort<TSelector> : RoutingPort<TSelector>
|
||||
{
|
||||
/// <summary>
|
||||
/// The IRoutingOutputs object this port lives on
|
||||
/// </summary>
|
||||
public IRoutingOutputs ParentDevice { get; private set; }
|
||||
|
||||
public InUseTracking InUseTracker { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="selector">An object used to refer to this port in the IRouting device's ExecuteSwitch method.
|
||||
/// May be string, number, whatever</param>
|
||||
/// <param name="parent">The IRoutingOutputs object this port lives on</param>
|
||||
public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType,
|
||||
TSelector selector, IRoutingOutputs parent)
|
||||
: this(key, type, connType, selector, parent, false)
|
||||
{
|
||||
}
|
||||
|
||||
public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType,
|
||||
TSelector selector, IRoutingOutputs parent, bool isInternal)
|
||||
: base(key, type, connType, selector, isInternal)
|
||||
{
|
||||
ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent));
|
||||
InUseTracker = new InUseTracking();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ParentDevice.Key + ":" + Key;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
using PepperDash.Core;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for RoutingInput and Output ports
|
||||
/// </summary>
|
||||
public abstract class RoutingPort : IKeyed
|
||||
{
|
||||
public string Key { get; private set; }
|
||||
public eRoutingSignalType Type { get; private set; }
|
||||
public eRoutingPortConnectionType ConnectionType { get; private set; }
|
||||
public readonly object Selector;
|
||||
public bool IsInternal { get; private set; }
|
||||
public object FeedbackMatchObject { get; set; }
|
||||
public object Port { get; set; }
|
||||
|
||||
public RoutingPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, bool isInternal)
|
||||
{
|
||||
Key = key;
|
||||
Type = type;
|
||||
ConnectionType = connType;
|
||||
Selector = selector;
|
||||
IsInternal = isInternal;
|
||||
}
|
||||
}
|
||||
|
||||
/*public abstract class RoutingPort<TSelector>:IKeyed
|
||||
{
|
||||
public string Key { get; private set; }
|
||||
public eRoutingSignalType Type { get; private set; }
|
||||
public eRoutingPortConnectionType ConnectionType { get; private set; }
|
||||
public readonly TSelector Selector;
|
||||
public bool IsInternal { get; private set; }
|
||||
public object FeedbackMatchObject { get; set; }
|
||||
public object Port { get; set; }
|
||||
|
||||
public RoutingPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, bool isInternal)
|
||||
{
|
||||
Key = key;
|
||||
Type = type;
|
||||
ConnectionType = connType;
|
||||
Selector = selector;
|
||||
IsInternal = isInternal;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class TieLine
|
||||
{
|
||||
public RoutingOutputPort SourcePort { get; private set; }
|
||||
public RoutingInputPort DestinationPort { get; private set; }
|
||||
//public int InUseCount { get { return DestinationUsingThis.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of this tie line. Will either be the type of the desination port
|
||||
/// or the type of OverrideType when it is set.
|
||||
/// </summary>
|
||||
public eRoutingSignalType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
if (OverrideType.HasValue) return OverrideType.Value;
|
||||
return DestinationPort.Type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use this to override the Type property for the destination port. For example,
|
||||
/// when the tie line is type AudioVideo, and the signal flow should be limited to
|
||||
/// Audio-only or Video only, changing this type will alter the signal paths
|
||||
/// available to the routing algorithm without affecting the actual Type
|
||||
/// of the destination port.
|
||||
/// </summary>
|
||||
public eRoutingSignalType? OverrideType { get; set; }
|
||||
|
||||
//List<IRoutingInputs> DestinationUsingThis = new List<IRoutingInputs>();
|
||||
|
||||
/// <summary>
|
||||
/// For tie lines that represent internal links, like from cards to the matrix in a DM.
|
||||
/// This property is true if SourcePort and DestinationPort IsInternal
|
||||
/// property are both true
|
||||
/// </summary>
|
||||
public bool IsInternal { get { return SourcePort.IsInternal && DestinationPort.IsInternal; } }
|
||||
public bool TypeMismatch { get { return SourcePort.Type != DestinationPort.Type; } }
|
||||
public bool ConnectionTypeMismatch { get { return SourcePort.ConnectionType != DestinationPort.ConnectionType; } }
|
||||
public string TypeMismatchNote { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sourcePort"></param>
|
||||
/// <param name="destinationPort"></param>
|
||||
public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort)
|
||||
{
|
||||
if (sourcePort == null || destinationPort == null)
|
||||
throw new ArgumentNullException("source or destination port");
|
||||
SourcePort = sourcePort;
|
||||
DestinationPort = destinationPort;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a tie line with an overriding Type. See help for OverrideType property for info
|
||||
/// </summary>
|
||||
/// <param name="overrideType">The signal type to limit the link to. Overrides DestinationPort.Type</param>
|
||||
public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType overrideType) :
|
||||
this(sourcePort, destinationPort)
|
||||
{
|
||||
OverrideType = overrideType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will link up video status from supporting inputs to connected outputs
|
||||
/// </summary>
|
||||
public void Activate()
|
||||
{
|
||||
// Now does nothing
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
// Now does nothing
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Tie line: {0}:{1} --> {2}:{3} {4}", SourcePort.ParentDevice.Key, SourcePort.Key,
|
||||
DestinationPort.ParentDevice.Key, DestinationPort.Key, Type.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
|
||||
public class TieLineCollection : List<TieLine>
|
||||
{
|
||||
public static TieLineCollection Default
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Default == null)
|
||||
_Default = new TieLineCollection();
|
||||
return _Default;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private static TieLineCollection _Default;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Crestron.SimplSharpPro;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Config
|
||||
{
|
||||
public class TieLineConfig
|
||||
{
|
||||
public string SourceKey { get; set; }
|
||||
public string SourceCard { get; set; }
|
||||
public string SourcePort { get; set; }
|
||||
public string DestinationKey { get; set; }
|
||||
public string DestinationCard { get; set; }
|
||||
public string DestinationPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the appropriate tie line for either a card-based device or
|
||||
/// regular device with ports on-device.
|
||||
/// </summary>
|
||||
/// <returns>null if config data does not match ports, cards or devices</returns>
|
||||
public TieLine GetTieLine()
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Build TieLine: {0}",null, this);
|
||||
// Get the source device
|
||||
var sourceDev = DeviceManager.GetDeviceForKey(SourceKey) as IRoutingOutputs;
|
||||
if (sourceDev == null)
|
||||
{
|
||||
LogError("Routable source not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the destination device
|
||||
var destDev = DeviceManager.GetDeviceForKey(DestinationKey) as IRoutingInputs;
|
||||
if (destDev == null)
|
||||
{
|
||||
LogError("Routable destination not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
//Get the source port
|
||||
var sourceOutputPort = sourceDev.OutputPorts[SourcePort];
|
||||
|
||||
if (sourceOutputPort == null)
|
||||
{
|
||||
LogError("Source does not contain port");
|
||||
return null;
|
||||
}
|
||||
|
||||
//Get the Destination port
|
||||
var destinationInputPort = destDev.InputPorts[DestinationPort];
|
||||
|
||||
if (destinationInputPort == null)
|
||||
{
|
||||
LogError("Destination does not contain port");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TieLine(sourceOutputPort, destinationInputPort);
|
||||
}
|
||||
|
||||
void LogError(string msg)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Error, "WARNING: Cannot create tie line: {message}:\r {tieLineConfig}",null, msg, this);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}.{1}.{2} --> {3}.{4}.{5}", SourceKey, SourceCard, SourcePort,
|
||||
DestinationKey, DestinationCard, DestinationPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public enum eRoutingPortConnectionType
|
||||
{
|
||||
None, BackplaneOnly, DisplayPort, Dvi, Hdmi, Rgb, Vga, LineAudio, DigitalAudio, Sdi,
|
||||
Composite, Component, DmCat, DmMmFiber, DmSmFiber, Speaker, Streaming, UsbC, HdBaseT
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
[Flags]
|
||||
public enum eRoutingSignalType
|
||||
{
|
||||
Audio = 1,
|
||||
Video = 2,
|
||||
AudioVideo = Audio | Video,
|
||||
UsbOutput = 8,
|
||||
UsbInput = 16,
|
||||
SecondaryAudio = 32
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class CrestronTouchpanelPropertiesConfig
|
||||
{
|
||||
[JsonProperty("control")]
|
||||
public EssentialsControlPropertiesConfig ControlProperties { get; set; }
|
||||
|
||||
[JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string IpId { get; set; }
|
||||
|
||||
[JsonProperty("defaultRoomKey", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string DefaultRoomKey { get; set; }
|
||||
|
||||
[JsonProperty("roomListKey", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string RoomListKey { get; set; }
|
||||
|
||||
[JsonProperty("sgdFile", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string SgdFile { get; set; }
|
||||
|
||||
[JsonProperty("projectName", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string ProjectName { get; set; }
|
||||
|
||||
[JsonProperty("showVolumeGauge", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? ShowVolumeGauge { get; set; }
|
||||
|
||||
[JsonProperty("usesSplashPage", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? UsesSplashPage { get; set; }
|
||||
|
||||
[JsonProperty("showDate", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? ShowDate { get; set; }
|
||||
|
||||
[JsonProperty("showTime", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? ShowTime { get; set; }
|
||||
|
||||
[JsonProperty("setup", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public UiSetupPropertiesConfig Setup { get; set; }
|
||||
|
||||
[JsonProperty("headerStyle", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string HeaderStyle { get; set; }
|
||||
|
||||
[JsonProperty("includeInFusionRoomHealth", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool? IncludeInFusionRoomHealth { get; set; }
|
||||
|
||||
[JsonProperty("screenSaverTimeoutMin", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public uint? ScreenSaverTimeoutMin { get; set; }
|
||||
|
||||
[JsonProperty("screenSaverMovePositionIntervalMs", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public uint? ScreenSaverMovePositionIntervalMs { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The count of sources that will trigger the "additional" arrows to show on the SRL.
|
||||
/// Defaults to 5
|
||||
/// </summary>
|
||||
[JsonProperty("sourcesOverflowCount", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public int? SourcesOverflowCount { get; set; }
|
||||
|
||||
public CrestronTouchpanelPropertiesConfig() : this(false) { }
|
||||
|
||||
public CrestronTouchpanelPropertiesConfig(bool setDefaultValues = false)
|
||||
{
|
||||
if(!setDefaultValues) { return; }
|
||||
SourcesOverflowCount = 5;
|
||||
HeaderStyle = Habanero;
|
||||
|
||||
// Default values
|
||||
ScreenSaverTimeoutMin = 5;
|
||||
ScreenSaverMovePositionIntervalMs = 15000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// "habanero"
|
||||
/// </summary>
|
||||
public const string Habanero = "habanero";
|
||||
/// <summary>
|
||||
/// "verbose"
|
||||
/// </summary>
|
||||
public const string Verbose = "verbose";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class UiSetupPropertiesConfig
|
||||
{
|
||||
[JsonProperty("isVisible", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool IsVisible { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Web;
|
||||
using PepperDash.Essentials.Core.Web.RequestHandlers;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web
|
||||
{
|
||||
public class EssentialsWebApi : EssentialsDevice
|
||||
{
|
||||
private readonly WebApiServer _server;
|
||||
|
||||
///<example>
|
||||
/// http(s)://{ipaddress}/cws/{basePath}
|
||||
/// http(s)://{ipaddress}/VirtualControl/Rooms/{roomId}/cws/{basePath}
|
||||
/// </example>
|
||||
private readonly string _defaultBasePath = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance
|
||||
? string.Format("/app{0:00}/api", InitialParametersClass.ApplicationNumber)
|
||||
: "/api";
|
||||
|
||||
private const int DebugTrace = 0;
|
||||
private const int DebugInfo = 1;
|
||||
private const int DebugVerbose = 2;
|
||||
|
||||
/// <summary>
|
||||
/// CWS base path
|
||||
/// </summary>
|
||||
public string BasePath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tracks if CWS is registered
|
||||
/// </summary>
|
||||
public bool IsRegistered
|
||||
{
|
||||
get { return _server.IsRegistered; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="name"></param>
|
||||
public EssentialsWebApi(string key, string name)
|
||||
: this(key, name, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="config"></param>
|
||||
public EssentialsWebApi(string key, string name, EssentialsWebApiPropertiesConfig config)
|
||||
: base(key, name)
|
||||
{
|
||||
Key = key;
|
||||
|
||||
if (config == null)
|
||||
BasePath = _defaultBasePath;
|
||||
else
|
||||
BasePath = string.IsNullOrEmpty(config.BasePath) ? _defaultBasePath : config.BasePath;
|
||||
|
||||
_server = new WebApiServer(Key, Name, BasePath);
|
||||
|
||||
SetupRoutes();
|
||||
}
|
||||
|
||||
private void SetupRoutes()
|
||||
{
|
||||
var routes = new List<HttpCwsRoute>
|
||||
{
|
||||
new HttpCwsRoute("versions")
|
||||
{
|
||||
Name = "ReportVersions",
|
||||
RouteHandler = new ReportVersionsRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("appdebug")
|
||||
{
|
||||
Name = "AppDebug",
|
||||
RouteHandler = new AppDebugRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("devices")
|
||||
{
|
||||
Name = "DevList",
|
||||
RouteHandler = new DevListRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("deviceCommands/{deviceKey}")
|
||||
{
|
||||
Name = "DevJson",
|
||||
RouteHandler = new DevJsonRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("deviceProperties/{deviceKey}")
|
||||
{
|
||||
Name = "DevProps",
|
||||
RouteHandler = new DevPropsRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("deviceMethods/{deviceKey}")
|
||||
{
|
||||
Name = "DevMethods",
|
||||
RouteHandler = new DevMethodsRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("deviceFeedbacks/{deviceKey}")
|
||||
{
|
||||
Name = "GetFeedbacksForDeviceKey",
|
||||
RouteHandler = new GetFeedbacksForDeviceRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("deviceStreamDebug")
|
||||
{
|
||||
Name = "SetDeviceStreamDebug",
|
||||
RouteHandler = new SetDeviceStreamDebugRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("disableAllStreamDebug")
|
||||
{
|
||||
Name = "DisableAllStreamDebug",
|
||||
RouteHandler = new DisableAllStreamDebugRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("config")
|
||||
{
|
||||
Name = "ShowConfig",
|
||||
RouteHandler = new ShowConfigRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("types")
|
||||
{
|
||||
Name = "GetTypes",
|
||||
RouteHandler = new GetTypesRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("types/{filter}")
|
||||
{
|
||||
Name = "GetTypesByFilter",
|
||||
RouteHandler = new GetTypesByFilterRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("joinMap/{bridgeKey}")
|
||||
{
|
||||
Name = "GetJoinMapsForBridgeKey",
|
||||
RouteHandler = new GetJoinMapForBridgeKeyRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("joinMap/{bridgeKey}/{deviceKey}")
|
||||
{
|
||||
Name = "GetJoinMapsForDeviceKey",
|
||||
RouteHandler = new GetJoinMapForDeviceKeyRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("debugSession")
|
||||
{
|
||||
Name = "DebugSession",
|
||||
RouteHandler = new DebugSessionRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("doNotLoadConfigOnNextBoot")
|
||||
{
|
||||
Name = "DoNotLoadConfigOnNextBoot",
|
||||
RouteHandler = new DoNotLoadConfigOnNextBootRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("restartProgram")
|
||||
{
|
||||
Name = "Restart Program",
|
||||
RouteHandler = new RestartProgramRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("loadConfig")
|
||||
{
|
||||
Name = "Load Config",
|
||||
RouteHandler = new LoadConfigRequestHandler()
|
||||
},
|
||||
new HttpCwsRoute("getTielines")
|
||||
{
|
||||
Name = "Get TieLines",
|
||||
RouteHandler = new GetTieLinesRequestHandler()
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
AddRoute(routes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a single route to the API. MUST be done during the activation phase
|
||||
/// </summary>
|
||||
/// <param name="route"></param>
|
||||
public void AddRoute(HttpCwsRoute route)
|
||||
{
|
||||
_server.AddRoute(route);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a collection of routes to the API. MUST be done during the activation phase
|
||||
/// </summary>
|
||||
/// <param name="routes"></param>
|
||||
public void AddRoute(List<HttpCwsRoute> routes)
|
||||
{
|
||||
foreach (var route in routes)
|
||||
{
|
||||
AddRoute(route);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the CWS class
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
// If running on an appliance
|
||||
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
|
||||
{
|
||||
/*
|
||||
WEBSERVER [ON | OFF | TIMEOUT <VALUE IN SECONDS> | MAXSESSIONSPERUSER <Number of sessions>]
|
||||
*/
|
||||
var response = string.Empty;
|
||||
CrestronConsole.SendControlSystemCommand("webserver", ref response);
|
||||
if (response.Contains("OFF")) return;
|
||||
|
||||
var is4Series = eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Starting Essentials Web API on {0} Appliance", is4Series ? "4-series" : "3-series");
|
||||
|
||||
_server.Start();
|
||||
|
||||
GetPaths();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Automatically start CWS when running on a server (Linux OS, Virtual Control)
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Starting Essentials Web API on Virtual Control Server");
|
||||
|
||||
_server.Start();
|
||||
|
||||
GetPaths();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print the available pahts
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// http(s)://{ipaddress}/cws/{basePath}
|
||||
/// http(s)://{ipaddress}/VirtualControl/Rooms/{roomId}/cws/{basePath}
|
||||
/// </example>
|
||||
public void GetPaths()
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50));
|
||||
|
||||
var currentIp = CrestronEthernetHelper.GetEthernetParameter(
|
||||
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
|
||||
|
||||
var hostname = CrestronEthernetHelper.GetEthernetParameter(
|
||||
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
|
||||
|
||||
var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server
|
||||
? $"http(s)://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{BasePath}"
|
||||
: $"http(s)://{currentIp}/cws{BasePath}";
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "Server:{path:l}", path);
|
||||
|
||||
var routeCollection = _server.GetRouteCollection();
|
||||
if (routeCollection == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "Server route collection is null");
|
||||
return;
|
||||
}
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "Configured Routes:");
|
||||
foreach (var route in routeCollection)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "{routeName:l}: {routePath:l}/{routeUrl:l}", route.Name, path, route.Url);
|
||||
}
|
||||
Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using Crestron.SimplSharpPro.EthernetCommunication;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Web.RequestHandlers;
|
||||
using Serilog.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||
{
|
||||
public class DebugSessionRequestHandler : WebApiBaseRequestHandler
|
||||
{
|
||||
public DebugSessionRequestHandler()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets details for a debug session
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandleGet(Crestron.SimplSharp.WebScripting.HttpCwsContext context)
|
||||
{
|
||||
var routeData = context.Request.RouteData;
|
||||
if (routeData == null)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ip = CrestronEthernetHelper.GetEthernetParameter(
|
||||
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
|
||||
|
||||
var port = 0;
|
||||
|
||||
if (!Debug.WebsocketSink.IsRunning)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Starting WS Server");
|
||||
// Generate a random port within a specified range
|
||||
port = new Random().Next(65435, 65535);
|
||||
// Start the WS Server
|
||||
Debug.WebsocketSink.StartServerAndSetPort(port);
|
||||
Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose);
|
||||
}
|
||||
|
||||
var url = Debug.WebsocketSink.Url;
|
||||
|
||||
object data = new
|
||||
{
|
||||
url = Debug.WebsocketSink.Url
|
||||
};
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Debug Session URL: {0}", url);
|
||||
|
||||
// Return the port number with the full url of the WS Server
|
||||
var res = JsonConvert.SerializeObject(data);
|
||||
|
||||
context.Response.ContentType = "application/json";
|
||||
context.Response.ContentEncoding = Encoding.UTF8;
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.Write(res, false);
|
||||
context.Response.End();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "Error: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops a debug session
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandlePost(HttpCwsContext context)
|
||||
{
|
||||
Debug.WebsocketSink.StopServer();
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.End();
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "Websocket Debug Session Stopped");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
using System;
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Web.RequestHandlers;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||
{
|
||||
public class DevJsonRequestHandler : WebApiBaseRequestHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// base(true) enables CORS support by default
|
||||
/// </remarks>
|
||||
public DevJsonRequestHandler()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles POST method requests
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandlePost(HttpCwsContext context)
|
||||
{
|
||||
var routeData = context.Request.RouteData;
|
||||
|
||||
if(routeData == null)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Request.ContentLength < 0)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request: no body";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var data = context.Request.GetRequestBody();
|
||||
|
||||
if (string.IsNullOrEmpty(data))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request: no body";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var daw = new DeviceActionWrapper { DeviceKey = (string) deviceKey};
|
||||
|
||||
JsonConvert.PopulateObject(data, daw);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Device Action Wrapper: {@wrapper}", null, daw);
|
||||
|
||||
DeviceJsonApi.DoDeviceAction(daw);
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.End();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(ex, "Error handling device command: {Exception}");
|
||||
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.Write(JsonConvert.SerializeObject(new { error = ex.Message }), false);
|
||||
context.Response.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Web.RequestHandlers;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||
{
|
||||
public class DevMethodsRequestHandler : WebApiBaseRequestHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// base(true) enables CORS support by default
|
||||
/// </remarks>
|
||||
public DevMethodsRequestHandler()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles GET method requests
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandleGet(HttpCwsContext context)
|
||||
{
|
||||
var routeData = context.Request.RouteData;
|
||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting DevMethods: {@routeData}", routeData);
|
||||
if (routeData == null)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
object deviceObj;
|
||||
if (!routeData.Values.TryGetValue("deviceKey", out deviceObj))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var device = DeviceManager.GetDeviceForKey(deviceObj.ToString());
|
||||
|
||||
if (device == null)
|
||||
{
|
||||
context.Response.StatusCode = 404;
|
||||
context.Response.StatusDescription = "Device Not Found";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var deviceMethods = DeviceJsonApi.GetMethods(device.Key);
|
||||
if (deviceMethods == null || deviceMethods.ToLower().Contains("no device"))
|
||||
{
|
||||
context.Response.StatusCode = 404;
|
||||
context.Response.StatusDescription = "Not Found";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.ContentType = "application/json";
|
||||
context.Response.ContentEncoding = Encoding.UTF8;
|
||||
context.Response.Write(deviceMethods, false);
|
||||
context.Response.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core.Web.RequestHandlers;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||
{
|
||||
public class DevPropsRequestHandler : WebApiBaseRequestHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// base(true) enables CORS support by default
|
||||
/// </remarks>
|
||||
public DevPropsRequestHandler()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles GET method requests
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandleGet(HttpCwsContext context)
|
||||
{
|
||||
var routeData = context.Request.RouteData;
|
||||
if (routeData == null)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
object deviceObj;
|
||||
if (!routeData.Values.TryGetValue("deviceKey", out deviceObj))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var device = DeviceManager.GetDeviceForKey(deviceObj.ToString());
|
||||
|
||||
if (device == null)
|
||||
{
|
||||
context.Response.StatusCode = 404;
|
||||
context.Response.StatusDescription = "Device Not Found";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var deviceProperties = DeviceJsonApi.GetProperties(device.Key);
|
||||
if (deviceProperties == null || deviceProperties.ToLower().Contains("no device"))
|
||||
{
|
||||
context.Response.StatusCode = 404;
|
||||
context.Response.StatusDescription = "Not Found";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.ContentType = "application/json";
|
||||
context.Response.ContentEncoding = Encoding.UTF8;
|
||||
context.Response.Write(deviceProperties, false);
|
||||
context.Response.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Web.RequestHandlers;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||
{
|
||||
public class DoNotLoadConfigOnNextBootRequestHandler : WebApiBaseRequestHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// base(true) enables CORS support by default
|
||||
/// </remarks>
|
||||
public DoNotLoadConfigOnNextBootRequestHandler()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles GET method requests
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandleGet(HttpCwsContext context)
|
||||
{
|
||||
var data = new Data
|
||||
{
|
||||
DoNotLoadConfigOnNextBoot = Debug.DoNotLoadConfigOnNextBoot
|
||||
};
|
||||
|
||||
var body = JsonConvert.SerializeObject(data, Formatting.Indented);
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.Write(body, false);
|
||||
context.Response.End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles POST method requests
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandlePost(HttpCwsContext context)
|
||||
{
|
||||
if (context.Request.ContentLength < 0)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var data = context.Request.GetRequestBody();
|
||||
if (string.IsNullOrEmpty(data))
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
context.Response.StatusDescription = "Bad Request";
|
||||
context.Response.End();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var d = new Data();
|
||||
var requestBody = JsonConvert.DeserializeAnonymousType(data, d);
|
||||
|
||||
Debug.SetDoNotLoadConfigOnNextBoot(requestBody.DoNotLoadConfigOnNextBoot);
|
||||
|
||||
var responseBody = JsonConvert.SerializeObject(d, Formatting.Indented);
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.Write(responseBody, false);
|
||||
context.Response.End();
|
||||
}
|
||||
}
|
||||
|
||||
public class Data
|
||||
{
|
||||
[JsonProperty("doNotLoadConfigOnNextBoot", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public bool DoNotLoadConfigOnNextBoot { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core.Web.RequestHandlers;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||
{
|
||||
public class GetTieLinesRequestHandler : WebApiBaseRequestHandler
|
||||
{
|
||||
public GetTieLinesRequestHandler() : base(true) { }
|
||||
|
||||
protected override void HandleGet(HttpCwsContext context)
|
||||
{
|
||||
var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new
|
||||
{
|
||||
sourceKey = tl.SourcePort.ParentDevice.Key,
|
||||
sourcePort = tl.SourcePort.Key,
|
||||
destinationKey = tl.DestinationPort.ParentDevice.Key,
|
||||
destinationPort = tl.DestinationPort.Key,
|
||||
type = tl.Type.ToString(),
|
||||
}));
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.ContentType = "application/json";
|
||||
context.Response.ContentEncoding = Encoding.UTF8;
|
||||
context.Response.Write(tieLineString, false);
|
||||
context.Response.End();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Web.RequestHandlers;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||
{
|
||||
public class LoadConfigRequestHandler : WebApiBaseRequestHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// base(true) enables CORS support by default
|
||||
/// </remarks>
|
||||
public LoadConfigRequestHandler()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles POST method requests
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandlePost(HttpCwsContext context)
|
||||
{
|
||||
var message = "";
|
||||
var cs = Global.ControlSystem as ILoadConfig;
|
||||
if(cs != null)
|
||||
cs.GoWithLoad();
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.Write(message, false);
|
||||
context.Response.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.WebScripting;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Web.RequestHandlers;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||
{
|
||||
public class RestartProgramRequestHandler : WebApiBaseRequestHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// base(true) enables CORS support by default
|
||||
/// </remarks>
|
||||
public RestartProgramRequestHandler()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles POST method requests
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected override void HandlePost(HttpCwsContext context)
|
||||
{
|
||||
var message = "";
|
||||
if(CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
|
||||
CrestronConsole.SendControlSystemCommand($"progres -p:{InitialParametersClass.ApplicationNumber}", ref message);
|
||||
|
||||
context.Response.StatusCode = 200;
|
||||
context.Response.StatusDescription = "OK";
|
||||
context.Response.Write(message, false);
|
||||
context.Response.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using Crestron.SimplSharpPro;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Common.Codec
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a cisco codec device that can allow configuration of cameras
|
||||
/// </summary>
|
||||
public interface ICiscoCodecCameraConfig
|
||||
{
|
||||
void SetCameraAssignedSerialNumber(uint cameraId, string serialNumber);
|
||||
|
||||
void SetCameraName(uint videoConnectorId, string name);
|
||||
|
||||
void SetInputSourceType(uint videoConnectorId, eCiscoCodecInputSourceType sourceType);
|
||||
}
|
||||
|
||||
public enum eCiscoCodecInputSourceType
|
||||
{
|
||||
PC,
|
||||
camera,
|
||||
document_camera,
|
||||
mediaplayer,
|
||||
other,
|
||||
whiteboard
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user