Compare commits

...

112 Commits
1.8.5 ... 1.9.2

Author SHA1 Message Date
Andrew Welker
d64cbc639a Merge pull request #762 from PepperDash/release/1.9.2
Release/1.9.2
2021-07-28 18:47:34 -06:00
Andrew Welker
8404e7d5a4 Merge branch 'main' into release/1.9.2 2021-07-28 17:07:01 -06:00
Andrew Welker
e4135a958c Merge pull request #764 from PepperDash/hotfix/add-tsw7xx-types-to-factory
Hotfix/add tsw7xx types to factory
2021-07-28 17:06:45 -06:00
Neil Dorin
f4ac4e6319 Minor updates to resolve oddities with ZoomRoom and TSW UI drivers (call status) 2021-07-28 16:38:20 -06:00
Andrew Welker
b026174cd2 Merge branch 'main' into release/1.9.2 2021-07-28 15:47:46 -06:00
Neil Dorin
66ff6b2e07 Brings in another small zoom update from @jkdevito 2021-07-28 15:33:04 -06:00
Neil Dorin
e7bbfbd40a Update to add populate call Id and Name properties to allow proper removal of inactive calls 2021-07-28 15:27:47 -06:00
Neil Dorin
eec86fde48 Updates incorrect path for ZoomRoom feedback exclusions and adds toll_free_callinList 2021-07-28 15:23:57 -06:00
Neil Dorin
7b57ce439e #761 Adds support for x70 series touchpanels 2021-07-28 14:47:17 -06:00
Andrew Welker
5d120391a5 Merge pull request #752 from PepperDash/feature/ndorin-patch-1
Adds a prompt to capture affected version
2021-07-21 13:16:59 -06:00
Neil Dorin
db5aa319ec Adds a prompt to capture affected version 2021-07-20 16:49:03 -06:00
Neil Dorin
10f5516a5a Merge pull request #749 from PepperDash/feature/occ-aggregator
Update Occupancy Aggregator to be real device
2021-07-19 15:43:58 -06:00
Andrew Welker
45e6dff26d fix: update access level for config constructor 2021-07-19 15:10:03 -06:00
Andrew Welker
10129b8178 feat: Add post activation action for aggregator 2021-07-19 15:09:37 -06:00
Andrew Welker
9128e108f7 feat: Add clear method to BoolOutputLogical
and do a bit of refactoring
2021-07-19 15:09:03 -06:00
Andrew Welker
760ec8be92 feat: Add occupancy aggregator factory and config 2021-07-19 14:08:57 -06:00
Andrew Welker
bbcdd3e179 Merge pull request #747 from PepperDash/feature/C2N-IO-add
Add C2NIoController to csproj
2021-07-19 14:06:33 -06:00
Andrew Welker
7a649f4ea8 Merge branch 'development' into feature/C2N-IO-add 2021-07-19 13:48:43 -06:00
Andrew Welker
6946946c12 chore: Add c2nIoController to csproj 2021-07-19 13:47:17 -06:00
Neil Dorin
dca73e1508 Merge pull request #745 from PepperDash/feature/C2N-IO-add
Add C2N-IO
2021-07-19 11:55:15 -06:00
Andrew Welker
990090e1de feat: Add support for C2N-IO 2021-07-19 10:29:30 -06:00
Andrew Welker
3b843104d8 Merge pull request #738 from PepperDash/feature/room-combining
Feature/room combining
2021-07-13 22:14:42 -06:00
Neil Dorin
a37814ab3c #736 adds IEssentialsHuddleVtc1Room and refactors to use interface rather than EssentialsHudleVtc1Room 2021-07-12 21:49:54 -06:00
Neil Dorin
2181410927 #736 Adds IEssentialsRoom and IEssentialsHuddleSpaceRoom interfaces
Refactors all references to EssentialsRoomBase and EssentialsHuddleSpaceRoom to use the new interfaces instead
2021-07-12 17:22:36 -06:00
Andrew Welker
d4191ceb75 Merge pull request #735 from PepperDash/hotfix/zip-release-upload
Hotfix/zip release upload
2021-07-08 12:04:57 -06:00
Andrew Welker
5f6d15c6c0 Merge branch 'development' into hotfix/zip-release-upload 2021-07-08 11:41:40 -06:00
Andrew Welker
4cc40227fd Merge pull request #734 from PepperDash/hotfix/zip-release-upload
ci: Remove condition on upload to release
2021-07-08 11:41:32 -06:00
Andrew Welker
d0dbbe095f ci: Remove condition on upload to release 2021-07-08 11:16:41 -06:00
Andrew Welker
c7180db2b7 Merge pull request #730 from PepperDash/feature/update-ihasscheduleawareness
Feature/update ihasscheduleawareness
2021-07-03 00:39:29 -06:00
Neil Dorin
d95ee27979 #728 corrects casing of folder name in Global.FilePathPrefix at startup 2021-07-02 15:01:51 -06:00
Neil Dorin
e964172200 #729 Updates to get CheckSchedule method working as designed 2021-07-02 15:01:17 -06:00
Neil Dorin
840934502b Working on getting meeting change events to trigger properly 2021-06-29 17:35:22 -06:00
Neil Dorin
a76f4c15dc Updates to IHasScheduleAwareness 2021-06-29 09:47:56 -06:00
Neil Dorin
b19e2e38ad Merge pull request #727 from PepperDash/hotfix/add-eisc-server-client-options-to-eiscapiadvanced-factory
Hotfix/add eisc server client options to eiscapiadvanced factory
2021-06-24 16:53:14 -06:00
Neil Dorin
9a7fe553f9 Merge branch 'development' into hotfix/add-eisc-server-client-options-to-eiscapiadvanced-factory 2021-06-24 16:35:29 -06:00
Neil Dorin
e6ecaf3a1e Merge pull request #726 from PepperDash/hotfix/add-eisc-server-client-options-to-eiscapiadvanced-factory
adds new type options to use EISCClient and EISCServer in eiscapiadvanced
2021-06-24 16:35:18 -06:00
Andrew Welker
895b76a0cd Merge pull request #723 from PepperDash/hotfix/zoom-room-views
Hotfix/zoom room views
2021-06-24 13:28:48 -06:00
Neil Dorin
5c9996e728 adds new type options to use EISCClient and EISCServer in eiscapiadvanced 2021-06-17 13:49:09 -06:00
Andrew Welker
0cc2328276 Merge branch 'development' into hotfix/zoom-room-views 2021-06-17 10:03:42 -06:00
Andrew Welker
8fadfa98f2 Merge pull request #724 from PepperDash/hotfix/zoom-room-views
Hotfix/zoom room views
2021-06-17 10:02:17 -06:00
Andrew Welker
1ccf54003f Merge branch 'main' into hotfix/zoom-room-views 2021-06-17 09:32:04 -06:00
Neil Dorin
54769ce270 Merge pull request #722 from PepperDash/hotfix/plugin-loading
Hotfix/plugin loading
2021-06-16 17:20:57 -06:00
Andrew Welker
6b85323949 Merge branch 'development' into hotfix/plugin-loading 2021-06-16 15:17:52 -06:00
Andrew Welker
319d8f99c5 Merge pull request #721 from PepperDash/hotfix/plugin-loading
adds check for abstract class before attempting to create instance
2021-06-16 15:17:32 -06:00
Neil Dorin
cc742f4291 adds check for abstract class before attempting to create instance 2021-06-16 13:11:45 -06:00
Jason DeVito
6beff106ec Updated packages.config to track latest PepperDash Core release. Updated ZoomRoom LinkZoomRoomToApi to update the bridge when it comes online. 2021-06-10 17:45:23 -05:00
Neil Dorin
cb35aa13f5 lets it fall through conditions to fire the ParticipantsChanged event if an already pinned participant is found 2021-06-09 17:55:55 -06:00
Neil Dorin
b71523bd2d Adds condition to not check for already pinned participant if incoming message has user id < 0 2021-06-09 17:38:50 -06:00
Neil Dorin
0c56da112c Changes to respond to new pinned participant message by clearing out already pinned participant fb first. 2021-06-09 17:07:25 -06:00
Neil Dorin
08f4d8e9a2 Attempts to unpin participant from same screenIndex if one is already pinned. 2021-06-09 16:57:42 -06:00
Neil Dorin
25e7e9634a updates PD Core version to include xsig token fixes 2021-06-09 16:56:56 -06:00
Neil Dorin
7ac3f81ea5 Initialize SreenIndexIsPinnedToFb to -1. Adds debugging for xsig tokens 2021-06-09 16:14:18 -06:00
Neil Dorin
1c06e8381b Fixed inverted video mute FB and adds debug statements to help see participant pin status 2021-06-09 13:30:36 -06:00
Jason DeVito
f5305197b3 Updates to LinkZoomRoomApi method 2021-06-09 13:37:01 -05:00
Jason DeVito
1805ebaf0f Converted ZoomRoom Layout Size properties and methods to interface, IHasSelfviewSize, following the patterns implemented for IHasSelfviewPosition and SelfviewPipPosition. 2021-06-08 17:56:00 -05:00
Jason DeVito
ca8207f2bd Removed Layout Position properties and methods. Using SelfviewPipPosition properties and methods. 2021-06-08 15:20:42 -05:00
Neil Dorin
4e81859695 Merge pull request #719 from PepperDash/bugfix/setdevicestreamdebug-fix
Bugfix/setdevicestreamdebug fix
2021-06-08 13:45:08 -06:00
Jason DeVito
655bb954fa Updated IHasCodecLayouts and ZoomRoom to test feedback of Layout Size and Layout Position. 2021-06-08 14:38:33 -05:00
Andrew Welker
1ebacf3f0f Fix formatting issue 2021-06-08 12:12:59 -06:00
Andrew Welker
7de0251188 add ConvertType method to convert type
This method should allow for using a string value in place of an enum as a parameter. Integers will still fail.
2021-06-08 11:44:09 -06:00
Jason DeVito
492e593263 Updated IHasCodecLayouts to implement Layout Position selection and feedback, updated bridge map to map Layout Position signals. Updated ZoomRoom to implement Layout Position selection and feedback. 2021-06-07 22:22:00 -05:00
Jason DeVito
afe2046c81 Added methods to select Call Layout Size. 2021-06-07 14:45:40 -05:00
Neil Dorin
98d3a4a2fa Merge pull request #713 from PepperDash/release/1.9.0
1.9.0
2021-05-25 14:48:52 -06:00
Andrew Welker
1702c69b73 Merge branch 'main' into release/1.9.0 2021-05-25 14:37:27 -06:00
Andrew Welker
722d28b1b3 Merge pull request #710 from PepperDash/hotfix/techroom-preset-recall-event
Hotfix/techroom preset recall event
2021-05-24 13:32:46 -06:00
Andrew Welker
ef7da0d7af Merge branch 'development' into hotfix/techroom-preset-recall-event 2021-05-24 13:19:45 -06:00
Neil Dorin
77d8e63a31 Merge pull request #709 from PepperDash/hotfix/techroom-preset-recall-event
Hotfix/techroom preset recall event
2021-05-24 12:59:54 -06:00
Neil Dorin
d2d99d4bfa Merge branch 'main' into hotfix/techroom-preset-recall-event 2021-05-24 12:45:27 -06:00
Neil Dorin
4bd71b04bf Merge pull request #708 from PepperDash/feature/add-zoomroom-participant-actions
Feature/add zoomroom participant actions
2021-05-20 20:34:45 -06:00
Andrew Welker
c5bcd89695 Merge branch 'development' into feature/add-zoomroom-participant-actions 2021-05-20 18:34:58 -06:00
Jason DeVito
c7cc98bff7 Removed old TODO's from VideoCodecBase.cs. Marked TODO's for Issue #697. 2021-05-20 19:32:11 -05:00
Jason DeVito
db60f8f1be ResponseObject.cs updates: Added and tested SortParticipantListtByHandStatus method. Found an issue with HandStatus response, property names include ': ', updated JsonProperty definitions to account for issues with expected returns vs. actual returns. 2021-05-20 15:43:02 -05:00
Andrew Welker
a91af6bd75 Merge pull request #703 from PepperDash/feature/add-rfi-issue-template
Adds RFI Template
2021-05-20 09:22:23 -06:00
Neil Dorin
2d36b80800 Adds CH5 option 2021-05-14 15:46:12 -06:00
Neil Dorin
e152b9a504 Merge branch 'development' into feature/add-rfi-issue-template 2021-05-14 15:05:25 -06:00
Neil Dorin
eac7c91327 Create rfi_request.md 2021-05-13 18:07:03 -06:00
Jason DeVito
ac0d5e59a0 ZoomRoom.cs, commented out Debug statement @ line 874 to remove 'JSON Curly Brace Count:' messages in console when using debug level 2. 2021-05-12 11:27:33 -05:00
Andrew Welker
78be8ec5f2 Merge pull request #701 from PepperDash/feature/reconfigurable-device-write-control
Feature/reconfigurable device write control
2021-05-11 20:22:04 -06:00
Jason Alborough
5fc4ff6027 #700 FIxes issue where ConfigWrite.UpdateDeviceConfig and UpdateRoomConfig do not write config to file 2021-05-11 20:28:15 -04:00
Neil Dorin
63853739f3 Updates object structure to deal with a bug in ZoomRoom 5.6.3 that responds with an incorrect object structure for the layout style property 2021-05-11 17:23:26 -06:00
Jason DeVito
c14193f9ac Updates to VideoCodecControllerJoinMap to fix joins for Participant triggers. Updated ZoomRoomJoinMaps to implement zConfiguration.eLayoutStyle to pass the name across the bridge. 2021-05-11 18:13:18 -05:00
Jason T Alborough
da179c01f5 Fixes UpdateDeviceConfig() 2021-05-11 17:52:26 -04:00
Jason Alborough
0ded3e30f9 Merge branch 'development' into feature/reconfigurable-device-write-control 2021-05-11 15:24:40 -04:00
Jason T Alborough
8d215930d9 Adds WriteControlProperty to ReconfigurableDevice
CameraBase now uses ReconfigurableDevice
2021-05-11 15:20:35 -04:00
Neil Dorin
b4edb021ee #698 merged in join map updates from JKD. Fixed enum bit comparison for available layout feedbacks 2021-05-11 12:23:27 -06:00
Neil Dorin
52caa98f33 Merge branch 'feature/add-zoomroom-layout-controls' into feature/add-zoomroom-participant-actions 2021-05-11 11:10:37 -06:00
Jason DeVito
4e041d1773 Removed unused DecodecParticipantsXSig method. 2021-05-11 11:36:17 -05:00
Jason DeVito
118bd5a54a Updates VideoCodecControllerJoinMap.cs to organize joins. Update to VideoCodecBase.cs UpdateParticipantsXSig. 2021-05-11 11:19:33 -05:00
Jason DeVito
116abbf962 Updates ZoomRoomJoinMap.cs with join numbers. Updated VideoCodecControllerJoinMap.cs to organize the joins in a logical pattern. Update VideoCodecBase to add the maxAnalogs to the logic calculating xsig indexes and offsets. 2021-05-11 08:34:16 -05:00
Neil Dorin
a06333e1c3 Adds temp join numbers for participant actions 2021-05-10 15:38:33 -06:00
Neil Dorin
d937dc14fc #698 Adds actions to toggle audio/video mute and pinning for participants 2021-05-10 15:09:33 -06:00
Neil Dorin
604f4ca22d #698 Adds join objects for participants audio/video mute and pin toggle 2021-05-10 12:58:07 -06:00
Neil Dorin
2d7ad8ba2a #698 Updates to add participant hand raised and pin/unpin 2021-05-07 18:07:25 -06:00
Neil Dorin
e4a3933743 Mostly coded. Needs join numbers for ZoomRoomJoinMap values 2021-05-06 16:54:41 -06:00
Neil Dorin
d6445861f5 Adds IHasZoomRoomLayouts interface. Update zStatus.Layout class to extend NotifiableObject 2021-05-05 21:55:28 -06:00
Jason T Alborough
03b076c8eb Merge pull request #696 from PepperDash/feature/dm-audio-routing-fix
Fixes DM Audio Routing
2021-04-30 15:28:08 -04:00
Andrew Welker
7c58221acc Merge branch 'development' into feature/dm-audio-routing-fix 2021-04-30 13:12:18 -06:00
Andrew Welker
14f7c27b33 Merge pull request #695 from PepperDash/bugfix/discovery-routing-endless-loop
Bugfix/discovery routing endless loop
2021-04-30 13:12:10 -06:00
Jason Alborough
9ea65883b7 Fixes DM Audio Routing 2021-04-30 14:58:39 -04:00
Alex Johnson
9d0020d999 Merge branch 'development' into bugfix/discovery-routing-endless-loop 2021-04-29 13:52:36 -04:00
Alex Johnson
fb44a3b93c Resolves looping in IRouting by adding the device to the tracking list before iterating down further. Adds debug statement to print when this condition occurs - "Skipping input <device> on <router-device>, this was already checked" 2021-04-29 13:44:47 -04:00
Andrew Welker
6b7c5c01f8 Merge pull request #693 from PepperDash/hotfix/console-response-crlf-fixes
Hotfix/console response crlf fixes
2021-04-28 21:58:44 -06:00
Andrew Welker
1a3eb9a546 Merge branch 'development' into hotfix/console-response-crlf-fixes 2021-04-28 09:54:39 -06:00
Neil Dorin
685c344785 #690 fixes incorrect conditional check before firing feedback 2021-04-20 14:38:24 -06:00
Andrew Welker
e6f5142fc3 Merge pull request #688 from PepperDash/feature/secretsManager
Feature/secrets manager
2021-04-16 12:13:38 -06:00
Trevor Payne
3c9ca1e527 Resoves #688
Added some QoL improvements to SecretsManager meant to protect the integrity of the providers dictionary from accidental manipulation

Debug statement improvements

Improvements to verbosity of console command returns for the SecretsManager
2021-04-16 12:29:41 -05:00
Trevor Payne
452d0a5a39 Changed DeviceFactory.GetSecret(SecretsPropertiesConfig data) to return an empty string instead of null on a failed retrieval 2021-04-16 09:59:58 -05:00
Trevor Payne
8643ed2caf #685 - Requested Fixes per AWelker 2021-04-15 19:14:24 -05:00
Trevor Payne
2787c7fc52 Close #685
Adds support for Secrets
2021-04-15 18:47:13 -05:00
Trevor Payne
babc3e4f1a fixed minor registration error 2021-04-15 14:36:43 -05:00
Trevor Payne
0a4ff82af0 Added SecretsManager
Added ISecrets

Added ISecretsProvider
2021-04-15 13:47:46 -05:00
Andrew Welker
b455e1af21 Merge pull request #684 from PepperDash/release/v1.8.3
add flags on both ends to prevent input switching loop
2021-04-09 16:50:54 -06:00
67 changed files with 10199 additions and 6962 deletions

View File

@@ -7,6 +7,9 @@ assignees: ''
---
**Was this bug identified in a specific build version?**
Please note the build version where this bug was identified
**Describe the bug**
A clear and concise description of what the bug is.

27
.github/ISSUE_TEMPLATE/rfi_request.md vendored Normal file
View File

@@ -0,0 +1,27 @@
---
name: Request for Information
about: Request specific information about capabilities of the framework
title: "[RFI]-"
labels: RFI
assignees: ''
---
**What is your request?**
Please provide as much detail as possible.
**What is the intended use case**
- [ ] Essentials Standalone Application
- [ ] Essentials + SIMPL Windows Hybrid
**User Interface Requirements**
- [ ] Not Applicable (logic only)
- [ ] Crestron Smart Graphics Touchpanel
- [ ] Cisco Touch10
- [ ] Mobile Control
- [ ] Crestron CH5 Touchpanel interface
**Additional context**
Add any other context or screenshots about the request here.

View File

@@ -90,7 +90,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Upload the build package to the release
- name: Upload Release Package
if: contains(env.VERSION,'-rc-') || contains(env.VERSION,'-hotfix-')
id: upload_release
uses: actions/upload-release-asset@v1
with:

View File

@@ -36,6 +36,7 @@ namespace PepperDash.Essentials
Thread.MaxNumberOfUserThreads = 400;
Global.ControlSystem = this;
DeviceManager.Initialize(this);
SecretsManager.Initialize();
SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true;
}
@@ -130,29 +131,46 @@ namespace PepperDash.Essentials
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows CE OS
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on {1} Appliance", Global.AssemblyVersion, Global.ProcessorSeries.ToString());
string userFolder;
string nvramFolder;
bool is4series = false;
if (eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4)) // Handle 4-series
{
is4series = true;
// Set path to user/
userFolder = "user";
nvramFolder = "nvram";
}
else
{
userFolder = "User";
nvramFolder = "Nvram";
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on {1} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series");
// Check if User/ProgramX exists
if (Directory.Exists(Global.ApplicationDirectoryPathPrefix + dirSeparator + "User"
if (Directory.Exists(Global.ApplicationDirectoryPathPrefix + dirSeparator + userFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
{
Debug.Console(0, @"User/program{0} directory found", InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + "User"
Debug.Console(0, @"{0}/program{1} directory found", userFolder, InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + userFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
// Check if Nvram/Programx exists
else if (Directory.Exists(directoryPrefix + dirSeparator + "Nvram"
else if (Directory.Exists(directoryPrefix + dirSeparator + nvramFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
{
Debug.Console(0, @"Nvram/program{0} directory found", InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + "Nvram"
Debug.Console(0, @"{0}/program{1} directory found", nvramFolder, InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + nvramFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
// If neither exists, set path to User/ProgramX
else
{
Debug.Console(0, @"No previous directory found. Using User/program{0}", InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + "User"
Debug.Console(0, @"No previous directory found. Using {0}/program{1}", userFolder, InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + userFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
}
@@ -434,7 +452,7 @@ namespace PepperDash.Essentials
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
{
var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as EssentialsRoomBase;
var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as IEssentialsRoom;
if (room != null)
{
// default IPID
@@ -456,7 +474,7 @@ namespace PepperDash.Essentials
}
}
if (room is EssentialsHuddleSpaceRoom)
if (room is IEssentialsHuddleSpaceRoom)
{
DeviceManager.AddDevice(room);
@@ -468,12 +486,12 @@ namespace PepperDash.Essentials
CreateMobileControlBridge(room);
}
else if (room is EssentialsHuddleVtc1Room)
else if (room is IEssentialsHuddleVtc1Room)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((EssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
@@ -506,7 +524,7 @@ namespace PepperDash.Essentials
}
private static void CreateMobileControlBridge(EssentialsRoomBase room)
private static void CreateMobileControlBridge(IEssentialsRoom room)
{
var mobileControl = GetMobileControlDevice();

View File

@@ -16,7 +16,7 @@ namespace PepperDash.Essentials.Fusion
{
BooleanSigData CodecIsInCall;
public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId, string joinMapKey)
public EssentialsHuddleVtc1FusionController(IEssentialsHuddleVtc1Room room, uint ipId, string joinMapKey)
: base(room, ipId, joinMapKey)
{
@@ -37,7 +37,7 @@ namespace PepperDash.Essentials.Fusion
{
try
{
var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec;
var codec = (Room as IEssentialsHuddleVtc1Room).VideoCodec;
if (codec == null)
{
@@ -141,7 +141,7 @@ namespace PepperDash.Essentials.Fusion
void codec_CallStatusChange(object sender, PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs e)
{
var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec;
var codec = (Room as IEssentialsHuddleVtc1Room).VideoCodec;
CodecIsInCall.InputSig.BoolValue = codec.IsInCall;
}
@@ -174,11 +174,11 @@ namespace PepperDash.Essentials.Fusion
// Moved to
CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(JoinMap.Display1CurrentSourceName.JoinNumber, JoinMap.Display1CurrentSourceName.AttributeName, eSigIoMask.InputSigOnly);
// Don't think we need to get current status of this as nothing should be alive yet.
(Room as EssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange;
(Room as IEssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange;
FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource);
FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey));
FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as IEssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource);
FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as IEssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey));
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
@@ -187,7 +187,7 @@ namespace PepperDash.Essentials.Fusion
protected override void SetUpSources()
{
// Sources
var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsHuddleVtc1Room).SourceListKey);
var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as IEssentialsHuddleVtc1Room).SourceListKey);
if (dict != null)
{
// NEW PROCESS:
@@ -238,7 +238,7 @@ namespace PepperDash.Essentials.Fusion
else
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'",
(Room as EssentialsHuddleVtc1Room).SourceListKey, Room.Key);
(Room as IEssentialsHuddleVtc1Room).SourceListKey, Room.Key);
}
}
@@ -259,7 +259,7 @@ namespace PepperDash.Essentials.Fusion
display.UsageTracker.DeviceUsageEnded += new EventHandler<DeviceUsageEventArgs>(UsageTracker_DeviceUsageEnded);
}
var defaultDisplay = (Room as EssentialsHuddleVtc1Room).DefaultDisplay as DisplayBase;
var defaultDisplay = (Room as IEssentialsHuddleVtc1Room).DefaultDisplay as DisplayBase;
if (defaultDisplay == null)
{
Debug.Console(1, this, "Cannot link null display to Fusion because default display is null");
@@ -332,7 +332,7 @@ namespace PepperDash.Essentials.Fusion
string displayName = string.Format("Display {0} - ", displayIndex);
if (display == (Room as EssentialsHuddleVtc1Room).DefaultDisplay)
if (display == (Room as IEssentialsHuddleVtc1Room).DefaultDisplay)
{
// Power on
var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig);
@@ -351,7 +351,7 @@ namespace PepperDash.Essentials.Fusion
// Current Source
var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig);
defaultDisplaySourceNone.OutputSig.UserObject = new Action<bool>(b => { if (!b) (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ;
defaultDisplaySourceNone.OutputSig.UserObject = new Action<bool>(b => { if (!b) (Room as IEssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ;
}
}
}

View File

@@ -149,6 +149,7 @@
<Compile Include="Room\Types\EssentialsNDisplayRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomConfig.cs" />
<Compile Include="Room\Types\EssentialsTechRoom.cs" />
<Compile Include="Room\Types\IEssentialsHuddleSpaceRoom.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsEnvironmentDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsLightingDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsShadeDriver.cs" />

View File

@@ -47,7 +47,7 @@ namespace PepperDash.Essentials.Room.Config
/// Gets and operating, standalone emergegncy object that can be plugged into a room.
/// Returns null if there is no emergency defined
/// </summary>
public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, EssentialsRoomBase room)
public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, IEssentialsRoom room)
{
// This emergency
var emergency = props.Emergency;
@@ -96,7 +96,7 @@ namespace PepperDash.Essentials.Room.Config
if (behaviour == "trackroomstate")
{
// Tie LED enable to room power state
var essRoom = room as EssentialsRoomBase;
var essRoom = room as IEssentialsRoom;
essRoom.OnFeedback.OutputChange += (o, a) =>
{
if (essRoom.OnFeedback.BoolValue)

View File

@@ -17,11 +17,11 @@ namespace PepperDash.Essentials.Room
public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase
{
EssentialsRoomBase Room;
IEssentialsRoom Room;
string Behavior;
bool TriggerOnClose;
public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, EssentialsRoomBase room) :
public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, IEssentialsRoom room) :
base(key)
{
Room = room;

View File

@@ -645,9 +645,9 @@ namespace PepperDash.Essentials
public static void AllRoomsOff()
{
var allRooms = DeviceManager.AllDevices.Where(d =>
d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
d is IEssentialsHuddleSpaceRoom && !(d as IEssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
(room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff", (room as EssentialsHuddleSpaceRoom).SourceListKey);
(room as IEssentialsHuddleSpaceRoom).RunRouteAction("roomOff", (room as IEssentialsHuddleSpaceRoom).SourceListKey);
}
#region IPrivacy Members

View File

@@ -13,7 +13,7 @@ using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasCurrentVolumeControls, IHasDefaultDisplay
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IEssentialsHuddleSpaceRoom
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSourceChange;

View File

@@ -17,8 +17,7 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials
{
public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IHasCurrentSourceInfoChange,
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback
public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IEssentialsHuddleVtc1Room
{
private bool _codecExternalSourceChange;
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
@@ -733,10 +732,10 @@ namespace PepperDash.Essentials
/// </summary>
public static void AllRoomsOff()
{
var allRooms = DeviceManager.AllDevices.Where(d =>
d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
var allRooms = DeviceManager.AllDevices.Where(d =>
d is IEssentialsRoom && !(d as IEssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
(room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
(room as IEssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
}

View File

@@ -107,14 +107,18 @@ namespace PepperDash.Essentials
private void TunerPresetsOnPresetRecalled(ISetTopBoxNumericKeypad device, string channel)
{
//Debug.Console(2, this, "TunerPresetsOnPresetRecalled");
if (!_currentPresets.ContainsKey(device.Key))
{
return;
}
//Debug.Console(2, this, "Tuner Key: {0} Channel: {1}", device.Key, channel);
_currentPresets[device.Key] = channel;
if (!CurrentPresetsFeedbacks.ContainsKey(device.Key))
if (CurrentPresetsFeedbacks.ContainsKey(device.Key))
{
CurrentPresetsFeedbacks[device.Key].FireUpdate();
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.AudioCodec;
using PepperDash.Core;
namespace PepperDash.Essentials
{
public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay
{
bool ExcludeFromGlobalFunctions { get; }
void RunRouteAction(string routeKey);
EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; }
IBasicVolumeControls CurrentVolumeControls { get; }
event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
}
public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange,
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback
{
EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; }
void RunRouteAction(string routeKey);
IHasScheduleAwareness ScheduleSource { get; }
BoolFeedback InCallFeedback { get; }
BoolFeedback PrivacyModeIsOnFeedback { get; }
string DefaultCodecRouteString { get; }
}
}

View File

@@ -79,6 +79,16 @@ namespace PepperDash.Essentials
Panel = new Tsw1052(id, Global.ControlSystem);
else if (type == "tsw1060")
Panel = new Tsw1060(id, Global.ControlSystem);
else if (type == "tsw570")
Panel = new Tsw570(id, Global.ControlSystem);
else if (type == "tsw770")
Panel = new Tsw770(id, Global.ControlSystem);
else if (type == "ts770")
Panel = new Ts770(id, Global.ControlSystem);
else if (type == "tsw1070")
Panel = new Tsw1070(id, Global.ControlSystem);
else if (type == "ts1070")
Panel = new Ts1070(id, Global.ControlSystem);
else
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW controller with type '{0}'", type);
@@ -203,7 +213,7 @@ namespace PepperDash.Essentials
{
public EssentialsTouchpanelControllerFactory()
{
TypeNames = new List<string>() { "tsw550", "tsw750", "tsw1050", "tsw560", "tsw760", "tsw1060", "xpanel" };
TypeNames = new List<string>() { "tsw550", "tsw750", "tsw1050", "tsw560", "tsw760", "tsw1060", "tsw570", "tsw770", "ts770", "tsw1070", "ts1070", "xpanel" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
@@ -222,7 +232,7 @@ namespace PepperDash.Essentials
// spin up different room drivers depending on room type
var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey);
if (room is EssentialsHuddleSpaceRoom)
if (room is IEssentialsHuddleSpaceRoom)
{
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, props);
@@ -236,7 +246,7 @@ namespace PepperDash.Essentials
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, props);
avDriver.DefaultRoomKey = props.DefaultRoomKey;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as EssentialsHuddleSpaceRoom;
avDriver.CurrentRoom = room as IEssentialsHuddleSpaceRoom;
// Environment Driver
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
@@ -270,7 +280,7 @@ namespace PepperDash.Essentials
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
}
}
else if (room is EssentialsHuddleVtc1Room)
else if (room is IEssentialsHuddleVtc1Room)
{
Debug.Console(0, panelController, "Adding huddle space VTC AV driver");
@@ -284,11 +294,11 @@ namespace PepperDash.Essentials
var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, props);
var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(panelController.Panel, avDriver,
(room as EssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver);
(room as IEssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver);
avDriver.SetVideoCodecDriver(codecDriver);
avDriver.DefaultRoomKey = props.DefaultRoomKey;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as EssentialsHuddleVtc1Room;
avDriver.CurrentRoom = room as IEssentialsHuddleVtc1Room;
// Environment Driver
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)

View File

@@ -764,6 +764,10 @@ namespace PepperDash.Essentials
/// </summary>
public const uint NextMeetingModalVisible = 15049;
/// <summary>
/// 15050
/// </summary>
public const uint NextMeetingNotificationRibbonVisible = 15050;
/// <summary>
/// 15051
/// </summary>
public const uint Display1SelectPressAndFb = 15051;

View File

@@ -146,18 +146,18 @@
// }
// void CurrentRoom_CurrentSourceInfoChange(EssentialsRoomBase room, SourceListItem info, ChangeType type)
// void CurrentRoom_CurrentSourceInfoChange(IEssentialsRoom room, SourceListItem info, ChangeType type)
// {
// }
// void CurrentRoom_CurrentDisplay1SourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type)
// void CurrentRoom_CurrentDisplay1SourceChange(IEssentialsRoom room, SourceListItem info, ChangeType type)
// {
// TriList.StringInput[UIStringJoin.Display1SourceLabel].StringValue = PendingSource.PreferredName;
// }
// void CurrentRoom_CurrentDisplay2SourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type)
// void CurrentRoom_CurrentDisplay2SourceChange(IEssentialsRoom room, SourceListItem info, ChangeType type)
// {
// TriList.StringInput[UIStringJoin.Display2SourceLabel].StringValue = PendingSource.PreferredName;
// }

View File

@@ -52,7 +52,7 @@ namespace PepperDash.Essentials
CaretInterlock = new JoinedSigInterlock(TriList);
}
void SetUpGear(IAVDriver avDriver, EssentialsRoomBase currentRoom)
void SetUpGear(IAVDriver avDriver, IEssentialsRoom currentRoom)
{
// Gear
TriList.SetString(UIStringJoin.HeaderButtonIcon5, "Gear");
@@ -105,7 +105,7 @@ namespace PepperDash.Essentials
{
string message = null;
var room = DeviceManager.GetDeviceForKey(Config.DefaultRoomKey)
as EssentialsHuddleSpaceRoom;
as IEssentialsHuddleSpaceRoom;
if (room != null)
message = room.PropertiesConfig.HelpMessage;
else
@@ -207,6 +207,7 @@ namespace PepperDash.Essentials
//TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 1);
// Set the call status text
Debug.Console(1, "Active Call Count: {0}", codec.ActiveCalls.Count);
if (codec.ActiveCalls.Count > 0)
{
if (codec.ActiveCalls.Count == 1)
@@ -221,7 +222,7 @@ namespace PepperDash.Essentials
/// <summary>
/// Sets up Header Buttons for the EssentialsHuddleVtc1Room type
/// </summary>
public void SetupHeaderButtons(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, EssentialsHuddleVtc1Room currentRoom)
public void SetupHeaderButtons(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, IEssentialsHuddleVtc1Room currentRoom)
{
HeaderButtonsAreSetUp = false;
@@ -283,7 +284,7 @@ namespace PepperDash.Essentials
/// <summary>
/// Sets up Header Buttons for the EssentialsHuddleSpaceRoom type
/// </summary>
public void SetupHeaderButtons(EssentialsHuddlePanelAvFunctionsDriver avDriver, EssentialsHuddleSpaceRoom currentRoom)
public void SetupHeaderButtons(EssentialsHuddlePanelAvFunctionsDriver avDriver, IEssentialsHuddleSpaceRoom currentRoom)
{
HeaderButtonsAreSetUp = false;

View File

@@ -983,7 +983,7 @@
// /// <summary>
// /// Handles source change
// /// </summary>
// void _CurrentRoom_SourceInfoChange(EssentialsRoomBase room,
// void _CurrentRoom_SourceInfoChange(IEssentialsRoom room,
// SourceListItem info, ChangeType change)
// {
// if (change == ChangeType.WillChange)
@@ -995,7 +995,7 @@
// /// <summary>
// ///
// /// </summary>
// void _CurrentRoom_CurrentDisplay1SourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type)
// void _CurrentRoom_CurrentDisplay1SourceChange(IEssentialsRoom room, SourceListItem info, ChangeType type)
// {
// if (type == ChangeType.DidChange)
// {
@@ -1021,7 +1021,7 @@
// /// <summary>
// ///
// /// </summary>
// void _CurrentRoom_CurrentDisplay2SourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type)
// void _CurrentRoom_CurrentDisplay2SourceChange(IEssentialsRoom room, SourceListItem info, ChangeType type)
// {
// if (type == ChangeType.DidChange)
// {

View File

@@ -78,7 +78,7 @@ namespace PepperDash.Essentials
/// <summary>
///
/// </summary>
public EssentialsHuddleSpaceRoom CurrentRoom
public IEssentialsHuddleSpaceRoom CurrentRoom
{
get { return _CurrentRoom; }
set
@@ -86,7 +86,7 @@ namespace PepperDash.Essentials
SetCurrentRoom(value);
}
}
EssentialsHuddleSpaceRoom _CurrentRoom;
IEssentialsHuddleSpaceRoom _CurrentRoom;
/// <summary>
///
@@ -498,7 +498,7 @@ namespace PepperDash.Essentials
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true;
// Run default source when room is off and share is pressed
if (!CurrentRoom.OnFeedback.BoolValue)
CurrentRoom.RunDefaultPresentRoute();
(CurrentRoom as IRunDefaultPresentRoute).RunDefaultPresentRoute();
}
@@ -583,7 +583,7 @@ namespace PepperDash.Essentials
void UiSelectSource(string key)
{
// Run the route and when it calls back, show the source
CurrentRoom.RunRouteAction(key, new Action(() => { }));
CurrentRoom.RunRouteAction(key);
}
/// <summary>
@@ -745,7 +745,7 @@ namespace PepperDash.Essentials
/// <summary>
/// Helper for property setter. Sets the panel to the given room, latching up all functionality
/// </summary>
public void RefreshCurrentRoom(EssentialsHuddleSpaceRoom room)
public void RefreshCurrentRoom(IEssentialsHuddleSpaceRoom room)
{
if (_CurrentRoom != null)
{
@@ -836,7 +836,7 @@ namespace PepperDash.Essentials
}
}
void SetCurrentRoom(EssentialsHuddleSpaceRoom room)
void SetCurrentRoom(IEssentialsHuddleSpaceRoom room)
{
if (_CurrentRoom == room) return;
// Disconnect current (probably never called)
@@ -871,7 +871,7 @@ namespace PepperDash.Essentials
UpdateMCJoins(_CurrentRoom);
}
void UpdateMCJoins(EssentialsHuddleSpaceRoom room)
void UpdateMCJoins(IEssentialsHuddleSpaceRoom room)
{
TriList.SetString(UIStringJoin.RoomMcUrl, room.MobileControlRoomBridge.McServerUrl);
TriList.SetString(UIStringJoin.RoomMcQrCodeUrl, room.MobileControlRoomBridge.QrCodeUrl);

View File

@@ -50,7 +50,7 @@ namespace PepperDash.Essentials
/// <summary>
///
/// </summary>
public EssentialsHuddleVtc1Room CurrentRoom
public IEssentialsHuddleVtc1Room CurrentRoom
{
get { return _CurrentRoom; }
set
@@ -58,7 +58,7 @@ namespace PepperDash.Essentials
SetCurrentRoom(value);
}
}
EssentialsHuddleVtc1Room _CurrentRoom;
IEssentialsHuddleVtc1Room _CurrentRoom;
/// <summary>
/// For hitting feedbacks
@@ -652,7 +652,7 @@ namespace PepperDash.Essentials
if (!CurrentRoom.OnFeedback.BoolValue)
{
// If there's no default, show UI elements
if (!CurrentRoom.RunDefaultPresentRoute())
if (!(CurrentRoom as IRunDefaultPresentRoute).RunDefaultPresentRoute())
TriList.SetBool(UIBoolJoin.SelectASourceVisible, true);
}
}
@@ -743,7 +743,7 @@ namespace PepperDash.Essentials
void UiSelectSource(string key)
{
// Run the route and when it calls back, show the source
CurrentRoom.RunRouteAction(key, new Action(() => { }));
CurrentRoom.RunRouteAction(key);
}
/// <summary>
@@ -894,7 +894,7 @@ namespace PepperDash.Essentials
/// <summary>
/// Helper for property setter. Sets the panel to the given room, latching up all functionality
/// </summary>
void RefreshCurrentRoom(EssentialsHuddleVtc1Room room)
void RefreshCurrentRoom(IEssentialsHuddleVtc1Room room)
{
if (_CurrentRoom != null)
@@ -969,7 +969,7 @@ namespace PepperDash.Essentials
}
}
void SetCurrentRoom(EssentialsHuddleVtc1Room room)
void SetCurrentRoom(IEssentialsHuddleVtc1Room room)
{
if (_CurrentRoom == room) return;
// Disconnect current (probably never called)
@@ -1004,7 +1004,7 @@ namespace PepperDash.Essentials
UpdateMCJoins(_CurrentRoom);
}
void UpdateMCJoins(EssentialsHuddleVtc1Room room)
void UpdateMCJoins(IEssentialsHuddleVtc1Room room)
{
TriList.SetString(UIStringJoin.RoomMcUrl, room.MobileControlRoomBridge.McServerUrl);
TriList.SetString(UIStringJoin.RoomMcQrCodeUrl, room.MobileControlRoomBridge.QrCodeUrl);
@@ -1035,7 +1035,7 @@ namespace PepperDash.Essentials
if (CurrentRoom.CurrentSourceInfo != null && CurrentRoom.CurrentSourceInfo.DisableCodecSharing)
{
Debug.Console(1, CurrentRoom, "Transitioning to in-call, cancelling non-sharable source");
CurrentRoom.RunRouteAction("codecOsd", CurrentRoom.SourceListKey);
CurrentRoom.RunRouteAction("codecOsd");
}
}
@@ -1443,7 +1443,7 @@ namespace PepperDash.Essentials
/// </summary>
public interface IAVWithVCDriver : IAVDriver
{
EssentialsHuddleVtc1Room CurrentRoom { get; }
IEssentialsHuddleVtc1Room CurrentRoom { get; }
PepperDash.Essentials.Core.Touchpanels.Keyboards.HabaneroKeyboardController Keyboard { get; }
/// <summary>

View File

@@ -38,7 +38,7 @@ namespace PepperDash.Essentials
/// <summary>
/// Sets feedback for the given room
/// </summary>
public void SetFeedbackForRoom(EssentialsHuddleSpaceRoom room)
public void SetFeedbackForRoom(IEssentialsHuddleSpaceRoom room)
{
var itemToSet = Items.FirstOrDefault(i => i.Room == room);
if (itemToSet != null)
@@ -48,11 +48,11 @@ namespace PepperDash.Essentials
public class SmartObjectRoomsListItem
{
public EssentialsHuddleSpaceRoom Room { get; private set; }
public IEssentialsHuddleSpaceRoom Room { get; private set; }
SmartObjectRoomsList Parent;
public uint Index { get; private set; }
public SmartObjectRoomsListItem(EssentialsHuddleSpaceRoom room, uint index, SmartObjectRoomsList parent,
public SmartObjectRoomsListItem(IEssentialsHuddleSpaceRoom room, uint index, SmartObjectRoomsList parent,
Action<bool> buttonAction)
{
Room = room;

View File

@@ -12,5 +12,5 @@ namespace PepperDash.Essentials
///// <summary>
///// The handler type for a Room's SourceInfoChange
///// </summary>
//public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type);
//public delegate void SourceInfoChangeHandler(IEssentialsRoom room, SourceListItem info, ChangeType type);
}

View File

@@ -385,7 +385,7 @@ namespace PepperDash.Essentials.Core.Bridges
{
public EiscApiAdvancedFactory()
{
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "vceiscapiadv", "vceiscapiadvanced" };
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
@@ -403,6 +403,16 @@ namespace PepperDash.Essentials.Core.Bridges
controlProperties.TcpSshProperties.Address, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
case "eiscapiadvancedserver":
{
var eisc = new EISCServer(controlProperties.IpIdInt, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
case "eiscapiadvancedclient":
{
var eisc = new EISCClient(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
case "vceiscapiadv":
case "vceiscapiadvanced":
{

View File

@@ -25,6 +25,7 @@ namespace PepperDash.Essentials.Core
public GenericComm(DeviceConfig config)
: base(config)
{
PropertiesConfig = CommFactory.GetControlPropertiesConfig(config);
var commPort = CommFactory.CreateCommForDevice(config);

View File

@@ -30,7 +30,19 @@ namespace PepperDash.Essentials.Core.Config
[JsonProperty("properties")]
[JsonConverter(typeof(DevicePropertiesConverter))]
public JToken Properties { get; set; }
public JToken Properties { get; set; }
public DeviceConfig(DeviceConfig dc)
{
Key = dc.Key;
Uid = dc.Uid;
Name = dc.Name;
Group = dc.Group;
Type = dc.Type;
Properties = JToken.FromObject(dc.Properties);
}
public DeviceConfig() {}
}
/// <summary>

View File

@@ -1,162 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
namespace PepperDash.Essentials.Core.Config
{
/// <summary>
/// Responsible for updating config at runtime, and writing the updates out to a local file
/// </summary>
public class ConfigWriter
{
public const string LocalConfigFolder = "LocalConfig";
public const long WriteTimeout = 30000;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
namespace PepperDash.Essentials.Core.Config
{
/// <summary>
/// Responsible for updating config at runtime, and writing the updates out to a local file
/// </summary>
public class ConfigWriter
{
public const string LocalConfigFolder = "LocalConfig";
public const long WriteTimeout = 30000;
public static CTimer WriteTimer;
static CCriticalSection fileLock = new CCriticalSection();
/// <summary>
/// Updates the config properties of a device
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="properties"></param>
/// <returns></returns>
public static bool UpdateDeviceProperties(string deviceKey, JToken properties)
{
bool success = false;
// Get the current device config
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(deviceKey));
if (deviceConfig != null)
{
// Replace the current properties JToken with the new one passed into this method
deviceConfig.Properties = properties;
Debug.Console(1, "Updated properties of device: '{0}'", deviceKey);
success = true;
}
ResetTimer();
return success;
}
public static bool UpdateDeviceConfig(DeviceConfig config)
{
bool success = false;
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(config.Key));
if (deviceConfig != null)
{
deviceConfig = config;
Debug.Console(1, "Updated config of device: '{0}'", config.Key);
success = true;
}
ResetTimer();
return success;
}
public static bool UpdateRoomConfig(DeviceConfig config)
{
bool success = false;
var deviceConfig = ConfigReader.ConfigObject.Rooms.FirstOrDefault(d => d.Key.Equals(config.Key));
if (deviceConfig != null)
{
deviceConfig = config;
Debug.Console(1, "Updated config of device: '{0}'", config.Key);
success = true;
}
ResetTimer();
return success;
}
/// <summary>
/// Resets (or starts) the write timer
/// </summary>
static void ResetTimer()
{
if (WriteTimer == null)
WriteTimer = new CTimer(WriteConfigFile, WriteTimeout);
WriteTimer.Reset(WriteTimeout);
Debug.Console(1, "Config File write timer has been reset.");
}
/// <summary>
/// Writes the current config to a file in the LocalConfig subfolder
/// </summary>
/// <returns></returns>
private static void WriteConfigFile(object o)
{
var filePath = Global.FilePathPrefix + LocalConfigFolder + Global.DirectorySeparator + "configurationFile.json";
var configData = JsonConvert.SerializeObject(ConfigReader.ConfigObject);
WriteFile(filePath, configData);
}
/// <summary>
/// Writes
/// </summary>
/// <param name="filepath"></param>
/// <param name="o"></param>
public static void WriteFile(string filePath, string configData)
{
if (WriteTimer != null)
WriteTimer.Stop();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Writing Configuration to file");
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to write config file: '{0}'", filePath);
try
{
if (fileLock.TryEnter())
{
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.Write(configData);
sw.Flush();
}
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Unable to enter FileLock");
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Config write failed: \r{0}", e);
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
}
}
static CCriticalSection fileLock = new CCriticalSection();
/// <summary>
/// Updates the config properties of a device
/// </summary>
/// <param name="deviceKey"></param>
/// <param name="properties"></param>
/// <returns></returns>
public static bool UpdateDeviceProperties(string deviceKey, JToken properties)
{
bool success = false;
// Get the current device config
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(deviceKey));
if (deviceConfig != null)
{
// Replace the current properties JToken with the new one passed into this method
deviceConfig.Properties = properties;
Debug.Console(1, "Updated properties of device: '{0}'", deviceKey);
success = true;
}
ResetTimer();
return success;
}
public static bool UpdateDeviceConfig(DeviceConfig config)
{
bool success = false;
var deviceConfigIndex = ConfigReader.ConfigObject.Devices.FindIndex(d => d.Key.Equals(config.Key));
if (deviceConfigIndex >= 0)
{
ConfigReader.ConfigObject.Devices[deviceConfigIndex] = config;
Debug.Console(1, "Updated config of device: '{0}'", config.Key);
success = true;
}
ResetTimer();
return success;
}
public static bool UpdateRoomConfig(DeviceConfig config)
{
bool success = false;
var roomConfigIndex = ConfigReader.ConfigObject.Rooms.FindIndex(d => d.Key.Equals(config.Key));
if (roomConfigIndex >= 0)
{
ConfigReader.ConfigObject.Rooms[roomConfigIndex] = config;
Debug.Console(1, "Updated room of device: '{0}'", config.Key);
success = true;
}
ResetTimer();
return success;
}
/// <summary>
/// Resets (or starts) the write timer
/// </summary>
static void ResetTimer()
{
if (WriteTimer == null)
WriteTimer = new CTimer(WriteConfigFile, WriteTimeout);
WriteTimer.Reset(WriteTimeout);
Debug.Console(1, "Config File write timer has been reset.");
}
/// <summary>
/// Writes the current config to a file in the LocalConfig subfolder
/// </summary>
/// <returns></returns>
private static void WriteConfigFile(object o)
{
var filePath = Global.FilePathPrefix + LocalConfigFolder + Global.DirectorySeparator + "configurationFile.json";
var configData = JsonConvert.SerializeObject(ConfigReader.ConfigObject);
WriteFile(filePath, configData);
}
/// <summary>
/// Writes
/// </summary>
/// <param name="filepath"></param>
/// <param name="o"></param>
public static void WriteFile(string filePath, string configData)
{
if (WriteTimer != null)
WriteTimer.Stop();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Writing Configuration to file");
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to write config file: '{0}'", filePath);
try
{
if (fileLock.TryEnter())
{
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.Write(configData);
sw.Flush();
}
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Unable to enter FileLock");
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Config write failed: \r{0}", e);
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
}
}
}

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.GeneralIO;
using PepperDash.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.CrestronIO
{
public class C2NIoController:CrestronGenericBaseDevice, IComPorts, IIROutputPorts, IRelayPorts
{
private C2nIo _device;
public C2NIoController(string key, Func<DeviceConfig, C2nIo> preActivationFunc, DeviceConfig config):base(key, config.Name)
{
AddPreActivationAction(() =>
{
_device = preActivationFunc(config);
RegisterCrestronGenericBase(_device);
});
}
#region Implementation of IComPorts
public CrestronCollection<ComPort> ComPorts
{
get { return _device.ComPorts; }
}
public int NumberOfComPorts
{
get { return _device.NumberOfComPorts; }
}
#endregion
#region Implementation of IIROutputPorts
public CrestronCollection<IROutputPort> IROutputPorts
{
get { return _device.IROutputPorts; }
}
public int NumberOfIROutputPorts
{
get { return _device.NumberOfIROutputPorts; }
}
#endregion
#region Implementation of IRelayPorts
public CrestronCollection<Relay> RelayPorts
{
get { return _device.RelayPorts; }
}
public int NumberOfRelayPorts
{
get { return _device.NumberOfRelayPorts; }
}
#endregion
}
public class C2NIoControllerFactory : EssentialsDeviceFactory<C2nRthsController>
{
public C2NIoControllerFactory()
{
TypeNames = new List<string>() { "c2nio" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new C2N-IO Device");
return new C2NIoController(dc.Key, GetC2NIoDevice, dc);
}
static C2nIo GetC2NIoDevice(DeviceConfig dc)
{
var control = CommFactory.GetControlPropertiesConfig(dc);
var cresnetId = control.CresnetIdInt;
var branchId = control.ControlPortNumber;
var parentKey = string.IsNullOrEmpty(control.ControlPortDevKey) ? "processor" : control.ControlPortDevKey;
if (parentKey.Equals("processor", StringComparison.CurrentCultureIgnoreCase))
{
Debug.Console(0, "Device {0} is a valid cresnet master - creating new C2nIo", parentKey);
return new C2nIo(cresnetId, Global.ControlSystem);
}
var cresnetBridge = DeviceManager.GetDeviceForKey(parentKey) as IHasCresnetBranches;
if (cresnetBridge != null)
{
Debug.Console(0, "Device {0} is a valid cresnet master - creating new C2nIo", parentKey);
return new C2nIo(cresnetId, cresnetBridge.CresnetBranches[branchId]);
}
Debug.Console(0, "Device {0} is not a valid cresnet master", parentKey);
return null;
}
}
}

View File

@@ -8,7 +8,7 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
/// </summary>
public interface IMobileControl : IKeyed
{
void CreateMobileControlRoomBridge(EssentialsRoomBase room, IMobileControl parent);
void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent);
void LinkSystemMonitorToAppServer();
}

View File

@@ -77,10 +77,9 @@ namespace PepperDash.Essentials.Core
var mParams = method.GetParameters();
var convertedParams = mParams
.Select((p, i) => Convert.ChangeType(action.Params[i], p.ParameterType,
System.Globalization.CultureInfo.InvariantCulture))
.Select((p, i) => ConvertType(action.Params[i], p.ParameterType))
.ToArray();
var ret = method.Invoke(obj, convertedParams);
method.Invoke(obj, convertedParams);
CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name,
action.DeviceKey);
@@ -91,6 +90,23 @@ namespace PepperDash.Essentials.Core
ex.Message);}
}
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>
@@ -275,6 +291,8 @@ namespace PepperDash.Essentials.Core
//var props = t.GetProperties().Select(p => new PropertyNameType(p, obj));
//return JsonConvert.SerializeObject(props, Formatting.Indented);
}
}
public class DeviceActionWrapper

View File

@@ -435,7 +435,7 @@ namespace PepperDash.Essentials.Core
var min = Convert.ToUInt32(timeout);
device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, min);
Debug.Console(0, "Device: '{0}' debug level set to {1) for {2} minutes", deviceKey, debugSetting, min);
Debug.Console(0, "Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min);
}
catch (Exception e)

View File

@@ -1,113 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Reflection;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class
/// </summary>
[Description("The base Essentials Device Class")]
public abstract class EssentialsDevice : Device
{
protected EssentialsDevice(string key)
: base(key)
{
}
protected EssentialsDevice(string key, string name)
: base(key, name)
{
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class DescriptionAttribute : Attribute
{
private string _Description;
public DescriptionAttribute(string description)
{
Debug.Console(2, "Setting Description: {0}", description);
_Description = description;
}
public string Description
{
get { return _Description; }
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class ConfigSnippetAttribute : Attribute
{
private string _ConfigSnippet;
public ConfigSnippetAttribute(string configSnippet)
{
Debug.Console(2, "Setting Config Snippet {0}", configSnippet);
_ConfigSnippet = configSnippet;
}
public string ConfigSnippet
{
get { return _ConfigSnippet; }
}
}
/// <summary>
/// Devices the basic needs for a Device Factory
/// </summary>
public abstract class EssentialsDeviceFactory<T> : IDeviceFactory where T:EssentialsDevice
{
#region IDeviceFactory Members
/// <summary>
/// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
/// </summary>
public List<string> TypeNames { get; protected set; }
/// <summary>
/// Loads an item to the DeviceFactory.FactoryMethods dictionary for each entry in the TypeNames list
/// </summary>
public void LoadTypeFactories()
{
foreach (var typeName in TypeNames)
{
Debug.Console(2, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Reflection;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class
/// </summary>
[Description("The base Essentials Device Class")]
public abstract class EssentialsDevice : Device
{
protected EssentialsDevice(string key)
: base(key)
{
}
protected EssentialsDevice(string key, string name)
: base(key, name)
{
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class DescriptionAttribute : Attribute
{
private string _Description;
public DescriptionAttribute(string description)
{
Debug.Console(2, "Setting Description: {0}", description);
_Description = description;
}
public string Description
{
get { return _Description; }
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class ConfigSnippetAttribute : Attribute
{
private string _ConfigSnippet;
public ConfigSnippetAttribute(string configSnippet)
{
Debug.Console(2, "Setting Config Snippet {0}", configSnippet);
_ConfigSnippet = configSnippet;
}
public string ConfigSnippet
{
get { return _ConfigSnippet; }
}
}
/// <summary>
/// Devices the basic needs for a Device Factory
/// </summary>
public abstract class EssentialsDeviceFactory<T> : IDeviceFactory where T:EssentialsDevice
{
#region IDeviceFactory Members
/// <summary>
/// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
/// </summary>
public List<string> TypeNames { get; protected set; }
/// <summary>
/// Loads an item to the DeviceFactory.FactoryMethods dictionary for each entry in the TypeNames list
/// </summary>
public void LoadTypeFactories()
{
foreach (var typeName in TypeNames)
{
Debug.Console(2, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
string description = descriptionAttribute[0].Description;
var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
}
}
/// <summary>
/// The method that will build the device
/// </summary>
/// <param name="dc">The device config</param>
/// <returns>An instance of the device</returns>
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
#endregion
}
/// <summary>
/// Devices the basic needs for a Device Factory
/// </summary>
public abstract class EssentialsPluginDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDeviceFactory where T : EssentialsDevice
{
/// <summary>
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
/// </summary>
public string MinimumEssentialsFrameworkVersion { get; protected set; }
}
var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
}
}
/// <summary>
/// The method that will build the device
/// </summary>
/// <param name="dc">The device config</param>
/// <returns>An instance of the device</returns>
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
#endregion
}
/// <summary>
/// Devices the basic needs for a Device Factory
/// </summary>
public abstract class EssentialsPluginDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDeviceFactory where T : EssentialsDevice
{
/// <summary>
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
/// </summary>
public string MinimumEssentialsFrameworkVersion { get; protected set; }
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Devices
{
public interface IReconfigurableDevice
{
event EventHandler<EventArgs> ConfigChanged;
DeviceConfig Config { get; }
void SetConfig(DeviceConfig config);
}
}

View File

@@ -7,13 +7,15 @@ using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Essentials.Core.Devices
{
/// <summary>
///
/// </summary>
public abstract class ReconfigurableDevice : EssentialsDevice
public abstract class ReconfigurableDevice : EssentialsDevice, IReconfigurableDevice
{
public event EventHandler<EventArgs> ConfigChanged;
@@ -52,6 +54,8 @@ namespace PepperDash.Essentials.Core.Devices
Name = config.Name;
}
/// <summary>
/// Used by the extending class to allow for any custom actions to be taken (tell the ConfigWriter to write config, etc)
/// </summary>

View File

@@ -59,6 +59,9 @@ namespace PepperDash.Essentials.Core
VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; });
MuteFeedback = new BoolFeedback("MuteOn", () => _IsMuted);
WarmupTime = 10000;
CooldownTime = 5000;
}
public override void PowerOn()

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Essentials.Core
{
public static class JsonExtensions
{
public static List<JToken> FindTokens(this JToken containerToken, string name)
{
List<JToken> matches = new List<JToken>();
FindTokens(containerToken, name, matches);
return matches;
}
private static void FindTokens(JToken containerToken, string name, List<JToken> matches)
{
if (containerToken.Type == JTokenType.Object)
{
foreach (JProperty child in containerToken.Children<JProperty>())
{
if (child.Name == name)
{
matches.Add(child.Value);
}
FindTokens(child.Value, name, matches);
}
}
else if (containerToken.Type == JTokenType.Array)
{
foreach (JToken child in containerToken.Children())
{
FindTokens(child, name, matches);
}
}
}
}
}

View File

@@ -7,6 +7,8 @@ using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.GeneralIO;
using Crestron.SimplSharp.Reflection;
using PepperDash.Core;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.CrestronIO;
@@ -83,33 +85,81 @@ namespace PepperDash.Essentials.Core
var wrapper = new DeviceFactoryWrapper() { CType = cType, Description = description, FactoryMethod = method };
DeviceFactory.FactoryMethods.Add(typeName, wrapper);
}
/// <summary>
/// The factory method for Core "things". Also iterates the Factory methods that have
/// been loaded from plugins
/// </summary>
/// <param name="dc"></param>
/// <returns></returns>
public static IKeyed GetDevice(DeviceConfig dc)
{
var key = dc.Key;
var name = dc.Name;
var type = dc.Type;
var properties = dc.Properties;
var typeName = dc.Type.ToLower();
// Check for types that have been added by plugin dlls.
if (FactoryMethods.ContainsKey(typeName))
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading '{0}' from Essentials Core", dc.Type);
return FactoryMethods[typeName].FactoryMethod(dc);
}
return null;
}
}
private static void CheckForSecrets(IEnumerable<JProperty> obj)
{
foreach (var prop in obj.Where(prop => prop.Value as 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 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.Console(1,
"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 Core "things". Also iterates the Factory methods that have
/// been loaded from plugins
/// </summary>
/// <param name="dc"></param>
/// <returns></returns>
public static IKeyed GetDevice(DeviceConfig dc)
{
try
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "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 JObject;
if (jObject != null)
{
var jProp = jObject.Properties();
CheckForSecrets(jProp);
}
Debug.Console(2, "typeName = {0}", typeName);
// Check for types that have been added by plugin dlls.
return !FactoryMethods.ContainsKey(typeName) ? null : FactoryMethods[typeName].FactoryMethod(localDc);
}
catch (Exception ex)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Exception occurred while creating device {0}: {1}", dc.Key, ex.Message);
Debug.Console(2, "{0}", ex.StackTrace);
return null;
}
}
/// <summary>
/// Prints the type names and associated metadata from the FactoryMethods collection.
/// </summary>

View File

@@ -23,7 +23,7 @@ namespace PepperDash.Essentials.Core
protected bool ComputedValue;
public BoolFeedbackLogic()
protected BoolFeedbackLogic()
{
Output = new BoolFeedback(() => ComputedValue);
}
@@ -40,21 +40,18 @@ namespace PepperDash.Essentials.Core
public void AddOutputsIn(List<BoolFeedback> outputs)
{
foreach (var o in outputs)
{
// skip existing
if (OutputsIn.Contains(o)) continue;
OutputsIn.Add(o);
o.OutputChange += AnyInput_OutputChange;
}
Evaluate();
foreach (var o in outputs.Where(o => !OutputsIn.Contains(o)))
{
OutputsIn.Add(o);
o.OutputChange += AnyInput_OutputChange;
}
Evaluate();
}
public void RemoveOutputIn(BoolFeedback output)
public void RemoveOutputIn(BoolFeedback output)
{
// Don't double up outputs
if (OutputsIn.Contains(output)) return;
if (!OutputsIn.Contains(output)) return;
OutputsIn.Remove(output);
output.OutputChange -= AnyInput_OutputChange;
@@ -71,6 +68,12 @@ namespace PepperDash.Essentials.Core
Evaluate();
}
public void ClearOutputs()
{
OutputsIn.Clear();
Evaluate();
}
void AnyInput_OutputChange(object sender, EventArgs e)
{
Evaluate();
@@ -85,11 +88,12 @@ namespace PepperDash.Essentials.Core
{
var prevValue = ComputedValue;
var newValue = OutputsIn.All(o => o.BoolValue);
if (newValue != prevValue)
{
ComputedValue = newValue;
Output.FireUpdate();
}
if (newValue == prevValue)
{
return;
}
ComputedValue = newValue;
Output.FireUpdate();
}
}
@@ -99,33 +103,35 @@ namespace PepperDash.Essentials.Core
{
var prevValue = ComputedValue;
var newValue = OutputsIn.Any(o => o.BoolValue);
if (newValue != prevValue)
{
ComputedValue = newValue;
Output.FireUpdate();
}
if (newValue == prevValue)
{
return;
}
ComputedValue = newValue;
Output.FireUpdate();
}
}
public class BoolFeedbackLinq : BoolFeedbackLogic
{
Func<IEnumerable<BoolFeedback>, bool> Predicate;
readonly Func<IEnumerable<BoolFeedback>, bool> _predicate;
public BoolFeedbackLinq(Func<IEnumerable<BoolFeedback>, bool> predicate)
: base()
{
Predicate = predicate;
_predicate = predicate;
}
protected override void Evaluate()
{
var prevValue = ComputedValue;
var newValue = Predicate(OutputsIn);
if (newValue != prevValue)
{
ComputedValue = newValue;
Output.FireUpdate();
}
var newValue = _predicate(OutputsIn);
if (newValue == prevValue)
{
return;
}
ComputedValue = newValue;
Output.FireUpdate();
}
}
}

View File

@@ -33,7 +33,7 @@ namespace PepperDash.Essentials.Core.Fusion
protected FusionRoom FusionRoom;
protected Dictionary<int, FusionAsset> FusionStaticAssets;
public long PushNotificationTimeout = 5000;
protected EssentialsRoomBase Room;
protected IEssentialsRoom Room;
public long SchedulePollInterval = 300000;
private Event _currentMeeting;
@@ -86,7 +86,7 @@ namespace PepperDash.Essentials.Core.Fusion
#endregion
public EssentialsHuddleSpaceFusionSystemControllerBase(EssentialsRoomBase room, uint ipId, string joinMapKey)
public EssentialsHuddleSpaceFusionSystemControllerBase(IEssentialsRoom room, uint ipId, string joinMapKey)
: base(room.Key + "-fusion")
{
try

View File

@@ -82,7 +82,7 @@ namespace PepperDash.Essentials.Core.Fusion
deviceConfig.Properties = JToken.FromObject(devProps);
}
else if (device is EssentialsRoomBase)
else if (device is IEssentialsRoom)
{
// Set the room name
if (!string.IsNullOrEmpty(roomInfo.Name))

View File

@@ -2,17 +2,18 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.GeneralIO;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Aggregates the RoomIsOccupied feedbacks of one or more IOccupancyStatusProvider objects
/// </summary>
public class IOccupancyStatusProviderAggregator : Device, IOccupancyStatusProvider
public class IOccupancyStatusProviderAggregator : EssentialsDevice, IOccupancyStatusProvider
{
/// <summary>
/// Aggregated feedback of all linked IOccupancyStatusProvider devices
@@ -21,16 +22,51 @@ namespace PepperDash.Essentials.Core
{
get
{
return AggregatedOccupancyStatus.Output;
return _aggregatedOccupancyStatus.Output;
}
}
private BoolFeedbackOr AggregatedOccupancyStatus;
private readonly BoolFeedbackOr _aggregatedOccupancyStatus;
public IOccupancyStatusProviderAggregator(string key, string name)
: base(key, name)
{
AggregatedOccupancyStatus = new BoolFeedbackOr();
_aggregatedOccupancyStatus = new BoolFeedbackOr();
}
public IOccupancyStatusProviderAggregator(string key, string name, OccupancyAggregatorConfig config)
: this(key, name)
{
AddPostActivationAction(() =>
{
if (config.DeviceKeys.Count == 0)
{
return;
}
foreach (var deviceKey in config.DeviceKeys)
{
var device = DeviceManager.GetDeviceForKey(deviceKey);
if (device == null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice,
"Unable to retrieve Occupancy provider with key {0}", deviceKey);
continue;
}
var provider = device as IOccupancyStatusProvider;
if (provider == null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice,
"Device with key {0} does NOT implement IOccupancyStatusProvider. Please check configuration.");
continue;
}
AddOccupancyStatusProvider(provider);
}
});
}
/// <summary>
@@ -39,7 +75,35 @@ namespace PepperDash.Essentials.Core
/// <param name="statusProvider"></param>
public void AddOccupancyStatusProvider(IOccupancyStatusProvider statusProvider)
{
AggregatedOccupancyStatus.AddOutputIn(statusProvider.RoomIsOccupiedFeedback);
_aggregatedOccupancyStatus.AddOutputIn(statusProvider.RoomIsOccupiedFeedback);
}
public void RemoveOccupancyStatusProvider(IOccupancyStatusProvider statusProvider)
{
_aggregatedOccupancyStatus.RemoveOutputIn(statusProvider.RoomIsOccupiedFeedback);
}
public void ClearOccupancyStatusProviders()
{
_aggregatedOccupancyStatus.ClearOutputs();
}
}
public class OccupancyAggregatorFactory : EssentialsDeviceFactory<IOccupancyStatusProviderAggregator>
{
public OccupancyAggregatorFactory()
{
TypeNames = new List<string> { "occupancyAggregator", "occAggregate" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new GlsOccupancySensorBaseController Device");
var config = dc.Properties.ToObject<OccupancyAggregatorConfig>();
return new IOccupancyStatusProviderAggregator(dc.Key, dc.Name, config);
}
}
}

View File

@@ -0,0 +1,15 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core
{
public class OccupancyAggregatorConfig
{
[JsonProperty("deviceKeys")] public List<string> DeviceKeys { get; set; }
public OccupancyAggregatorConfig()
{
DeviceKeys = new List<string>();
}
}
}

View File

@@ -162,6 +162,7 @@
<Compile Include="Config\Essentials\ConfigWriter.cs" />
<Compile Include="Config\Essentials\EssentialsConfig.cs" />
<Compile Include="Config\SourceDevicePropertiesConfigBase.cs" />
<Compile Include="Crestron IO\C2nIo\C2nIoController.cs" />
<Compile Include="Crestron IO\C2nRts\C2nRthsController.cs" />
<Compile Include="Crestron IO\Cards\C3CardControllerBase.cs" />
<Compile Include="Crestron IO\Cards\C3Com3Controller.cs" />
@@ -197,6 +198,7 @@
<Compile Include="Devices\GenericIRController.cs" />
<Compile Include="Devices\IDspPreset.cs" />
<Compile Include="Devices\IProjectorInterfaces.cs" />
<Compile Include="Devices\IReconfigurableDevice.cs" />
<Compile Include="Devices\PC\InRoomPc.cs" />
<Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" />
@@ -209,6 +211,7 @@
<Compile Include="DeviceTypeInterfaces\IHasFarEndContentStatus.cs" />
<Compile Include="DeviceTypeInterfaces\IHasPhoneDialing.cs" />
<Compile Include="DeviceTypeInterfaces\IMobileControl.cs" />
<Compile Include="Extensions\JsonExtensions.cs" />
<Compile Include="Factory\DeviceFactory.cs" />
<Compile Include="Factory\IDeviceFactory.cs" />
<Compile Include="Factory\ReadyEventArgs.cs" />
@@ -231,6 +234,7 @@
<Compile Include="Interfaces\ILogStringsWithLevel.cs" />
<Compile Include="Occupancy\GlsOccupancySensorPropertiesConfig.cs" />
<Compile Include="Occupancy\GlsOirOccupancySensorController.cs" />
<Compile Include="Occupancy\OccupancyAggregatorConfig.cs" />
<Compile Include="Queues\ComsMessage.cs" />
<Compile Include="Queues\ProcessStringMessage.cs" />
<Compile Include="Queues\GenericQueue.cs" />
@@ -287,6 +291,7 @@
<Compile Include="Room\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" />
<Compile Include="Room\EssentialsRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomScheduledEventsConfig.cs" />
<Compile Include="Room\IEssentialsRoom.cs" />
<Compile Include="Room\Interfaces.cs" />
<Compile Include="Room\iOccupancyStatusProvider.cs" />
<Compile Include="Routing\DummyRoutingInputsDevice.cs" />
@@ -320,6 +325,10 @@
<Compile Include="Feedbacks\BoolFeedbackPulseExtender.cs" />
<Compile Include="Routing\RoutingPortNames.cs" />
<Compile Include="Routing\TieLineConfig.cs" />
<Compile Include="Secrets\CrestronSecretsProvider.cs" />
<Compile Include="Secrets\Interfaces.cs" />
<Compile Include="Secrets\SecretsManager.cs" />
<Compile Include="Secrets\SecretsPropertiesConfig.cs" />
<Compile Include="Shades\Shade Interfaces.cs" />
<Compile Include="Shades\ShadeBase.cs" />
<Compile Include="Shades\ShadeController.cs" />

View File

@@ -375,7 +375,7 @@ namespace PepperDash.Essentials
{
try
{
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type))
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
{
var plugin =
(IPluginDeviceFactory) Crestron.SimplSharp.Reflection.Activator.CreateInstance(type);

View File

@@ -38,7 +38,7 @@ namespace PepperDash.Essentials.Core
ScheduledEventGroup FeatureEventGroup;
public EssentialsRoomBase Room { get; private set; }
public IEssentialsRoom Room { get; private set; }
private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom;
@@ -84,7 +84,7 @@ namespace PepperDash.Essentials.Core
/// </summary>
void SetUpDevice()
{
Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as EssentialsRoomBase;
Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as IEssentialsRoom;
if (Room != null)
{

View File

@@ -16,7 +16,7 @@ namespace PepperDash.Essentials.Core
/// <summary>
///
/// </summary>
public abstract class EssentialsRoomBase : ReconfigurableDevice
public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom
{
/// <summary>
///

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Describes the basic functionality of an EssentialsRoom
/// </summary>
public interface IEssentialsRoom : IKeyName, IReconfigurableDevice
{
BoolFeedback OnFeedback { get; }
event EventHandler<EventArgs> RoomOccupancyIsSet;
BoolFeedback IsWarmingUpFeedback { get; }
BoolFeedback IsCoolingDownFeedback { get; }
IOccupancyStatusProvider RoomOccupancy { get; }
bool OccupancyStatusProviderIsRemote { get; }
bool IsMobileControlEnabled { get; }
IMobileControlRoomBridge MobileControlRoomBridge { get; }
string SourceListKey { get; }
SecondsCountdownTimer ShutdownPromptTimer { get; }
int ShutdownPromptSeconds { get; }
int ShutdownVacancySeconds { get; }
eShutdownType ShutdownType { get; }
EssentialsRoomEmergencyBase Emergency { get; }
Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; }
string LogoUrlLightBkgnd { get; }
string LogoUrlDarkBkgnd { get; }
eVacancyMode VacancyMode { get; }
bool ZeroVolumeWhenSwtichingVolumeDevices { get; }
void StartShutdown(eShutdownType type);
void StartRoomVacancyTimer(eVacancyMode mode);
void Shutdown();
void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes);
void PowerOnToDefaultOrLastSource();
bool RunDefaultPresentRoute();
void SetDefaultLevels();
void RoomVacatedForTimeoutPeriod(object o);
}
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
/// <summary>
@@ -64,5 +65,7 @@ namespace PepperDash.Essentials.Core
{
bool RunDefaultCallRoute();
}
}

View File

@@ -123,25 +123,34 @@ namespace PepperDash.Essentials.Core
// No direct tie? Run back out on the inputs' attached devices...
// Only the ones that are routing devices
var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
if (alreadyCheckedDevices == null)
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
foreach (var inputTieToTry in attachedMidpoints)
{
Debug.Console(2, destination, "Trying to find route on {0}", inputTieToTry.SourcePort.ParentDevice.Key);
var upstreamDeviceOutputPort = inputTieToTry.SourcePort;
var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs;
Debug.Console(2, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key);
// Check if this previous device has already been walked
if (!(alreadyCheckedDevices != null && alreadyCheckedDevices.Contains(upstreamRoutingDevice)))
{
// haven't seen this device yet. Do it. Pass the output port to the next
// level to enable switching on success
var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
alreadyCheckedDevices, signalType, cycle, routeTable);
if (upstreamRoutingSuccess)
{
Debug.Console(2, destination, "Upstream device route found");
goodInputPort = inputTieToTry.DestinationPort;
break; // Stop looping the inputs in this cycle
}
}
if (alreadyCheckedDevices.Contains(upstreamRoutingDevice))
{
Debug.Console(2, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key);
continue;
}
// haven't seen this device yet. Do it. Pass the output port to the next
// level to enable switching on success
var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
alreadyCheckedDevices, signalType, cycle, routeTable);
if (upstreamRoutingSuccess)
{
Debug.Console(2, destination, "Upstream device route found");
goodInputPort = inputTieToTry.DestinationPort;
break; // Stop looping the inputs in this cycle
}
}
}
@@ -163,10 +172,6 @@ namespace PepperDash.Essentials.Core
//Debug.Console(2, destination, "Exiting cycle {0}", cycle);
return true;
}
if(alreadyCheckedDevices == null)
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
Debug.Console(2, destination, "No route found to {0}", source.Key);
return false;

View File

@@ -0,0 +1,97 @@
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronDataStore;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
public class CrestronSecretsProvider : ISecretProvider
{
public string Key { get; set; }
//Added for reference
private static readonly bool SecureSupported;
public CrestronSecretsProvider(string key)
{
Key = key;
}
static CrestronSecretsProvider()
{
//Added for future encrypted reference
SecureSupported = CrestronSecureStorage.Supported;
CrestronDataStoreStatic.InitCrestronDataStore();
if (SecureSupported)
{
//doThingsFuture
}
}
/// <summary>
/// Set secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <param name="value">Secret Value</param>
public bool SetSecret(string key, object value)
{
var secret = value as string;
if (String.IsNullOrEmpty(secret))
{
Debug.Console(2, this, "Unable to set secret for {0}:{1} - value is empty.", Key, key);
return false;
}
var setErrorCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret);
switch (setErrorCode)
{
case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
Debug.Console(1, this,"Secret Successfully Set for {0}:{1}", Key, key);
return true;
default:
Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Unable to set secret for {0}:{1} - {2}", Key, key, setErrorCode.ToString());
return false;
}
}
/// <summary>
/// Retrieve secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <returns>ISecret Object containing key, provider, and value</returns>
public ISecret GetSecret(string key)
{
string mySecret;
var getErrorCode = CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret);
switch (getErrorCode)
{
case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
Debug.Console(2, this, "Secret Successfully retrieved for {0}:{1}", Key, key);
return new CrestronSecret(key, mySecret, this);
default:
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to retrieve secret for {0}:{1} - {2}",
Key, key, getErrorCode.ToString());
return null;
}
}
}
/// <summary>
/// Special container class for CrestronSecret provider
/// </summary>
public class CrestronSecret : ISecret
{
public ISecretProvider Provider { get; private set; }
public string Key { get; private set; }
public object Value { get; private set; }
public CrestronSecret(string key, string value, ISecretProvider provider)
{
Key = key;
Value = value;
Provider = provider;
}
}
}

View File

@@ -0,0 +1,24 @@
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// All ISecrecretProvider classes must implement this interface.
/// </summary>
public interface ISecretProvider : IKeyed
{
bool SetSecret(string key, object value);
ISecret GetSecret(string key);
}
/// <summary>
/// interface for delivering secrets in Essentials.
/// </summary>
public interface ISecret
{
ISecretProvider Provider { get; }
string Key { get; }
object Value { get; }
}
}

View File

@@ -0,0 +1,281 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
public static class SecretsManager
{
public static Dictionary<string, ISecretProvider> Secrets { get; private set; }
/// <summary>
/// Initialize the SecretsManager
/// </summary>
public static void Initialize()
{
AddSecretProvider("default", new CrestronSecretsProvider("default"));
CrestronConsole.AddNewConsoleCommand(SetSecretProcess, "setsecret",
"Adds secrets to secret provider",
ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(UpdateSecretProcess, "updatesecret",
"Updates secrets in secret provider",
ConsoleAccessLevelEnum.AccessAdministrator);
CrestronConsole.AddNewConsoleCommand(DeleteSecretProcess, "deletesecret",
"Deletes secrets in secret provider",
ConsoleAccessLevelEnum.AccessAdministrator);
}
static SecretsManager()
{
Secrets = new Dictionary<string, ISecretProvider>();
}
/// <summary>
/// Get Secret Provider from dictionary by key
/// </summary>
/// <param name="key">Dictionary Key for provider</param>
/// <returns>ISecretProvider</returns>
public static ISecretProvider GetSecretProviderByKey(string key)
{
ISecretProvider secret;
Secrets.TryGetValue(key, out secret);
if (secret == null)
{
Debug.Console(1, "SecretsManager unable to retrieve SecretProvider with the key '{0}'", key);
}
return secret;
}
/// <summary>
/// Add secret provider to secrets dictionary
/// </summary>
/// <param name="key">Key of new entry</param>
/// <param name="provider">New Provider Entry</param>
public static void AddSecretProvider(string key, ISecretProvider provider)
{
if (!Secrets.ContainsKey(key))
{
Secrets.Add(key, provider);
Debug.Console(1, "Secrets provider '{0}' added to SecretsManager", key);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key );
}
/// <summary>
/// Add secret provider to secrets dictionary, with optional overwrite parameter
/// </summary>
/// <param name="key">Key of new entry</param>
/// <param name="provider">New provider entry</param>
/// <param name="overwrite">true to overwrite any existing providers in the dictionary</param>
public static void AddSecretProvider(string key, ISecretProvider provider, bool overwrite)
{
if (!Secrets.ContainsKey(key))
{
Secrets.Add(key, provider);
Debug.Console(1, "Secrets provider '{0}' added to SecretsManager", key);
}
if (overwrite)
{
Secrets.Add(key, provider);
Debug.Console(1, Debug.ErrorLogLevel.Notice, "Provider with the key '{0}' already exists in secrets. Overwriting with new secrets provider.", key);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key);
}
private static void SetSecretProcess(string cmd)
{
string response;
var args = cmd.Split(' ');
if (args.Length == 0)
{
//some Instructional Text
response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1 && args[0] == "?")
{
response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length < 3)
{
response = "Improper number of arguments";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
var provider = GetSecretProviderByKey(args[0]);
if (provider == null)
{
//someFail
response = "Provider key invalid";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
var key = args[1];
var secret = args[2];
if (provider.GetSecret(key) == null)
{
response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response =
String.Format(
"Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it");
CrestronConsole.ConsoleCommandResponse(response);
}
private static void UpdateSecretProcess(string cmd)
{
string response;
var args = cmd.Split(' ');
if (args.Length == 0)
{
//some Instructional Text
response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1 && args[0] == "?")
{
response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length < 3)
{
//someFail
response = "Improper number of arguments";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
var provider = GetSecretProviderByKey(args[0]);
if (provider == null)
{
//someFail
response = "Provider key invalid";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
var key = args[1];
var secret = args[2];
if (provider.GetSecret(key) != null)
{
response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response =
String.Format(
"Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to create a new secret");
CrestronConsole.ConsoleCommandResponse(response);
}
private static void DeleteSecretProcess(string cmd)
{
string response;
var args = cmd.Split(' ');
if (args.Length == 0)
{
//some Instructional Text
response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1 && args[0] == "?")
{
response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length < 2)
{
//someFail
response = "Improper number of arguments";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
var provider = GetSecretProviderByKey(args[0]);
if (provider == null)
{
//someFail
response = "Provider key invalid";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
var key = args[1];
provider.SetSecret(key, "");
response = provider.SetSecret(key, "")
? String.Format(
"Secret successfully deleted for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to delete secret for {0}:{1}",
provider.Key, key);
CrestronConsole.ConsoleCommandResponse(response);
return;
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Provide a way to easily deserialize into a secret object from config
/// </summary>
public class SecretsPropertiesConfig
{
[JsonProperty("provider")]
public string Provider { get; set; }
[JsonProperty("key")]
public string Key { get; set; }
}
}

View File

@@ -8,6 +8,8 @@ using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Presets;
using PepperDash.Essentials.Devices.Common.Codec;
@@ -25,7 +27,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
Focus = 8
}
public abstract class CameraBase : EssentialsDevice, IRoutingOutputs
public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs
{
public eCameraControlMode ControlMode { get; protected set; }
@@ -70,12 +72,18 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
// A bitmasked value to indicate the movement capabilites of this camera
protected eCameraCapabilities Capabilities { get; set; }
protected CameraBase(string key, string name) :
base(key, name)
{
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
protected CameraBase(DeviceConfig config) : base(config)
{
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
ControlMode = eCameraControlMode.Manual;
ControlMode = eCameraControlMode.Manual;
}
protected CameraBase(string key, string name) :
this (new DeviceConfig{Name = name, Key = key})
{
}
protected void LinkCameraToApi(CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey,

View File

@@ -4,15 +4,20 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
[Flags]
public enum eMeetingEventChangeType
{
Unkown = 0,
MeetingStartWarning,
MeetingStart,
MeetingEndWarning,
MeetingEnd
Unknown = 0,
MeetingStartWarning = 1,
MeetingStart = 2,
MeetingEndWarning = 4,
MeetingEnd = 8
}
public interface IHasScheduleAwareness
@@ -32,6 +37,10 @@ namespace PepperDash.Essentials.Devices.Common.Codec
private int _meetingWarningMinutes = 5;
private Meeting _previousChangedMeeting;
private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown;
public int MeetingWarningMinutes
{
get { return _meetingWarningMinutes; }
@@ -75,38 +84,72 @@ namespace PepperDash.Essentials.Devices.Common.Codec
_scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime);
}
/// <summary>
/// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting
/// </summary>
/// <param name="changeType"></param>
/// <param name="meeting"></param>
private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting)
{
var handler = MeetingEventChange;
if (handler != null)
Debug.Console(2, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType);
if (changeType != (changeType & meeting.NotifiedChangeTypes))
{
handler(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting });
// Add this change type to the NotifiedChangeTypes
meeting.NotifiedChangeTypes |= changeType;
var handler = MeetingEventChange;
if (handler != null)
{
handler(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting });
}
}
else
{
Debug.Console(2, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType);
}
}
/// <summary>
/// Checks the schedule to see if any MeetingEventChange updates should be fired
/// </summary>
/// <param name="o"></param>
private void CheckSchedule(object o)
{
// Iterate the meeting list and check if any meeting need to do anythingk
// Iterate the meeting list and check if any meeting need to do anything
const double meetingTimeEpsilon = 0.0001;
const double meetingTimeEpsilon = 0.05;
foreach (var m in Meetings)
{
var changeType = eMeetingEventChangeType.Unkown;
var changeType = eMeetingEventChangeType.Unknown;
if (m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to start
if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start
{
Debug.Console(2, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds);
changeType = eMeetingEventChangeType.MeetingStartWarning;
else if (Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start
}
else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start
{
Debug.Console(2, "********************* MeetingStart");
changeType = eMeetingEventChangeType.MeetingStart;
else if (m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to end
}
else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end
{
Debug.Console(2, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds);
changeType = eMeetingEventChangeType.MeetingEndWarning;
else if (Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended
}
else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended
{
Debug.Console(2, "********************* MeetingEnd");
changeType = eMeetingEventChangeType.MeetingEnd;
}
if (changeType != eMeetingEventChangeType.Unkown)
OnMeetingChange(changeType, m);
if (changeType != eMeetingEventChangeType.Unknown)
{
OnMeetingChange(changeType, m);
}
}
}
}
@@ -115,17 +158,24 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary>
public class Meeting
{
[JsonProperty("minutesBeforeMeeting")]
public int MinutesBeforeMeeting;
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("organizer")]
public string Organizer { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("agenda")]
public string Agenda { get; set; }
[JsonProperty("meetingWarningMinutes")]
public TimeSpan MeetingWarningMinutes
{
get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); }
}
[JsonProperty("timeToMeetingStart")]
public TimeSpan TimeToMeetingStart
{
get
@@ -133,6 +183,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec
return StartTime - DateTime.Now;
}
}
[JsonProperty("timeToMeetingEnd")]
public TimeSpan TimeToMeetingEnd
{
get
@@ -140,8 +191,11 @@ namespace PepperDash.Essentials.Devices.Common.Codec
return EndTime - DateTime.Now;
}
}
[JsonProperty("startTime")]
public DateTime StartTime { get; set; }
[JsonProperty("endTime")]
public DateTime EndTime { get; set; }
[JsonProperty("duration")]
public TimeSpan Duration
{
get
@@ -149,21 +203,34 @@ namespace PepperDash.Essentials.Devices.Common.Codec
return EndTime - StartTime;
}
}
[JsonProperty("privacy")]
public eMeetingPrivacy Privacy { get; set; }
[JsonProperty("joinable")]
public bool Joinable
{
get
{
return StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now
&& DateTime.Now <= EndTime; //.AddMinutes(-5);
var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now
&& DateTime.Now <= EndTime.AddMinutes(-5);
//Debug.Console(2, "Meeting Id: {0} joinable: {1}", Id, joinable);
return joinable;
}
}
//public string ConferenceNumberToDial { get; set; }
[JsonProperty("conferencePassword")]
public string ConferencePassword { get; set; }
[JsonProperty("isOneButtonToPushMeeting")]
public bool IsOneButtonToPushMeeting { get; set; }
[JsonProperty("calls")]
public List<Call> Calls { get; private set; }
/// <summary>
/// Tracks the change types that have already been notified for
/// </summary>
[JsonIgnore]
public eMeetingEventChangeType NotifiedChangeTypes { get; set; }
public Meeting()
{
Calls = new List<Call>();

View File

@@ -122,6 +122,7 @@
<Compile Include="Display\PanasonicThDisplay.cs" />
<Compile Include="VideoCodec\Interfaces\IHasParticipants.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewSize.cs" />
<Compile Include="VideoCodec\Interfaces\iVideoCodecInfo.cs" />
<Compile Include="Codec\iHasCallFavorites.cs" />
<Compile Include="Codec\iHasCallHistory.cs" />
@@ -176,6 +177,7 @@
<Compile Include="VideoCodec\ZoomRoom\ResponseObjects.cs" />
<Compile Include="VideoCodec\ZoomRoom\ZoomRoom.cs" />
<Compile Include="VideoCodec\ZoomRoom\ZoomRoomCamera.cs" />
<Compile Include="VideoCodec\ZoomRoom\ZoomRoomJoinMap.cs" />
<Compile Include="VideoCodec\ZoomRoom\ZoomRoomPropertiesConfig.cs" />
<None Include="Properties\ControlSystem.cfg" />
</ItemGroup>

View File

@@ -19,4 +19,32 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
void LocalLayoutToggleSingleProminent();
void MinMaxLayoutToggle();
}
/// <summary>
/// Defines the requirements for Zoom Room layout control
/// </summary>
public interface IHasZoomRoomLayouts : IHasCodecLayouts
{
event EventHandler<LayoutInfoChangedEventArgs> AvailableLayoutsChanged;
BoolFeedback LayoutViewIsOnFirstPageFeedback { get; } // TODO: #697 [*] Consider modifying to report button visibility in func
BoolFeedback LayoutViewIsOnLastPageFeedback { get; } // TODO: #697 [*] Consider modifying to report button visibility in func
BoolFeedback CanSwapContentWithThumbnailFeedback { get; }
BoolFeedback ContentSwappedWithThumbnailFeedback { get; }
ZoomRoom.zConfiguration.eLayoutStyle LastSelectedLayout { get; }
ZoomRoom.zConfiguration.eLayoutStyle AvailableLayouts { get; }
void GetAvailableLayouts(); // Mot sure this is necessary if we're already subscribed to zStatus Call Layout
void SetLayout(ZoomRoom.zConfiguration.eLayoutStyle layoutStyle);
void SwapContentWithThumbnail();
void LayoutTurnNextPage();
void LayoutTurnPreviousPage();
}
public class LayoutInfoChangedEventArgs : EventArgs
{
public ZoomRoom.zConfiguration.eLayoutStyle AvailableLayouts { get; set; }
}
}

View File

@@ -1,13 +1,20 @@
using System;
using System.Collections.Generic;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
/// <summary>
/// Describes a device that has call participants
/// </summary>
public interface IHasParticipants
{
CodecParticipants Participants { get; }
}
/// <summary>
/// Describes the ability to mute and unmute a participant's video in a meeting
/// </summary>
public interface IHasParticipantVideoMute:IHasParticipants
{
void MuteVideoForParticipant(int userId);
@@ -15,13 +22,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
void ToggleVideoForParticipant(int userId);
}
public interface IHasParticipantAudioMute:IHasParticipantVideoMute
/// <summary>
/// Describes the ability to mute and unmute a participant's audio in a meeting
/// </summary>
public interface IHasParticipantAudioMute : IHasParticipantVideoMute
{
void MuteAudioForParticipant(int userId);
void UnmuteAudioForParticipant(int userId);
void ToggleAudioForParticipant(int userId);
}
/// <summary>
/// Describes the ability to pin and unpin a participant in a meeting
/// </summary>
public interface IHasParticipantPinUnpin : IHasParticipants
{
IntFeedback NumberOfScreensFeedback { get; }
int ScreenIndexToPinUserTo { get; }
void PinParticipant(int userId, int screenIndex);
void UnPinParticipant(int userId);
void ToggleParticipantPinState(int userId, int screenIndex);
}
public class CodecParticipants
{
private List<Participant> _currentParticipants;
@@ -31,11 +54,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
set
{
_currentParticipants = value;
var handler = ParticipantsListHasChanged;
if(handler == null) return;
handler(this, new EventArgs());
OnParticipantsChanged();
}
}
@@ -45,15 +64,37 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
_currentParticipants = new List<Participant>();
}
public void OnParticipantsChanged()
{
var handler = ParticipantsListHasChanged;
if (handler == null) return;
handler(this, new EventArgs());
}
}
/// <summary>
/// Represents a call participant
/// </summary>
public class Participant
{
public int UserId { get; set; }
public bool IsHost { get; set; }
public string Name { get; set; }
public bool CanMuteVideo { get; set; }
public bool CanUnmuteVideo { get; set; }
public bool VideoMuteFb { get; set; }
public bool AudioMuteFb { get; set; }
public bool HandIsRaisedFb { get; set; }
public bool IsPinnedFb { get; set; }
public int ScreenIndexIsPinnedToFb { get; set; }
public Participant()
{
// Initialize to -1 (no screen)
ScreenIndexIsPinnedToFb = -1;
}
}
}

View File

@@ -0,0 +1,13 @@
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IHasSelfviewSize
{
StringFeedback SelfviewPipSizeFeedback { get; }
void SelfviewPipSizeSet(CodecCommandWithLabel size);
void SelfviewPipSizeToggle();
}
}

View File

@@ -139,7 +139,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public override void Dial(Meeting meeting)
{
throw new NotImplementedException();
Debug.Console(1, this, "Dial Meeting: {0}", meeting.Id);
var call = new CodecActiveCallItem() { Name = meeting.Title, Number = meeting.Id, Id = meeting.Id, Status = eCodecCallStatus.Dialing, Direction = eCodecCallDirection.Outgoing, Type = eCodecCallType.Video };
ActiveCalls.Add(call);
OnCallStatusChange(call);
//ActiveCallCountFeedback.FireUpdate();
// Simulate 2-second ring, then connecting, then connected
new CTimer(o =>
{
call.Type = eCodecCallType.Video;
SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call);
new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000);
}, 2000);
}
/// <summary>
@@ -396,12 +409,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
if (_CodecSchedule == null || _CodecSchedule.Meetings.Count == 0
|| _CodecSchedule.Meetings[_CodecSchedule.Meetings.Count - 1].StartTime < DateTime.Now)
{
_CodecSchedule = new CodecScheduleAwareness();
_CodecSchedule = new CodecScheduleAwareness(1000);
for (int i = 0; i < 5; i++)
{
var m = new Meeting();
m.StartTime = DateTime.Now.AddMinutes(3).AddHours(i);
m.EndTime = DateTime.Now.AddHours(i).AddMinutes(30);
m.MinutesBeforeMeeting = 5;
m.Id = i.ToString();
m.Organizer = "Employee " + 1;
m.StartTime = DateTime.Now.AddMinutes(6).AddHours(i);
m.EndTime = DateTime.Now.AddHours(i).AddMinutes(16);
m.Title = "Meeting " + i;
m.Calls.Add(new Call() { Number = i + "meeting@fake.com"});
_CodecSchedule.Meetings.Add(m);

View File

@@ -28,6 +28,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced
{
private const int XSigEncoding = 28591;
protected const int MaxParticipants = 50;
private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs();
protected VideoCodecBase(DeviceConfig config)
: base(config)
@@ -271,6 +272,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
/// <summary>
/// Use this method when using a plain VideoCodecControllerJoinMap
/// </summary>
/// <param name="codec"></param>
/// <param name="trilist"></param>
/// <param name="joinStart"></param>
/// <param name="joinMapKey"></param>
/// <param name="bridge"></param>
protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, uint joinStart, string joinMapKey,
EiscApiAdvanced bridge)
{
@@ -288,10 +297,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
bridge.AddJoinMap(Key, joinMap);
}
LinkVideoCodecToApi(codec, trilist, joinMap);
}
/// <summary>
/// Use this method when you need to pass in a join map that extends VideoCodecControllerJoinMap
/// </summary>
/// <param name="codec"></param>
/// <param name="trilist"></param>
/// <param name="joinMap"></param>
protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
Debug.Console(1, this, "Linking to Trilist {0}", trilist.ID.ToString("X"));
LinkVideoCodecDtmfToApi(trilist, joinMap);
LinkVideoCodecCallControlsToApi(trilist, joinMap);
@@ -512,34 +530,96 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
private void LinkVideoCodecParticipantsToApi(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
// make sure to update the values when the EISC comes online
trilist.OnlineStatusChange += (sender, args) =>
{
if (sender.IsOnline)
{
UpdateParticipantsXSig(codec, trilist, joinMap);
}
};
// set actions and update the values when the list changes
codec.Participants.ParticipantsListHasChanged += (sender, args) =>
{
string participantsXSig;
SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants);
if (codec.Participants.CurrentParticipants.Count == 0)
{
participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
return;
}
participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
UpdateParticipantsXSig(codec, trilist, joinMap);
};
}
private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{
string participantsXSig;
if (codec.Participants.CurrentParticipants.Count == 0)
{
participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
return;
}
participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants);
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig);
trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count);
}
/// <summary>
/// Sets the actions for each participant in the list
/// </summary>
private void SetParticipantActions(BasicTriList trilist, VideoCodecControllerJoinMap joinMap, List<Participant> currentParticipants)
{
uint index = 0; // track the index of the participant in the
foreach (var participant in currentParticipants)
{
var p = participant;
if (index > MaxParticipants) break;
var audioMuteCodec = this as IHasParticipantAudioMute;
if (audioMuteCodec != null)
{
trilist.SetSigFalseAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index,
() => audioMuteCodec.ToggleAudioForParticipant(p.UserId));
trilist.SetSigFalseAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index,
() => audioMuteCodec.ToggleVideoForParticipant(p.UserId));
}
var pinCodec = this as IHasParticipantPinUnpin;
if (pinCodec != null)
{
trilist.SetSigFalseAction(joinMap.ParticipantPinToggleStart.JoinNumber + index,
() => pinCodec.ToggleParticipantPinState(p.UserId, pinCodec.ScreenIndexToPinUserTo));
}
index++;
}
// Clear out any previously set actions
while (index < MaxParticipants)
{
trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index);
trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index);
trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index);
index++;
}
}
private string UpdateParticipantsXSig(List<Participant> currentParticipants)
{
const int maxParticipants = 50;
const int maxDigitals = 5;
const int maxParticipants = MaxParticipants;
const int maxDigitals = 7;
const int maxStrings = 1;
const int offset = maxDigitals + maxStrings;
var digitalIndex = maxStrings * maxParticipants; //15
const int maxAnalogs = 1;
const int offset = maxDigitals + maxStrings + maxAnalogs; // 9
var digitalIndex = (maxStrings + maxAnalogs) * maxParticipants; // 100
var stringIndex = 0;
var analogIndex = stringIndex + maxParticipants;
var meetingIndex = 0;
var tokenArray = new XSigToken[maxParticipants * offset];
@@ -548,38 +628,91 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
if (meetingIndex >= maxParticipants * offset) break;
Debug.Console(2, this,
@"Updating Participant on xsig:
Name: {0} (s{9})
AudioMute: {1} (d{10})
VideoMute: {2} (d{11})
CanMuteVideo: {3} (d{12})
CanUMuteVideo: {4} (d{13})
IsHost: {5} (d{14})
HandIsRaised: {6} (d{15})
IsPinned: {7} (d{16})
ScreenIndexIsPinnedTo: {8} (a{17})
",
participant.Name,
participant.AudioMuteFb,
participant.VideoMuteFb,
participant.CanMuteVideo,
participant.CanUnmuteVideo,
participant.IsHost,
participant.HandIsRaisedFb,
participant.IsPinnedFb,
participant.ScreenIndexIsPinnedToFb,
stringIndex + 1,
digitalIndex + 1,
digitalIndex + 2,
digitalIndex + 3,
digitalIndex + 4,
digitalIndex + 5,
digitalIndex + 6,
digitalIndex + 7,
analogIndex + 1
);
//digitals
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, participant.AudioMuteFb);
tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, participant.VideoMuteFb);
tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, participant.CanMuteVideo);
tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, participant.CanUnmuteVideo);
tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, participant.IsHost);
tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, participant.HandIsRaisedFb);
tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, participant.IsPinnedFb);
Debug.Console(2, this, "Index: {0} byte value: {1}", digitalIndex + 7, ComTextHelper.GetEscapedText(tokenArray[digitalIndex + 6].GetBytes()));
//serials
tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name);
//analogs
tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, (ushort)participant.ScreenIndexIsPinnedToFb);
digitalIndex += maxDigitals;
meetingIndex += offset;
stringIndex += maxStrings;
analogIndex += maxAnalogs;
}
while (meetingIndex < maxParticipants * offset)
{
//digitals
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false);
tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false);
tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, false);
tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, false);
tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, false);
tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, false);
tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, false);
//serials
tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty);
//analogs
tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, 0);
digitalIndex += maxDigitals;
meetingIndex += offset;
stringIndex += maxStrings;
analogIndex += maxAnalogs;
}
return GetXSigString(tokenArray);
var returnString = GetXSigString(tokenArray);
//Debug.Console(2, this, "{0}", ComTextHelper.GetEscapedText(Encoding.GetEncoding(28591).GetBytes(returnString)));
return returnString;
}
private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
@@ -595,7 +728,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
trilist.SetBoolSigAction(joinMap.SourceShareAutoStart.JoinNumber, (b) => AutoShareContentWhileInCall = b);
}
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
private List<Meeting> _currentMeetings = new List<Meeting>();
private void LinkVideoCodecScheduleToApi(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
@@ -607,7 +739,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
codec.CodecSchedule.MeetingWarningMinutes = i;
});
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
trilist.SetSigFalseAction(joinMap.DialMeeting1.JoinNumber, () =>
{
var mtg = 1;
@@ -617,7 +748,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
if (_currentMeetings[index] != null)
Dial(_currentMeetings[index]);
});
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
trilist.SetSigFalseAction(joinMap.DialMeeting2.JoinNumber, () =>
{
var mtg = 2;
@@ -627,7 +758,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
if (_currentMeetings[index] != null)
Dial(_currentMeetings[index]);
});
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
trilist.SetSigFalseAction(joinMap.DialMeeting3.JoinNumber, () =>
{
var mtg = 3;
@@ -652,14 +783,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
var currentTime = DateTime.Now;
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
// - changed var currentMeetings >> field _currentMeetings
//_currentMeetings.Clear();
_currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList();
// TODO [ ] 2021-01-06, jkd: Added to debug OBTP dialing issues
// - moved the trilist.SetSigFlaseAction(joinMap.DialMeeting1..3.JoinNumber) lambda's to LinkVideoCodecScheduleToApi
var meetingsData = UpdateMeetingsListXSig(_currentMeetings);
trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData);
trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)_currentMeetings.Count);
@@ -847,7 +972,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
Debug.Console(1, this, "Call Direction: {0}", args.CallItem.Direction);
Debug.Console(1, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming);
trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status == eCodecCallStatus.Ringing);
trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status == eCodecCallStatus.Ringing);
if (args.CallItem.Direction == eCodecCallDirection.Incoming)
{

View File

@@ -0,0 +1,301 @@
using System;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges.JoinMaps;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{
public class ZoomRoomJoinMap : VideoCodecControllerJoinMap
{
#region Digital
[JoinName("CanSwapContentWithThumbnail")]
public JoinDataComplete CanSwapContentWithThumbnail = new JoinDataComplete(
new JoinData
{
JoinNumber = 206,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if content can be swapped with thumbnail",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SwapContentWithThumbnail")]
public JoinDataComplete SwapContentWithThumbnail = new JoinDataComplete(
new JoinData
{
JoinNumber = 206,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Pulse to swap content with thumbnail. FB reports current state",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("GetAvailableLayouts")]
public JoinDataComplete GetAvailableLayouts = new JoinDataComplete(
new JoinData
{
JoinNumber = 215,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Gets the available layouts. Will update the LayoutXXXXXIsAvailbale signals.",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutIsOnFirstPage")]
public JoinDataComplete LayoutIsOnFirstPage = new JoinDataComplete(
new JoinData
{
JoinNumber = 216,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Indicates if layout is on first page",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutIsOnLastPage")]
public JoinDataComplete LayoutIsOnLastPage = new JoinDataComplete(
new JoinData
{
JoinNumber = 217,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Indicates if layout is on first page",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutTurnToNextPage")]
public JoinDataComplete LayoutTurnToNextPage = new JoinDataComplete(
new JoinData
{
JoinNumber = 216,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Turns layout view to next page",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutTurnToPreviousPage")]
public JoinDataComplete LayoutTurnToPreviousPage = new JoinDataComplete(
new JoinData
{
JoinNumber = 217,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Turns layout view to previous page",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LayoutGalleryIsAvailable")]
public JoinDataComplete LayoutGalleryIsAvailable = new JoinDataComplete(
new JoinData
{
JoinNumber = 221,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if layout 'Gallery' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
});
[JoinName("LayoutSpeakerIsAvailable")]
public JoinDataComplete LayoutSpeakerIsAvailable = new JoinDataComplete(
new JoinData
{
JoinNumber = 222,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if layout 'Speaker' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
});
[JoinName("LayoutStripIsAvailable")]
public JoinDataComplete LayoutStripIsAvailable = new JoinDataComplete(
new JoinData
{
JoinNumber = 223,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if layout 'Strip' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
});
[JoinName("LayoutShareAllIsAvailable")]
public JoinDataComplete LayoutShareAllIsAvailable = new JoinDataComplete(
new JoinData
{
JoinNumber = 224,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FB Indicates if layout 'ShareAll' is available",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
});
// TODO: #714 [ ] JoinMap >> SelfivewPipSizeToggle
[JoinName("SelfviewPipSizeToggle")]
public JoinDataComplete SelfviewPipSizeToggle = new JoinDataComplete(
new JoinData
{
JoinNumber = 231,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Toggles the selfview pip size, (aka layout size)",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
//[JoinName("ParticipantAudioMuteToggleStart")]
//public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 500,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's audio mute status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
//[JoinName("ParticipantVideoMuteToggleStart")]
//public JoinDataComplete ParticipantVideoMuteToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 800,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's video mute status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
//[JoinName("ParticipantPinToggleStart")]
//public JoinDataComplete ParticipantPinToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 1100,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's pin status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
#endregion
#region Analog
[JoinName("NumberOfScreens")]
public JoinDataComplete NumberOfScreens = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Reports the number of screens connected",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("ScreenIndexToPinUserTo")]
public JoinDataComplete ScreenIndexToPinUserTo = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Specifies the screen index a participant should be pinned to",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Analog
});
#endregion
#region Serials
[JoinName("GetSetCurrentLayout")]
public JoinDataComplete GetSetCurrentLayout = new JoinDataComplete(
new JoinData
{
JoinNumber = 215,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Sets and reports the current layout. Use the LayoutXXXXIsAvailable signals to determine valid layouts",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Serial
});
// TODO: #714 [ ] JoinMap >> GetSetSelfviewPipSize
[JoinName("GetSetSelfviewPipSize")]
public JoinDataComplete GetSetSelfviewPipSize = new JoinDataComplete(
new JoinData
{
JoinNumber = 230,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Sets and reports the selfview pip size, (aka layout size).",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.DigitalSerial
});
#endregion
public ZoomRoomJoinMap(uint joinStart)
: base(joinStart, typeof(ZoomRoomJoinMap))
{
}
public ZoomRoomJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -1,3 +1,3 @@
<packages>
<package id="PepperDashCore" version="1.0.45" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
<package id="PepperDashCore" version="1.0.47" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
</packages>