Compare commits

...

39 Commits

Author SHA1 Message Date
Andrew Welker
dd6e26ae4b add logic to only start logo server if it's required 2020-10-27 13:43:58 -06:00
Andrew Welker
fac1dd3d61 add protections for invalid paths in logo server 2020-10-27 13:43:37 -06:00
Andrew Welker
f22bf60eb6 Merge pull request #461 from PepperDash/release/1.6.5
Release/1.6.5 Main
2020-10-22 13:31:25 -06:00
Andrew Welker
d1b99fdda3 Merge pull request #460 from PepperDash/feature/i18n-addition
Add lists for optional things
2020-10-22 11:26:52 -06:00
Andrew Welker
e1a4cfca4e Add lists for additional values 2020-10-22 11:23:32 -06:00
Andrew Welker
8a43824f3d Merge pull request #459 from PepperDash/hotfix/dm-rx-DMPS
Multiple fixes for DMPS and Essentials
2020-10-21 16:15:09 -06:00
Andrew Welker
b948fc7264 Merge pull request #458 from PepperDash/feature/IDspPreset
Add IDspPreset Interface
2020-10-21 16:14:54 -06:00
Trevor Payne
d9f891dfb1 removed IHasDspPreset from Tesira Classes 2020-10-21 16:59:45 -05:00
Trevor Payne
a9524bcc33 Updated Interface to be more genericized 2020-10-21 16:30:48 -05:00
Andrew Welker
4b537cb79d Fixing some things for Essentials routing and linking to bridge 2020-10-21 13:00:12 -06:00
Trevor Payne
1484c26434 added IDspPreset Interface
Implemented IDspPreset Interface on internal Tesira DSP

Resolves #457
2020-10-21 12:55:41 -05:00
Andrew Welker
36e8dc9fa5 Add check for NameSig Support 2020-10-21 11:53:52 -06:00
Andrew Welker
8feb7037aa Change cast to ACTUAL Dmps3Dmoutput 2020-10-21 11:53:32 -06:00
Andrew Welker
d8863142c7 Refactor CustomActivate & LinkToApi 2020-10-21 10:21:40 -06:00
Andrew Welker
061109c901 add method to create a rmc for DMPS chassis 2020-10-21 10:05:19 -06:00
Andrew Welker
f95b50c99d Merge pull request #445 from PepperDash/feature/I18N-Support
Add interfaces for I18N support
2020-10-20 09:56:27 -06:00
Andrew Welker
def5cc273c Merge branch 'development' into feature/I18N-Support 2020-10-19 17:04:39 -06:00
Andrew Welker
e01d2c9569 Merge pull request #450 from PepperDash/bugfix/fix-docker-image
Update docker.yml
2020-10-19 17:04:11 -06:00
Andrew Welker
415dbbb195 Update docker.yml 2020-10-16 08:16:47 -06:00
Andrew Welker
765d90214d Merge branch 'feature/I18N-Support' of https://github.com/PepperDash/Essentials into feature/I18N-Support 2020-10-15 17:00:01 -06:00
Andrew Welker
36fd1dcda9 file name change 2020-10-15 16:59:39 -06:00
Andrew Welker
812b9b731b Merge branch 'development' into feature/I18N-Support 2020-10-15 16:59:20 -06:00
Andrew Welker
e80a68485d Merge pull request #449 from PepperDash/bugfix/zoom-room-incomingcall
Fix for Incoming Call issues
2020-10-15 16:58:37 -06:00
Andrew Welker
535f4ccb8e Merge branch 'development' into bugfix/zoom-room-incomingcall 2020-10-15 16:39:51 -06:00
Andrew Welker
7bbdf43452 add full implementation for LanguageLabel 2020-10-15 16:37:41 -06:00
Andrew Welker
59881d6b3b fix for unanticipated messages from Zoom 2020-10-15 16:14:27 -06:00
Andrew Welker
085e198409 fix for incoming call stuff 2020-10-15 13:34:47 -06:00
Neil Dorin
81f27fcbde Merge branch 'development' into feature/I18N-Support 2020-10-15 12:41:49 -06:00
Neil Dorin
50dae0ef69 Merge pull request #447 from PepperDash/bugfix/card-cage-iteration-fix
Bugfix/card cage iteration fix
2020-10-15 12:41:35 -06:00
Alex Johnson
e0fdefa28e Fix to allow card cage creation loop to continue even if a previous card encountered an issue 2020-10-15 12:36:14 -04:00
Andrew Welker
f6a826505c Merge branch 'development' into feature/I18N-Support 2020-10-13 23:39:12 -06:00
Andrew Welker
68ac506a25 Merge pull request #444 from PepperDash/feature/add-encoding-overload
Add SetString Overload to allow for setting encoding on a sig
2020-10-13 18:11:45 -05:00
Andrew Welker
1150d9e497 add IKeyed to ILanguageLabel to easily get the key 2020-10-13 15:18:31 -06:00
Andrew Welker
633a946f26 Merge branch 'development' into feature/add-encoding-overload 2020-10-13 16:15:04 -05:00
Andrew Welker
b373ab8708 #443 Add SetString Overload 2020-10-13 14:06:48 -06:00
Andrew Welker
cb752850ff correct interfaces 2020-10-13 13:30:29 -06:00
Andrew Welker
08c929699f #440 Updates for csproj file 2020-10-13 10:29:30 -06:00
Andrew Welker
1862090a89 #440 add interfaces 2020-10-13 09:53:18 -06:00
Neil Dorin
f036c3f1cc Merge pull request #401 from PepperDash/hotfix/unable-to-use-hightest-IR-port-number
Multiple Fixes for IR
2020-09-01 10:56:13 -06:00
17 changed files with 872 additions and 643 deletions

View File

@@ -60,7 +60,7 @@ jobs:
- name: Build Solution
shell: powershell
run: |
Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder:v1.4.1 c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)"
Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)"
# Zip up the output files as needed
- name: Zip Build Output
shell: powershell

View File

@@ -538,6 +538,20 @@ namespace PepperDash.Essentials
/// </summary>
void LoadLogoServer()
{
if (ConfigReader.ConfigObject.Rooms == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "No rooms configured. Bypassing Logo server startup.");
return;
}
if (
!ConfigReader.ConfigObject.Rooms.Any(
CheckRoomConfig))
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "No rooms configured to use system Logo server. Bypassing Logo server startup");
return;
}
try
{
LogoServer = new HttpLogoServer(8080, Global.DirectorySeparator + "html" + Global.DirectorySeparator + "logo");
@@ -547,5 +561,30 @@ namespace PepperDash.Essentials
Debug.Console(0, Debug.ErrorLogLevel.Notice, "NOTICE: Logo server cannot be started. Likely already running in another program");
}
}
private bool CheckRoomConfig(DeviceConfig c)
{
string logoDark = null;
string logoLight = null;
string logo = null;
if (c.Properties["logoDark"] != null)
{
logoDark = c.Properties["logoDark"].Value<string>("type");
}
if (c.Properties["logoLight"] != null)
{
logoLight = c.Properties["logoLight"].Value<string>("type");
}
if (c.Properties["logo"] != null)
{
logo = c.Properties["logo"].Value<string>("type");
}
return ((logoDark != null && logoDark == "system") ||
(logoLight != null && logoLight == "system") || (logo != null && logo == "system"));
}
}
}

View File

@@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Net.Http;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials
{
@@ -16,12 +13,12 @@ namespace PepperDash.Essentials
/// <summary>
///
/// </summary>
HttpServer Server;
readonly HttpServer _server;
/// <summary>
///
/// </summary>
string FileDirectory;
readonly string _fileDirectory;
/// <summary>
///
@@ -45,18 +42,17 @@ namespace PepperDash.Essentials
//{ ".js", "application/javascript" },
//{ ".json", "application/json" },
//{ ".map", "application/x-navimap" },
{ ".pdf", "application.pdf" },
{ ".pdf", "application/pdf" },
{ ".png", "image/png" },
//{ ".txt", "text/plain" },
};
Server = new HttpServer();
Server.Port = port;
FileDirectory = directory;
Server.OnHttpRequest += new OnHttpRequestHandler(Server_OnHttpRequest);
Server.Open();
_server = new HttpServer {Port = port};
_fileDirectory = directory;
_server.OnHttpRequest += Server_OnHttpRequest;
_server.Open();
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
}
/// <summary>
@@ -67,27 +63,40 @@ namespace PepperDash.Essentials
var path = args.Request.Path;
Debug.Console(2, "HTTP Request with path: '{0}'", args.Request.Path);
if (File.Exists(FileDirectory + path))
try
{
string filePath = path.Replace('/', '\\');
string localPath = string.Format(@"{0}{1}", FileDirectory, filePath);
Debug.Console(2, "HTTP Logo Server attempting to find file: '{0}'", localPath);
if (File.Exists(localPath))
if (File.Exists(_fileDirectory + path))
{
args.Response.Header.ContentType = GetContentType(new FileInfo(localPath).Extension);
args.Response.ContentStream = new FileStream(localPath, FileMode.Open, FileAccess.Read);
var filePath = path.Replace('/', '\\');
var localPath = string.Format(@"{0}{1}", _fileDirectory, filePath);
Debug.Console(2, "HTTP Logo Server attempting to find file: '{0}'", localPath);
if (File.Exists(localPath))
{
args.Response.Header.ContentType = GetContentType(new FileInfo(localPath).Extension);
args.Response.ContentStream = new FileStream(localPath, FileMode.Open, FileAccess.Read);
}
else
{
Debug.Console(2, "HTTP Logo Server Cannot find file '{0}'", localPath);
args.Response.ContentString = string.Format("Not found: '{0}'", filePath);
args.Response.Code = 404;
}
}
else
{
Debug.Console(2, "HTTP Logo Server Cannot find file '{0}'", localPath);
args.Response.ContentString = string.Format("Not found: '{0}'", filePath);
Debug.Console(2, "HTTP Logo Server: '{0}' does not exist", _fileDirectory + path);
args.Response.ContentString = string.Format("Not found: '{0}'", _fileDirectory + path);
args.Response.Code = 404;
}
}
else
catch (Exception ex)
{
Debug.Console(2, "HTTP Logo Server: '{0}' does not exist", FileDirectory + path);
Debug.Console(0, Debug.ErrorLogLevel.Error, "Exception getting file: {0}", ex.Message);
Debug.Console(0, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.StackTrace);
args.Response.Code = 400;
args.Response.ContentString = string.Format("invalid request");
}
}
@@ -97,7 +106,7 @@ namespace PepperDash.Essentials
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
Server.Close();
_server.Close();
}
/// <summary>
@@ -107,11 +116,7 @@ namespace PepperDash.Essentials
/// <returns></returns>
public static string GetContentType(string extension)
{
string type;
if (ExtensionContentTypes.ContainsKey(extension))
type = ExtensionContentTypes[extension];
else
type = "text/plain";
var type = ExtensionContentTypes.ContainsKey(extension) ? ExtensionContentTypes[extension] : "text/plain";
return type;
}
}

View File

@@ -73,21 +73,21 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
string cardType;
if (!_config.Cards.TryGetValue(i, out cardType))
{
Debug.Console(1, this, "No card found for slot {0}", i);
Debug.Console(0, this, "No card found for slot {0}", i);
continue;
}
if (String.IsNullOrEmpty(cardType))
{
Debug.Console(0, this, "No card specified for slot {0}", i);
return;
continue;
}
Func<uint, C3CardControllerBase> cardBuilder;
if (!_cardDict.TryGetValue(cardType.ToLower(), out cardBuilder))
{
Debug.Console(0, "Unable to find factory for 3-Series card type {0}.", cardType);
return;
continue;
}
try

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
{
public interface ILanguageDefinition
{
string LocaleName { get; set; }
string FriendlyName { get; set; }
bool Enable { get; set; }
List<LanguageLabel> UiLabels { get; set; }
List<LanguageLabel> Sources { get; set; }
List<LanguageLabel> Destinations { get; set; }
List<LanguageLabel> SourceGroupNames { get; set; }
List<LanguageLabel> DestinationGroupNames { get; set; }
List<LanguageLabel> RoomNames { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
{
public interface ILanguageProvider
{
ILanguageDefinition CurrentLanguage { get; set; }
event EventHandler CurrentLanguageChanged;
}
}

View File

@@ -0,0 +1,12 @@
using PepperDash.Core;
namespace PepperDash_Essentials_Core.DeviceTypeInterfaces
{
public class LanguageLabel
{
public string Key { get; set; }
public string Description { get; set; }
public string DisplayText { get; set; }
public uint JoinNumber { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace PepperDash.Essentials.Core
{
public interface IHasDspPresets
{
List<IDspPreset> Presets { get; }
void RecallPreset(IDspPreset preset);
}
public interface IDspPreset
{
string Name { get; }
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash_Essentials_Core.Gateways
{
public class CenCn2Controller
{
}
}

View File

@@ -190,12 +190,16 @@
<Compile Include="Devices\EssentialsBridgeableDevice.cs" />
<Compile Include="Devices\EssentialsDevice.cs" />
<Compile Include="Devices\GenericIRController.cs" />
<Compile Include="Devices\IDspPreset.cs" />
<Compile Include="Devices\IProjectorInterfaces.cs" />
<Compile Include="Devices\PC\InRoomPc.cs" />
<Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" />
<Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" />
<Compile Include="DeviceTypeInterfaces\IHasBranding.cs" />
<Compile Include="DeviceTypeInterfaces\ILanguageDefinition.cs" />
<Compile Include="DeviceTypeInterfaces\IHasFarEndContentStatus.cs" />
<Compile Include="DeviceTypeInterfaces\IHasPhoneDialing.cs" />
<Compile Include="DeviceTypeInterfaces\IMobileControl.cs" />

View File

@@ -251,6 +251,12 @@ namespace PepperDash.Essentials.Core
tl.StringInput[sigNum].StringValue = value;
}
public static void SetString(this BasicTriList tl, uint sigNum, string value, eStringEncoding encoding)
{
tl.StringInput[sigNum].StringEncoding = encoding;
tl.StringInput[sigNum].StringValue = value;
}
/// <summary>
/// Returns bool value of trilist sig
/// </summary>

View File

@@ -118,7 +118,10 @@ namespace PepperDash.Essentials.DM
OutputEndpointOnlineFeedbacks = new Dictionary<uint, BoolFeedback>();
Debug.Console(1, this, "{0} Switcher Inputs Present.", Dmps.SwitcherInputs.Count);
Debug.Console(1, this, "{0} Switcher Outputs Present.", Dmps.SwitcherOutputs.Count);
Debug.Console(1, this, "{0} Switcher Outputs Present.", Dmps.SwitcherOutputs.Count);
Debug.Console(1, this, "{0} Inputs in ControlSystem", Dmps.NumberOfSwitcherInputs);
Debug.Console(1, this, "{0} Outputs in ControlSystem", Dmps.NumberOfSwitcherOutputs);
SetupOutputCards();
@@ -128,32 +131,50 @@ namespace PepperDash.Essentials.DM
public override bool CustomActivate()
{
// Set input and output names from config
if (InputNames != null)
{
foreach (var kvp in InputNames)
{
var input = (Dmps.SwitcherInputs[kvp.Key] as DMInput);
if (input != null)
input.Name.StringValue = kvp.Value;
}
}
if (OutputNames != null)
{
foreach (var kvp in OutputNames)
{
var output = (Dmps.SwitcherOutputs[kvp.Key] as DMOutput);
if (output != null)
output.Name.StringValue = kvp.Value;
}
}
SetInputNames();
SetOutputNames();
// Subscribe to events
Dmps.DMInputChange += new DMInputEventHandler(Dmps_DMInputChange);
Dmps.DMOutputChange += new DMOutputEventHandler(Dmps_DMOutputChange);
Dmps.DMInputChange += Dmps_DMInputChange;
Dmps.DMOutputChange += Dmps_DMOutputChange;
return base.CustomActivate();
}
}
private void SetOutputNames()
{
if (OutputNames == null)
{
return;
}
foreach (var kvp in OutputNames)
{
var output = (Dmps.SwitcherOutputs[kvp.Key] as DMOutput);
if (output != null && output.Name.Type != eSigType.NA)
{
output.Name.StringValue = kvp.Value;
}
}
}
private void SetInputNames()
{
if (InputNames == null)
{
return;
}
foreach (var kvp in InputNames)
{
var input = (Dmps.SwitcherInputs[kvp.Key] as DMInput);
if (input != null && input.Name.Type != eSigType.NA)
{
input.Name.StringValue = kvp.Value;
}
}
}
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
var joinMap = new DmpsRoutingControllerJoinMap(joinStart);
@@ -175,171 +196,197 @@ namespace PepperDash.Essentials.DM
Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
// Link up outputs
for (uint i = 1; i <= Dmps.NumberOfSwitcherInputs; i++)
{
Debug.Console(2, this, "Linking Input Card {0}", i);
LinkInputsToApi(trilist, joinMap);
var ioSlot = i;
var ioSlotJoin = ioSlot - 1;
//if (TxDictionary.ContainsKey(ioSlot))
//{
// Debug.Console(2, "Creating Tx Feedbacks {0}", ioSlot);
// var TxKey = TxDictionary[ioSlot];
// var TxDevice = DeviceManager.GetDeviceForKey(TxKey) as DmTxControllerBase;
// //TxDevice.IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.InputEndpointOnline + ioSlot]);
// // TxDevice.AnyVideoInput.VideoStatus.VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputEndpointOnline + ioSlot]);
// // trilist.SetUShortSigAction((ApiMap.HdcpSupport[ioSlot]), u => TxDevice.SetHdcpSupportAll((ePdtHdcpSupport)(u)));
// // TxDevice.HdcpSupportAllFeedback.LinkInputSig(trilist.UShortInput[joinMap. + ioSlot]);
// // trilist.UShortInput[ApiMap.HdcpSupportCapability[ioSlot]].UShortValue = TxDevice.HdcpSupportCapability;
//}
//else
//{
// // dmChassis.VideoInputSyncFeedbacks[ioSlot].LinkInputSig(trilist.BooleanInput[ApiMap.TxVideoSyncStatus[ioSlot]]);
//}
if (VideoInputSyncFeedbacks[ioSlot] != null)
VideoInputSyncFeedbacks[ioSlot].LinkInputSig(trilist.BooleanInput[joinMap.VideoSyncStatus.JoinNumber + ioSlotJoin]);
if (InputNameFeedbacks[ioSlot] != null)
InputNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.InputNames.JoinNumber + ioSlotJoin]);
LinkOutputsToApi(trilist, joinMap);
}
private void LinkOutputsToApi(BasicTriList trilist, DmpsRoutingControllerJoinMap joinMap)
{
for (uint i = 1; i <= Dmps.SwitcherOutputs.Count; i++)
{
Debug.Console(2, this, "Linking Output Card {0}", i);
trilist.SetStringSigAction(joinMap.InputNames.JoinNumber + ioSlotJoin, new Action<string>(s =>
{
var inputCard = Dmps.SwitcherInputs[ioSlot] as DMInput;
if (inputCard != null)
{
if (inputCard.NameFeedback != null && !string.IsNullOrEmpty(inputCard.NameFeedback.StringValue) && inputCard.NameFeedback.StringValue != s)
if (inputCard.Name != null)
inputCard.Name.StringValue = s;
}
}));
if (InputEndpointOnlineFeedbacks[ioSlot] != null)
InputEndpointOnlineFeedbacks[ioSlot].LinkInputSig(trilist.BooleanInput[joinMap.InputEndpointOnline.JoinNumber + ioSlotJoin]);
}
for (uint i = 1; i <= Dmps.NumberOfSwitcherOutputs; i++)
{
Debug.Console(2, this, "Linking Output Card {0}", i);
var ioSlot = i;
var ioSlotJoin = ioSlot - 1;
var ioSlotJoin = ioSlot - 1;
// Control
trilist.SetUShortSigAction(joinMap.OutputVideo.JoinNumber + ioSlotJoin, o => ExecuteSwitch(o, ioSlot, eRoutingSignalType.Video));
trilist.SetUShortSigAction(joinMap.OutputAudio.JoinNumber + ioSlotJoin, o => ExecuteSwitch(o, ioSlot, eRoutingSignalType.Audio));
trilist.SetUShortSigAction(joinMap.OutputVideo.JoinNumber + ioSlotJoin,
o => ExecuteSwitch(o, ioSlot, eRoutingSignalType.Video));
trilist.SetUShortSigAction(joinMap.OutputAudio.JoinNumber + ioSlotJoin,
o => ExecuteSwitch(o, ioSlot, eRoutingSignalType.Audio));
trilist.SetStringSigAction(joinMap.OutputNames.JoinNumber + ioSlotJoin, s =>
{
var outputCard = Dmps.SwitcherOutputs[ioSlot] as DMOutput;
//Debug.Console(2, dmpsRouter, "Output Name String Sig Action for Output Card {0}", ioSlot);
if (outputCard != null)
{
//Debug.Console(2, dmpsRouter, "Card Type: {0}", outputCard.CardInputOutputType);
if (!(outputCard is Card.Dmps3CodecOutput) && outputCard.NameFeedback != null)
{
if (!string.IsNullOrEmpty(outputCard.NameFeedback.StringValue))
{
//Debug.Console(2, dmpsRouter, "NameFeedabck: {0}", outputCard.NameFeedback.StringValue);
if (outputCard.NameFeedback.StringValue != s && outputCard.Name != null)
{
outputCard.Name.StringValue = s;
}
}
}
}
});
// Feedback
trilist.SetStringSigAction(joinMap.OutputNames.JoinNumber + ioSlotJoin, s =>
{
var outputCard = Dmps.SwitcherOutputs[ioSlot] as DMOutput;
//Debug.Console(2, dmpsRouter, "Output Name String Sig Action for Output Card {0}", ioSlot);
if (outputCard == null)
{
return;
}
//Debug.Console(2, dmpsRouter, "Card Type: {0}", outputCard.CardInputOutputType);
if (outputCard is Card.Dmps3CodecOutput || outputCard.NameFeedback == null)
{
return;
}
if (string.IsNullOrEmpty(outputCard.NameFeedback.StringValue))
{
return;
}
//Debug.Console(2, dmpsRouter, "NameFeedabck: {0}", outputCard.NameFeedback.StringValue);
if (outputCard.NameFeedback.StringValue != s && outputCard.Name != null)
{
outputCard.Name.StringValue = s;
}
});
// Feedback
if (VideoOutputFeedbacks[ioSlot] != null)
VideoOutputFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[joinMap.OutputVideo.JoinNumber + ioSlotJoin]);
{
VideoOutputFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[joinMap.OutputVideo.JoinNumber + ioSlotJoin]);
}
if (AudioOutputFeedbacks[ioSlot] != null)
AudioOutputFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[joinMap.OutputAudio.JoinNumber + ioSlotJoin]);
{
AudioOutputFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[joinMap.OutputAudio.JoinNumber + ioSlotJoin]);
}
if (OutputNameFeedbacks[ioSlot] != null)
OutputNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.OutputNames.JoinNumber + ioSlotJoin]);
{
OutputNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.OutputNames.JoinNumber + ioSlotJoin]);
}
if (OutputVideoRouteNameFeedbacks[ioSlot] != null)
OutputVideoRouteNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.OutputCurrentVideoInputNames.JoinNumber + ioSlotJoin]);
{
OutputVideoRouteNameFeedbacks[ioSlot].LinkInputSig(
trilist.StringInput[joinMap.OutputCurrentVideoInputNames.JoinNumber + ioSlotJoin]);
}
if (OutputAudioRouteNameFeedbacks[ioSlot] != null)
OutputAudioRouteNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.OutputCurrentAudioInputNames.JoinNumber + ioSlotJoin]);
{
OutputAudioRouteNameFeedbacks[ioSlot].LinkInputSig(
trilist.StringInput[joinMap.OutputCurrentAudioInputNames.JoinNumber + ioSlotJoin]);
}
if (OutputEndpointOnlineFeedbacks[ioSlot] != null)
OutputEndpointOnlineFeedbacks[ioSlot].LinkInputSig(trilist.BooleanInput[joinMap.OutputEndpointOnline.JoinNumber + ioSlotJoin]);
}
}
{
OutputEndpointOnlineFeedbacks[ioSlot].LinkInputSig(
trilist.BooleanInput[joinMap.OutputEndpointOnline.JoinNumber + ioSlotJoin]);
}
}
}
private void LinkInputsToApi(BasicTriList trilist, DmpsRoutingControllerJoinMap joinMap)
{
for (uint i = 1; i <= Dmps.SwitcherInputs.Count; i++)
{
Debug.Console(2, this, "Linking Input Card {0}", i);
var ioSlot = i;
var ioSlotJoin = ioSlot - 1;
if (VideoInputSyncFeedbacks[ioSlot] != null)
{
VideoInputSyncFeedbacks[ioSlot].LinkInputSig(
trilist.BooleanInput[joinMap.VideoSyncStatus.JoinNumber + ioSlotJoin]);
}
if (InputNameFeedbacks[ioSlot] != null)
{
InputNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.InputNames.JoinNumber + ioSlotJoin]);
}
trilist.SetStringSigAction(joinMap.InputNames.JoinNumber + ioSlotJoin, s =>
{
var inputCard = Dmps.SwitcherInputs[ioSlot] as DMInput;
if (inputCard == null)
{
return;
}
if (inputCard.NameFeedback == null || string.IsNullOrEmpty(inputCard.NameFeedback.StringValue) ||
inputCard.NameFeedback.StringValue == s)
{
return;
}
if (inputCard.Name != null)
{
inputCard.Name.StringValue = s;
}
});
if (InputEndpointOnlineFeedbacks[ioSlot] != null)
{
InputEndpointOnlineFeedbacks[ioSlot].LinkInputSig(
trilist.BooleanInput[joinMap.InputEndpointOnline.JoinNumber + ioSlotJoin]);
}
}
}
/// <summary>
/// Iterate the SwitcherOutputs collection to setup feedbacks and add routing ports
/// </summary>
void SetupOutputCards()
{
foreach (var card in Dmps.SwitcherOutputs)
{
var outputCard = card as DMOutput;
foreach (var card in Dmps.SwitcherOutputs)
{
Debug.Console(1, this, "Output Card Type: {0}", card.CardInputOutputType);
var outputCard = card as DMOutput;
if (outputCard == null)
{
Debug.Console(1, this, "Output card {0} is not a DMOutput", card.CardInputOutputType);
continue;
}
Debug.Console(1, this, "Adding Output Card Number {0} Type: {1}", outputCard.Number, outputCard.CardInputOutputType.ToString());
if (outputCard != null)
VideoOutputFeedbacks[outputCard.Number] = new IntFeedback(() =>
{
VideoOutputFeedbacks[outputCard.Number] = new IntFeedback(() =>
{
if (outputCard.VideoOutFeedback != null) { return (ushort)outputCard.VideoOutFeedback.Number; }
else { return 0; };
});
AudioOutputFeedbacks[outputCard.Number] = new IntFeedback(() =>
{
if (outputCard.AudioOutFeedback != null) { return (ushort)outputCard.AudioOutFeedback.Number; }
else { return 0; };
});
if (outputCard.VideoOutFeedback != null) { return (ushort)outputCard.VideoOutFeedback.Number; }
return 0;
;
});
AudioOutputFeedbacks[outputCard.Number] = new IntFeedback(() =>
{
if (outputCard.AudioOutFeedback != null) { return (ushort)outputCard.AudioOutFeedback.Number; }
return 0;
;
});
OutputNameFeedbacks[outputCard.Number] = new StringFeedback(() =>
OutputNameFeedbacks[outputCard.Number] = new StringFeedback(() =>
{
if (outputCard.NameFeedback != null && !string.IsNullOrEmpty(outputCard.NameFeedback.StringValue))
{
if (outputCard.NameFeedback != null && !string.IsNullOrEmpty(outputCard.NameFeedback.StringValue))
{
Debug.Console(2, this, "Output Card {0} Name: {1}", outputCard.Number, outputCard.NameFeedback.StringValue);
return outputCard.NameFeedback.StringValue;
}
else
{
return "";
}
});
Debug.Console(2, this, "Output Card {0} Name: {1}", outputCard.Number, outputCard.NameFeedback.StringValue);
return outputCard.NameFeedback.StringValue;
}
return "";
});
OutputVideoRouteNameFeedbacks[outputCard.Number] = new StringFeedback(() =>
OutputVideoRouteNameFeedbacks[outputCard.Number] = new StringFeedback(() =>
{
if (outputCard.VideoOutFeedback != null && outputCard.VideoOutFeedback.NameFeedback != null)
{
if (outputCard.VideoOutFeedback != null && outputCard.VideoOutFeedback.NameFeedback != null)
{
return outputCard.VideoOutFeedback.NameFeedback.StringValue;
}
else
{
return NoRouteText;
}
});
OutputAudioRouteNameFeedbacks[outputCard.Number] = new StringFeedback(() =>
return outputCard.VideoOutFeedback.NameFeedback.StringValue;
}
return NoRouteText;
});
OutputAudioRouteNameFeedbacks[outputCard.Number] = new StringFeedback(() =>
{
if (outputCard.AudioOutFeedback != null && outputCard.AudioOutFeedback.NameFeedback != null)
{
if (outputCard.AudioOutFeedback != null && outputCard.AudioOutFeedback.NameFeedback != null)
{
return outputCard.AudioOutFeedback.NameFeedback.StringValue;
}
else
{
return NoRouteText;
return outputCard.AudioOutFeedback.NameFeedback.StringValue;
}
return NoRouteText;
});
}
});
OutputEndpointOnlineFeedbacks[outputCard.Number] = new BoolFeedback(() => outputCard.EndpointOnlineFeedback);
OutputEndpointOnlineFeedbacks[outputCard.Number] = new BoolFeedback(() => { return outputCard.EndpointOnlineFeedback; });
AddOutputCard(outputCard.Number, outputCard);
}
AddOutputCard(outputCard.Number, outputCard);
}
}
@@ -494,18 +541,23 @@ namespace PepperDash.Essentials.DM
var cecPort = hdmiOutputCard.HdmiOutputPort;
AddHdmiOutputPort(number, cecPort);
return;
AddHdmiOutputPort(number, cecPort);
}
else if (outputCard is Card.Dmps3HdmiOutputBackend)
{
var hdmiOutputCard = outputCard as Card.Dmps3HdmiOutputBackend;
var cecPort = hdmiOutputCard.HdmiOutputPort;
AddHdmiOutputPort(number, cecPort);
}
else if (outputCard is Card.Dmps3DmOutput)
{
var dmOutputCard = outputCard as Card.Dmps3DmOutput;
var cecPort = dmOutputCard.DmOutputPort;
AddDmOutputPort(number);
return;
{
AddDmOutputPort(number);
}
else if (outputCard is Card.Dmps3DmOutputBackend)
{
AddDmOutputPort(number);
}
else if (outputCard is Card.Dmps3ProgramOutput)
{
@@ -513,50 +565,51 @@ namespace PepperDash.Essentials.DM
var programOutput = new DmpsAudioOutputController(string.Format("processor-programAudioOutput"), "Program Audio Output", outputCard as Card.Dmps3OutputBase);
DeviceManager.AddDevice(programOutput);
return;
DeviceManager.AddDevice(programOutput);
}
else if (outputCard is Card.Dmps3AuxOutput)
{
if (outputCard.CardInputOutputType == eCardInputOutputType.Dmps3Aux1Output)
{
AddAudioOnlyOutputPort(number, "Aux1");
else if (outputCard is Card.Dmps3AuxOutput)
{
switch (outputCard.CardInputOutputType)
{
case eCardInputOutputType.Dmps3Aux1Output:
{
AddAudioOnlyOutputPort(number, "Aux1");
var aux1Output = new DmpsAudioOutputController(string.Format("processor-aux1AudioOutput"), "Program Audio Output", outputCard as Card.Dmps3OutputBase);
var aux1Output = new DmpsAudioOutputController(string.Format("processor-aux1AudioOutput"), "Program Audio Output", outputCard as Card.Dmps3OutputBase);
DeviceManager.AddDevice(aux1Output);
}
else if (outputCard.CardInputOutputType == eCardInputOutputType.Dmps3Aux2Output)
{
AddAudioOnlyOutputPort(number, "Aux2");
DeviceManager.AddDevice(aux1Output);
}
break;
case eCardInputOutputType.Dmps3Aux2Output:
{
AddAudioOnlyOutputPort(number, "Aux2");
var aux2Output = new DmpsAudioOutputController(string.Format("processor-aux2AudioOutput"), "Program Audio Output", outputCard as Card.Dmps3OutputBase);
var aux2Output = new DmpsAudioOutputController(string.Format("processor-aux2AudioOutput"), "Program Audio Output", outputCard as Card.Dmps3OutputBase);
DeviceManager.AddDevice(aux2Output);
}
return;
}
else if (outputCard is Card.Dmps3CodecOutput)
{
if (number == (uint)CrestronControlSystem.eDmps300cOutputs.Codec1
|| number == (uint)CrestronControlSystem.eDmps3200cOutputs.Codec1
|| number == (uint)CrestronControlSystem.eDmps3300cAecOutputs.Codec1
|| number == (uint)CrestronControlSystem.eDmps34K250COutputs.Codec1
|| number == (uint)CrestronControlSystem.eDmps34K350COutputs.Codec1)
AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps300cOutputs.Codec1.ToString());
else if (number == (uint)CrestronControlSystem.eDmps300cOutputs.Codec2
|| number == (uint)CrestronControlSystem.eDmps3200cOutputs.Codec2
|| number == (uint)CrestronControlSystem.eDmps3300cAecOutputs.Codec2
|| number == (uint)CrestronControlSystem.eDmps34K250COutputs.Codec2
|| number == (uint)CrestronControlSystem.eDmps34K350COutputs.Codec2)
AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps300cOutputs.Codec2.ToString());
return;
}
DeviceManager.AddDevice(aux2Output);
}
break;
}
}
else if (outputCard is Card.Dmps3CodecOutput)
{
switch (number)
{
case (uint)CrestronControlSystem.eDmps34K350COutputs.Codec1:
case (uint)CrestronControlSystem.eDmps34K250COutputs.Codec1:
case (uint)CrestronControlSystem.eDmps3300cAecOutputs.Codec1:
AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps300cOutputs.Codec1.ToString());
break;
case (uint)CrestronControlSystem.eDmps34K350COutputs.Codec2:
case (uint)CrestronControlSystem.eDmps34K250COutputs.Codec2:
case (uint)CrestronControlSystem.eDmps3300cAecOutputs.Codec2:
AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps300cOutputs.Codec2.ToString());
break;
}
}
else if (outputCard is Card.Dmps3DialerOutput)
{
AddAudioOnlyOutputPort(number, "Dialer");
return;
AddAudioOnlyOutputPort(number, "Dialer");
}
else if (outputCard is Card.Dmps3DigitalMixOutput)
{
@@ -567,13 +620,11 @@ namespace PepperDash.Essentials.DM
if (number == (uint)CrestronControlSystem.eDmps34K250COutputs.Mix2
|| number == (uint)CrestronControlSystem.eDmps34K300COutputs.Mix2
|| number == (uint)CrestronControlSystem.eDmps34K350COutputs.Mix2)
AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps34K250COutputs.Mix2.ToString());
return;
AddAudioOnlyOutputPort(number, CrestronControlSystem.eDmps34K250COutputs.Mix2.ToString());
}
else if (outputCard is Card.Dmps3AecOutput)
{
AddAudioOnlyOutputPort(number, "Aec");
return;
AddAudioOnlyOutputPort(number, "Aec");
}
else
{

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DM;
using Crestron.SimplSharpPro.DM.Cards;
using Crestron.SimplSharpPro.DM.Endpoints.Receivers;
using Newtonsoft.Json;
using PepperDash.Core;
@@ -221,6 +222,10 @@ namespace PepperDash.Essentials.DM
DmRmcPropertiesConfig props, string pKey, uint ipid)
{
var parentDev = DeviceManager.GetDeviceForKey(pKey);
if (parentDev is DmpsRoutingController)
{
return GetDmRmcControllerForDmps(key, name, typeName, parentDev as DmpsRoutingController, props.ParentOutputNumber);
}
if (!(parentDev is IDmSwitch))
{
Debug.Console(0, "Cannot create DM device '{0}'. '{1}' is not a DM Chassis.",
@@ -285,6 +290,28 @@ namespace PepperDash.Essentials.DM
return null;
}
private static CrestronGenericBaseDevice GetDmRmcControllerForDmps(string key, string name, string typeName,
DmpsRoutingController controller, uint num)
{
Func<string, string, DMOutput, CrestronGenericBaseDevice> dmpsHandler;
if (ChassisCpu3Dict.TryGetValue(typeName.ToLower(), out dmpsHandler))
{
var output = controller.Dmps.SwitcherOutputs[num] as DMOutput;
if (output != null)
{
return dmpsHandler(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.",
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 GetDmRmcControllerForProcessor(string key, string name, string typeName, uint ipid)
{
try
@@ -305,6 +332,8 @@ namespace PepperDash.Essentials.DM
return null;
}
}
}
public class DmRmcControllerFactory : EssentialsDeviceFactory<DmRmcControllerBase>

View File

@@ -6,390 +6,398 @@ using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common.DSP
{
// QUESTIONS:
//
// When subscribing, just use the Instance ID for Custom Name?
// Verbose on subscriptions?
// Example subscription feedback responses
// ! "publishToken":"name" "value":-77.0
// ! "myLevelName" -77
public class BiampTesiraForteDsp : DspBase
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
new public Dictionary<string, TesiraForteLevelControl> LevelControlPoints { get; private set; }
public bool isSubscribed;
private CTimer SubscriptionTimer;
CrestronQueue CommandQueue;
bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public BiampTesiraForteDsp(string key, string name, IBasicCommunication comm, BiampTesiraFortePropertiesConfig props) :
base(key, name)
{
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0d\x0a");
PortGather.LineReceived += this.Port_LineReceived;
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties);
}
else
{
//#warning Need to deal with this poll string
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000, "SESSION get aliases\x0d\x0a");
}
LevelControlPoints = new Dictionary<string, TesiraForteLevelControl>();
foreach (KeyValuePair<string, BiampTesiraForteLevelControlBlockConfig> block in props.LevelControlBlocks)
{
this.LevelControlPoints.Add(block.Key, new TesiraForteLevelControl(block.Key, block.Value, this));
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange += (o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
return true;
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
// Tasks on connect
}
else
{
// Cleanup items from this session
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
void SubscribeToAttributes()
{
SendLine("SESSION set verbose true");
foreach (KeyValuePair<string, TesiraForteLevelControl> level in LevelControlPoints)
{
level.Value.Subscribe();
}
if (!CommandQueueInProgress)
SendNextQueuedCommand();
ResetSubscriptionTimer();
}
/// <summary>
/// Resets or Sets the subscription timer
/// </summary>
void ResetSubscriptionTimer()
{
isSubscribed = true;
if (SubscriptionTimer != null)
{
SubscriptionTimer = new CTimer(o => SubscribeToAttributes(), 30000);
SubscriptionTimer.Reset();
}
}
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "RX: '{0}'",
ShowHexResponse ? ComTextHelper.GetEscapedText(args.Text) : args.Text);
Debug.Console(1, this, "RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("Welcome to the Tesira Text Protocol Server...") > -1)
{
// Indicates a new TTP session
SubscribeToAttributes();
}
else if (args.Text.IndexOf("publishToken") > -1)
{
// response is from a subscribed attribute
string pattern = "! \"publishToken\":[\"](.*)[\"] \"value\":(.*)";
Match match = Regex.Match(args.Text, pattern);
if (match.Success)
{
string key;
string customName;
string value;
customName = match.Groups[1].Value;
// Finds the key (everything before the '~' character
key = customName.Substring(0, customName.IndexOf("~", 0) - 1);
value = match.Groups[2].Value;
foreach (KeyValuePair<string, TesiraForteLevelControl> controlPoint in LevelControlPoints)
{
if (customName == controlPoint.Value.LevelCustomName || customName == controlPoint.Value.MuteCustomName)
{
controlPoint.Value.ParseSubscriptionMessage(customName, value);
return;
}
}
}
/// same for dialers
/// same for switchers
}
else if (args.Text.IndexOf("+OK") > -1)
{
if (args.Text == "+OK" || args.Text.IndexOf("list\":") > -1 ) // Check for a simple "+OK" only 'ack' repsonse or a list response and ignore
return;
// response is not from a subscribed attribute. From a get/set/toggle/increment/decrement command
if (!CommandQueue.IsEmpty)
{
if (CommandQueue.Peek() is QueuedCommand)
{
// Expected response belongs to a child class
QueuedCommand tempCommand = (QueuedCommand)CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
tempCommand.ControlPoint.ParseGetMessage(tempCommand.AttributeCode, args.Text);
}
else
{
// Expected response belongs to this class
string temp = (string)CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
}
if (CommandQueue.IsEmpty)
CommandQueueInProgress = false;
else
SendNextQueuedCommand();
}
}
else if (args.Text.IndexOf("-ERR") > -1)
{
// Error response
switch (args.Text)
{
case "-ERR ALREADY_SUBSCRIBED":
{
ResetSubscriptionTimer();
break;
}
default:
{
Debug.Console(0, this, "Error From DSP: '{0}'", args.Text);
break;
}
}
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TX: '{0}'", s);
Communication.SendText(s + "\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if(!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
void SendNextQueuedCommand()
{
//Debug.Console(2, this, "Attempting to send next queued command. CommandQueueInProgress: {0} Communication isConnected: {1}", CommandQueueInProgress, Communication.IsConnected);
//if (CommandQueue.IsEmpty)
// CommandQueueInProgress = false;
//Debug.Console(1, this, "CommandQueue has {0} Elements:\n", CommandQueue.Count);
//foreach (object o in CommandQueue)
//{
// if (o is string)
// Debug.Console(1, this, "{0}", o);
// else if(o is QueuedCommand)
// {
// var item = (QueuedCommand)o;
// Debug.Console(1, this, "{0}", item.Command);
// }
//}
//Debug.Console(1, this, "End of CommandQueue");
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand)CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string)CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
/// <summary>
/// Sends a command to execute a preset
/// </summary>
/// <param name="name">Preset Name</param>
public override void RunPreset(string name)
{
SendLine(string.Format("DEVICE recallPreset {0}", name));
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
public TesiraForteControlPoint ControlPoint { get; set; }
}
}
public class BiampTesiraForteDspFactory : EssentialsDeviceFactory<BiampTesiraForteDsp>
{
public BiampTesiraForteDspFactory()
{
TypeNames = new List<string>() { "biamptesira" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new BiampTesira Device");
var comm = CommFactory.CreateCommForDevice(dc);
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<BiampTesiraFortePropertiesConfig>(
dc.Properties.ToString());
return new BiampTesiraForteDsp(dc.Key, dc.Name, comm, props);
}
}
}
using System.Text.RegularExpressions;
namespace PepperDash.Essentials.Devices.Common.DSP
{
// QUESTIONS:
//
// When subscribing, just use the Instance ID for Custom Name?
// Verbose on subscriptions?
// Example subscription feedback responses
// ! "publishToken":"name" "value":-77.0
// ! "myLevelName" -77
public class BiampTesiraForteDsp : DspBase
{
public IBasicCommunication Communication { get; private set; }
public CommunicationGather PortGather { get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public new Dictionary<string, TesiraForteLevelControl> LevelControlPoints { get; private set; }
public bool isSubscribed;
private CTimer SubscriptionTimer;
private CrestronQueue CommandQueue;
private bool CommandQueueInProgress = false;
//new public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
//new public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
/// <summary>
/// Shows received lines as hex
/// </summary>
public bool ShowHexResponse { get; set; }
public BiampTesiraForteDsp(string key, string name, IBasicCommunication comm,
BiampTesiraFortePropertiesConfig props) :
base(key, name)
{
CommandQueue = new CrestronQueue(100);
Communication = comm;
var socket = comm as ISocketStatus;
if (socket != null)
{
// This instance uses IP control
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
}
else
{
// This instance uses RS-232 control
}
PortGather = new CommunicationGather(Communication, "\x0d\x0a");
PortGather.LineReceived += this.Port_LineReceived;
if (props.CommunicationMonitorProperties != null)
{
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication,
props.CommunicationMonitorProperties);
}
else
{
//#warning Need to deal with this poll string
CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 120000, 120000, 300000,
"SESSION get aliases\x0d\x0a");
}
LevelControlPoints = new Dictionary<string, TesiraForteLevelControl>();
foreach (KeyValuePair<string, BiampTesiraForteLevelControlBlockConfig> block in props.LevelControlBlocks)
{
this.LevelControlPoints.Add(block.Key, new TesiraForteLevelControl(block.Key, block.Value, this));
}
}
public override bool CustomActivate()
{
Communication.Connect();
CommunicationMonitor.StatusChange +=
(o, a) => { Debug.Console(2, this, "Communication monitor state: {0}", CommunicationMonitor.Status); };
CommunicationMonitor.Start();
CrestronConsole.AddNewConsoleCommand(SendLine, "send" + Key, "", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "",
ConsoleAccessLevelEnum.AccessOperator);
return true;
}
private void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)
{
Debug.Console(2, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString());
if (e.Client.IsConnected)
{
// Tasks on connect
}
else
{
// Cleanup items from this session
if (SubscriptionTimer != null)
{
SubscriptionTimer.Stop();
SubscriptionTimer = null;
}
isSubscribed = false;
CommandQueue.Clear();
CommandQueueInProgress = false;
}
}
/// <summary>
/// Initiates the subscription process to the DSP
/// </summary>
private void SubscribeToAttributes()
{
SendLine("SESSION set verbose true");
foreach (KeyValuePair<string, TesiraForteLevelControl> level in LevelControlPoints)
{
level.Value.Subscribe();
}
if (!CommandQueueInProgress)
SendNextQueuedCommand();
ResetSubscriptionTimer();
}
/// <summary>
/// Resets or Sets the subscription timer
/// </summary>
private void ResetSubscriptionTimer()
{
isSubscribed = true;
if (SubscriptionTimer != null)
{
SubscriptionTimer = new CTimer(o => SubscribeToAttributes(), 30000);
SubscriptionTimer.Reset();
}
}
/// <summary>
/// Handles a response message from the DSP
/// </summary>
/// <param name="dev"></param>
/// <param name="args"></param>
private void Port_LineReceived(object dev, GenericCommMethodReceiveTextArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "RX: '{0}'",
ShowHexResponse ? ComTextHelper.GetEscapedText(args.Text) : args.Text);
Debug.Console(1, this, "RX: '{0}'", args.Text);
try
{
if (args.Text.IndexOf("Welcome to the Tesira Text Protocol Server...") > -1)
{
// Indicates a new TTP session
SubscribeToAttributes();
}
else if (args.Text.IndexOf("publishToken") > -1)
{
// response is from a subscribed attribute
string pattern = "! \"publishToken\":[\"](.*)[\"] \"value\":(.*)";
Match match = Regex.Match(args.Text, pattern);
if (match.Success)
{
string key;
string customName;
string value;
customName = match.Groups[1].Value;
// Finds the key (everything before the '~' character
key = customName.Substring(0, customName.IndexOf("~", 0) - 1);
value = match.Groups[2].Value;
foreach (KeyValuePair<string, TesiraForteLevelControl> controlPoint in LevelControlPoints)
{
if (customName == controlPoint.Value.LevelCustomName ||
customName == controlPoint.Value.MuteCustomName)
{
controlPoint.Value.ParseSubscriptionMessage(customName, value);
return;
}
}
}
/// same for dialers
/// same for switchers
}
else if (args.Text.IndexOf("+OK") > -1)
{
if (args.Text == "+OK" || args.Text.IndexOf("list\":") > -1)
// Check for a simple "+OK" only 'ack' repsonse or a list response and ignore
return;
// response is not from a subscribed attribute. From a get/set/toggle/increment/decrement command
if (!CommandQueue.IsEmpty)
{
if (CommandQueue.Peek() is QueuedCommand)
{
// Expected response belongs to a child class
QueuedCommand tempCommand = (QueuedCommand) CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
tempCommand.ControlPoint.ParseGetMessage(tempCommand.AttributeCode, args.Text);
}
else
{
// Expected response belongs to this class
string temp = (string) CommandQueue.TryToDequeue();
//Debug.Console(1, this, "Command Dequeued. CommandQueue Size: {0}", CommandQueue.Count);
}
if (CommandQueue.IsEmpty)
CommandQueueInProgress = false;
else
SendNextQueuedCommand();
}
}
else if (args.Text.IndexOf("-ERR") > -1)
{
// Error response
switch (args.Text)
{
case "-ERR ALREADY_SUBSCRIBED":
{
ResetSubscriptionTimer();
break;
}
default:
{
Debug.Console(0, this, "Error From DSP: '{0}'", args.Text);
break;
}
}
}
}
catch (Exception e)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Error parsing response: '{0}'\n{1}", args.Text, e);
}
}
/// <summary>
/// Sends a command to the DSP (with delimiter appended)
/// </summary>
/// <param name="s">Command to send</param>
public void SendLine(string s)
{
Debug.Console(1, this, "TX: '{0}'", s);
Communication.SendText(s + "\x0a");
}
/// <summary>
/// Adds a command from a child module to the queue
/// </summary>
/// <param name="command">Command object from child module</param>
public void EnqueueCommand(QueuedCommand commandToEnqueue)
{
CommandQueue.Enqueue(commandToEnqueue);
//Debug.Console(1, this, "Command (QueuedCommand) Enqueued '{0}'. CommandQueue has '{1}' Elements.", commandToEnqueue.Command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Adds a raw string command to the queue
/// </summary>
/// <param name="command"></param>
public void EnqueueCommand(string command)
{
CommandQueue.Enqueue(command);
//Debug.Console(1, this, "Command (string) Enqueued '{0}'. CommandQueue has '{1}' Elements.", command, CommandQueue.Count);
if (!CommandQueueInProgress)
SendNextQueuedCommand();
}
/// <summary>
/// Sends the next queued command to the DSP
/// </summary>
private void SendNextQueuedCommand()
{
//Debug.Console(2, this, "Attempting to send next queued command. CommandQueueInProgress: {0} Communication isConnected: {1}", CommandQueueInProgress, Communication.IsConnected);
//if (CommandQueue.IsEmpty)
// CommandQueueInProgress = false;
//Debug.Console(1, this, "CommandQueue has {0} Elements:\n", CommandQueue.Count);
//foreach (object o in CommandQueue)
//{
// if (o is string)
// Debug.Console(1, this, "{0}", o);
// else if(o is QueuedCommand)
// {
// var item = (QueuedCommand)o;
// Debug.Console(1, this, "{0}", item.Command);
// }
//}
//Debug.Console(1, this, "End of CommandQueue");
if (Communication.IsConnected && !CommandQueue.IsEmpty)
{
CommandQueueInProgress = true;
if (CommandQueue.Peek() is QueuedCommand)
{
QueuedCommand nextCommand = new QueuedCommand();
nextCommand = (QueuedCommand) CommandQueue.Peek();
SendLine(nextCommand.Command);
}
else
{
string nextCommand = (string) CommandQueue.Peek();
SendLine(nextCommand);
}
}
}
/// <summary>
/// Sends a command to execute a preset
/// </summary>
/// <param name="name">Preset Name</param>
public void RunPreset(string name)
{
SendLine(string.Format("DEVICE recallPreset {0}", name));
}
public class QueuedCommand
{
public string Command { get; set; }
public string AttributeCode { get; set; }
public TesiraForteControlPoint ControlPoint { get; set; }
}
}
public class BiampTesiraForteDspFactory : EssentialsDeviceFactory<BiampTesiraForteDsp>
{
public BiampTesiraForteDspFactory()
{
TypeNames = new List<string>() {"biamptesira"};
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new BiampTesira Device");
var comm = CommFactory.CreateCommForDevice(dc);
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<BiampTesiraFortePropertiesConfig>(
dc.Properties.ToString());
return new BiampTesiraForteDsp(dc.Key, dc.Name, comm, props);
}
}
}

View File

@@ -15,18 +15,19 @@ namespace PepperDash.Essentials.Devices.Common.DSP
public Dictionary<string, DspControlPoint> DialerControlPoints { get; private set; }
public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
public abstract void RunPreset(string name);
public DspBase(string key, string name) :
base(key, name) { }
public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
public DspBase(string key, string name) :
base(key, name)
{
}
// in audio call feedback
// VOIP
// Phone dialer
// Phone dialer
}
// Fusion

View File

@@ -812,8 +812,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
CallStatusChange += (sender, args) =>
{
trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall);
trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming);
Debug.Console(1, this, "Call Direction: {0}", args.CallItem.Direction);
Debug.Console(1, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming);
trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status != eCodecCallStatus.Disconnected);
if (args.CallItem.Direction == eCodecCallDirection.Incoming)
{

View File

@@ -1605,6 +1605,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public override void AcceptCall(CodecActiveCallItem call)
{
SendText(string.Format("zCommand Call Accept callerJID: {0}", call.Id));
call.Status = eCodecCallStatus.Connected;
OnCallStatusChange(call);
UpdateCallStatus();
}
public void RejectCall()
@@ -1619,6 +1625,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public override void RejectCall(CodecActiveCallItem call)
{
SendText(string.Format("zCommand Call Reject callerJID: {0}", call.Id));
call.Status = eCodecCallStatus.Disconnected;
OnCallStatusChange(call);
UpdateCallStatus();
}
public override void Dial(Meeting meeting)