diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs
index 9a48000a..1ab3b28e 100644
--- a/PepperDashEssentials/ControlSystem.cs
+++ b/PepperDashEssentials/ControlSystem.cs
@@ -83,10 +83,10 @@ namespace PepperDash.Essentials
CrestronConsole.AddNewConsoleCommand(BridgeHelper.PrintJoinMap, "getjoinmap", "map(s) for bridge or device on bridge [brKey [devKey]]", ConsoleAccessLevelEnum.AccessOperator);
- CrestronConsole.AddNewConsoleCommand(s =>
- {
- Debug.Console(0, Debug.ErrorLogLevel.Notice, "CONSOLE MESSAGE: {0}", s);
- }, "appdebugmessage", "Writes message to log", ConsoleAccessLevelEnum.AccessOperator);
+ CrestronConsole.AddNewConsoleCommand(BridgeHelper.JoinmapMarkdown, "getjoinmapmarkdown"
+ , "generate markdown of map(s) for bridge or device on bridge [brKey [devKey]]", ConsoleAccessLevelEnum.AccessOperator);
+
+ CrestronConsole.AddNewConsoleCommand(s => Debug.Console(0, Debug.ErrorLogLevel.Notice, "CONSOLE MESSAGE: {0}", s), "appdebugmessage", "Writes message to log", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
@@ -103,12 +103,16 @@ namespace PepperDash.Essentials
(ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented));
}, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator);
- CrestronConsole.AddNewConsoleCommand(s =>
- {
- CrestronConsole.ConsoleCommandResponse("This system can be found at the following URLs:\r\n" +
- "System URL: {0}\r\n" +
- "Template URL: {1}", ConfigReader.ConfigObject.SystemUrl, ConfigReader.ConfigObject.TemplateUrl);
- }, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator);
+ CrestronConsole.AddNewConsoleCommand(s =>
+ CrestronConsole.ConsoleCommandResponse(
+ "This system can be found at the following URLs:\r\n" +
+ "System URL: {0}\r\n" +
+ "Template URL: {1}",
+ ConfigReader.ConfigObject.SystemUrl,
+ ConfigReader.ConfigObject.TemplateUrl),
+ "portalinfo",
+ "Shows portal URLS from configuration",
+ ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(DeviceManager.GetRoutingPorts,
@@ -298,6 +302,10 @@ namespace PepperDash.Essentials
if (!Directory.Exists(pluginDir))
Directory.Create(pluginDir);
+ var joinmapDir = Global.FilePathPrefix + "joinmaps";
+ if(!Directory.Exists(joinmapDir))
+ Directory.Create(joinmapDir);
+
return configExists;
}
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs
index 252c9c48..11b8f4ff 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs
@@ -46,6 +46,33 @@ namespace PepperDash.Essentials.Core.Bridges
bridge.PrintJoinMaps();
}
}
+ public static void JoinmapMarkdown(string command)
+ {
+ var targets = command.Split(' ');
+
+ var bridgeKey = targets[0].Trim();
+
+ var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced;
+
+ if (bridge == null)
+ {
+ Debug.Console(0, "Unable to find advanced bridge with key: '{0}'", bridgeKey);
+ return;
+ }
+
+ if (targets.Length > 1)
+ {
+ var deviceKey = targets[1].Trim();
+
+ if (string.IsNullOrEmpty(deviceKey)) return;
+ bridge.MarkdownJoinMapForDevice(deviceKey, bridgeKey);
+ }
+ else
+ {
+ bridge.MarkdownForBridge(bridgeKey);
+
+ }
+ }
}
@@ -227,6 +254,19 @@ namespace PepperDash.Essentials.Core.Bridges
joinMap.Value.PrintJoinMapInfo();
}
}
+ ///
+ /// Generates markdown for all join maps on this bridge
+ ///
+ public virtual void MarkdownForBridge(string bridgeKey)
+ {
+ Debug.Console(0, this, "Writing Joinmaps to files for EISC IPID: {0}", Eisc.ID.ToString("X"));
+
+ foreach (var joinMap in JoinMaps)
+ {
+ Debug.Console(0, "Generating markdown for device '{0}':", joinMap.Key);
+ joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey);
+ }
+ }
///
/// Prints the join map for a device by key
@@ -242,9 +282,26 @@ namespace PepperDash.Essentials.Core.Bridges
return;
}
- Debug.Console(0, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
+ Debug.Console(0, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
joinMap.PrintJoinMapInfo();
}
+ ///
+ /// Prints the join map for a device by key
+ ///
+ ///
+ public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey)
+ {
+ var joinMap = JoinMaps[deviceKey];
+
+ if (joinMap == null)
+ {
+ Debug.Console(0, this, "Unable to find joinMap for device with key: '{0}'", deviceKey);
+ return;
+ }
+
+ Debug.Console(0, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
+ joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey);
+ }
///
/// Used for debugging to trigger an action based on a join number and type
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IAnalogInputJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IAnalogInputJoinMap.cs
new file mode 100644
index 00000000..eaf70f3a
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IAnalogInputJoinMap.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace PepperDash.Essentials.Core.Bridges
+{
+ public class IAnalogInputJoinMap : JoinMapBaseAdvanced
+ {
+
+ [JoinName("InputValue")]
+ public JoinDataComplete InputValue = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
+ new JoinMetadata { Description = "Input Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog });
+ [JoinName("MinimumChange")]
+ public JoinDataComplete MinimumChange = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 },
+ new JoinMetadata { Description = "Minimum voltage change required to reflect a change", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
+
+ ///
+ /// Constructor to use when instantiating this Join Map without inheriting from it
+ ///
+ /// Join this join map will start at
+ public IAnalogInputJoinMap(uint joinStart)
+ : this(joinStart, typeof(IAnalogInputJoinMap))
+ {
+ }
+
+ ///
+ /// Constructor to use when extending this Join map
+ ///
+ /// Join this join map will start at
+ /// Type of the child join map
+ protected IAnalogInputJoinMap(uint joinStart, Type type)
+ : base(joinStart, type)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalInputJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalInputJoinMap.cs
index 085a33bd..83e6cdab 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalInputJoinMap.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalInputJoinMap.cs
@@ -1,13 +1,13 @@
using System;
-namespace PepperDash.Essentials.Core.Bridges
-{
- public class IDigitalInputJoinMap : JoinMapBaseAdvanced
- {
-
+namespace PepperDash.Essentials.Core.Bridges
+{
+ public class IDigitalInputJoinMap : JoinMapBaseAdvanced
+ {
+
[JoinName("InputState")]
public JoinDataComplete InputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
- new JoinMetadata { Description = "Room Email Url", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
+ new JoinMetadata { Description = "Input State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
///
/// Constructor to use when instantiating this Join Map without inheriting from it
@@ -26,6 +26,6 @@ namespace PepperDash.Essentials.Core.Bridges
protected IDigitalInputJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
- }
- }
+ }
+ }
}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalOutputJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalOutputJoinMap.cs
new file mode 100644
index 00000000..cbe62398
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/IDigitalOutputJoinMap.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace PepperDash.Essentials.Core.Bridges
+{
+ public class IDigitalOutputJoinMap : JoinMapBaseAdvanced
+ {
+
+ [JoinName("OutputState")]
+ public JoinDataComplete OutputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
+ new JoinMetadata { Description = "Get / Set state of Digital Input", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
+
+ ///
+ /// Constructor to use when instantiating this Join Map without inheriting from it
+ ///
+ /// Join this join map will start at
+ public IDigitalOutputJoinMap(uint joinStart)
+ : this(joinStart, typeof(IDigitalOutputJoinMap))
+ {
+ }
+
+ ///
+ /// Constructor to use when extending this Join map
+ ///
+ /// Join this join map will start at
+ /// Type of the child join map
+ protected IDigitalOutputJoinMap(uint joinStart, Type type)
+ : base(joinStart, type)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/DinIo8/DinIo8Controller.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/DinIo8/DinIo8Controller.cs
new file mode 100644
index 00000000..794fe609
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/DinIo8/DinIo8Controller.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using Crestron.SimplSharpPro;
+using Crestron.SimplSharpPro.DeviceSupport;
+using Crestron.SimplSharpPro.GeneralIO;
+using PepperDash.Core;
+using PepperDash.Essentials.Core.Bridges;
+using PepperDash.Essentials.Core.Config;
+
+namespace PepperDash.Essentials.Core.CrestronIO
+{
+ public class DinIo8Controller:CrestronGenericBaseDevice, IIOPorts
+ {
+ private DinIo8 _device;
+
+ public DinIo8Controller(string key, Func preActivationFunc, DeviceConfig config):base(key, config.Name)
+ {
+ AddPreActivationAction(() =>
+ {
+ _device = preActivationFunc(config);
+
+ RegisterCrestronGenericBase(_device);
+ });
+ }
+
+ #region Implementation of IIOPorts
+
+ public CrestronCollection VersiPorts
+ {
+ get { return _device.VersiPorts; }
+ }
+
+ public int NumberOfVersiPorts
+ {
+ get { return _device.NumberOfVersiPorts; }
+ }
+
+ #endregion
+
+
+ }
+
+ public class DinIo8ControllerFactory : EssentialsDeviceFactory
+ {
+ public DinIo8ControllerFactory()
+ {
+ TypeNames = new List() { "DinIo8" };
+ }
+
+ public override EssentialsDevice BuildDevice(DeviceConfig dc)
+ {
+ Debug.Console(1, "Factory Attempting to create new DinIo8 Device");
+
+ return new DinIo8Controller(dc.Key, GetDinIo8Device, dc);
+ }
+
+ static DinIo8 GetDinIo8Device(DeviceConfig dc)
+ {
+ var control = CommFactory.GetControlPropertiesConfig(dc);
+ var cresnetId = control.CresnetIdInt;
+ var branchId = control.ControlPortNumber;
+ var parentKey = string.IsNullOrEmpty(control.ControlPortDevKey) ? "processor" : control.ControlPortDevKey;
+
+ if (parentKey.Equals("processor", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Debug.Console(0, "Device {0} is a valid cresnet master - creating new DinIo8", parentKey);
+ return new DinIo8(cresnetId, Global.ControlSystem);
+ }
+ var cresnetBridge = DeviceManager.GetDeviceForKey(parentKey) as IHasCresnetBranches;
+
+ if (cresnetBridge != null)
+ {
+ Debug.Console(0, "Device {0} is a valid cresnet master - creating new DinIo8", parentKey);
+ return new DinIo8(cresnetId, cresnetBridge.CresnetBranches[branchId]);
+ }
+ Debug.Console(0, "Device {0} is not a valid cresnet master", parentKey);
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/IOPortConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/IOPortConfig.cs
index 09061ff2..5fbe10e1 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/IOPortConfig.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/IOPortConfig.cs
@@ -15,5 +15,7 @@ namespace PepperDash.Essentials.Core.CrestronIO
public uint PortNumber { get; set; }
[JsonProperty("disablePullUpResistor")]
public bool DisablePullUpResistor { get; set; }
+ [JsonProperty("minimumChange")]
+ public int MinimumChange { get; set; }
}
}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/GenericVersiportAnalogInputDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/GenericVersiportAnalogInputDevice.cs
new file mode 100644
index 00000000..70be2f6f
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/GenericVersiportAnalogInputDevice.cs
@@ -0,0 +1,208 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Crestron.SimplSharp;
+using Crestron.SimplSharpPro;
+using Crestron.SimplSharpPro.DeviceSupport;
+
+using PepperDash.Core;
+using PepperDash.Essentials.Core.Config;
+using PepperDash.Essentials.Core.Bridges;
+
+
+using Newtonsoft.Json;
+
+namespace PepperDash.Essentials.Core.CrestronIO
+{
+ ///
+ /// Represents a generic digital input deviced tied to a versiport
+ ///
+ public class GenericVersiportAnalogInputDevice : EssentialsBridgeableDevice, IAnalogInput
+ {
+ public Versiport InputPort { get; private set; }
+
+ public IntFeedback InputValueFeedback { get; private set; }
+ public IntFeedback InputMinimumChangeFeedback { get; private set; }
+
+ Func InputValueFeedbackFunc
+ {
+ get
+ {
+ return () => InputPort.AnalogIn;
+ }
+ }
+
+ Func InputMinimumChangeFeedbackFunc
+ {
+ get { return () => InputPort.AnalogMinChange; }
+ }
+
+ public GenericVersiportAnalogInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) :
+ base(key, name)
+ {
+ InputValueFeedback = new IntFeedback(InputValueFeedbackFunc);
+ InputMinimumChangeFeedback = new IntFeedback(InputMinimumChangeFeedbackFunc);
+
+ AddPostActivationAction(() =>
+ {
+ InputPort = postActivationFunc(config);
+
+ InputPort.Register();
+
+ InputPort.SetVersiportConfiguration(eVersiportConfiguration.AnalogInput);
+ InputPort.AnalogMinChange = (ushort)(config.MinimumChange > 0 ? config.MinimumChange : 655);
+ if (config.DisablePullUpResistor)
+ InputPort.DisablePullUpResistor = true;
+
+ InputPort.VersiportChange += InputPort_VersiportChange;
+
+ Debug.Console(1, this, "Created GenericVersiportAnalogInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor);
+
+ });
+
+ }
+
+ ///
+ /// Set minimum voltage change for device to update voltage changed method
+ ///
+ /// valid values range from 0 - 65535, representing the full 100% range of the processor voltage source. Check processor documentation for details
+ public void SetMinimumChange(ushort value)
+ {
+ InputPort.AnalogMinChange = value;
+ }
+
+ void InputPort_VersiportChange(Versiport port, VersiportEventArgs args)
+ {
+ Debug.Console(1, this, "Versiport change: {0}", args.Event);
+
+ if(args.Event == eVersiportEvent.AnalogInChange)
+ InputValueFeedback.FireUpdate();
+ if (args.Event == eVersiportEvent.AnalogMinChangeChange)
+ InputMinimumChangeFeedback.FireUpdate();
+ }
+
+
+ #region Bridge Linking
+
+ public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
+ {
+ var joinMap = new IAnalogInputJoinMap(joinStart);
+
+ var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
+
+ if (!string.IsNullOrEmpty(joinMapSerialized))
+ joinMap = JsonConvert.DeserializeObject(joinMapSerialized);
+
+ if (bridge != null)
+ {
+ bridge.AddJoinMap(Key, joinMap);
+ }
+ else
+ {
+ Debug.Console(0, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
+ }
+
+ try
+ {
+ Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
+
+ // Link feedback for input state
+ InputValueFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputValue.JoinNumber]);
+ InputMinimumChangeFeedback.LinkInputSig(trilist.UShortInput[joinMap.MinimumChange.JoinNumber]);
+ trilist.SetUShortSigAction(joinMap.MinimumChange.JoinNumber, SetMinimumChange);
+
+ }
+ catch (Exception e)
+ {
+ Debug.Console(1, this, "Unable to link device '{0}'. Input is null", Key);
+ Debug.Console(1, this, "Error: {0}", e);
+ }
+
+ trilist.OnlineStatusChange += (d, args) =>
+ {
+ if (!args.DeviceOnLine) return;
+ InputValueFeedback.FireUpdate();
+ InputMinimumChangeFeedback.FireUpdate();
+ };
+
+ }
+
+ void trilist_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+
+ public static Versiport GetVersiportDigitalInput(IOPortConfig dc)
+ {
+
+ IIOPorts ioPortDevice;
+
+ if (dc.PortDeviceKey.Equals("processor"))
+ {
+ if (!Global.ControlSystem.SupportsVersiport)
+ {
+ Debug.Console(0, "GetVersiportAnalogInput: Processor does not support Versiports");
+ return null;
+ }
+ ioPortDevice = Global.ControlSystem;
+ }
+ else
+ {
+ var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts;
+ if (ioPortDev == null)
+ {
+ Debug.Console(0, "GetVersiportAnalogInput: Device {0} is not a valid device", dc.PortDeviceKey);
+ return null;
+ }
+ ioPortDevice = ioPortDev;
+ }
+ if (ioPortDevice == null)
+ {
+ Debug.Console(0, "GetVersiportAnalogInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey);
+ return null;
+ }
+
+ if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts)
+ {
+ Debug.Console(0, "GetVersiportAnalogInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber);
+ return null;
+ }
+ if(!ioPortDevice.VersiPorts[dc.PortNumber].SupportsAnalogInput)
+ {
+ Debug.Console(0, "GetVersiportAnalogInput: Device {0} does not support AnalogInput on port {1}", dc.PortDeviceKey, dc.PortNumber);
+ return null;
+ }
+
+
+ return ioPortDevice.VersiPorts[dc.PortNumber];
+
+
+ }
+ }
+
+
+ public class GenericVersiportAbalogInputDeviceFactory : EssentialsDeviceFactory
+ {
+ public GenericVersiportAbalogInputDeviceFactory()
+ {
+ TypeNames = new List() { "versiportanaloginput" };
+ }
+
+ public override EssentialsDevice BuildDevice(DeviceConfig dc)
+ {
+ Debug.Console(1, "Factory Attempting to create new Generic Versiport Device");
+
+ var props = JsonConvert.DeserializeObject(dc.Properties.ToString());
+
+ if (props == null) return null;
+
+ var portDevice = new GenericVersiportAnalogInputDevice(dc.Key, dc.Name, GenericVersiportAnalogInputDevice.GetVersiportDigitalInput, props);
+
+ return portDevice;
+ }
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/IAnalogInput.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/IAnalogInput.cs
new file mode 100644
index 00000000..44af9954
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Inputs/IAnalogInput.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Crestron.SimplSharp;
+using PepperDash.Essentials.Core;
+
+namespace PepperDash.Essentials.Core.CrestronIO
+{
+ public interface IAnalogInput
+ {
+ IntFeedback InputValueFeedback { get; }
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/GenericVersiportOutputDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/GenericVersiportOutputDevice.cs
new file mode 100644
index 00000000..2d1ae9c4
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/GenericVersiportOutputDevice.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Crestron.SimplSharp;
+using Crestron.SimplSharpPro;
+using Crestron.SimplSharpPro.DeviceSupport;
+
+using PepperDash.Core;
+using PepperDash.Essentials.Core.Config;
+using PepperDash.Essentials.Core.Bridges;
+
+
+using Newtonsoft.Json;
+
+namespace PepperDash.Essentials.Core.CrestronIO
+{
+ ///
+ /// Represents a generic digital input deviced tied to a versiport
+ ///
+ public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput
+ {
+ public Versiport OutputPort { get; private set; }
+
+ public BoolFeedback OutputStateFeedback { get; private set; }
+
+ Func OutputStateFeedbackFunc
+ {
+ get
+ {
+ return () => OutputPort.DigitalOut;
+ }
+ }
+
+ public GenericVersiportDigitalOutputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) :
+ base(key, name)
+ {
+ OutputStateFeedback = new BoolFeedback(OutputStateFeedbackFunc);
+
+ AddPostActivationAction(() =>
+ {
+ OutputPort = postActivationFunc(config);
+
+ OutputPort.Register();
+
+
+ if (!OutputPort.SupportsDigitalOutput)
+ {
+ Debug.Console(0, this, "Device does not support configuration as a Digital Output");
+ return;
+ }
+
+ OutputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalOutput);
+
+
+ OutputPort.VersiportChange += OutputPort_VersiportChange;
+
+ });
+
+ }
+
+ void OutputPort_VersiportChange(Versiport port, VersiportEventArgs args)
+ {
+ Debug.Console(1, this, "Versiport change: {0}", args.Event);
+
+ if(args.Event == eVersiportEvent.DigitalOutChange)
+ OutputStateFeedback.FireUpdate();
+ }
+
+ ///
+ /// Set value of the versiport digital output
+ ///
+ /// value to set the output to
+ public void SetOutput(bool state)
+ {
+ if (OutputPort.SupportsDigitalOutput)
+ {
+ Debug.Console(0, this, "Passed the Check");
+
+ OutputPort.DigitalOut = state;
+
+ }
+ else
+ {
+ Debug.Console(0, this, "Versiport does not support Digital Output Mode");
+ }
+
+ }
+
+ #region Bridge Linking
+
+ public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
+ {
+ var joinMap = new IDigitalOutputJoinMap(joinStart);
+
+ var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
+
+ if (!string.IsNullOrEmpty(joinMapSerialized))
+ joinMap = JsonConvert.DeserializeObject(joinMapSerialized);
+
+ if (bridge != null)
+ {
+ bridge.AddJoinMap(Key, joinMap);
+ }
+ else
+ {
+ Debug.Console(0, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
+ }
+
+ try
+ {
+ Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
+
+ // Link feedback for input state
+ OutputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.OutputState.JoinNumber]);
+ trilist.SetBoolSigAction(joinMap.OutputState.JoinNumber, SetOutput);
+ }
+ catch (Exception e)
+ {
+ Debug.Console(1, this, "Unable to link device '{0}'. Input is null", Key);
+ Debug.Console(1, this, "Error: {0}", e);
+ }
+ }
+
+ #endregion
+
+
+ public static Versiport GetVersiportDigitalOutput(IOPortConfig dc)
+ {
+
+ IIOPorts ioPortDevice;
+
+ if (dc.PortDeviceKey.Equals("processor"))
+ {
+ if (!Global.ControlSystem.SupportsVersiport)
+ {
+ Debug.Console(0, "GetVersiportDigitalOuptut: Processor does not support Versiports");
+ return null;
+ }
+ ioPortDevice = Global.ControlSystem;
+ }
+ else
+ {
+ var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts;
+ if (ioPortDev == null)
+ {
+ Debug.Console(0, "GetVersiportDigitalOuptut: Device {0} is not a valid device", dc.PortDeviceKey);
+ return null;
+ }
+ ioPortDevice = ioPortDev;
+ }
+ if (ioPortDevice == null)
+ {
+ Debug.Console(0, "GetVersiportDigitalOuptut: Device '0' is not a valid IOPorts Device", dc.PortDeviceKey);
+ return null;
+ }
+
+ if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts)
+ {
+ Debug.Console(0, "GetVersiportDigitalOuptut: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber);
+ }
+ var port = ioPortDevice.VersiPorts[dc.PortNumber];
+ return port;
+
+ }
+ }
+
+
+ public class GenericVersiportDigitalOutputDeviceFactory : EssentialsDeviceFactory
+ {
+ public GenericVersiportDigitalOutputDeviceFactory()
+ {
+ TypeNames = new List() { "versiportoutput" };
+ }
+
+ public override EssentialsDevice BuildDevice(DeviceConfig dc)
+ {
+ Debug.Console(1, "Factory Attempting to create new Generic Versiport Device");
+
+ var props = JsonConvert.DeserializeObject(dc.Properties.ToString());
+
+ if (props == null) return null;
+
+ var portDevice = new GenericVersiportDigitalOutputDevice(dc.Key, dc.Name, GenericVersiportDigitalOutputDevice.GetVersiportDigitalOutput, props);
+
+ return portDevice;
+ }
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/IDigitalOutput.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/IDigitalOutput.cs
new file mode 100644
index 00000000..b4151941
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Outputs/IDigitalOutput.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Crestron.SimplSharp;
+
+namespace PepperDash.Essentials.Core.CrestronIO
+{
+ ///
+ /// Represents a device that provides digital input
+ ///
+ public interface IDigitalOutput
+ {
+ BoolFeedback OutputStateFeedback { get; }
+ void SetOutput(bool state);
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Extensions/StringExtensions.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Extensions/StringExtensions.cs
index 708ed930..39501387 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Extensions/StringExtensions.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Extensions/StringExtensions.cs
@@ -16,5 +16,9 @@ namespace PepperDash.Essentials.Core
{
return string.IsNullOrEmpty(s.Trim()) ? null : s;
}
+ public static string ReplaceIfNullOrEmpty(this string s, string newString)
+ {
+ return string.IsNullOrEmpty(s) ? newString : s;
+ }
}
}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs
index 04abc7f8..6ffb16cc 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/JoinMaps/JoinMapBase.cs
@@ -1,8 +1,13 @@
using System;
using System.Collections.Generic;
+using System.Data;
+using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Text;
using Crestron.SimplSharp.Reflection;
+using Crestron.SimplSharp.CrestronIO;
+using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
@@ -193,19 +198,6 @@ namespace PepperDash.Essentials.Core
protected void AddJoins(Type type)
{
- // Add all the JoinDataComplete properties to the Joins Dictionary and pass in the offset
- //Joins = this.GetType()
- // .GetCType()
- // .GetFields(BindingFlags.Public | BindingFlags.Instance)
- // .Where(field => field.IsDefined(typeof(JoinNameAttribute), true))
- // .Select(field => (JoinDataComplete)field.GetValue(this))
- // .ToDictionary(join => join.GetNameAttribute(), join =>
- // {
- // join.SetJoinOffset(_joinOffset);
- // return join;
- // });
-
- //type = this.GetType(); <- this wasn't working because 'this' was always the base class, never the derived class
var fields =
type.GetCType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
@@ -219,7 +211,7 @@ namespace PepperDash.Essentials.Core
if (value == null)
{
- Debug.Console(0, "Unable to caset base class to {0}", type.Name);
+ Debug.Console(0, "Unable to cast base class to {0}", type.Name);
continue;
}
@@ -256,12 +248,64 @@ namespace PepperDash.Essentials.Core
var analogs = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Analog Joins", analogs.Count);
PrintJoinList(GetSortedJoins(analogs));
-
+
Debug.Console(0, "Serials:");
var serials = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Serial Joins", serials.Count);
PrintJoinList(GetSortedJoins(serials));
+ }
+ ///
+ /// Prints the join information to console
+ ///
+ public void MarkdownJoinMapInfo(string deviceKey, string bridgeKey)
+ {
+ var pluginType = GetType().Name;
+
+ Debug.Console(0, "{0}:\n", pluginType);
+
+ var sb = new StringBuilder();
+
+ sb.AppendLine(String.Format("# {0}", GetType().Name));
+ sb.AppendLine(String.Format("Generated from '{0}' on bridge '{1}'", deviceKey, bridgeKey));
+ sb.AppendLine();
+ sb.AppendLine("## Digitals");
+ // Get the joins of each type and print them
+ var digitals = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value);
+ Debug.Console(2, "Found {0} Digital Joins", digitals.Count);
+ var digitalSb = AppendJoinList(GetSortedJoins(digitals));
+ digitalSb.AppendLine("## Analogs");
+ digitalSb.AppendLine();
+
+ Debug.Console(0, "Analogs:");
+ var analogs = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value);
+ Debug.Console(2, "Found {0} Analog Joins", analogs.Count);
+ var analogSb = AppendJoinList(GetSortedJoins(analogs));
+ analogSb.AppendLine("## Serials");
+ analogSb.AppendLine();
+
+ Debug.Console(0, "Serials:");
+ var serials = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value);
+ Debug.Console(2, "Found {0} Serial Joins", serials.Count);
+ var serialSb = AppendJoinList(GetSortedJoins(serials));
+
+ sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length);
+ sb.Append(digitalSb).Append(analogSb).Append(serialSb);
+
+ WriteJoinmapMarkdown(sb, pluginType, bridgeKey, deviceKey);
+
+ }
+
+ private static void WriteJoinmapMarkdown(StringBuilder stringBuilder, string pluginType, string bridgeKey, string deviceKey)
+ {
+ var fileName = String.Format("{0}{1}{2}__{3}__{4}.md", Global.FilePathPrefix, "joinMaps/", pluginType, bridgeKey, deviceKey);
+
+ using (var sw = new StreamWriter(fileName))
+ {
+ sw.WriteLine(stringBuilder.ToString());
+ Debug.Console(0, "Joinmap Readme generated and written to {0}", fileName);
+ }
+
}
///
@@ -293,6 +337,39 @@ namespace PepperDash.Essentials.Core
}
}
+ static StringBuilder AppendJoinList(List> joins)
+ {
+ var sb = new StringBuilder();
+ const string stringFormatter = "| {0} | {1} | {2} | {3} | {4} |";
+ const int joinNumberLen = 11;
+ const int joinSpanLen = 9;
+ const int typeLen = 19;
+ const int capabilitiesLen = 12;
+ var descriptionLen = (from @join in joins select @join.Value into j select j.Metadata.Description.Length).Concat(new[] {11}).Max();
+
+ //build header
+ sb.AppendLine(String.Format(stringFormatter,
+ String.Format("Join Number").PadRight(joinNumberLen, ' '),
+ String.Format("Join Span").PadRight(joinSpanLen, ' '),
+ String.Format("Description").PadRight(descriptionLen, ' '),
+ String.Format("Type").PadRight(typeLen, ' '),
+ String.Format("Capabilities").PadRight(capabilitiesLen, ' ')));
+ //build table seperator
+ sb.AppendLine(String.Format(stringFormatter,
+ new String('-', joinNumberLen),
+ new String('-', joinSpanLen),
+ new String('-', descriptionLen),
+ new String('-', typeLen),
+ new String('-', capabilitiesLen)));
+
+ foreach (var join in joins)
+ {
+ sb.AppendLine(join.Value.GetMarkdownFormattedData(stringFormatter, descriptionLen));
+ }
+ sb.AppendLine();
+ return sb;
+ }
+
///
/// Attempts to find the matching key for the custom join and if found overwrites the default JoinData with the custom
///
@@ -459,6 +536,64 @@ namespace PepperDash.Essentials.Core
Metadata = metadata;
}
+ public string GetMarkdownFormattedData(string stringFormatter, int descriptionLen)
+ {
+
+ //Fixed Width Headers
+ var joinNumberLen = String.Format("Join Number").Length;
+ var joinSpanLen = String.Format("Join Span").Length;
+ var typeLen = String.Format("AnalogDigitalSerial").Length;
+ var capabilitiesLen = String.Format("ToFromFusion").Length;
+
+ //Track which one failed, if it did
+ const string placeholder = "unknown";
+ var dataArray = new Dictionary
+ {
+ {"joinNumber", placeholder.PadRight(joinNumberLen, ' ')},
+ {"joinSpan", placeholder.PadRight(joinSpanLen, ' ')},
+ {"description", placeholder.PadRight(descriptionLen, ' ')},
+ {"joinType", placeholder.PadRight(typeLen, ' ')},
+ {"capabilities", placeholder.PadRight(capabilitiesLen, ' ')}
+ };
+
+
+ try
+ {
+ dataArray["joinNumber"] = String.Format("{0}", JoinNumber.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinNumberLen, ' ');
+ dataArray["joinSpan"] = String.Format("{0}", JoinSpan.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinSpanLen, ' ');
+ dataArray["description"] = String.Format("{0}", Metadata.Description.ReplaceIfNullOrEmpty(placeholder)).PadRight(descriptionLen, ' ');
+ dataArray["joinType"] = String.Format("{0}", Metadata.JoinType.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(typeLen, ' ');
+ dataArray["capabilities"] = String.Format("{0}", Metadata.JoinCapabilities.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(capabilitiesLen, ' ');
+
+ return String.Format(stringFormatter,
+ dataArray["joinNumber"],
+ dataArray["joinSpan"],
+ dataArray["description"],
+ dataArray["joinType"],
+ dataArray["capabilities"]);
+
+ }
+ catch (Exception e)
+ {
+ //Don't Throw - we don't want to kill the system if this falls over - it's not mission critical. Print the error, use placeholder data
+ var errorKey = string.Empty;
+ foreach (var item in dataArray)
+ {
+ if (item.Value.TrimEnd() == placeholder) ;
+ errorKey = item.Key;
+ break;
+ }
+ Debug.Console(0, "Unable to decode join metadata {1}- {0}", e.Message, !String.IsNullOrEmpty(errorKey) ? (' ' + errorKey) : String.Empty);
+ return String.Format(stringFormatter,
+ dataArray["joinNumber"],
+ dataArray["joinSpan"],
+ dataArray["description"],
+ dataArray["joinType"],
+ dataArray["capabilities"]);
+ }
+ }
+
+
///
/// Sets the join offset value
///
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj
index dfa59b88..268d4f12 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj
@@ -123,6 +123,8 @@
+
+
@@ -179,12 +181,17 @@
+
+
+
+
+
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/IRoutingInputsExtensions.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/IRoutingInputsExtensions.cs
index d371c2d6..4cd0d4ff 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/IRoutingInputsExtensions.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/IRoutingInputsExtensions.cs
@@ -1,425 +1,425 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Crestron.SimplSharp;
-using Crestron.SimplSharpPro;
-using Crestron.SimplSharpPro.DM;
-
-using PepperDash.Core;
-
-
-namespace PepperDash.Essentials.Core
-{
- public class RouteRequest
- {
- public IRoutingSink Destination {get; set;}
- public IRoutingOutputs Source {get; set;}
- public eRoutingSignalType SignalType {get; set;}
-
- public void HandleCooldown(object sender, FeedbackEventArgs args)
- {
- var coolingDevice = sender as IWarmingCooling;
-
- if(args.BoolValue == false)
- {
- Destination.ReleaseAndMakeRoute(Source, SignalType);
-
- if(sender == null) return;
-
- coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown;
- }
- }
- }
-
- ///
- /// Extensions added to any IRoutingInputs classes to provide discovery-based routing
- /// on those destinations.
- ///
- public static class IRoutingInputsExtensions
- {
- private static Dictionary RouteRequests = new Dictionary();
- ///
- /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
- /// and then attempts a new Route and if sucessful, stores that RouteDescriptor
- /// in RouteDescriptorCollection.DefaultCollection
- ///
- public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
- {
- var routeRequest = new RouteRequest {
- Destination = destination,
- Source = source,
- SignalType = signalType
- };
-
- var coolingDevice = destination as IWarmingCooling;
-
- RouteRequest existingRouteRequest;
-
- //We already have a route request for this device, and it's a cooling device and is cooling
- if (RouteRequests.TryGetValue(destination.Key, out existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
- {
- coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
-
- coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
-
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Crestron.SimplSharp;
+using Crestron.SimplSharpPro;
+using Crestron.SimplSharpPro.DM;
+
+using PepperDash.Core;
+
+
+namespace PepperDash.Essentials.Core
+{
+ public class RouteRequest
+ {
+ public IRoutingSink Destination {get; set;}
+ public IRoutingOutputs Source {get; set;}
+ public eRoutingSignalType SignalType {get; set;}
+
+ public void HandleCooldown(object sender, FeedbackEventArgs args)
+ {
+ var coolingDevice = sender as IWarmingCooling;
+
+ if(args.BoolValue == false)
+ {
+ Destination.ReleaseAndMakeRoute(Source, SignalType);
+
+ if(sender == null) return;
+
+ coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown;
+ }
+ }
+ }
+
+ ///
+ /// Extensions added to any IRoutingInputs classes to provide discovery-based routing
+ /// on those destinations.
+ ///
+ public static class IRoutingInputsExtensions
+ {
+ private static Dictionary RouteRequests = new Dictionary();
+ ///
+ /// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
+ /// and then attempts a new Route and if sucessful, stores that RouteDescriptor
+ /// in RouteDescriptorCollection.DefaultCollection
+ ///
+ public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
+ {
+ var routeRequest = new RouteRequest {
+ Destination = destination,
+ Source = source,
+ SignalType = signalType
+ };
+
+ var coolingDevice = destination as IWarmingCooling;
+
+ RouteRequest existingRouteRequest;
+
+ //We already have a route request for this device, and it's a cooling device and is cooling
+ if (RouteRequests.TryGetValue(destination.Key, out existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
+ {
+ coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
+
+ coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
+
RouteRequests[destination.Key] = routeRequest;
- Debug.Console(2, "******************************************************** Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", destination.Key, routeRequest.Source.Key);
-
- return;
- }
-
- //New Request
- if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
- {
- coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown;
-
- coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
-
+ Debug.Console(2, "******************************************************** Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", destination.Key, routeRequest.Source.Key);
+
+ return;
+ }
+
+ //New Request
+ if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
+ {
+ coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown;
+
+ coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
+
RouteRequests.Add(destination.Key, routeRequest);
Debug.Console(2, "******************************************************** Device: {0} is cooling down. Storing route request to route to source key: {1}", destination.Key, routeRequest.Source.Key);
- return;
- }
-
- if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false)
- {
+ return;
+ }
+
+ if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false)
+ {
RouteRequests.Remove(destination.Key);
Debug.Console(2, "******************************************************** Device: {0} is NOT cooling down. Removing stored route request and routing to source key: {1}", destination.Key, routeRequest.Source.Key);
- }
-
- destination.ReleaseRoute();
-
- RunRouteRequest(routeRequest);
- }
-
- public static void RunRouteRequest(RouteRequest request)
- {
- if (request.Source == null) return;
- var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType);
- if (newRoute == null) return;
- RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute);
- Debug.Console(2, request.Destination, "Executing full route");
- newRoute.ExecuteRoutes();
- }
-
- ///
- /// Will release the existing route on the destination, if it is found in
- /// RouteDescriptorCollection.DefaultCollection
- ///
- ///
- public static void ReleaseRoute(this IRoutingSink destination)
- {
- RouteRequest existingRequest;
-
- if (RouteRequests.TryGetValue(destination.Key, out existingRequest) && destination is IWarmingCooling)
- {
- var coolingDevice = destination as IWarmingCooling;
-
- coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown;
- }
-
- RouteRequests.Remove(destination.Key);
-
- var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination);
- if (current != null)
- {
- Debug.Console(1, destination, "Releasing current route: {0}", current.Source.Key);
- current.ReleaseRoutes();
- }
- }
-
- ///
- /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices.
- /// Routes of type AudioVideo will be built as two separate routes, audio and video. If
- /// a route is discovered, a new RouteDescriptor is returned. If one or both parts
- /// of an audio/video route are discovered a route descriptor is returned. If no route is
- /// discovered, then null is returned
- ///
- public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
- {
- var routeDescr = new RouteDescriptor(source, destination, signalType);
- // if it's a single signal type, find the route
- if ((signalType & (eRoutingSignalType.Audio & eRoutingSignalType.Video)) == (eRoutingSignalType.Audio & eRoutingSignalType.Video))
- {
- Debug.Console(1, destination, "Attempting to build source route from {0}", source.Key);
- if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescr))
- routeDescr = null;
- }
- // otherwise, audioVideo needs to be handled as two steps.
- else
- {
- Debug.Console(1, destination, "Attempting to build audio and video routes from {0}", source.Key);
- var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescr);
- if (!audioSuccess)
- Debug.Console(1, destination, "Cannot find audio route to {0}", source.Key);
- var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescr);
- if (!videoSuccess)
- Debug.Console(1, destination, "Cannot find video route to {0}", source.Key);
- if (!audioSuccess && !videoSuccess)
- routeDescr = null;
- }
-
- //Debug.Console(1, destination, "Route{0} discovered", routeDescr == null ? " NOT" : "");
- return routeDescr;
- }
-
- ///
- /// The recursive part of this. Will stop on each device, search its inputs for the
- /// desired source and if not found, invoke this function for the each input port
- /// hoping to find the source.
- ///
- ///
- ///
- /// The RoutingOutputPort whose link is being checked for a route
- /// Prevents Devices from being twice-checked
- /// This recursive function should not be called with AudioVideo
- /// Just an informational counter
- /// The RouteDescriptor being populated as the route is discovered
- /// true if source is hit
- static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
- RoutingOutputPort outputPortToUse, List alreadyCheckedDevices,
- eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable)
- {
- cycle++;
- Debug.Console(2, "GetRouteToSource: {0} {1}--> {2}", cycle, source.Key, destination.Key);
-
- RoutingInputPort goodInputPort = null;
- var destDevInputTies = TieLineCollection.Default.Where(t =>
- t.DestinationPort.ParentDevice == destination && (t.Type == signalType || (t.Type & (eRoutingSignalType.Audio | eRoutingSignalType.Video)) == (eRoutingSignalType.Audio | eRoutingSignalType.Video)));
-
- // find a direct tie
- var directTie = destDevInputTies.FirstOrDefault(
- t => t.DestinationPort.ParentDevice == destination
- && t.SourcePort.ParentDevice == source);
- if (directTie != null) // Found a tie directly to the source
- {
- goodInputPort = directTie.DestinationPort;
- }
- else // no direct-connect. Walk back devices.
- {
- Debug.Console(2, destination, "is not directly connected to {0}. Walking down tie lines", source.Key);
-
- // No direct tie? Run back out on the inputs' attached devices...
- // Only the ones that are routing devices
- var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
-
- //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
- if (alreadyCheckedDevices == null)
- alreadyCheckedDevices = new List();
- alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
-
- foreach (var inputTieToTry in attachedMidpoints)
- {
- var upstreamDeviceOutputPort = inputTieToTry.SourcePort;
- var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs;
- Debug.Console(2, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key);
-
- // Check if this previous device has already been walked
- if (alreadyCheckedDevices.Contains(upstreamRoutingDevice))
- {
- Debug.Console(2, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key);
- continue;
- }
- // haven't seen this device yet. Do it. Pass the output port to the next
- // level to enable switching on success
- var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
- alreadyCheckedDevices, signalType, cycle, routeTable);
- if (upstreamRoutingSuccess)
- {
- Debug.Console(2, destination, "Upstream device route found");
- goodInputPort = inputTieToTry.DestinationPort;
- break; // Stop looping the inputs in this cycle
- }
- }
- }
-
- // we have a route on corresponding inputPort. *** Do the route ***
- if (goodInputPort != null)
- {
- //Debug.Console(2, destination, "adding RouteDescriptor");
- if (outputPortToUse == null)
- {
- // it's a sink device
- routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
- }
- else if (destination is IRouting)
- {
- routeTable.Routes.Add(new RouteSwitchDescriptor (outputPortToUse, goodInputPort));
- }
- else // device is merely IRoutingInputOutputs
- Debug.Console(2, destination, " No routing. Passthrough device");
- //Debug.Console(2, destination, "Exiting cycle {0}", cycle);
- return true;
- }
-
- Debug.Console(2, destination, "No route found to {0}", source.Key);
- return false;
- }
- }
-
-
-
-
-
- // MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE
-
-
- ///
- /// A collection of RouteDescriptors - typically the static DefaultCollection is used
- ///
- public class RouteDescriptorCollection
- {
- public static RouteDescriptorCollection DefaultCollection
- {
- get
- {
- if (_DefaultCollection == null)
- _DefaultCollection = new RouteDescriptorCollection();
- return _DefaultCollection;
- }
- }
- static RouteDescriptorCollection _DefaultCollection;
-
- List RouteDescriptors = new List();
-
- ///
- /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the
- /// destination exists already, it will not be added - in order to preserve
- /// proper route releasing.
- ///
- ///
- public void AddRouteDescriptor(RouteDescriptor descriptor)
- {
- if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination))
- {
- Debug.Console(1, descriptor.Destination,
- "Route to [{0}] already exists in global routes table", descriptor.Source.Key);
- return;
- }
- RouteDescriptors.Add(descriptor);
- }
-
- ///
- /// Gets the RouteDescriptor for a destination
- ///
- /// null if no RouteDescriptor for a destination exists
- public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination)
- {
- return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination);
- }
-
- ///
- /// Returns the RouteDescriptor for a given destination AND removes it from collection.
- /// Returns null if no route with the provided destination exists.
- ///
- public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination)
- {
- var descr = GetRouteDescriptorForDestination(destination);
- if (descr != null)
- RouteDescriptors.Remove(descr);
- return descr;
- }
- }
-
- ///
- /// Represents an collection of individual route steps between Source and Destination
- ///
- public class RouteDescriptor
- {
- public IRoutingInputs Destination { get; private set; }
- public IRoutingOutputs Source { get; private set; }
- public eRoutingSignalType SignalType { get; private set; }
- public List Routes { get; private set; }
-
-
- public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType)
- {
- Destination = destination;
- Source = source;
- SignalType = signalType;
- Routes = new List();
- }
-
- ///
- /// Executes all routes described in this collection. Typically called via
- /// extension method IRoutingInputs.ReleaseAndMakeRoute()
- ///
- public void ExecuteRoutes()
- {
- foreach (var route in Routes)
- {
- Debug.Console(2, "ExecuteRoutes: {0}", route.ToString());
- if (route.SwitchingDevice is IRoutingSink)
- {
- var device = route.SwitchingDevice as IRoutingSinkWithSwitching;
- if (device == null)
- continue;
-
- device.ExecuteSwitch(route.InputPort.Selector);
- }
- else if (route.SwitchingDevice is IRouting)
- {
- (route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
- route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
- Debug.Console(2, "Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
- }
- }
- }
-
- ///
- /// Releases all routes in this collection. Typically called via
- /// extension method IRoutingInputs.ReleaseAndMakeRoute()
- ///
- public void ReleaseRoutes()
- {
- foreach (var route in Routes)
- {
- if (route.SwitchingDevice is IRouting)
- {
- // Pull the route from the port. Whatever is watching the output's in use tracker is
- // responsible for responding appropriately.
- route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType);
- Debug.Console(2, "Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
- }
- }
- }
-
- public override string ToString()
- {
- var routesText = Routes.Select(r => r.ToString()).ToArray();
- return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText));
- }
- }
-
- ///
- /// Represents an individual link for a route
- ///
- public class RouteSwitchDescriptor
- {
- public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } }
- public RoutingOutputPort OutputPort { get; set; }
- public RoutingInputPort InputPort { get; set; }
-
- public RouteSwitchDescriptor(RoutingInputPort inputPort)
- {
- InputPort = inputPort;
- }
-
- public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort)
- {
- InputPort = inputPort;
- OutputPort = outputPort;
- }
-
- public override string ToString()
- {
- if(SwitchingDevice is IRouting)
- return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector);
- else
- return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector);
-
- }
- }
+ }
+
+ destination.ReleaseRoute();
+
+ RunRouteRequest(routeRequest);
+ }
+
+ public static void RunRouteRequest(RouteRequest request)
+ {
+ if (request.Source == null) return;
+ var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType);
+ if (newRoute == null) return;
+ RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute);
+ Debug.Console(2, request.Destination, "Executing full route");
+ newRoute.ExecuteRoutes();
+ }
+
+ ///
+ /// Will release the existing route on the destination, if it is found in
+ /// RouteDescriptorCollection.DefaultCollection
+ ///
+ ///
+ public static void ReleaseRoute(this IRoutingSink destination)
+ {
+ RouteRequest existingRequest;
+
+ if (RouteRequests.TryGetValue(destination.Key, out existingRequest) && destination is IWarmingCooling)
+ {
+ var coolingDevice = destination as IWarmingCooling;
+
+ coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown;
+ }
+
+ RouteRequests.Remove(destination.Key);
+
+ var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination);
+ if (current != null)
+ {
+ Debug.Console(1, destination, "Releasing current route: {0}", current.Source.Key);
+ current.ReleaseRoutes();
+ }
+ }
+
+ ///
+ /// Builds a RouteDescriptor that contains the steps necessary to make a route between devices.
+ /// Routes of type AudioVideo will be built as two separate routes, audio and video. If
+ /// a route is discovered, a new RouteDescriptor is returned. If one or both parts
+ /// of an audio/video route are discovered a route descriptor is returned. If no route is
+ /// discovered, then null is returned
+ ///
+ public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
+ {
+ var routeDescr = new RouteDescriptor(source, destination, signalType);
+ // if it's a single signal type, find the route
+ if ((signalType & (eRoutingSignalType.Audio & eRoutingSignalType.Video)) == (eRoutingSignalType.Audio & eRoutingSignalType.Video))
+ {
+ Debug.Console(1, destination, "Attempting to build source route from {0}", source.Key);
+ if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescr))
+ routeDescr = null;
+ }
+ // otherwise, audioVideo needs to be handled as two steps.
+ else
+ {
+ Debug.Console(1, destination, "Attempting to build audio and video routes from {0}", source.Key);
+ var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescr);
+ if (!audioSuccess)
+ Debug.Console(1, destination, "Cannot find audio route to {0}", source.Key);
+ var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescr);
+ if (!videoSuccess)
+ Debug.Console(1, destination, "Cannot find video route to {0}", source.Key);
+ if (!audioSuccess && !videoSuccess)
+ routeDescr = null;
+ }
+
+ //Debug.Console(1, destination, "Route{0} discovered", routeDescr == null ? " NOT" : "");
+ return routeDescr;
+ }
+
+ ///
+ /// The recursive part of this. Will stop on each device, search its inputs for the
+ /// desired source and if not found, invoke this function for the each input port
+ /// hoping to find the source.
+ ///
+ ///
+ ///
+ /// The RoutingOutputPort whose link is being checked for a route
+ /// Prevents Devices from being twice-checked
+ /// This recursive function should not be called with AudioVideo
+ /// Just an informational counter
+ /// The RouteDescriptor being populated as the route is discovered
+ /// true if source is hit
+ static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
+ RoutingOutputPort outputPortToUse, List alreadyCheckedDevices,
+ eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable)
+ {
+ cycle++;
+ Debug.Console(2, "GetRouteToSource: {0} {1}--> {2}", cycle, source.Key, destination.Key);
+
+ RoutingInputPort goodInputPort = null;
+ var destDevInputTies = TieLineCollection.Default.Where(t =>
+ t.DestinationPort.ParentDevice == destination && (t.Type == signalType || (t.Type & (eRoutingSignalType.Audio | eRoutingSignalType.Video)) == (eRoutingSignalType.Audio | eRoutingSignalType.Video)));
+
+ // find a direct tie
+ var directTie = destDevInputTies.FirstOrDefault(
+ t => t.DestinationPort.ParentDevice == destination
+ && t.SourcePort.ParentDevice == source);
+ if (directTie != null) // Found a tie directly to the source
+ {
+ goodInputPort = directTie.DestinationPort;
+ }
+ else // no direct-connect. Walk back devices.
+ {
+ Debug.Console(2, destination, "is not directly connected to {0}. Walking down tie lines", source.Key);
+
+ // No direct tie? Run back out on the inputs' attached devices...
+ // Only the ones that are routing devices
+ var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
+
+ //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
+ if (alreadyCheckedDevices == null)
+ alreadyCheckedDevices = new List();
+ alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
+
+ foreach (var inputTieToTry in attachedMidpoints)
+ {
+ var upstreamDeviceOutputPort = inputTieToTry.SourcePort;
+ var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs;
+ Debug.Console(2, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key);
+
+ // Check if this previous device has already been walked
+ if (alreadyCheckedDevices.Contains(upstreamRoutingDevice))
+ {
+ Debug.Console(2, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key);
+ continue;
+ }
+ // haven't seen this device yet. Do it. Pass the output port to the next
+ // level to enable switching on success
+ var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
+ alreadyCheckedDevices, signalType, cycle, routeTable);
+ if (upstreamRoutingSuccess)
+ {
+ Debug.Console(2, destination, "Upstream device route found");
+ goodInputPort = inputTieToTry.DestinationPort;
+ break; // Stop looping the inputs in this cycle
+ }
+ }
+ }
+
+ // we have a route on corresponding inputPort. *** Do the route ***
+ if (goodInputPort != null)
+ {
+ //Debug.Console(2, destination, "adding RouteDescriptor");
+ if (outputPortToUse == null)
+ {
+ // it's a sink device
+ routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
+ }
+ else if (destination is IRouting)
+ {
+ routeTable.Routes.Add(new RouteSwitchDescriptor (outputPortToUse, goodInputPort));
+ }
+ else // device is merely IRoutingInputOutputs
+ Debug.Console(2, destination, " No routing. Passthrough device");
+ //Debug.Console(2, destination, "Exiting cycle {0}", cycle);
+ return true;
+ }
+
+ Debug.Console(2, destination, "No route found to {0}", source.Key);
+ return false;
+ }
+ }
+
+
+
+
+
+ // MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE
+
+
+ ///
+ /// A collection of RouteDescriptors - typically the static DefaultCollection is used
+ ///
+ public class RouteDescriptorCollection
+ {
+ public static RouteDescriptorCollection DefaultCollection
+ {
+ get
+ {
+ if (_DefaultCollection == null)
+ _DefaultCollection = new RouteDescriptorCollection();
+ return _DefaultCollection;
+ }
+ }
+ static RouteDescriptorCollection _DefaultCollection;
+
+ List RouteDescriptors = new List();
+
+ ///
+ /// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the
+ /// destination exists already, it will not be added - in order to preserve
+ /// proper route releasing.
+ ///
+ ///
+ public void AddRouteDescriptor(RouteDescriptor descriptor)
+ {
+ if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination))
+ {
+ Debug.Console(1, descriptor.Destination,
+ "Route to [{0}] already exists in global routes table", descriptor.Source.Key);
+ return;
+ }
+ RouteDescriptors.Add(descriptor);
+ }
+
+ ///
+ /// Gets the RouteDescriptor for a destination
+ ///
+ /// null if no RouteDescriptor for a destination exists
+ public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination)
+ {
+ return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination);
+ }
+
+ ///
+ /// Returns the RouteDescriptor for a given destination AND removes it from collection.
+ /// Returns null if no route with the provided destination exists.
+ ///
+ public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination)
+ {
+ var descr = GetRouteDescriptorForDestination(destination);
+ if (descr != null)
+ RouteDescriptors.Remove(descr);
+ return descr;
+ }
+ }
+
+ ///
+ /// Represents an collection of individual route steps between Source and Destination
+ ///
+ public class RouteDescriptor
+ {
+ public IRoutingInputs Destination { get; private set; }
+ public IRoutingOutputs Source { get; private set; }
+ public eRoutingSignalType SignalType { get; private set; }
+ public List Routes { get; private set; }
+
+
+ public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType)
+ {
+ Destination = destination;
+ Source = source;
+ SignalType = signalType;
+ Routes = new List();
+ }
+
+ ///
+ /// Executes all routes described in this collection. Typically called via
+ /// extension method IRoutingInputs.ReleaseAndMakeRoute()
+ ///
+ public void ExecuteRoutes()
+ {
+ foreach (var route in Routes)
+ {
+ Debug.Console(2, "ExecuteRoutes: {0}", route.ToString());
+ if (route.SwitchingDevice is IRoutingSink)
+ {
+ var device = route.SwitchingDevice as IRoutingSinkWithSwitching;
+ if (device == null)
+ continue;
+
+ device.ExecuteSwitch(route.InputPort.Selector);
+ }
+ else if (route.SwitchingDevice is IRouting)
+ {
+ (route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
+ route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
+ Debug.Console(2, "Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
+ }
+ }
+ }
+
+ ///
+ /// Releases all routes in this collection. Typically called via
+ /// extension method IRoutingInputs.ReleaseAndMakeRoute()
+ ///
+ public void ReleaseRoutes()
+ {
+ foreach (var route in Routes)
+ {
+ if (route.SwitchingDevice is IRouting)
+ {
+ // Pull the route from the port. Whatever is watching the output's in use tracker is
+ // responsible for responding appropriately.
+ route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType);
+ Debug.Console(2, "Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
+ }
+ }
+ }
+
+ public override string ToString()
+ {
+ var routesText = Routes.Select(r => r.ToString()).ToArray();
+ return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText));
+ }
+ }
+
+ ///
+ /// Represents an individual link for a route
+ ///
+ public class RouteSwitchDescriptor
+ {
+ public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } }
+ public RoutingOutputPort OutputPort { get; set; }
+ public RoutingInputPort InputPort { get; set; }
+
+ public RouteSwitchDescriptor(RoutingInputPort inputPort)
+ {
+ InputPort = inputPort;
+ }
+
+ public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort)
+ {
+ InputPort = inputPort;
+ OutputPort = outputPort;
+ }
+
+ public override string ToString()
+ {
+ if(SwitchingDevice is IRouting)
+ return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector);
+ else
+ return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector);
+
+ }
+ }
}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsManager.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsManager.cs
index 95a94a24..8e0cbc55 100644
--- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsManager.cs
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Secrets/SecretsManager.cs
@@ -148,6 +148,7 @@ namespace PepperDash.Essentials.Core
{
Secrets.Add(key, provider);
Debug.Console(1, "Secrets provider '{0}' added to SecretsManager", key);
+ return;
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key );
}
@@ -164,13 +165,13 @@ namespace PepperDash.Essentials.Core
{
Secrets.Add(key, provider);
Debug.Console(1, "Secrets provider '{0}' added to SecretsManager", key);
-
+ return;
}
if (overwrite)
{
Secrets.Add(key, provider);
Debug.Console(1, Debug.ErrorLogLevel.Notice, "Provider with the key '{0}' already exists in secrets. Overwriting with new secrets provider.", key);
-
+ return;
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key);
}