mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-20 23:24:57 +00:00
Compare commits
56 Commits
1.9.5-hotf
...
1.9.7-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d67a161e32 | ||
|
|
493b391d6f | ||
|
|
805022631b | ||
|
|
5442a1db48 | ||
|
|
61be312826 | ||
|
|
fb624ef20c | ||
|
|
a6430a7bfe | ||
|
|
b71c83bac0 | ||
|
|
5940ec17c2 | ||
|
|
10445508b2 | ||
|
|
66ecf43508 | ||
|
|
e855359f61 | ||
|
|
5f50f14a71 | ||
|
|
1e9139f38e | ||
|
|
c521a1d551 | ||
|
|
d22c1bf344 | ||
|
|
fd232beae1 | ||
|
|
35edbeacfc | ||
|
|
b5cabfc644 | ||
|
|
bead782bd5 | ||
|
|
1e98484082 | ||
|
|
e7915b1e99 | ||
|
|
23600d8bc9 | ||
|
|
a165ba911f | ||
|
|
16db2663a6 | ||
|
|
8d1f187643 | ||
|
|
a6741e47e4 | ||
|
|
77c4272219 | ||
|
|
3d543dfd09 | ||
|
|
9c22c4cb5f | ||
|
|
f0942a3932 | ||
|
|
acd2be3679 | ||
|
|
e7cfe1143d | ||
|
|
26bf7d8f73 | ||
|
|
12e8dca47e | ||
|
|
5c02d72ed1 | ||
|
|
115a20d8e6 | ||
|
|
c298d37b9f | ||
|
|
5f5ded74fc | ||
|
|
1bf828b8a9 | ||
|
|
397a5b1794 | ||
|
|
0867d08c5a | ||
|
|
5c3e1ca915 | ||
|
|
1de42b9e97 | ||
|
|
0e41cafdad | ||
|
|
77672237e6 | ||
|
|
8ae03a8187 | ||
|
|
7114e60c04 | ||
|
|
6542c062b9 | ||
|
|
2db397b474 | ||
|
|
bfa48091d9 | ||
|
|
c4752b2ac2 | ||
|
|
152dcbe81e | ||
|
|
56f9a29c61 | ||
|
|
61d8370329 | ||
|
|
c8b0c7dd01 |
@@ -28,6 +28,7 @@ namespace PepperDash.Essentials
|
||||
HttpLogoServer LogoServer;
|
||||
|
||||
private CTimer _startTimer;
|
||||
private CEvent _initializeEvent;
|
||||
private const long StartupTime = 500;
|
||||
|
||||
public ControlSystem()
|
||||
@@ -46,6 +47,24 @@ namespace PepperDash.Essentials
|
||||
public override void InitializeSystem()
|
||||
{
|
||||
_startTimer = new CTimer(StartSystem,StartupTime);
|
||||
|
||||
|
||||
// If the control system is a DMPS type, we need to wait to exit this method until all devices have had time to activate
|
||||
// to allow any HD-BaseT DM endpoints to register first.
|
||||
if (Global.ControlSystemIsDmpsType)
|
||||
{
|
||||
Debug.Console(2, "******************* InitializeSystem() Entering **********************");
|
||||
|
||||
_initializeEvent = new CEvent();
|
||||
|
||||
DeviceManager.AllDevicesActivated += (o, a) =>
|
||||
{
|
||||
_initializeEvent.Set();
|
||||
Debug.Console(2, "******************* InitializeSystem() Exiting **********************");
|
||||
};
|
||||
|
||||
_initializeEvent.Wait(30000);
|
||||
}
|
||||
}
|
||||
|
||||
private void StartSystem(object obj)
|
||||
@@ -343,7 +362,7 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
var prompt = Global.ControlSystem.ControllerPrompt;
|
||||
|
||||
var typeMatch = String.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) &&
|
||||
var typeMatch = String.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) ||
|
||||
String.Equals(devConf.Type, prompt.Replace("-", ""), StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (!typeMatch)
|
||||
@@ -361,9 +380,7 @@ namespace PepperDash.Essentials
|
||||
if(propertiesConfig == null)
|
||||
propertiesConfig = new DM.Config.DmpsRoutingPropertiesConfig();
|
||||
|
||||
var dmpsRoutingController = DmpsRoutingController.GetDmpsRoutingController("processor-avRouting", this.ControllerPrompt, propertiesConfig);
|
||||
|
||||
DeviceManager.AddDevice(dmpsRoutingController);
|
||||
DeviceManager.AddDevice(DmpsRoutingController.GetDmpsRoutingController("processor-avRouting", this.ControllerPrompt, propertiesConfig));
|
||||
}
|
||||
else if (this.ControllerPrompt.IndexOf("mpc3", StringComparison.OrdinalIgnoreCase) > -1)
|
||||
{
|
||||
@@ -489,8 +506,11 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
DeviceManager.AddDevice(room);
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
|
||||
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
|
||||
if (!(room is EssentialsCombinedHuddleVtc1Room))
|
||||
{
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
|
||||
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
|
||||
}
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@
|
||||
<Compile Include="Room\Config\EssentialsRoomEmergencyConfig.cs" />
|
||||
<Compile Include="Room\Config\EssentialsTechRoomConfig.cs" />
|
||||
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
|
||||
<Compile Include="Room\Types\EssentialsCombinedHuddleVtc1Room.cs" />
|
||||
<Compile Include="Room\Types\EssentialsDualDisplayRoom.cs" />
|
||||
<Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" />
|
||||
<Compile Include="Room\Types\EssentialsNDisplayRoomBase.cs" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ControlSystem>
|
||||
<Name>192.168.10.1</Name>
|
||||
<Address>auto 192.168.10.1</Address>
|
||||
<Name>Test RMC3</Name>
|
||||
<Address>auto 192.168.1.40;username crestron</Address>
|
||||
<ProgramSlot>Program01</ProgramSlot>
|
||||
<Storage>Internal Flash</Storage>
|
||||
</ControlSystem>
|
||||
@@ -39,6 +39,10 @@ namespace PepperDash.Essentials.Room.Config
|
||||
{
|
||||
return new EssentialsDualDisplayRoom(roomConfig);
|
||||
}
|
||||
if (typeName == "combinedhuddlevtc1")
|
||||
{
|
||||
return new EssentialsCombinedHuddleVtc1Room(roomConfig);
|
||||
}
|
||||
|
||||
return typeName != "techroom" ? null : new EssentialsTechRoom(roomConfig);
|
||||
}
|
||||
@@ -183,6 +187,12 @@ namespace PepperDash.Essentials.Room.Config
|
||||
[JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")]
|
||||
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if this room represents a combination of other rooms
|
||||
/// </summary>
|
||||
[JsonProperty("isRoomCombinationScenario")]
|
||||
public bool IsRoomCombinationScenario { get; set; }
|
||||
|
||||
public EssentialsRoomPropertiesConfig()
|
||||
{
|
||||
LogoLight = new EssentialsLogoPropertiesConfig();
|
||||
|
||||
@@ -0,0 +1,821 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
using PepperDash.Essentials.Devices.Common.Codec;
|
||||
using PepperDash.Essentials.Devices.Common.VideoCodec;
|
||||
using PepperDash.Essentials.Devices.Common.AudioCodec;
|
||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
public class EssentialsCombinedHuddleVtc1Room : EssentialsRoomBase, IEssentialsHuddleVtc1Room
|
||||
{
|
||||
private bool _codecExternalSourceChange;
|
||||
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
|
||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
||||
|
||||
|
||||
//************************
|
||||
// Call-related stuff
|
||||
|
||||
public BoolFeedback InCallFeedback { get; private set; }
|
||||
|
||||
///// <summary>
|
||||
///// Make this more specific
|
||||
///// </summary>
|
||||
//public List<CodecActiveCallItem> ActiveCalls { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
|
||||
/// </summary>
|
||||
public IntFeedback CallTypeFeedback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// When something in the room is sharing with the far end or through other means
|
||||
/// </summary>
|
||||
public BoolFeedback IsSharingFeedback { get; private set; }
|
||||
|
||||
//************************
|
||||
|
||||
protected override Func<bool> OnFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
|
||||
var displays = Displays.OfType<DisplayBase>().ToList();
|
||||
|
||||
var val = CurrentSourceInfo != null
|
||||
&& CurrentSourceInfo.Type == eSourceListItemType.Route
|
||||
&& displays.Count > 0;
|
||||
//&& disp.PowerIsOnFeedback.BoolValue;
|
||||
return val;
|
||||
};
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override Func<bool> IsWarmingFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () => Displays.OfType<TwoWayDisplayBase>().Any((d) => d.IsWarmingUpFeedback.BoolValue);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override Func<bool> IsCoolingFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () => Displays.OfType<TwoWayDisplayBase>().Any((d) => d.IsCoolingDownFeedback.BoolValue);
|
||||
}
|
||||
}
|
||||
|
||||
public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; }
|
||||
|
||||
private List<IRoutingSinkWithSwitching> Displays;
|
||||
|
||||
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
|
||||
|
||||
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
|
||||
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
|
||||
|
||||
public VideoCodecBase VideoCodec { get; private set; }
|
||||
|
||||
public AudioCodecBase AudioCodec { get; private set; }
|
||||
|
||||
public bool ExcludeFromGlobalFunctions { get; set; }
|
||||
|
||||
public string DefaultSourceItem { get; set; }
|
||||
|
||||
public ushort DefaultVolume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If room is off, enables power on to last source. Default true
|
||||
/// </summary>
|
||||
public bool EnablePowerOnToLastSource { get; set; }
|
||||
string LastSourceKey;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the volume control device, and attaches/removes InUseTrackers with "audio"
|
||||
/// tag to device.
|
||||
/// </summary>
|
||||
public IBasicVolumeControls CurrentVolumeControls
|
||||
{
|
||||
get { return _CurrentAudioDevice; }
|
||||
set
|
||||
{
|
||||
if (value == _CurrentAudioDevice) return;
|
||||
|
||||
var oldDev = _CurrentAudioDevice;
|
||||
// derigister this room from the device, if it can
|
||||
if (oldDev is IInUseTracking)
|
||||
(oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
|
||||
var handler = CurrentVolumeDeviceChange;
|
||||
if (handler != null)
|
||||
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
|
||||
_CurrentAudioDevice = value;
|
||||
if (handler != null)
|
||||
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
|
||||
// register this room with new device, if it can
|
||||
if (_CurrentAudioDevice is IInUseTracking)
|
||||
(_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
|
||||
}
|
||||
}
|
||||
IBasicVolumeControls _CurrentAudioDevice;
|
||||
|
||||
/// <summary>
|
||||
/// The SourceListItem last run - containing names and icons
|
||||
/// </summary>
|
||||
public SourceListItem CurrentSourceInfo
|
||||
{
|
||||
get { return _CurrentSourceInfo; }
|
||||
set
|
||||
{
|
||||
if (value == _CurrentSourceInfo) return;
|
||||
|
||||
var handler = CurrentSourceChange;
|
||||
// remove from in-use tracker, if so equipped
|
||||
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
|
||||
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
|
||||
|
||||
if (handler != null)
|
||||
handler(_CurrentSourceInfo, ChangeType.WillChange);
|
||||
|
||||
_CurrentSourceInfo = value;
|
||||
|
||||
// add to in-use tracking
|
||||
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
|
||||
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
|
||||
if (handler != null)
|
||||
handler(_CurrentSourceInfo, ChangeType.DidChange);
|
||||
|
||||
var vc = VideoCodec as IHasExternalSourceSwitching;
|
||||
if (vc != null && !_codecExternalSourceChange)
|
||||
{
|
||||
vc.SetSelectedSource(CurrentSourceInfoKey);
|
||||
}
|
||||
|
||||
_codecExternalSourceChange = false;
|
||||
}
|
||||
}
|
||||
SourceListItem _CurrentSourceInfo;
|
||||
|
||||
public string CurrentSourceInfoKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// "codecOsd"
|
||||
/// </summary>
|
||||
public string DefaultCodecRouteString { get { return "codecOsd"; } }
|
||||
|
||||
/// <summary>
|
||||
/// Temporary implementation. Returns the schedule-ready object or null if none. Fow now,
|
||||
/// always returns the VideoCodec if it is capable
|
||||
/// </summary>
|
||||
public IHasScheduleAwareness ScheduleSource { get { return VideoCodec as IHasScheduleAwareness; } }
|
||||
|
||||
CCriticalSection SourceSelectLock = new CCriticalSection();
|
||||
|
||||
public EssentialsCombinedHuddleVtc1Room(DeviceConfig config)
|
||||
: base(config)
|
||||
{
|
||||
try
|
||||
{
|
||||
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsConferenceRoomPropertiesConfig>
|
||||
(config.Properties.ToString());
|
||||
|
||||
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
|
||||
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
|
||||
|
||||
|
||||
if (VideoCodec == null)
|
||||
throw new ArgumentNullException("codec cannot be null");
|
||||
|
||||
AudioCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.AudioCodecKey) as
|
||||
PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase;
|
||||
if (AudioCodec == null)
|
||||
Debug.Console(0, this, "No Audio Codec Found");
|
||||
|
||||
DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IBasicVolumeControls;
|
||||
|
||||
Displays = new List<IRoutingSinkWithSwitching>();
|
||||
|
||||
Initialize();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(1, this, "Error building room: \n{0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DefaultAudioDevice is IBasicVolumeControls)
|
||||
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
|
||||
else if (DefaultAudioDevice is IHasVolumeDevice)
|
||||
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
|
||||
CurrentVolumeControls = DefaultVolumeControls;
|
||||
|
||||
|
||||
// Combines call feedback from both codecs if available
|
||||
InCallFeedback = new BoolFeedback(() =>
|
||||
{
|
||||
bool inAudioCall = false;
|
||||
bool inVideoCall = false;
|
||||
|
||||
if (AudioCodec != null)
|
||||
inAudioCall = AudioCodec.IsInCall;
|
||||
|
||||
if (VideoCodec != null)
|
||||
inVideoCall = VideoCodec.IsInCall;
|
||||
|
||||
if (inAudioCall || inVideoCall)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
});
|
||||
|
||||
SetupDisplays();
|
||||
|
||||
// Get Microphone Privacy object, if any MUST HAPPEN AFTER setting InCallFeedback
|
||||
this.MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
|
||||
|
||||
Debug.Console(2, this, "Microphone Privacy Config evaluated.");
|
||||
|
||||
// Get emergency object, if any
|
||||
this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
|
||||
|
||||
Debug.Console(2, this, "Emergency Config evaluated.");
|
||||
|
||||
|
||||
VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
|
||||
VideoCodec.IsReadyChange += (o, a) => { this.SetCodecExternalSources(); SetCodecBranding(); };
|
||||
|
||||
if (AudioCodec != null)
|
||||
AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
|
||||
|
||||
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
|
||||
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => this.IsSharingFeedback.FireUpdate();
|
||||
|
||||
// link privacy to VC (for now?)
|
||||
PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
|
||||
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => this.PrivacyModeIsOnFeedback.FireUpdate();
|
||||
|
||||
CallTypeFeedback = new IntFeedback(() => 0);
|
||||
|
||||
SetSourceListKey();
|
||||
|
||||
EnablePowerOnToLastSource = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(0, this, "Error Initializing Room: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupDisplays()
|
||||
{
|
||||
//DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
|
||||
|
||||
var destinationList = ConfigReader.ConfigObject.DestinationLists[PropertiesConfig.DestinationListKey];
|
||||
|
||||
foreach (var destination in destinationList)
|
||||
{
|
||||
var dest = destination.Value.SinkDevice as IRoutingSinkWithSwitching;
|
||||
|
||||
if (dest != null)
|
||||
{
|
||||
Displays.Add(dest);
|
||||
}
|
||||
|
||||
var display = dest as DisplayBase;
|
||||
if (display != null)
|
||||
{
|
||||
// Link power, warming, cooling to display
|
||||
var dispTwoWay = display as IHasPowerControlWithFeedback;
|
||||
if (dispTwoWay != null)
|
||||
{
|
||||
dispTwoWay.PowerIsOnFeedback.OutputChange += (o, a) =>
|
||||
{
|
||||
if (dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
|
||||
{
|
||||
//if (!dispTwoWay.PowerIsOnFeedback.BoolValue)
|
||||
// CurrentSourceInfo = null;
|
||||
OnFeedback.FireUpdate();
|
||||
}
|
||||
if (dispTwoWay.PowerIsOnFeedback.BoolValue)
|
||||
{
|
||||
SetDefaultLevels();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
display.IsWarmingUpFeedback.OutputChange += (o, a) =>
|
||||
{
|
||||
IsWarmingUpFeedback.FireUpdate();
|
||||
if (!IsWarmingUpFeedback.BoolValue)
|
||||
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
|
||||
};
|
||||
display.IsCoolingDownFeedback.OutputChange += (o, a) =>
|
||||
{
|
||||
IsCoolingDownFeedback.FireUpdate();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSourceListKey()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey))
|
||||
{
|
||||
SetSourceListKey(PropertiesConfig.SourceListKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSourceListKey(Key);
|
||||
}
|
||||
|
||||
SetCodecExternalSources();
|
||||
}
|
||||
|
||||
protected override void CustomSetConfig(DeviceConfig config)
|
||||
{
|
||||
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsConferenceRoomPropertiesConfig>(config.Properties.ToString());
|
||||
|
||||
if (newPropertiesConfig != null)
|
||||
PropertiesConfig = newPropertiesConfig;
|
||||
|
||||
ConfigWriter.UpdateRoomConfig(config);
|
||||
}
|
||||
|
||||
public override bool CustomActivate()
|
||||
{
|
||||
// Add Occupancy object from config
|
||||
if (PropertiesConfig.Occupancy != null)
|
||||
{
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Setting Occupancy Provider for room");
|
||||
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
|
||||
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
|
||||
}
|
||||
|
||||
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
|
||||
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
|
||||
|
||||
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
|
||||
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
|
||||
|
||||
return base.CustomActivate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override void EndShutdown()
|
||||
{
|
||||
VideoCodec.EndAllCalls();
|
||||
|
||||
SetDefaultLevels();
|
||||
|
||||
RunDefaultPresentRoute();
|
||||
|
||||
CrestronEnvironment.Sleep(1000);
|
||||
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting down room");
|
||||
|
||||
RunRouteAction("roomOff");
|
||||
VideoCodec.StopSharing();
|
||||
VideoCodec.StandbyActivate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Routes the default source item, if any. Returns true when default route exists
|
||||
/// </summary>
|
||||
public override bool RunDefaultPresentRoute()
|
||||
{
|
||||
if (DefaultSourceItem != null)
|
||||
RunRouteAction(DefaultSourceItem);
|
||||
|
||||
return DefaultSourceItem != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the room when started into call mode without presenting a source
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool RunDefaultCallRoute()
|
||||
{
|
||||
RunRouteAction(DefaultCodecRouteString);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RunRouteActionCodec(string routeKey, string sourceListKey)
|
||||
{
|
||||
_codecExternalSourceChange = true;
|
||||
RunRouteAction(routeKey, sourceListKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="routeKey"></param>
|
||||
public void RunRouteAction(string routeKey)
|
||||
{
|
||||
RunRouteAction(routeKey, new Action(() => { }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="routeKey"></param>
|
||||
/// <param name="souceListKey"></param>
|
||||
/// <param name="successCallback"></param>
|
||||
public void RunRouteAction(string routeKey, string sourceListKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sourceListKey))
|
||||
{
|
||||
Debug.Console(1, this, "No sourceListKey present. RunRouteAction assumes default source list.");
|
||||
RunRouteAction(routeKey, new Action(() => { }));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "sourceListKey present but not yet implemented");
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="routeKey"></param>
|
||||
/// <param name="souceListKey"></param>
|
||||
/// <param name="successCallback"></param>
|
||||
public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sourceListKey))
|
||||
{
|
||||
RunRouteAction(routeKey, successCallback);
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a source from config list SourceListKey and dynamically build and executes the
|
||||
/// route or commands
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public void RunRouteAction(string routeKey, Action successCallback)
|
||||
{
|
||||
// Run this on a separate thread
|
||||
new CTimer(o =>
|
||||
{
|
||||
// try to prevent multiple simultaneous selections
|
||||
SourceSelectLock.TryEnter();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Run route action '{0}'", routeKey);
|
||||
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
|
||||
if (dict == null)
|
||||
{
|
||||
Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to get the list item by it's string key
|
||||
if (!dict.ContainsKey(routeKey))
|
||||
{
|
||||
Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'",
|
||||
routeKey, SourceListKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// End usage timer on last source
|
||||
if (!string.IsNullOrEmpty(LastSourceKey))
|
||||
{
|
||||
var usageLastSource = dict[LastSourceKey].SourceDevice as IUsageTracking;
|
||||
if (usageLastSource != null && usageLastSource.UsageTracker != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// There MAY have been failures in here. Protect
|
||||
usageLastSource.UsageTracker.EndDeviceUsage();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(1, this, "*#* EXCEPTION in end usage tracking:\r{0}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Let's run it
|
||||
var item = dict[routeKey];
|
||||
if (routeKey.ToLower() != "roomoff")
|
||||
{
|
||||
|
||||
LastSourceKey = routeKey;
|
||||
}
|
||||
else
|
||||
CurrentSourceInfoKey = null;
|
||||
|
||||
// hand off the individual routes to this helper
|
||||
foreach (var route in item.RouteList)
|
||||
DoRouteItem(route);
|
||||
|
||||
// Start usage timer on routed source
|
||||
var usageNewSource = item.SourceDevice as IUsageTracking;
|
||||
if (usageNewSource != null && usageNewSource.UsageTracker != null) // Have to make sure there is a usage tracker!
|
||||
{
|
||||
(item.SourceDevice as IUsageTracking).UsageTracker.StartDeviceUsage();
|
||||
}
|
||||
|
||||
// See if this can be moved into common, base-class method -------------
|
||||
|
||||
|
||||
// Set volume control, using default if non provided
|
||||
IBasicVolumeControls volDev = null;
|
||||
// Handle special cases for volume control
|
||||
if (string.IsNullOrEmpty(item.VolumeControlKey)
|
||||
|| item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase))
|
||||
volDev = DefaultVolumeControls;
|
||||
//else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
|
||||
// volDev = DefaultDisplay as IBasicVolumeControls;
|
||||
// Or a specific device, probably rarely used.
|
||||
else
|
||||
{
|
||||
var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey);
|
||||
if (dev is IBasicVolumeControls)
|
||||
volDev = dev as IBasicVolumeControls;
|
||||
else if (dev is IHasVolumeDevice)
|
||||
volDev = (dev as IHasVolumeDevice).VolumeDevice;
|
||||
}
|
||||
|
||||
if (volDev != CurrentVolumeControls)
|
||||
{
|
||||
// zero the volume on the device we are leaving.
|
||||
// Set the volume to default on device we are entering
|
||||
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
|
||||
{
|
||||
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
|
||||
SavedVolumeLevels[vd] = (uint)vd.VolumeLevelFeedback.IntValue;
|
||||
vd.SetVolume(0);
|
||||
}
|
||||
|
||||
CurrentVolumeControls = volDev;
|
||||
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
|
||||
{
|
||||
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
|
||||
ushort vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume);
|
||||
vd.SetVolume(vol);
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// store the name and UI info for routes
|
||||
if (item.SourceKey == "$off")
|
||||
{
|
||||
CurrentSourceInfoKey = routeKey;
|
||||
CurrentSourceInfo = null;
|
||||
}
|
||||
else if (item.SourceKey != null)
|
||||
{
|
||||
CurrentSourceInfoKey = routeKey;
|
||||
CurrentSourceInfo = item;
|
||||
}
|
||||
|
||||
OnFeedback.FireUpdate();
|
||||
|
||||
if (OnFeedback.BoolValue)
|
||||
{
|
||||
if (VideoCodec.UsageTracker.InUseTracker.InUseFeedback.BoolValue)
|
||||
{
|
||||
Debug.Console(1, this, "Video Codec in use, deactivating standby on codec");
|
||||
VideoCodec.StandbyDeactivate();
|
||||
}
|
||||
|
||||
if (VideoCodec.StandbyIsOnFeedback.BoolValue)
|
||||
{
|
||||
VideoCodec.StandbyDeactivate();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "Video codec not in standby. No need to wake.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "Room OnFeedback state: {0}", OnFeedback.BoolValue);
|
||||
}
|
||||
|
||||
// report back when done
|
||||
if (successCallback != null)
|
||||
successCallback();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(1, this, "ERROR in routing: {0}", e);
|
||||
}
|
||||
|
||||
SourceSelectLock.Leave();
|
||||
}, 0); // end of CTimer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="route"></param>
|
||||
void DoRouteItem(SourceRouteListItem route)
|
||||
{
|
||||
// if there is a $defaultAll on route, run two separate
|
||||
if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var display in Displays)
|
||||
{
|
||||
var tempVideo = new SourceRouteListItem
|
||||
{
|
||||
DestinationKey = display.Key,
|
||||
SourceKey = route.SourceKey,
|
||||
Type = eRoutingSignalType.Video
|
||||
};
|
||||
DoRoute(tempVideo);
|
||||
}
|
||||
}
|
||||
else
|
||||
DoRoute(route);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="route"></param>
|
||||
/// <returns></returns>
|
||||
bool DoRoute(SourceRouteListItem route)
|
||||
{
|
||||
IRoutingSink dest = null;
|
||||
|
||||
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
|
||||
dest = DefaultAudioDevice as IRoutingSink;
|
||||
//else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
|
||||
// dest = DefaultDisplay;
|
||||
else
|
||||
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink;
|
||||
|
||||
if (dest == null)
|
||||
{
|
||||
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
dest.ReleaseRoute();
|
||||
if (dest is IHasPowerControl)
|
||||
(dest as IHasPowerControl).PowerOff();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
|
||||
if (source == null)
|
||||
{
|
||||
Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey);
|
||||
return false;
|
||||
}
|
||||
dest.ReleaseAndMakeRoute(source, route.Type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void RoomVacatedForTimeoutPeriod(object o)
|
||||
{
|
||||
//Implement this
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does what it says
|
||||
/// </summary>
|
||||
public override void SetDefaultLevels()
|
||||
{
|
||||
Debug.Console(1, this, "Restoring default levels");
|
||||
var vc = CurrentVolumeControls as IBasicVolumeWithFeedback;
|
||||
if (vc != null)
|
||||
vc.SetVolume(DefaultVolume);
|
||||
}
|
||||
/// <summary>
|
||||
/// Will power the room on with the last-used source
|
||||
/// </summary>
|
||||
public override void PowerOnToDefaultOrLastSource()
|
||||
{
|
||||
if (!EnablePowerOnToLastSource || LastSourceKey == null)
|
||||
return;
|
||||
RunRouteAction(LastSourceKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions
|
||||
/// </summary>
|
||||
public static void AllRoomsOff()
|
||||
{
|
||||
var allRooms = DeviceManager.AllDevices.Where(d =>
|
||||
d is IEssentialsRoom && !(d as IEssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
|
||||
foreach (var room in allRooms)
|
||||
(room as IEssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Setup the external sources for the Cisco Touch 10 devices that support IHasExternalSourceSwitch
|
||||
/// </summary>
|
||||
private void SetCodecExternalSources()
|
||||
{
|
||||
var videoCodecWithExternalSwitching = VideoCodec as IHasExternalSourceSwitching;
|
||||
|
||||
if (videoCodecWithExternalSwitching == null || !videoCodecWithExternalSwitching.ExternalSourceListEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Get the tie line that the external switcher is connected to
|
||||
string codecInputConnectorName = ConfigReader.ConfigObject.TieLines.SingleOrDefault(
|
||||
x => x.DestinationKey == VideoCodec.Key && x.DestinationPort == videoCodecWithExternalSwitching.ExternalSourceInputPort).DestinationPort;
|
||||
|
||||
videoCodecWithExternalSwitching.ClearExternalSources();
|
||||
videoCodecWithExternalSwitching.RunRouteAction = RunRouteActionCodec;
|
||||
var srcList = ConfigReader.ConfigObject.SourceLists.SingleOrDefault(x => x.Key == SourceListKey).Value.OrderBy(kv => kv.Value.Order); ;
|
||||
|
||||
foreach (var kvp in srcList)
|
||||
{
|
||||
var srcConfig = kvp.Value;
|
||||
|
||||
if (kvp.Key != DefaultCodecRouteString && kvp.Key != "roomOff")
|
||||
{
|
||||
videoCodecWithExternalSwitching.AddExternalSource(codecInputConnectorName, kvp.Key, srcConfig.PreferredName, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType.desktop);
|
||||
videoCodecWithExternalSwitching.SetExternalSourceState(kvp.Key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode.Ready);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(2, this, "Error setting codec external sources: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCodecBranding()
|
||||
{
|
||||
var vcWithBranding = VideoCodec as IHasBranding;
|
||||
|
||||
if (vcWithBranding == null) return;
|
||||
|
||||
Debug.Console(1, this, "Setting Codec Branding");
|
||||
vcWithBranding.InitializeBranding(Key);
|
||||
}
|
||||
|
||||
#region IPrivacy Members
|
||||
|
||||
|
||||
public void PrivacyModeOff()
|
||||
{
|
||||
VideoCodec.PrivacyModeOff();
|
||||
}
|
||||
|
||||
public void PrivacyModeOn()
|
||||
{
|
||||
VideoCodec.PrivacyModeOn();
|
||||
}
|
||||
|
||||
public void PrivacyModeToggle()
|
||||
{
|
||||
VideoCodec.PrivacyModeToggle();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
}
|
||||
|
||||
public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
|
||||
public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; }
|
||||
|
||||
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
|
||||
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
|
||||
@@ -210,7 +210,7 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>
|
||||
(config.Properties.ToString());
|
||||
DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
|
||||
DefaultDisplay = DeviceManager.GetDeviceForKey((PropertiesConfig as EssentialsHuddleVtc1PropertiesConfig).DefaultDisplayKey) as IRoutingSinkWithSwitching;
|
||||
|
||||
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
|
||||
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
|
||||
|
||||
@@ -10,7 +10,9 @@ namespace PepperDash.Essentials
|
||||
public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange,
|
||||
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback
|
||||
{
|
||||
EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; }
|
||||
EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; }
|
||||
|
||||
bool ExcludeFromGlobalFunctions { get; }
|
||||
|
||||
void RunRouteAction(string routeKey);
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
public class EssentialsTouchpanelController : EssentialsDevice, IHasBasicTriListWithSmartObject
|
||||
{
|
||||
private CrestronTouchpanelPropertiesConfig _propertiesConfig;
|
||||
|
||||
public BasicTriListWithSmartObject Panel { get; private set; }
|
||||
|
||||
public PanelDriverBase PanelDriver { get; private set; }
|
||||
@@ -27,7 +29,14 @@ namespace PepperDash.Essentials
|
||||
: base(key, name)
|
||||
{
|
||||
Panel = tsw;
|
||||
tsw.LoadSmartObjects(sgdPath);
|
||||
|
||||
if (!string.IsNullOrEmpty(sgdPath))
|
||||
Panel.LoadSmartObjects(sgdPath);
|
||||
else
|
||||
Debug.Console(1, this, "No SGD file path defined");
|
||||
|
||||
|
||||
|
||||
tsw.SigChange += Panel_SigChange;
|
||||
}
|
||||
|
||||
@@ -37,7 +46,7 @@ namespace PepperDash.Essentials
|
||||
Panel = dge;
|
||||
|
||||
if (!string.IsNullOrEmpty(sgdPath))
|
||||
dge.LoadSmartObjects(sgdPath);
|
||||
Panel.LoadSmartObjects(sgdPath);
|
||||
else
|
||||
Debug.Console(1, this, "No SGD file path defined");
|
||||
|
||||
@@ -50,6 +59,7 @@ namespace PepperDash.Essentials
|
||||
public EssentialsTouchpanelController(string key, string name, string type, CrestronTouchpanelPropertiesConfig props, uint id)
|
||||
: base(key, name)
|
||||
{
|
||||
_propertiesConfig = props;
|
||||
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating touchpanel hardware...");
|
||||
type = type.ToLower();
|
||||
@@ -61,6 +71,8 @@ namespace PepperDash.Essentials
|
||||
app.ParameterProjectName.Value = props.ProjectName;
|
||||
Panel = app;
|
||||
}
|
||||
else if (type == "xpanel")
|
||||
Panel = new XpanelForSmartGraphics(id, Global.ControlSystem);
|
||||
else if (type == "tsw550")
|
||||
Panel = new Tsw550(id, Global.ControlSystem);
|
||||
else if (type == "tsw552")
|
||||
@@ -134,10 +146,194 @@ namespace PepperDash.Essentials
|
||||
Panel.LoadSmartObjects(sgdName);
|
||||
Panel.SigChange += Panel_SigChange;
|
||||
|
||||
AddPostActivationAction(() =>
|
||||
{
|
||||
// Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event
|
||||
var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner;
|
||||
|
||||
if (roomCombiner != null)
|
||||
{
|
||||
// Subscribe to the even
|
||||
roomCombiner.RoomCombinationScenarioChanged += new EventHandler<EventArgs>(roomCombiner_RoomCombinationScenarioChanged);
|
||||
|
||||
// Connect to the initial roomKey
|
||||
if (roomCombiner.CurrentScenario != null)
|
||||
{
|
||||
// Use the current scenario
|
||||
DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Current Scenario not yet set. Use default
|
||||
SetupPanelDrivers(_propertiesConfig.DefaultRoomKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No room combiner, use the default key
|
||||
SetupPanelDrivers(_propertiesConfig.DefaultRoomKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void roomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e)
|
||||
{
|
||||
var roomCombiner = sender as IEssentialsRoomCombiner;
|
||||
|
||||
DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the room key to use based on the scenario
|
||||
/// </summary>
|
||||
/// <param name="scenario"></param>
|
||||
void DetermineRoomKeyFromScenario(IRoomCombinationScenario scenario)
|
||||
{
|
||||
string newRoomKey = null;
|
||||
|
||||
if (scenario.UiMap.ContainsKey(Key))
|
||||
{
|
||||
newRoomKey = scenario.UiMap[Key];
|
||||
}
|
||||
else if (scenario.UiMap.ContainsKey(_propertiesConfig.DefaultRoomKey))
|
||||
{
|
||||
newRoomKey = scenario.UiMap[_propertiesConfig.DefaultRoomKey];
|
||||
}
|
||||
|
||||
SetupPanelDrivers(newRoomKey);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets up drivers and links them to the room specified
|
||||
/// </summary>
|
||||
/// <param name="roomKey">key of room to link the drivers to</param>
|
||||
void SetupPanelDrivers(string roomKey)
|
||||
{
|
||||
// Clear out any existing actions
|
||||
Panel.ClearAllSigActions();
|
||||
|
||||
Debug.Console(0, this, "Linking TP '{0}' to Room '{1}'", Key, roomKey);
|
||||
|
||||
var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, _propertiesConfig);
|
||||
// Then the sub drivers
|
||||
|
||||
// spin up different room drivers depending on room type
|
||||
var room = DeviceManager.GetDeviceForKey(roomKey);
|
||||
if (room is IEssentialsHuddleSpaceRoom)
|
||||
{
|
||||
// Screen Saver Driver
|
||||
|
||||
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, _propertiesConfig);
|
||||
|
||||
// Header Driver
|
||||
Debug.Console(0, this, "Adding header driver");
|
||||
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, _propertiesConfig);
|
||||
|
||||
// AV Driver
|
||||
Debug.Console(0, this, "Adding huddle space AV driver");
|
||||
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, _propertiesConfig);
|
||||
avDriver.DefaultRoomKey = roomKey;
|
||||
mainDriver.AvDriver = avDriver;
|
||||
avDriver.CurrentRoom = room as IEssentialsHuddleSpaceRoom;
|
||||
|
||||
// Environment Driver
|
||||
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
|
||||
{
|
||||
Debug.Console(0, this, "Adding environment driver");
|
||||
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, _propertiesConfig);
|
||||
|
||||
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
|
||||
}
|
||||
|
||||
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
|
||||
|
||||
if (Panel is TswFt5ButtonSystem)
|
||||
{
|
||||
var tsw = Panel as TswFt5ButtonSystem;
|
||||
// Wire up hard keys
|
||||
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.PowerButtonPressed(); });
|
||||
if (mainDriver.EnvironmentDriver != null)
|
||||
tsw.Lights.UserObject = new Action<bool>(b =>
|
||||
{
|
||||
if (!b)
|
||||
{
|
||||
mainDriver.EnvironmentDriver.Toggle();
|
||||
}
|
||||
});
|
||||
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
|
||||
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
|
||||
}
|
||||
}
|
||||
else if (room is IEssentialsHuddleVtc1Room)
|
||||
{
|
||||
Debug.Console(0, this, "Adding huddle space VTC AV driver");
|
||||
|
||||
// Screen Saver Driver
|
||||
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, _propertiesConfig);
|
||||
|
||||
// Header Driver
|
||||
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, _propertiesConfig);
|
||||
|
||||
// AV Driver
|
||||
var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, _propertiesConfig);
|
||||
|
||||
var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(Panel, avDriver,
|
||||
(room as IEssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver);
|
||||
avDriver.SetVideoCodecDriver(codecDriver);
|
||||
avDriver.DefaultRoomKey = roomKey;
|
||||
mainDriver.AvDriver = avDriver;
|
||||
avDriver.CurrentRoom = room as IEssentialsHuddleVtc1Room;
|
||||
|
||||
// Environment Driver
|
||||
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
|
||||
{
|
||||
Debug.Console(0, this, "Adding environment driver");
|
||||
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, _propertiesConfig);
|
||||
|
||||
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
|
||||
}
|
||||
|
||||
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
|
||||
|
||||
|
||||
if (Panel is TswFt5ButtonSystem)
|
||||
{
|
||||
var tsw = Panel as TswFt5ButtonSystem;
|
||||
// Wire up hard keys
|
||||
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.EndMeetingPress(); });
|
||||
if (mainDriver.EnvironmentDriver != null)
|
||||
tsw.Lights.UserObject = new Action<bool>(b =>
|
||||
{
|
||||
if (!b)
|
||||
{
|
||||
mainDriver.EnvironmentDriver.Toggle();
|
||||
}
|
||||
});
|
||||
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
|
||||
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
|
||||
}
|
||||
|
||||
LoadAndShowDriver(mainDriver);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(0, this, "ERROR: Cannot load AvFunctionsDriver for room '{0}'", roomKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void LoadAndShowDriver(PanelDriverBase driver)
|
||||
{
|
||||
if (PanelDriver != null)
|
||||
{
|
||||
var mainDriver = PanelDriver as EssentialsPanelMainInterfaceDriver;
|
||||
if (mainDriver != null)
|
||||
{
|
||||
mainDriver.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
PanelDriver = driver;
|
||||
driver.Show();
|
||||
}
|
||||
@@ -148,7 +344,6 @@ namespace PepperDash.Essentials
|
||||
PanelDriver.BackButtonPressed();
|
||||
}
|
||||
|
||||
|
||||
void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args)
|
||||
{
|
||||
// If the sig is transitioning on, mark it in case it was home button that transitioned it
|
||||
@@ -225,119 +420,6 @@ namespace PepperDash.Essentials
|
||||
|
||||
var panelController = new EssentialsTouchpanelController(dc.Key, dc.Name, dc.Type, props, comm.IpIdInt);
|
||||
|
||||
panelController.AddPostActivationAction(() =>
|
||||
{
|
||||
var mainDriver = new EssentialsPanelMainInterfaceDriver(panelController.Panel, props);
|
||||
// Then the sub drivers
|
||||
|
||||
// spin up different room drivers depending on room type
|
||||
var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey);
|
||||
if (room is IEssentialsHuddleSpaceRoom)
|
||||
{
|
||||
// Screen Saver Driver
|
||||
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, props);
|
||||
|
||||
// Header Driver
|
||||
Debug.Console(0, panelController, "Adding header driver");
|
||||
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, props);
|
||||
|
||||
// AV Driver
|
||||
Debug.Console(0, panelController, "Adding huddle space AV driver");
|
||||
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, props);
|
||||
avDriver.DefaultRoomKey = props.DefaultRoomKey;
|
||||
mainDriver.AvDriver = avDriver;
|
||||
avDriver.CurrentRoom = room as IEssentialsHuddleSpaceRoom;
|
||||
|
||||
// Environment Driver
|
||||
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
|
||||
{
|
||||
Debug.Console(0, panelController, "Adding environment driver");
|
||||
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, props);
|
||||
|
||||
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
|
||||
}
|
||||
|
||||
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
|
||||
|
||||
panelController.LoadAndShowDriver(mainDriver); // This is a little convoluted.
|
||||
|
||||
if (panelController.Panel is TswFt5ButtonSystem)
|
||||
{
|
||||
var tsw = panelController.Panel as TswFt5ButtonSystem;
|
||||
// Wire up hard keys
|
||||
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.PowerButtonPressed(); });
|
||||
//tsw.Home.UserObject = new Action<bool>(b => { if (!b) HomePressed(); });
|
||||
if (mainDriver.EnvironmentDriver != null)
|
||||
tsw.Lights.UserObject = new Action<bool>(b =>
|
||||
{
|
||||
if (!b)
|
||||
{
|
||||
//mainDriver.AvDriver.PopupInterlock.ShowInterlockedWithToggle(mainDriver.EnvironmentDriver.BackgroundSubpageJoin);
|
||||
mainDriver.EnvironmentDriver.Toggle();
|
||||
}
|
||||
});
|
||||
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
|
||||
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
|
||||
}
|
||||
}
|
||||
else if (room is IEssentialsHuddleVtc1Room)
|
||||
{
|
||||
Debug.Console(0, panelController, "Adding huddle space VTC AV driver");
|
||||
|
||||
// Screen Saver Driver
|
||||
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, props);
|
||||
|
||||
// Header Driver
|
||||
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, props);
|
||||
|
||||
// AV Driver
|
||||
var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, props);
|
||||
|
||||
var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(panelController.Panel, avDriver,
|
||||
(room as IEssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver);
|
||||
avDriver.SetVideoCodecDriver(codecDriver);
|
||||
avDriver.DefaultRoomKey = props.DefaultRoomKey;
|
||||
mainDriver.AvDriver = avDriver;
|
||||
avDriver.CurrentRoom = room as IEssentialsHuddleVtc1Room;
|
||||
|
||||
// Environment Driver
|
||||
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
|
||||
{
|
||||
Debug.Console(0, panelController, "Adding environment driver");
|
||||
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, props);
|
||||
|
||||
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
|
||||
}
|
||||
|
||||
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
|
||||
|
||||
panelController.LoadAndShowDriver(mainDriver); // This is a little convoluted.
|
||||
|
||||
if (panelController.Panel is TswFt5ButtonSystem)
|
||||
{
|
||||
var tsw = panelController.Panel as TswFt5ButtonSystem;
|
||||
// Wire up hard keys
|
||||
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.EndMeetingPress(); });
|
||||
//tsw.Home.UserObject = new Action<bool>(b => { if (!b) HomePressed(); });
|
||||
if (mainDriver.EnvironmentDriver != null)
|
||||
tsw.Lights.UserObject = new Action<bool>(b =>
|
||||
{
|
||||
if (!b)
|
||||
{
|
||||
//mainDriver.AvDriver.PopupInterlock.ShowInterlockedWithToggle(mainDriver.EnvironmentDriver.BackgroundSubpageJoin);
|
||||
mainDriver.EnvironmentDriver.Toggle();
|
||||
}
|
||||
});
|
||||
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
|
||||
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(0, panelController, "ERROR: Cannot load AvFunctionsDriver for room '{0}'", props.DefaultRoomKey);
|
||||
}
|
||||
});
|
||||
|
||||
return panelController;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
public SourceListItem SourceItem { get; private set; }
|
||||
|
||||
private IHasCurrentSourceInfoChange _room;
|
||||
|
||||
public SubpageReferenceListSourceItem(uint index, SubpageReferenceList owner,
|
||||
SourceListItem sourceItem, Action<bool> routeAction)
|
||||
: base(index, owner)
|
||||
@@ -25,6 +27,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
public void RegisterForSourceChange(IHasCurrentSourceInfoChange room)
|
||||
{
|
||||
_room = room;
|
||||
room.CurrentSourceChange -= room_CurrentSourceInfoChange;
|
||||
room.CurrentSourceChange += room_CurrentSourceInfoChange;
|
||||
}
|
||||
@@ -44,6 +47,9 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
Owner.BoolInputSig(Index, 1).UserObject = null;
|
||||
Owner.StringInputSig(Index, 1).StringValue = "";
|
||||
|
||||
if(_room != null)
|
||||
_room.CurrentSourceChange -= room_CurrentSourceInfoChange;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace PepperDash.Essentials
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class EssentialsPanelMainInterfaceDriver : PanelDriverBase, IHasScreenSaverController
|
||||
public class EssentialsPanelMainInterfaceDriver : PanelDriverBase, IHasScreenSaverController, IDisposable
|
||||
{
|
||||
CTimer InactivityTimer;
|
||||
|
||||
@@ -69,6 +69,35 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var avDriver = AvDriver as PanelDriverBase;
|
||||
if (avDriver != null)
|
||||
{
|
||||
avDriver.Hide();
|
||||
}
|
||||
if (ScreenSaverController != null)
|
||||
{
|
||||
ScreenSaverController.Dispose();
|
||||
}
|
||||
if (HeaderDriver != null)
|
||||
{
|
||||
HeaderDriver.Hide();
|
||||
}
|
||||
if (EnvironmentDriver != null)
|
||||
{
|
||||
EnvironmentDriver.Hide();
|
||||
}
|
||||
if (CurrentChildDriver != null)
|
||||
{
|
||||
CurrentChildDriver.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
void ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange(Crestron.SimplSharpPro.DeviceExtender currentDeviceExtender, Crestron.SimplSharpPro.SigEventArgs args)
|
||||
{
|
||||
|
||||
@@ -130,7 +159,7 @@ namespace PepperDash.Essentials
|
||||
if(CurrentChildDriver != null)
|
||||
CurrentChildDriver.BackButtonPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IHasScreenSaverController
|
||||
{
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () =>
|
||||
{
|
||||
if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
|
||||
if (CurrentRoom != null && CurrentRoom.DefaultDisplay != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
|
||||
(CurrentRoom.DefaultDisplay as IHasPowerControl).PowerToggle();
|
||||
});
|
||||
|
||||
|
||||
@@ -354,7 +354,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () =>
|
||||
{
|
||||
if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
|
||||
if (CurrentRoom != null && CurrentRoom.DefaultDisplay != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
|
||||
(CurrentRoom.DefaultDisplay as IHasPowerControl).PowerToggle();
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace PepperDash.Essentials
|
||||
/// <summary>
|
||||
/// Driver responsible for controlling the screenshaver showing the client logo, MC connection information and QR Code. Moves the elements around to prevent screen burn in
|
||||
/// </summary>
|
||||
public class ScreenSaverController : PanelDriverBase
|
||||
public class ScreenSaverController : PanelDriverBase, IDisposable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
@@ -42,7 +42,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
PositionInterlock = new JoinedSigInterlock(parent.TriList);
|
||||
|
||||
var cmdName = String.Format("shwscrsvr-{0}", parent.TriList.ID);
|
||||
var cmdName = String.Format("shwscrsvr-{0:X2}", parent.TriList.ID);
|
||||
|
||||
CrestronConsole.AddNewConsoleCommand((o) => Show(), cmdName, "Shows Panel Screensaver", ConsoleAccessLevelEnum.AccessOperator);
|
||||
|
||||
@@ -51,6 +51,8 @@ namespace PepperDash.Essentials
|
||||
|
||||
public override void Show()
|
||||
{
|
||||
Debug.Console(2, "Showing ScreenSaverController: {0:X2}", TriList.ID);
|
||||
|
||||
if (_parent.AvDriver != null)
|
||||
{
|
||||
_parent.AvDriver.PopupInterlock.ShowInterlocked(UIBoolJoin.MCScreenSaverVisible);
|
||||
@@ -65,10 +67,11 @@ namespace PepperDash.Essentials
|
||||
|
||||
public override void Hide()
|
||||
{
|
||||
Debug.Console(1, "Hiding ScreenSaverController");
|
||||
Debug.Console(2, "Hiding ScreenSaverController: {0:X2}", TriList.ID);
|
||||
|
||||
if (PositionTimer != null)
|
||||
{
|
||||
Debug.Console(2, "Stopping PositionTimer: {0:X2}", TriList.ID);
|
||||
PositionTimer.Stop();
|
||||
PositionTimer.Dispose();
|
||||
PositionTimer = null;
|
||||
@@ -86,6 +89,8 @@ namespace PepperDash.Essentials
|
||||
|
||||
void StartPositionTimer()
|
||||
{
|
||||
Debug.Console(2, "Starting Position Timer: {0:X2}", TriList.ID);
|
||||
|
||||
if (PositionTimer == null)
|
||||
{
|
||||
PositionTimer = new CTimer((o) => PositionTimerExpired(), PositionTimeoutMs);
|
||||
@@ -117,7 +122,7 @@ namespace PepperDash.Essentials
|
||||
CurrentPositionIndex = 0;
|
||||
}
|
||||
|
||||
Debug.Console(1, "ScreenSaver Position Timer Expired: Setting new position: {0}", CurrentPositionIndex);
|
||||
Debug.Console(2, "ScreenSaver Position Timer Expired: Setting new position: {0} ID: {1:X2}", CurrentPositionIndex, TriList.ID);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -129,9 +134,19 @@ namespace PepperDash.Essentials
|
||||
|
||||
void ClearAllPositions()
|
||||
{
|
||||
Debug.Console(1, "Hiding all screensaver positions");
|
||||
Debug.Console(2, "Hiding all screensaver positions: {0:X2}", TriList.ID);
|
||||
|
||||
PositionInterlock.HideAndClear();
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
@@ -632,7 +632,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
|
||||
|
||||
VCControlsInterlock.StatusChanged += new EventHandler<StatusChangedEventArgs>(VCControlsInterlock_StatusChanged);
|
||||
|
||||
|
||||
var codecOffCameras = Codec as IHasCameraOff;
|
||||
|
||||
var supportsCameraOffMode = Codec.SupportsCameraOff;
|
||||
@@ -643,6 +642,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
|
||||
|
||||
if (codecAutoCameras != null && supportsAutoCameraMode)
|
||||
{
|
||||
|
||||
CameraModeList.SetItemButtonAction(1,(b) => codecAutoCameras.CameraAutoModeOn());
|
||||
TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 1 Visible"].BoolValue = true;
|
||||
codecAutoCameras.CameraAutoModeIsOnFeedback.LinkInputSig(CameraModeList.SmartObject.BooleanInput["Item 1 Selected"]);
|
||||
@@ -672,6 +672,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Manual button always visible
|
||||
@@ -683,6 +684,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
|
||||
|
||||
if (codecOffCameras != null && supportsCameraOffMode)
|
||||
{
|
||||
|
||||
TriList.SmartObjects[UISmartObjectJoin.VCCameraMode].BooleanInput["Item 3 Visible"].BoolValue = true;
|
||||
codecOffCameras.CameraIsOffFeedback.LinkInputSig(CameraModeList.SmartObject.BooleanInput["Item 3 Selected"]);
|
||||
CameraModeList.SetItemButtonAction(3, (b) => codecOffCameras.CameraOff());
|
||||
@@ -710,6 +712,7 @@ namespace PepperDash.Essentials.UIDrivers.VC
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,3 +42,6 @@ devjson:2 {"deviceKey":"display01Comm-com", "methodName":"SendText", "params": [
|
||||
|
||||
devjson:10 {"deviceKey":"dmLink-ssh", "methodName":"Connect", "params": []}
|
||||
|
||||
devjson:2 {"deviceKey":"roomCombiner", "methodName":"SetRoomCombinationScenario", "params": ["combined"]}
|
||||
|
||||
devjson:2 {"deviceKey":"roomCombiner", "methodName":"SetRoomCombinationScenario", "params": ["divided"]}
|
||||
@@ -10,7 +10,7 @@ namespace PepperDash.Essentials.Core.Bridges
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "DM Chassis enable audio breakaway routing",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
JoinCapabilities = eJoinCapabilities.FromSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace PepperDash.Essentials.Core.Bridges
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "DM Chassis enable USB breakaway routing",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
JoinCapabilities = eJoinCapabilities.FromSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Bridges
|
||||
{
|
||||
public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced
|
||||
{
|
||||
namespace PepperDash.Essentials.Core.Bridges
|
||||
{
|
||||
public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced
|
||||
{
|
||||
[JoinName("SystemPowerOn")]
|
||||
public JoinDataComplete SystemPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 },
|
||||
new JoinMetadata { Description = "DMPS System Power On Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
|
||||
|
||||
[JoinName("SystemPowerOff")]
|
||||
public JoinDataComplete SystemPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 },
|
||||
new JoinMetadata { Description = "DMPS System Power Off Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
|
||||
|
||||
[JoinName("VideoSyncStatus")]
|
||||
public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 },
|
||||
new JoinMetadata { Description = "DM Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
|
||||
@@ -61,5 +69,5 @@ namespace PepperDash.Essentials.Core.Bridges
|
||||
protected DmpsRoutingControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,19 +69,28 @@ namespace PepperDash.Essentials.Core
|
||||
public override bool CustomActivate()
|
||||
{
|
||||
Debug.Console(0, this, "Activating");
|
||||
if (!PreventRegistration)
|
||||
{
|
||||
if (!PreventRegistration)
|
||||
{
|
||||
//Debug.Console(1, this, " Does not require registration. Skipping");
|
||||
|
||||
var response = Hardware.RegisterWithLogging(Key);
|
||||
if (response != eDeviceRegistrationUnRegistrationResponse.Success)
|
||||
{
|
||||
//Debug.Console(0, this, "ERROR: Cannot register Crestron device: {0}", response);
|
||||
return false;
|
||||
}
|
||||
var response = Hardware.RegisterWithLogging(Key);
|
||||
if (response != eDeviceRegistrationUnRegistrationResponse.Success)
|
||||
{
|
||||
//Debug.Console(0, this, "ERROR: Cannot register Crestron device: {0}", response);
|
||||
return false;
|
||||
}
|
||||
|
||||
IsRegistered.FireUpdate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddPostActivationAction(() =>
|
||||
{
|
||||
var response = Hardware.RegisterWithLogging(Key);
|
||||
|
||||
IsRegistered.FireUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var f in Feedbacks)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public DescriptionAttribute(string description)
|
||||
{
|
||||
Debug.Console(2, "Setting Description: {0}", description);
|
||||
//Debug.Console(2, "Setting Description: {0}", description);
|
||||
_Description = description;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public ConfigSnippetAttribute(string configSnippet)
|
||||
{
|
||||
Debug.Console(2, "Setting Config Snippet {0}", configSnippet);
|
||||
//Debug.Console(2, "Setting Config Snippet {0}", configSnippet);
|
||||
_ConfigSnippet = configSnippet;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
foreach (var typeName in TypeNames)
|
||||
{
|
||||
Debug.Console(2, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
|
||||
//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[];
|
||||
|
||||
@@ -69,13 +69,13 @@ namespace PepperDash.Essentials.Core
|
||||
/// <returns></returns>
|
||||
public static void AddFactoryForType(string typeName, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
Debug.Console(1, Debug.ErrorLogLevel.Notice, "Adding factory method for type '{0}'", typeName);
|
||||
//Debug.Console(1, Debug.ErrorLogLevel.Notice, "Adding factory method for type '{0}'", typeName);
|
||||
DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
|
||||
}
|
||||
|
||||
public static void AddFactoryForType(string typeName, string description, CType cType, Func<DeviceConfig, IKeyed> method)
|
||||
{
|
||||
Debug.Console(1, Debug.ErrorLogLevel.Notice, "Adding factory method for type '{0}'", typeName);
|
||||
//Debug.Console(1, Debug.ErrorLogLevel.Notice, "Adding factory method for type '{0}'", typeName);
|
||||
|
||||
if(FactoryMethods.ContainsKey(typeName))
|
||||
{
|
||||
|
||||
@@ -32,6 +32,27 @@ namespace PepperDash.Essentials.Core
|
||||
// TODO: consider making this configurable later
|
||||
public static IFormatProvider Culture = CultureInfo.CreateSpecificCulture("en-US");
|
||||
|
||||
/// <summary>
|
||||
/// True when the processor type is a DMPS variant
|
||||
/// </summary>
|
||||
public static bool ControlSystemIsDmpsType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ControlSystem.ControllerPrompt.ToLower().IndexOf("dmps") > -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True when the processor type is a DMPS 4K variant
|
||||
/// </summary>
|
||||
public static bool ControlSystemIsDmps4kType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ControlSystemIsDmpsType && ControlSystem.ControllerPrompt.ToLower().IndexOf("4k") > -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The file path prefix to the folder containing configuration files
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace PepperDash.Essentials
|
||||
/// <param name="fileName"></param>
|
||||
static LoadedAssembly LoadAssembly(string filePath)
|
||||
{
|
||||
Debug.Console(2, "Attempting to load {0}", filePath);
|
||||
//Debug.Console(2, "Attempting to load {0}", filePath);
|
||||
var assembly = Assembly.LoadFrom(filePath);
|
||||
if (assembly != null)
|
||||
{
|
||||
|
||||
@@ -54,13 +54,20 @@ namespace PepperDash.Essentials.Core
|
||||
SetupPartitionStateProviders();
|
||||
|
||||
SetRooms();
|
||||
|
||||
if (isInAutoMode)
|
||||
{
|
||||
DetermineRoomCombinationScenario();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRoomCombinationScenario(_propertiesConfig.defaultScenarioKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CreateScenarios()
|
||||
{
|
||||
RoomCombinationScenarios = new List<IRoomCombinationScenario>();
|
||||
|
||||
foreach (var scenarioConfig in _propertiesConfig.Scenarios)
|
||||
{
|
||||
var scenario = new RoomCombinationScenario(scenarioConfig);
|
||||
@@ -160,12 +167,26 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
return _currentScenario;
|
||||
}
|
||||
set
|
||||
private set
|
||||
{
|
||||
if (value != _currentScenario)
|
||||
{
|
||||
// Deactivate the old scenario first
|
||||
if (_currentScenario != null)
|
||||
{
|
||||
_currentScenario.Deactivate();
|
||||
}
|
||||
|
||||
_currentScenario = value;
|
||||
Debug.Console(1, this, "Current Scenario: {0}", _currentScenario.Name);
|
||||
|
||||
// Activate the new scenario
|
||||
if (_currentScenario != null)
|
||||
{
|
||||
_currentScenario.Activate();
|
||||
|
||||
Debug.Console(1, this, "Current Scenario: {0}", _currentScenario.Name);
|
||||
}
|
||||
|
||||
var handler = RoomCombinationScenarioChanged;
|
||||
if (handler != null)
|
||||
{
|
||||
@@ -220,9 +241,11 @@ namespace PepperDash.Essentials.Core
|
||||
// Get the scenario
|
||||
var scenario = RoomCombinationScenarios.FirstOrDefault((s) => s.Key.Equals(scenarioKey));
|
||||
|
||||
|
||||
// Set the parition states from the scenario manually
|
||||
if (scenario != null)
|
||||
{
|
||||
Debug.Console(0, this, "Manually setting scenario to '{0}'", scenario.Key);
|
||||
foreach (var partitionState in scenario.PartitionStates)
|
||||
{
|
||||
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey));
|
||||
@@ -231,15 +254,25 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
if (partitionState.PartitionPresent)
|
||||
{
|
||||
Debug.Console(0, this, "Manually setting state to Present for: '{0}'", partition.Key);
|
||||
partition.SetPartitionStatePresent();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(0, this, "Manually setting state to Not Present for: '{0}'", partition.Key);
|
||||
partition.SetPartitionStateNotPresent();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "Unable to find partition with key: '{0}'", partitionState.PartitionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "Unable to find scenario with key: '{0}'", scenarioKey);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace PepperDash.Essentials.Core
|
||||
/// <summary>
|
||||
/// The list of rooms keys that can be combined
|
||||
/// </summary>
|
||||
[JsonProperty("roomMap")]
|
||||
[JsonProperty("roomKeys")]
|
||||
public List<string> RoomKeys {get; set;}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,6 +87,9 @@ namespace PepperDash.Essentials.Core
|
||||
[JsonProperty("partitionStates")]
|
||||
public List<PartitionState> PartitionStates { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines which UI devices get mapped to which room in this scenario. The Key should be the key of the UI device and the Value should be the key of the room to map to
|
||||
/// </summary>
|
||||
[JsonProperty("uiMap")]
|
||||
public Dictionary<string, string> UiMap { get; set; }
|
||||
|
||||
|
||||
@@ -78,6 +78,11 @@ namespace PepperDash.Essentials.Core
|
||||
/// </summary>
|
||||
void Activate();
|
||||
|
||||
/// <summary>
|
||||
/// Deactivates this room combination scenario
|
||||
/// </summary>
|
||||
void Deactivate();
|
||||
|
||||
/// <summary>
|
||||
/// The state of the partitions that would activate this scenario
|
||||
/// </summary>
|
||||
|
||||
@@ -4,6 +4,8 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
@@ -27,9 +29,9 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public BoolFeedback IsActiveFeedback { get; private set; }
|
||||
|
||||
List<DeviceActionWrapper> activationActions;
|
||||
private List<DeviceActionWrapper> activationActions;
|
||||
|
||||
List<DeviceActionWrapper> deactivationActions;
|
||||
private List<DeviceActionWrapper> deactivationActions;
|
||||
|
||||
public RoomCombinationScenario(RoomCombinationScenarioConfig config)
|
||||
{
|
||||
@@ -52,6 +54,8 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
Debug.Console(1, "Activating Scenario: '{0}' with {1} action(s) defined", Name, activationActions.Count);
|
||||
|
||||
if (activationActions != null)
|
||||
{
|
||||
foreach (var action in activationActions)
|
||||
@@ -66,6 +70,8 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
Debug.Console(1, "Deactivating Scenario: '{0}' with {1} action(s) defined", Name, deactivationActions.Count);
|
||||
|
||||
if (deactivationActions != null)
|
||||
{
|
||||
foreach (var action in deactivationActions)
|
||||
|
||||
@@ -206,6 +206,27 @@ namespace PepperDash.Essentials.Core
|
||||
return ClearSigAction(tl.StringOutput[sigNum]) as StringOutputSig;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all actions on all sigs
|
||||
/// </summary>
|
||||
public static void ClearAllSigActions(this BasicTriList t1)
|
||||
{
|
||||
foreach (var sig in t1.BooleanOutput)
|
||||
{
|
||||
ClearSigAction(sig);
|
||||
}
|
||||
|
||||
foreach (var sig in t1.UShortOutput)
|
||||
{
|
||||
ClearSigAction(sig);
|
||||
}
|
||||
|
||||
foreach (var sig in t1.StringOutput)
|
||||
{
|
||||
ClearSigAction(sig);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to set the value of a bool Sig on TriList
|
||||
/// </summary>
|
||||
|
||||
@@ -25,9 +25,16 @@ namespace PepperDash.Essentials.DM
|
||||
|
||||
public CrestronControlSystem Dmps { get; set; }
|
||||
public ISystemControl SystemControl { get; private set; }
|
||||
|
||||
//Check if DMPS is a DMPS3-4K type for endpoint creation
|
||||
public bool Dmps4kType { get; private set; }
|
||||
|
||||
//IroutingNumericEvent
|
||||
public event EventHandler<RoutingNumericEventArgs> NumericSwitchChange;
|
||||
|
||||
//Feedback for DMPS System Power
|
||||
public BoolFeedback SystemPowerOnFeedback { get; private set; }
|
||||
public BoolFeedback SystemPowerOffFeedback { get; private set; }
|
||||
|
||||
// Feedbacks for EssentialDM
|
||||
public Dictionary<uint, IntFeedback> VideoOutputFeedbacks { get; private set; }
|
||||
@@ -112,10 +119,29 @@ namespace PepperDash.Essentials.DM
|
||||
/// <param name="chassis"></param>
|
||||
public DmpsRoutingController(string key, string name, ISystemControl systemControl)
|
||||
: base(key, name)
|
||||
{
|
||||
|
||||
{
|
||||
Dmps = Global.ControlSystem;
|
||||
SystemControl = systemControl;
|
||||
|
||||
switch (name.Replace("-", "").Replace("c", "").Replace("C", ""))
|
||||
{
|
||||
case "dmps34k50":
|
||||
case "dmps34k100":
|
||||
case "dmps34k150":
|
||||
SystemControl = systemControl as Dmps34K150CSystemControl;
|
||||
Dmps4kType = true;
|
||||
break;
|
||||
case "dmps34k200":
|
||||
case "dmps34k250":
|
||||
case "dmps34k300":
|
||||
case "dmps34k350":
|
||||
SystemControl = systemControl as Dmps34K300CSystemControl;
|
||||
Dmps4kType = true;
|
||||
break;
|
||||
default:
|
||||
SystemControl = systemControl as Dmps3SystemControl;
|
||||
Dmps4kType = false;
|
||||
break;
|
||||
}
|
||||
|
||||
InputPorts = new RoutingPortCollection<RoutingInputPort>();
|
||||
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
|
||||
@@ -123,6 +149,29 @@ namespace PepperDash.Essentials.DM
|
||||
TxDictionary = new Dictionary<uint, string>();
|
||||
RxDictionary = new Dictionary<uint, string>();
|
||||
|
||||
SystemPowerOnFeedback = new BoolFeedback(() =>
|
||||
{
|
||||
if (SystemControl is Dmps3SystemControl)
|
||||
{
|
||||
return ((Dmps3SystemControl)SystemControl).SystemPowerOnFeedBack.BoolValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
SystemPowerOffFeedback = new BoolFeedback(() =>
|
||||
{
|
||||
if (SystemControl is Dmps3SystemControl)
|
||||
{
|
||||
return ((Dmps3SystemControl)SystemControl).SystemPowerOffFeedBack.BoolValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
VideoOutputFeedbacks = new Dictionary<uint, IntFeedback>();
|
||||
AudioOutputFeedbacks = new Dictionary<uint, IntFeedback>();
|
||||
VideoInputSyncFeedbacks = new Dictionary<uint, BoolFeedback>();
|
||||
@@ -154,6 +203,7 @@ namespace PepperDash.Essentials.DM
|
||||
// Subscribe to events
|
||||
Dmps.DMInputChange += Dmps_DMInputChange;
|
||||
Dmps.DMOutputChange += Dmps_DMOutputChange;
|
||||
Dmps.DMSystemChange += Dmps_DMSystemChange;
|
||||
|
||||
return base.CustomActivate();
|
||||
}
|
||||
@@ -191,6 +241,22 @@ namespace PepperDash.Essentials.DM
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPowerOn(bool a)
|
||||
{
|
||||
if (SystemControl is Dmps3SystemControl)
|
||||
{
|
||||
((Dmps3SystemControl)SystemControl).SystemPowerOn();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPowerOff(bool a)
|
||||
{
|
||||
if (SystemControl is Dmps3SystemControl)
|
||||
{
|
||||
((Dmps3SystemControl)SystemControl).SystemPowerOff();
|
||||
}
|
||||
}
|
||||
|
||||
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
||||
{
|
||||
var joinMap = new DmpsRoutingControllerJoinMap(joinStart);
|
||||
@@ -211,9 +277,22 @@ namespace PepperDash.Essentials.DM
|
||||
|
||||
Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
|
||||
|
||||
//Link up system
|
||||
trilist.SetBoolSigAction(joinMap.SystemPowerOn.JoinNumber, SetPowerOn);
|
||||
trilist.SetBoolSigAction(joinMap.SystemPowerOff.JoinNumber, SetPowerOff);
|
||||
if (SystemPowerOnFeedback != null)
|
||||
{
|
||||
SystemPowerOnFeedback.LinkInputSig(
|
||||
trilist.BooleanInput[joinMap.SystemPowerOn.JoinNumber]);
|
||||
}
|
||||
if (SystemPowerOffFeedback != null)
|
||||
{
|
||||
SystemPowerOffFeedback.LinkInputSig(
|
||||
trilist.BooleanInput[joinMap.SystemPowerOff.JoinNumber]);
|
||||
}
|
||||
|
||||
// Link up outputs
|
||||
LinkInputsToApi(trilist, joinMap);
|
||||
|
||||
LinkOutputsToApi(trilist, joinMap);
|
||||
}
|
||||
|
||||
@@ -719,28 +798,36 @@ namespace PepperDash.Essentials.DM
|
||||
|
||||
void Dmps_DMInputChange(Switch device, DMInputEventArgs args)
|
||||
{
|
||||
//Debug.Console(2, this, "DMSwitch:{0} Input:{1} Event:{2}'", this.Name, args.Number, args.EventId.ToString());
|
||||
|
||||
switch (args.EventId)
|
||||
try
|
||||
{
|
||||
case (DMInputEventIds.OnlineFeedbackEventId):
|
||||
{
|
||||
Debug.Console(2, this, "DM Input OnlineFeedbackEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback);
|
||||
InputEndpointOnlineFeedbacks[args.Number].FireUpdate();
|
||||
break;
|
||||
}
|
||||
case (DMInputEventIds.VideoDetectedEventId):
|
||||
{
|
||||
Debug.Console(2, this, "DM Input {0} VideoDetectedEventId", args.Number);
|
||||
VideoInputSyncFeedbacks[args.Number].FireUpdate();
|
||||
break;
|
||||
}
|
||||
case (DMInputEventIds.InputNameEventId):
|
||||
{
|
||||
Debug.Console(2, this, "DM Input {0} NameFeedbackEventId", args.Number);
|
||||
InputNameFeedbacks[args.Number].FireUpdate();
|
||||
break;
|
||||
}
|
||||
switch (args.EventId)
|
||||
{
|
||||
case (DMInputEventIds.OnlineFeedbackEventId):
|
||||
{
|
||||
Debug.Console(2, this, "DM Input OnlineFeedbackEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback);
|
||||
InputEndpointOnlineFeedbacks[args.Number].FireUpdate();
|
||||
break;
|
||||
}
|
||||
case (DMInputEventIds.VideoDetectedEventId):
|
||||
{
|
||||
Debug.Console(2, this, "DM Input {0} VideoDetectedEventId", args.Number);
|
||||
VideoInputSyncFeedbacks[args.Number].FireUpdate();
|
||||
break;
|
||||
}
|
||||
case (DMInputEventIds.InputNameEventId):
|
||||
{
|
||||
Debug.Console(2, this, "DM Input {0} NameFeedbackEventId", args.Number);
|
||||
if(InputNameFeedbacks.ContainsKey(args.Number))
|
||||
{
|
||||
InputNameFeedbacks[args.Number].FireUpdate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "DMSwitch Input Change:{0} Input:{1} Event:{2}\rException: {3}", this.Name, args.Number, args.EventId.ToString(), e.ToString());
|
||||
}
|
||||
}
|
||||
void Dmps_DMOutputChange(Switch device, DMOutputEventArgs args)
|
||||
@@ -812,6 +899,23 @@ namespace PepperDash.Essentials.DM
|
||||
|
||||
}
|
||||
|
||||
void Dmps_DMSystemChange(Switch device, DMSystemEventArgs args)
|
||||
{
|
||||
switch (args.EventId)
|
||||
{
|
||||
case DMSystemEventIds.SystemPowerOnEventId:
|
||||
{
|
||||
SystemPowerOnFeedback.FireUpdate();
|
||||
break;
|
||||
}
|
||||
case DMSystemEventIds.SystemPowerOffEventId:
|
||||
{
|
||||
SystemPowerOffFeedback.FireUpdate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@@ -879,7 +983,6 @@ namespace PepperDash.Essentials.DM
|
||||
// NOTE THAT BITWISE COMPARISONS - TO CATCH ALL ROUTING TYPES
|
||||
if ((sigType & eRoutingSignalType.Video) == eRoutingSignalType.Video)
|
||||
{
|
||||
|
||||
output.VideoOut = input;
|
||||
}
|
||||
|
||||
@@ -903,7 +1006,6 @@ namespace PepperDash.Essentials.DM
|
||||
|
||||
if ((sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput)
|
||||
{
|
||||
|
||||
output.USBRoutedTo = input;
|
||||
}
|
||||
|
||||
|
||||
@@ -329,7 +329,14 @@ namespace PepperDash.Essentials.DM
|
||||
var parentDev = DeviceManager.GetDeviceForKey(pKey);
|
||||
if (parentDev is DmpsRoutingController)
|
||||
{
|
||||
return GetDmRmcControllerForDmps(key, name, typeName, parentDev as DmpsRoutingController, props.ParentOutputNumber);
|
||||
if ((parentDev as DmpsRoutingController).Dmps4kType)
|
||||
{
|
||||
return GetDmRmcControllerForDmps4k(key, name, typeName, parentDev as DmpsRoutingController, props.ParentOutputNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetDmRmcControllerForDmps(key, name, typeName, ipid, parentDev as DmpsRoutingController, props.ParentOutputNumber);
|
||||
}
|
||||
}
|
||||
if (!(parentDev is IDmSwitch))
|
||||
{
|
||||
@@ -395,25 +402,47 @@ namespace PepperDash.Essentials.DM
|
||||
return null;
|
||||
}
|
||||
|
||||
private static CrestronGenericBaseDevice GetDmRmcControllerForDmps(string key, string name, string typeName,
|
||||
private static CrestronGenericBaseDevice GetDmRmcControllerForDmps(string key, string name, string typeName,
|
||||
uint ipid, DmpsRoutingController controller, uint num)
|
||||
{
|
||||
Func<string, string, uint, DMOutput, CrestronGenericBaseDevice> dmpsHandler;
|
||||
if (ChassisDict.TryGetValue(typeName.ToLower(), out dmpsHandler))
|
||||
{
|
||||
var output = controller.Dmps.SwitcherOutputs[num] as DMOutput;
|
||||
|
||||
if (output != null)
|
||||
{
|
||||
return dmpsHandler(key, name, ipid, output);
|
||||
}
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Error,
|
||||
"Cannot attach DM-RMC of type '{0}' to output {1} on DMPS chassis. Output is not a DM Output.",
|
||||
typeName, num);
|
||||
return null;
|
||||
}
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Error, "Cannot create DM-RMC of type '{0}' to output {1} on DMPS chassis", typeName, num);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static CrestronGenericBaseDevice GetDmRmcControllerForDmps4k(string key, string name, string typeName,
|
||||
DmpsRoutingController controller, uint num)
|
||||
{
|
||||
Func<string, string, DMOutput, CrestronGenericBaseDevice> dmpsHandler;
|
||||
if (ChassisCpu3Dict.TryGetValue(typeName.ToLower(), out dmpsHandler))
|
||||
Func<string, string, DMOutput, CrestronGenericBaseDevice> dmps4kHandler;
|
||||
if (ChassisCpu3Dict.TryGetValue(typeName.ToLower(), out dmps4kHandler))
|
||||
{
|
||||
var output = controller.Dmps.SwitcherOutputs[num] as DMOutput;
|
||||
|
||||
if (output != null)
|
||||
{
|
||||
return dmpsHandler(key, name, output);
|
||||
return dmps4kHandler(key, name, output);
|
||||
}
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Error,
|
||||
"Cannot attach DM-RMC of type '{0}' to output {1} on DMPS chassis. Output is not a DM Output.",
|
||||
"Cannot attach DM-RMC of type '{0}' to output {1} on DMPS-4K chassis. Output is not a DM Output.",
|
||||
typeName, num);
|
||||
return null;
|
||||
}
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Error, "Cannot create DM-RMC of type '{0}' to output {1} on DMPS chassis", typeName, num);
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Error, "Cannot create DM-RMC of type '{0}' to output {1} on DMPS-4K chassis", typeName, num);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace PepperDash.Essentials.DM
|
||||
var ipid = props.Control.IpIdInt;
|
||||
var pKey = props.ParentDeviceKey.ToLower();
|
||||
|
||||
if (pKey == "processor")
|
||||
if (pKey == "processor")
|
||||
{
|
||||
// Catch constructor failures, mainly dues to IPID
|
||||
try
|
||||
@@ -65,99 +65,135 @@ namespace PepperDash.Essentials.DM
|
||||
{
|
||||
Debug.Console(0, "[{0}] WARNING: Cannot create DM-TX device: {1}", key, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parentDev = DeviceManager.GetDeviceForKey(pKey);
|
||||
if (!(parentDev is IDmSwitch))
|
||||
{
|
||||
Debug.Console(0, "Cannot create DM device '{0}'. '{1}' is not a DM Chassis.",
|
||||
key, pKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
var parentDev = DeviceManager.GetDeviceForKey(pKey);
|
||||
DMInput dmInput;
|
||||
bool isCpu3 = false;
|
||||
|
||||
if (parentDev is IDmSwitch)
|
||||
{
|
||||
// Get the Crestron chassis and link stuff up
|
||||
var switchDev = (parentDev as IDmSwitch);
|
||||
var chassis = switchDev.Chassis;
|
||||
var switchDev = (parentDev as IDmSwitch);
|
||||
var chassis = switchDev.Chassis;
|
||||
|
||||
var num = props.ParentInputNumber;
|
||||
if (num <= 0 || num > chassis.NumberOfInputs)
|
||||
{
|
||||
Debug.Console(0, "Cannot create DM device '{0}'. Input number '{1}' is out of range",
|
||||
key, num);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
//Check that the input is within range of this chassis' possible inputs
|
||||
var num = props.ParentInputNumber;
|
||||
if (num <= 0 || num > chassis.NumberOfInputs)
|
||||
{
|
||||
Debug.Console(0, "Cannot create DM device '{0}'. Input number '{1}' is out of range",
|
||||
key, num);
|
||||
return null;
|
||||
}
|
||||
|
||||
switchDev.TxDictionary.Add(num, key);
|
||||
dmInput = chassis.Inputs[num];
|
||||
|
||||
//Determine if IpId is needed for this chassis type
|
||||
if (chassis is DmMd8x8Cpu3 || chassis is DmMd16x16Cpu3 ||
|
||||
chassis is DmMd32x32Cpu3 || chassis is DmMd8x8Cpu3rps ||
|
||||
chassis is DmMd16x16Cpu3rps || chassis is DmMd32x32Cpu3rps ||
|
||||
chassis is DmMd128x128 || chassis is DmMd64x64)
|
||||
{
|
||||
var controller = (parentDev as IDmSwitch);
|
||||
controller.TxDictionary.Add(num, key);
|
||||
isCpu3 = true;
|
||||
}
|
||||
|
||||
// Catch constructor failures, mainly dues to IPID
|
||||
try
|
||||
{
|
||||
// Must use different constructor for CPU3 chassis types. No IPID
|
||||
if (chassis is DmMd8x8Cpu3 || chassis is DmMd16x16Cpu3 ||
|
||||
chassis is DmMd32x32Cpu3 || chassis is DmMd8x8Cpu3rps ||
|
||||
chassis is DmMd16x16Cpu3rps || chassis is DmMd32x32Cpu3rps||
|
||||
chassis is DmMd128x128 || chassis is DmMd64x64)
|
||||
{
|
||||
if (typeName.StartsWith("dmtx200"))
|
||||
return new DmTx200Controller(key, name, new DmTx200C2G(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx201c"))
|
||||
return new DmTx201CController(key, name, new DmTx201C(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx201s"))
|
||||
return new DmTx201SController(key, name, new DmTx201S(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4k100"))
|
||||
return new DmTx4k100Controller(key, name, new DmTx4K100C1G(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4kz100"))
|
||||
return new DmTx4kz100Controller(key, name, new DmTx4kz100C1G(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4k202"))
|
||||
return new DmTx4k202CController(key, name, new DmTx4k202C(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4kz202"))
|
||||
return new DmTx4kz202CController(key, name, new DmTx4kz202C(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4k302"))
|
||||
return new DmTx4k302CController(key, name, new DmTx4k302C(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4kz302"))
|
||||
return new DmTx4kz302CController(key, name, new DmTx4kz302C(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx401"))
|
||||
return new DmTx401CController(key, name, new DmTx401C(chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("hdbasettx"))
|
||||
return new HDBaseTTxController(key, name, new HDTx3CB(chassis.Inputs[num]));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (typeName.StartsWith("dmtx200"))
|
||||
return new DmTx200Controller(key, name, new DmTx200C2G(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx201c"))
|
||||
return new DmTx201CController(key, name, new DmTx201C(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx201s"))
|
||||
return new DmTx201SController(key, name, new DmTx201S(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4k100"))
|
||||
return new DmTx4k100Controller(key, name, new DmTx4K100C1G(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4kz100"))
|
||||
return new DmTx4kz100Controller(key, name, new DmTx4kz100C1G(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4k202"))
|
||||
return new DmTx4k202CController(key, name, new DmTx4k202C(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4kz202"))
|
||||
return new DmTx4kz202CController(key, name, new DmTx4kz202C(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4k302"))
|
||||
return new DmTx4k302CController(key, name, new DmTx4k302C(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx4kz302"))
|
||||
return new DmTx4kz302CController(key, name, new DmTx4kz302C(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("dmtx401"))
|
||||
return new DmTx401CController(key, name, new DmTx401C(ipid, chassis.Inputs[num]));
|
||||
if (typeName.StartsWith("hdbasettx"))
|
||||
return new HDBaseTTxController(key, name, new HDTx3CB(ipid, chassis.Inputs[num]));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(0, "[{0}] WARNING: Cannot create DM-TX device: {1}", key, e);
|
||||
}
|
||||
}
|
||||
else if(parentDev is DmpsRoutingController)
|
||||
{
|
||||
// Get the DMPS chassis and link stuff up
|
||||
var dmpsDev = (parentDev as DmpsRoutingController);
|
||||
var chassis = dmpsDev.Dmps;
|
||||
|
||||
//Check that the input is within range of this chassis' possible inputs
|
||||
var num = props.ParentInputNumber;
|
||||
if (num <= 0 || num > chassis.SwitcherInputs.Count)
|
||||
{
|
||||
Debug.Console(0, "Cannot create DMPS device '{0}'. Input number '{1}' is out of range",
|
||||
key, num);
|
||||
return null;
|
||||
}
|
||||
|
||||
dmpsDev.TxDictionary.Add(num, key);
|
||||
|
||||
try
|
||||
{
|
||||
dmInput = chassis.SwitcherInputs[num] as DMInput;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.Console(0, "Cannot create DMPS device '{0}'. Input number '{1}' is not a DM input", key, num);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Debug.Console(0, "Cannot create DM device '{0}'. '{1}' is not a processor, DM Chassis or DMPS.", key, pKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// Must use different constructor for CPU3 or DMPS3-4K types. No IPID
|
||||
if (isCpu3 || Global.ControlSystemIsDmps4kType)
|
||||
{
|
||||
if (typeName.StartsWith("dmtx200"))
|
||||
return new DmTx200Controller(key, name, new DmTx200C2G(dmInput));
|
||||
if (typeName.StartsWith("dmtx201c"))
|
||||
return new DmTx201CController(key, name, new DmTx201C(dmInput));
|
||||
if (typeName.StartsWith("dmtx201s"))
|
||||
return new DmTx201SController(key, name, new DmTx201S(dmInput));
|
||||
if (typeName.StartsWith("dmtx4k100"))
|
||||
return new DmTx4k100Controller(key, name, new DmTx4K100C1G(dmInput));
|
||||
if (typeName.StartsWith("dmtx4kz100"))
|
||||
return new DmTx4kz100Controller(key, name, new DmTx4kz100C1G(dmInput));
|
||||
if (typeName.StartsWith("dmtx4k202"))
|
||||
return new DmTx4k202CController(key, name, new DmTx4k202C(dmInput));
|
||||
if (typeName.StartsWith("dmtx4kz202"))
|
||||
return new DmTx4kz202CController(key, name, new DmTx4kz202C(dmInput));
|
||||
if (typeName.StartsWith("dmtx4k302"))
|
||||
return new DmTx4k302CController(key, name, new DmTx4k302C(dmInput));
|
||||
if (typeName.StartsWith("dmtx4kz302"))
|
||||
return new DmTx4kz302CController(key, name, new DmTx4kz302C(dmInput));
|
||||
if (typeName.StartsWith("dmtx401"))
|
||||
return new DmTx401CController(key, name, new DmTx401C(dmInput));
|
||||
if (typeName.StartsWith("hdbasettx"))
|
||||
return new HDBaseTTxController(key, name, new HDTx3CB(dmInput));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (typeName.StartsWith("dmtx200"))
|
||||
return new DmTx200Controller(key, name, new DmTx200C2G(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx201c"))
|
||||
return new DmTx201CController(key, name, new DmTx201C(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx201s"))
|
||||
return new DmTx201SController(key, name, new DmTx201S(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx4k100"))
|
||||
return new DmTx4k100Controller(key, name, new DmTx4K100C1G(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx4kz100"))
|
||||
return new DmTx4kz100Controller(key, name, new DmTx4kz100C1G(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx4k202"))
|
||||
return new DmTx4k202CController(key, name, new DmTx4k202C(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx4kz202"))
|
||||
return new DmTx4kz202CController(key, name, new DmTx4kz202C(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx4k302"))
|
||||
return new DmTx4k302CController(key, name, new DmTx4k302C(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx4kz302"))
|
||||
return new DmTx4kz302CController(key, name, new DmTx4kz302C(ipid, dmInput));
|
||||
if (typeName.StartsWith("dmtx401"))
|
||||
return new DmTx401CController(key, name, new DmTx401C(ipid, dmInput));
|
||||
if (typeName.StartsWith("hdbasettx"))
|
||||
return new HDBaseTTxController(key, name, new HDTx3CB(ipid, dmInput));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(0, "[{0}] WARNING: Cannot create DM-TX device: {1}", key, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,11 +221,12 @@ namespace PepperDash.Essentials.DM
|
||||
protected DmTxControllerBase(string key, string name, EndpointTransmitterBase hardware)
|
||||
: base(key, name, hardware)
|
||||
{
|
||||
// if wired to a chassis, skip registration step in base class
|
||||
if (hardware.DMInput != null)
|
||||
{
|
||||
this.PreventRegistration = true;
|
||||
}
|
||||
// if wired to a chassis or DMPS, skip registration step in base class
|
||||
if (hardware.DMInput != null || (Global.ControlSystemIsDmpsType && hardware.DMInput != null))
|
||||
{
|
||||
this.PreventRegistration = true;
|
||||
}
|
||||
|
||||
AddToFeedbackList(ActiveVideoInputFeedback);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Essentials.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Common.Codec
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a device that has Do Not Disturb mode capability
|
||||
/// </summary>
|
||||
public interface IHasDoNotDisturbMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Indictes whether Do Not Disturb mode is on (Activated)
|
||||
/// </summary>
|
||||
BoolFeedback DoNotDisturbModeIsOnFeedback { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Activates Do Not Disturb mode
|
||||
/// </summary>
|
||||
void ActivateDoNotDisturbMode();
|
||||
|
||||
/// <summary>
|
||||
/// Deactivates Do Not Disturb mode
|
||||
/// </summary>
|
||||
void DeactivateDoNotDisturbMode();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles Do Not Disturb mode
|
||||
/// </summary>
|
||||
void ToggleDoNotDisturbMode();
|
||||
}
|
||||
|
||||
public interface IHasDoNotDisturbModeWithTimeout : IHasDoNotDisturbMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Activates Do Not Disturb mode with a timeout
|
||||
/// </summary>
|
||||
/// <param name="timeout"></param>
|
||||
void ActivateDoNotDisturbMode(int timeout);
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,7 @@
|
||||
<Compile Include="Codec\eCodecCallStatus.cs" />
|
||||
<Compile Include="Codec\eMeetingPrivacy.cs" />
|
||||
<Compile Include="Codec\iCodecAudio.cs" />
|
||||
<Compile Include="Codec\IHasDoNotDisturb.cs" />
|
||||
<Compile Include="Codec\IHasExternalSourceSwitching.cs" />
|
||||
<Compile Include="ImageProcessors\TVOneCorio.cs" />
|
||||
<Compile Include="ImageProcessors\TVOneCorioPropertiesConfig.cs" />
|
||||
@@ -117,6 +118,7 @@
|
||||
<Compile Include="ImageProcessors\AnalogWay\AnalogWayLiveCorePropertiesConfig.cs" />
|
||||
<Compile Include="SoftCodec\BlueJeansPc.cs" />
|
||||
<Compile Include="VideoCodec\CiscoCodec\CiscoCamera.cs" />
|
||||
<Compile Include="VideoCodec\CiscoCodec\CiscoCodecJoinMap.cs" />
|
||||
<Compile Include="VideoCodec\CiscoCodec\RoomPresets.cs" />
|
||||
<Compile Include="Cameras\CameraControl.cs" />
|
||||
<Compile Include="Display\PanasonicThDisplay.cs" />
|
||||
@@ -125,6 +127,7 @@
|
||||
<Compile Include="VideoCodec\Interfaces\IHasPresentationOnlyMeeting.cs" />
|
||||
<Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" />
|
||||
<Compile Include="VideoCodec\Interfaces\IHasSelfviewSize.cs" />
|
||||
<Compile Include="VideoCodec\Interfaces\IHasStandbyMode.cs" />
|
||||
<Compile Include="VideoCodec\Interfaces\IHasStartMeeting.cs" />
|
||||
<Compile Include="VideoCodec\Interfaces\iVideoCodecInfo.cs" />
|
||||
<Compile Include="Codec\iHasCallFavorites.cs" />
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Bridges.JoinMaps;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
{
|
||||
public class CiscoCodecJoinMap : VideoCodecControllerJoinMap
|
||||
{
|
||||
#region Digital
|
||||
|
||||
[JoinName("ActivateDoNotDisturbMode")]
|
||||
public JoinDataComplete ActivateDoNotDisturbMode = new JoinDataComplete(
|
||||
new JoinData
|
||||
{
|
||||
JoinNumber = 221,
|
||||
JoinSpan = 1
|
||||
},
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "Activates Do Not Disturb Mode. FB High if active.",
|
||||
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
[JoinName("DeactivateDoNotDisturbMode")]
|
||||
public JoinDataComplete DeactivateDoNotDisturbMode = new JoinDataComplete(
|
||||
new JoinData
|
||||
{
|
||||
JoinNumber = 222,
|
||||
JoinSpan = 1
|
||||
},
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "Deactivates Do Not Disturb Mode. FB High if deactivated.",
|
||||
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
[JoinName("ToggleDoNotDisturbMode")]
|
||||
public JoinDataComplete ToggleDoNotDisturbMode = new JoinDataComplete(
|
||||
new JoinData
|
||||
{
|
||||
JoinNumber = 223,
|
||||
JoinSpan = 1
|
||||
},
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "Toggles Do Not Disturb Mode.",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
[JoinName("ActivateStandby")]
|
||||
public JoinDataComplete ActivateStandby = new JoinDataComplete(
|
||||
new JoinData
|
||||
{
|
||||
JoinNumber = 226,
|
||||
JoinSpan = 1
|
||||
},
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "Activates Standby Mode. FB High if active.",
|
||||
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
[JoinName("DeactivateStandby")]
|
||||
public JoinDataComplete DeactivateStandby = new JoinDataComplete(
|
||||
new JoinData
|
||||
{
|
||||
JoinNumber = 227,
|
||||
JoinSpan = 1
|
||||
},
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "Deactivates Standby Mode. FB High if deactivated.",
|
||||
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
[JoinName("ActivateHalfWakeMode")]
|
||||
public JoinDataComplete ActivateHalfWakeMode = new JoinDataComplete(
|
||||
new JoinData
|
||||
{
|
||||
JoinNumber = 228,
|
||||
JoinSpan = 1
|
||||
},
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "Activates Half Wake Mode. FB High if active.",
|
||||
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
[JoinName("EnteringStandbyMode")]
|
||||
public JoinDataComplete EnteringStandbyMode = new JoinDataComplete(
|
||||
new JoinData
|
||||
{
|
||||
JoinNumber = 229,
|
||||
JoinSpan = 1
|
||||
},
|
||||
new JoinMetadata
|
||||
{
|
||||
Description = "High to indicate that the codec is entering standby mode",
|
||||
JoinCapabilities = eJoinCapabilities.ToSIMPL,
|
||||
JoinType = eJoinType.Digital
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Analog
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Serials
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
public CiscoCodecJoinMap(uint joinStart)
|
||||
: base(joinStart, typeof(CiscoCodecJoinMap))
|
||||
{
|
||||
}
|
||||
|
||||
public CiscoCodecJoinMap(uint joinStart, Type type)
|
||||
: base(joinStart, type)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
|
||||
public class CiscoSparkCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory,
|
||||
IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayouts, IHasCodecSelfView,
|
||||
ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute
|
||||
ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets,
|
||||
IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute, IHasDoNotDisturbMode,
|
||||
IHasHalfWakeMode
|
||||
{
|
||||
private bool _externalSourceChangeRequested;
|
||||
|
||||
@@ -316,6 +318,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
CameraIsMutedFeedback = CameraIsOffFeedback;
|
||||
SupportsCameraOff = true;
|
||||
|
||||
DoNotDisturbModeIsOnFeedback = new BoolFeedback(() => CodecStatus.Status.Conference.DoNotDisturb.BoolValue);
|
||||
HalfWakeModeIsOnFeedback = new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "halfwake");
|
||||
EnteringStandbyModeFeedback = new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "enteringstandby");
|
||||
|
||||
PresentationViewMaximizedFeedback = new BoolFeedback(() => CurrentPresentationView == "Maximized");
|
||||
|
||||
Communication = comm;
|
||||
@@ -413,7 +419,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate;
|
||||
CodecStatus.Status.Audio.VolumeMute.ValueChangedAction = MuteFeedback.FireUpdate;
|
||||
CodecStatus.Status.Audio.Microphones.Mute.ValueChangedAction = PrivacyModeIsOnFeedback.FireUpdate;
|
||||
CodecStatus.Status.Standby.State.ValueChangedAction = StandbyIsOnFeedback.FireUpdate;
|
||||
CodecStatus.Status.Standby.State.ValueChangedAction = new Action(() =>
|
||||
{
|
||||
StandbyIsOnFeedback.FireUpdate();
|
||||
HalfWakeModeIsOnFeedback.FireUpdate();
|
||||
EnteringStandbyModeFeedback.FireUpdate();
|
||||
});
|
||||
CodecStatus.Status.RoomAnalytics.PeoplePresence.ValueChangedAction = RoomIsOccupiedFeedback.FireUpdate;
|
||||
CodecStatus.Status.RoomAnalytics.PeopleCount.Current.ValueChangedAction = PeopleCountFeedback.FireUpdate;
|
||||
CodecStatus.Status.Cameras.SpeakerTrack.Status.ValueChangedAction = CameraAutoModeIsOnFeedback.FireUpdate;
|
||||
@@ -423,6 +434,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
CodecStatus.Status.Video.Layout.LayoutFamily.Local.ValueChangedAction = ComputeLocalLayout;
|
||||
CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = SharingContentIsOnFeedback.FireUpdate;
|
||||
CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = FarEndIsSharingContentFeedback.FireUpdate;
|
||||
CodecStatus.Status.Conference.DoNotDisturb.ValueChangedAction = DoNotDisturbModeIsOnFeedback.FireUpdate;
|
||||
|
||||
try
|
||||
{
|
||||
CodecStatus.Status.Video.Input.MainVideoMute.ValueChangedAction = CameraIsOffFeedback.FireUpdate;
|
||||
@@ -575,6 +588,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
prefix + "/Status/Audio" + Delimiter +
|
||||
prefix + "/Status/Call" + Delimiter +
|
||||
prefix + "/Status/Conference/Presentation" + Delimiter +
|
||||
prefix + "/Status/Conference/DoNotDisturb" + Delimiter +
|
||||
prefix + "/Status/Cameras/SpeakerTrack" + Delimiter +
|
||||
prefix + "/Status/RoomAnalytics" + Delimiter +
|
||||
prefix + "/Status/RoomPreset" + Delimiter +
|
||||
@@ -583,10 +597,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
prefix + "/Status/Video/Layout" + Delimiter +
|
||||
prefix + "/Status/Video/Input/MainVideoMute" + Delimiter +
|
||||
prefix + "/Bookings" + Delimiter +
|
||||
prefix + "/Event/CallDisconnect" + Delimiter +
|
||||
prefix + "/Event/Bookings" + Delimiter +
|
||||
prefix + "/Event/CameraPresetListUpdated" + Delimiter +
|
||||
prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter;
|
||||
prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter +
|
||||
prefix + "/Event/CallDisconnect" + Delimiter; // Keep CallDisconnect last to detect when feedback registration completes correctly
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1495,7 +1510,50 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
|
||||
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
||||
{
|
||||
var joinMap = new CiscoCodecJoinMap(joinStart);
|
||||
|
||||
var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey);
|
||||
|
||||
if (customJoins != null)
|
||||
{
|
||||
joinMap.SetCustomJoinData(customJoins);
|
||||
}
|
||||
|
||||
if (bridge != null)
|
||||
{
|
||||
bridge.AddJoinMap(Key, joinMap);
|
||||
}
|
||||
|
||||
LinkVideoCodecToApi(this, trilist, joinStart, joinMapKey, bridge);
|
||||
|
||||
LinkCiscoCodecToApi(trilist, joinMap);
|
||||
}
|
||||
|
||||
public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap)
|
||||
{
|
||||
var dndCodec = this as IHasDoNotDisturbMode;
|
||||
if (dndCodec != null)
|
||||
{
|
||||
dndCodec.DoNotDisturbModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateDoNotDisturbMode.JoinNumber]);
|
||||
dndCodec.DoNotDisturbModeIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.DeactivateDoNotDisturbMode.JoinNumber]);
|
||||
|
||||
trilist.SetSigFalseAction(joinMap.ActivateDoNotDisturbMode.JoinNumber, () => dndCodec.ActivateDoNotDisturbMode());
|
||||
trilist.SetSigFalseAction(joinMap.DeactivateDoNotDisturbMode.JoinNumber, () => dndCodec.DeactivateDoNotDisturbMode());
|
||||
trilist.SetSigFalseAction(joinMap.ToggleDoNotDisturbMode.JoinNumber, () => dndCodec.ToggleDoNotDisturbMode());
|
||||
}
|
||||
|
||||
var halfwakeCodec = this as IHasHalfWakeMode;
|
||||
if (halfwakeCodec != null)
|
||||
{
|
||||
halfwakeCodec.StandbyIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateStandby.JoinNumber]);
|
||||
halfwakeCodec.StandbyIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.DeactivateStandby.JoinNumber]);
|
||||
halfwakeCodec.HalfWakeModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateHalfWakeMode.JoinNumber]);
|
||||
halfwakeCodec.EnteringStandbyModeFeedback.LinkInputSig(trilist.BooleanInput[joinMap.EnteringStandbyMode.JoinNumber]);
|
||||
|
||||
trilist.SetSigFalseAction(joinMap.ActivateStandby.JoinNumber, () => halfwakeCodec.StandbyActivate());
|
||||
trilist.SetSigFalseAction(joinMap.DeactivateStandby.JoinNumber, () => halfwakeCodec.StandbyDeactivate());
|
||||
trilist.SetSigFalseAction(joinMap.ActivateHalfWakeMode.JoinNumber, () => halfwakeCodec.HalfwakeActivate());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2069,6 +2127,47 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
else
|
||||
CameraMuteOn();
|
||||
}
|
||||
|
||||
#region IHasDoNotDisturbMode Members
|
||||
|
||||
public BoolFeedback DoNotDisturbModeIsOnFeedback { get; private set; }
|
||||
|
||||
public void ActivateDoNotDisturbMode()
|
||||
{
|
||||
SendText("xCommand Conference DoNotDisturb Activate");
|
||||
}
|
||||
|
||||
public void DeactivateDoNotDisturbMode()
|
||||
{
|
||||
SendText("xCommand Conference DoNotDisturb Deactivate");
|
||||
}
|
||||
|
||||
public void ToggleDoNotDisturbMode()
|
||||
{
|
||||
if (DoNotDisturbModeIsOnFeedback.BoolValue)
|
||||
{
|
||||
DeactivateDoNotDisturbMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
ActivateDoNotDisturbMode();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHasHalfWakeMode Members
|
||||
|
||||
public BoolFeedback HalfWakeModeIsOnFeedback { get; private set; }
|
||||
|
||||
public BoolFeedback EnteringStandbyModeFeedback { get; private set; }
|
||||
|
||||
public void HalfwakeActivate()
|
||||
{
|
||||
SendText("xCommand Standby Halfwake");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -440,9 +440,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
public CallId CallId { get; set; }
|
||||
}
|
||||
|
||||
public class DoNotDisturb
|
||||
public class DoNotDisturb : ValueProperty
|
||||
{
|
||||
public string Value { get; set; }
|
||||
string _Value;
|
||||
|
||||
public bool BoolValue { get; private set; }
|
||||
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
_Value = value;
|
||||
// If the incoming value is "On" it sets the BoolValue true, otherwise sets it false
|
||||
BoolValue = value == "On" || value == "Active";
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Mode
|
||||
@@ -600,6 +617,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
public Conference2()
|
||||
{
|
||||
Presentation = new Presentation();
|
||||
DoNotDisturb = new DoNotDisturb();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1380,12 +1398,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
|
||||
public class State : ValueProperty
|
||||
{
|
||||
string _value;
|
||||
|
||||
public bool BoolValue { get; private set; }
|
||||
|
||||
public string Value // Valid values are Standby/EnteringStandby/Halfwake/Off
|
||||
{
|
||||
get { return _value; }
|
||||
set
|
||||
{
|
||||
_value = value;
|
||||
// If the incoming value is "On" it sets the BoolValue true, otherwise sets it false
|
||||
BoolValue = value == "On" || value == "Standby";
|
||||
OnValueChanged();
|
||||
@@ -2091,6 +2113,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
|
||||
Conference = new Conference2();
|
||||
SystemUnit = new SystemUnit();
|
||||
Video = new Video();
|
||||
Conference = new Conference2();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Essentials.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a device that has Standby Mode capability
|
||||
/// </summary>
|
||||
public interface IHasStandbyMode
|
||||
{
|
||||
BoolFeedback StandbyIsOnFeedback { get; }
|
||||
|
||||
void StandbyActivate();
|
||||
|
||||
void StandbyDeactivate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a device that has Half Waek Mode capability
|
||||
/// </summary>
|
||||
public interface IHasHalfWakeMode : IHasStandbyMode
|
||||
{
|
||||
BoolFeedback HalfWakeModeIsOnFeedback { get; }
|
||||
|
||||
BoolFeedback EnteringStandbyModeFeedback { get; }
|
||||
|
||||
void HalfwakeActivate();
|
||||
}
|
||||
}
|
||||
@@ -431,8 +431,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
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.StartTime = DateTime.Now.AddMinutes(5).AddHours(i);
|
||||
m.EndTime = DateTime.Now.AddHours(i).AddMinutes(50);
|
||||
m.Title = "Meeting " + i;
|
||||
m.Calls.Add(new Call() { Number = i + "meeting@fake.com"});
|
||||
_CodecSchedule.Meetings.Add(m);
|
||||
@@ -602,6 +602,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
|
||||
CameraAutoModeIsOnFeedback = new BoolFeedback(() => _CameraAutoModeIsOn);
|
||||
|
||||
SupportsCameraAutoMode = true;
|
||||
|
||||
CameraAutoModeIsOnFeedback.FireUpdate();
|
||||
|
||||
DeviceManager.AddDevice(internalCamera);
|
||||
@@ -609,7 +611,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
|
||||
NearEndPresets = new List<CodecRoomPreset>(15); // Fix the capacity to emulate Cisco
|
||||
|
||||
NearEndPresets = PropertiesConfig.Presets;
|
||||
if (PropertiesConfig.Presets != null && PropertiesConfig.Presets.Count > 0)
|
||||
{
|
||||
NearEndPresets = PropertiesConfig.Presets;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i <= NearEndPresets.Capacity; i++)
|
||||
{
|
||||
var label = string.Format("Near End Preset {0}", i);
|
||||
NearEndPresets.Add(new CodecRoomPreset(i, label, true, false));
|
||||
}
|
||||
}
|
||||
|
||||
FarEndRoomPresets = new List<CodecRoomPreset>(15); // Fix the capacity to emulate Cisco
|
||||
|
||||
|
||||
@@ -18,5 +18,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
|
||||
[JsonProperty("presets")]
|
||||
public List<CodecRoomPreset> Presets { get; set; }
|
||||
|
||||
public MockVcPropertiesConfig()
|
||||
{
|
||||
Favorites = new List<CodecActiveCallItem>();
|
||||
Presets = new List<CodecRoomPreset>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ using Feedback = PepperDash.Essentials.Core.Feedback;
|
||||
namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||
{
|
||||
public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs,
|
||||
IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced
|
||||
IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced, IHasStandbyMode
|
||||
{
|
||||
private const int XSigEncoding = 28591;
|
||||
protected const int MaxParticipants = 50;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<packages>
|
||||
<package id="PepperDashCore" version="1.0.48" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
|
||||
<package id="PepperDashCore" version="1.1.0" targetFramework="net35" allowedVersions="[1.0,2.0)"/>
|
||||
</packages>
|
||||
Reference in New Issue
Block a user