Repository: PepperDash/Essentials Branch: main Commit: e1a5c32c1f19 Files: 784 Total size: 5.1 MB Directory structure: gitextract_fb__7fh1/ ├── .config/ │ └── dotnet-tools.json ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ └── rfi_request.md │ ├── scripts/ │ │ ├── GenerateVersionNumber-2.0.0.ps1 │ │ ├── GenerateVersionNumber.ps1 │ │ ├── UpdateAssemblyVersion.ps1 │ │ └── ZipBuildOutput.ps1 │ └── workflows/ │ ├── EssentialsPlugins-builds-4-series-caller.yml │ └── publish-docs.yml ├── .gitignore ├── .gitmodules ├── .releaserc.json ├── .vscode/ │ └── extensions.json ├── CONTRIBUTING.md ├── Crestron-Library-Usage-Analysis.md ├── IR Drivers/ │ ├── Apple_AppleTV_4th_Gen_Essentials.ir │ ├── Cisco Explorer 4642HDC.ir │ ├── Comcast Motorola DVR.ir │ ├── Comcast X1.ir │ ├── DirecTV H21.ir │ ├── EXPLORER 8200HD Full Set Pulsed.ir │ ├── Etisalat Cable Box.ir │ ├── Etisalat e-Vision.ir │ ├── Panasonic DMP-BD70.ir │ ├── Sony BDP Series.ir │ └── samsung_un_series.ir ├── LICENSE.md ├── PepperDash.Essentials.4Series.sln ├── README.md ├── Sample Presets/ │ └── SampleDirecTV.json ├── docs/ │ ├── docfx.json │ ├── docs/ │ │ ├── CardFrame.md │ │ ├── Get-started.md │ │ ├── Home.md │ │ ├── Plugins-Deprecated.md │ │ ├── SIMPL-Bridging-Deprecated.md │ │ ├── SIMPL-Bridging.md │ │ ├── getting-started.md │ │ ├── how-to/ │ │ │ └── how-to-add-docs.md │ │ ├── technical-docs/ │ │ │ ├── Arch-1.md │ │ │ ├── Arch-activate.md │ │ │ ├── Arch-lifecycle.md │ │ │ ├── Arch-summary.md │ │ │ ├── Arch-topics.md │ │ │ ├── Communication-Basics.md │ │ │ ├── ConfigurationStructure.md │ │ │ ├── Connection-Based-Routing.md │ │ │ ├── Debugging.md │ │ │ ├── Feedback-Classes.md │ │ │ ├── Glossary-of-Terms.md │ │ │ ├── Plugins.md │ │ │ └── Supported-Devices.md │ │ ├── toc.yml │ │ └── usage/ │ │ ├── Bridging-To-Hardware-Resources.md │ │ ├── DigitalInput.md │ │ ├── GenericComm.md │ │ ├── IR-Driver-Bridging.md │ │ ├── JoinMaps.md │ │ ├── RelayOutput.md │ │ ├── SIMPL-Bridging-Updated.md │ │ └── Standalone-Use.md │ ├── index.md │ └── toc.yml └── src/ ├── Directory.Build.props ├── Directory.Build.targets ├── PepperDash.Core/ │ ├── ComTextHelper.cs │ ├── Comm/ │ │ ├── CommunicationGather.cs │ │ ├── CommunicationStreamDebugging.cs │ │ ├── ControlPropertiesConfig.cs │ │ ├── EventArgs.cs │ │ ├── GenericSecureTcpIpClient.cs │ │ ├── GenericSecureTcpIpClient_ForServer.cs │ │ ├── GenericSecureTcpIpServer.cs │ │ ├── GenericSshClient.cs │ │ ├── GenericTcpIpClient.cs │ │ ├── GenericTcpIpClient_ForServer.cs │ │ ├── GenericTcpIpServer.cs │ │ ├── GenericUdpClient.cs │ │ ├── GenericUdpServer.cs │ │ ├── StreamDebuggingExtensions.cs │ │ ├── TcpClientConfigObject.cs │ │ ├── TcpServerConfigObject.cs │ │ ├── eControlMethods.cs │ │ ├── eStreamDebuggingDataTypeSettings.cs │ │ └── eStreamDebuggingSetting.cs │ ├── CommunicationExtras.cs │ ├── Config/ │ │ └── PortalConfigReader.cs │ ├── Conversion/ │ │ └── Convert.cs │ ├── CoreInterfaces.cs │ ├── Device.cs │ ├── EthernetHelper.cs │ ├── EventArgs.cs │ ├── GenericRESTfulCommunications/ │ │ ├── Constants.cs │ │ └── GenericRESTfulClient.cs │ ├── JsonStandardObjects/ │ │ ├── EventArgs and Constants.cs │ │ ├── JsonToSimplDevice.cs │ │ └── JsonToSimplDeviceConfig.cs │ ├── JsonToSimpl/ │ │ ├── Constants.cs │ │ ├── Global.cs │ │ ├── JsonToSimplArrayLookupChild.cs │ │ ├── JsonToSimplChildObjectBase.cs │ │ ├── JsonToSimplFileMaster.cs │ │ ├── JsonToSimplFixedPathObject.cs │ │ ├── JsonToSimplGenericMaster.cs │ │ ├── JsonToSimplMaster.cs │ │ └── JsonToSimplPortalFileMaster.cs │ ├── Logging/ │ │ ├── CrestronEnricher.cs │ │ ├── Debug.cs │ │ ├── DebugConsoleSink.cs │ │ ├── DebugContext.cs │ │ ├── DebugCrestronLoggerSink.cs │ │ ├── DebugErrorLogSink.cs │ │ ├── DebugExtensions.cs │ │ ├── DebugMemory.cs │ │ └── DebugWebsocketSink.cs │ ├── Network/ │ │ └── DiscoveryThings.cs │ ├── PasswordManagement/ │ │ ├── Config.cs │ │ ├── Constants.cs │ │ ├── PasswordClient.cs │ │ └── PasswordManager.cs │ ├── PepperDash.Core.csproj │ ├── PepperDashCore.build/ │ │ └── net472/ │ │ ├── PepperDashCore.props │ │ └── PepperDashCore.targets │ ├── Properties/ │ │ └── ControlSystem.cfg │ ├── SystemInfo/ │ │ ├── EventArgs and Constants.cs │ │ ├── SystemInfoConfig.cs │ │ └── SystemInfoToSimpl.cs │ ├── Web/ │ │ ├── BouncyCertificate.cs │ │ ├── RequestHandlers/ │ │ │ ├── DefaultRequestHandler.cs │ │ │ ├── WebApiBaseRequestAsyncHandler.cs │ │ │ └── WebApiBaseRequestHandler.cs │ │ └── WebApiServer.cs │ ├── WebApi/ │ │ └── Presets/ │ │ ├── Preset.cs │ │ ├── User.cs │ │ └── WebApiPasscodeClient.cs │ └── XSigUtility/ │ ├── Serialization/ │ │ ├── IXSigSerialization.cs │ │ └── XSigSerializationException.cs │ ├── Tokens/ │ │ ├── XSigAnalogToken.cs │ │ ├── XSigDigitalToken.cs │ │ ├── XSigSerialToken.cs │ │ ├── XSigToken.cs │ │ └── XSigTokenType.cs │ ├── XSigHelpers.cs │ ├── XSigTokenStreamReader.cs │ └── XSigTokenStreamWriter.cs ├── PepperDash.Essentials/ │ ├── AssetLoader.cs │ ├── ClassDiagram1.cd │ ├── ControlSystem.cs │ ├── Example Configuration/ │ │ ├── EssentialsHuddleSpaceRoom/ │ │ │ └── configurationFile-HuddleSpace-2-Source.json │ │ ├── EssentialsHuddleVtc1Room/ │ │ │ └── configurationFile-mockVideoCodec_din-ap3_-_dm4x1.json │ │ └── SIMPLBridging/ │ │ ├── SIMPLBridgeExample_configurationFile.json │ │ └── configurationFile-dmps3300c-avRouting.json │ ├── Factory/ │ │ └── DeviceFactory.cs │ ├── HttpLogoServer.cs │ ├── PepperDash.Essentials.csproj │ ├── Properties/ │ │ ├── ControlSystem.cfg │ │ └── UpdateAssemblyVersion.ps1 │ ├── SGD/ │ │ ├── PepperDash Essentials TSW-560.sgd │ │ ├── PepperDash Essentials TSW-760.sgd │ │ └── PepperDash Essentials iPad.sgd │ └── app.config ├── PepperDash.Essentials.Core/ │ ├── Bridges/ │ │ ├── BridgeBase.cs │ │ ├── BridgeHelper.cs │ │ ├── IBridge.cs │ │ └── JoinMaps/ │ │ ├── AirMediaControllerJoinMap.cs │ │ ├── AppleTvJoinMap.cs │ │ ├── C2nRthsControllerJoinMap.cs │ │ ├── CameraControllerJoinMap.cs │ │ ├── CenOdtOccupancySensorBaseJoinMap.cs │ │ ├── DisplayControllerJoinMap.cs │ │ ├── DmBladeChassisControllerJoinMap.cs │ │ ├── DmChassisControllerJoinMap.cs │ │ ├── DmRmcControllerJoinMap.cs │ │ ├── DmTxControllerJoinMap.cs │ │ ├── DmpsAudioOutputControllerJoinMap.cs │ │ ├── DmpsMicrophoneControllerJoinMap.cs │ │ ├── DmpsRoutingControllerJoinMap.cs │ │ ├── GenericIrControllerJoinMap.cs │ │ ├── GenericLightingJoinMap.cs │ │ ├── GenericRelayControllerJoinMap.cs │ │ ├── GlsOccupancySensorBaseJoinMap.cs │ │ ├── GlsPartitionSensorJoinMap.cs │ │ ├── HdMdNxM4kEControllerJoinMap.cs │ │ ├── HdMdxxxCEControllerJoinMap.cs │ │ ├── HdPsXxxControllerJoinMap.cs │ │ ├── Hrxxx0WirelessRemoteControllerJoinMap.cs │ │ ├── IAnalogInputJoinMap.cs │ │ ├── IBasicCommunicationJoinMap.cs │ │ ├── IDigitalInputJoinMap.cs │ │ ├── IDigitalOutputJoinMap.cs │ │ ├── IRBlurayBaseJoinMap.cs │ │ ├── PduJoinMapBase.cs │ │ ├── SetTopBoxControllerJoinMap.cs │ │ ├── StatusSignControllerJoinMap.cs │ │ ├── SystemMonitorJoinMap.cs │ │ └── VideoCodecControllerJoinMap.cs │ ├── Comm and IR/ │ │ ├── CecPortController.cs │ │ ├── ComPortController.cs │ │ ├── ComSpecJsonConverter.cs │ │ ├── CommBridge.cs │ │ ├── CommFactory.cs │ │ ├── CommunicationExtras.cs │ │ ├── ConsoleCommMockDevice.cs │ │ ├── GenericComm.cs │ │ ├── GenericHttpClient.cs │ │ └── IRPortHelper.cs │ ├── Config/ │ │ ├── AudioControlPointListItem.cs │ │ ├── BaseStreamingDeviceProperties.cs │ │ ├── BasicConfig.cs │ │ ├── ConfigPropertiesHelpers.cs │ │ ├── DeviceConfig.cs │ │ ├── Essentials/ │ │ │ ├── ConfigReader.cs │ │ │ ├── ConfigUpdater.cs │ │ │ ├── ConfigWriter.cs │ │ │ └── EssentialsConfig.cs │ │ ├── ILoadConfig.cs │ │ ├── InfoConfig.cs │ │ └── SourceDevicePropertiesConfigBase.cs │ ├── Crestron/ │ │ ├── CrestronGenericBaseDevice.cs │ │ └── CrestronGenericBaseDevice.cs.orig │ ├── CrestronIO/ │ │ ├── GenericDigitalInputDevice.cs │ │ ├── GenericRelayDevice.cs │ │ ├── GenericVersiportAnalogInputDevice.cs │ │ ├── GenericVersiportInputDevice.cs │ │ ├── GenericVersiportOutputDevice.cs │ │ ├── IAnalogInput.cs │ │ ├── IDigitalInput.cs │ │ ├── IDigitalOutput.cs │ │ ├── IHasCresnetBranches.cs │ │ ├── IOPortConfig.cs │ │ └── ISwitchedOutput.cs │ ├── Device Info/ │ │ ├── DeviceInfo.cs │ │ ├── DeviceInfoEventArgs.cs │ │ ├── IDeviceInfoProvider.cs │ │ └── NetworkDeviceHelpers.cs │ ├── DeviceControlsParentInterfaces/ │ │ └── IPresentationSource.cs │ ├── DeviceTypeInterfaces/ │ │ ├── IAudioZone.cs │ │ ├── IAudioZones.cs │ │ ├── IBasicVolumeControls.cs │ │ ├── IBasicVolumeWithFeedback.cs │ │ ├── IBasicVolumeWithFeedbackAdvanced.cs │ │ ├── IChannel.cs │ │ ├── IColorFunctions.cs │ │ ├── ICustomMobileControl.cs │ │ ├── IDPad.cs │ │ ├── IDiscPlayerControls.cs │ │ ├── IDisplay.cs │ │ ├── IDisplayBasic.cs │ │ ├── IDumbSource.cs │ │ ├── IDvr.cs │ │ ├── IEmergencyOSD.cs │ │ ├── IFullAudioSettings.cs │ │ ├── IHasBranding.cs │ │ ├── IHasCurrentVolumeControls.cs │ │ ├── IHasFarEndContentStatus.cs │ │ ├── IHasInputs.cs │ │ ├── IHasMuteControl.cs │ │ ├── IHasMuteControlWithFeedback.cs │ │ ├── IHasPhoneDialing.cs │ │ ├── IHasScreensWithLayouts.cs │ │ ├── IHasSurroundSoundModes.cs │ │ ├── IHasVolumeControl.cs │ │ ├── IHasVolumeControlWithFeedback.cs │ │ ├── IHasVolumeDevice.cs │ │ ├── IHasWebView.cs │ │ ├── IHumiditySensor.cs │ │ ├── ILanguageDefinition.cs │ │ ├── ILanguageProvider.cs │ │ ├── ILevelControls.cs │ │ ├── IMeterFeedback.cs │ │ ├── IMobileControl.cs │ │ ├── IMobileControlAction.cs │ │ ├── IMobileControlCrestronTouchpanelController.cs │ │ ├── IMobileControlMessage.cs │ │ ├── IMobileControlMessenger.cs │ │ ├── IMobileControlMessengerWithSubscriptions.cs │ │ ├── IMobileControlRoomMessenger.cs │ │ ├── IMobileControlTouchpanelController.cs │ │ ├── INumeric.cs │ │ ├── INvxNetworkPortInformation.cs │ │ ├── IPasswordPrompt.cs │ │ ├── IPower.cs │ │ ├── IProjectorScreenLiftControl.cs │ │ ├── ISelectableItem.cs │ │ ├── ISelectableItems.cs │ │ ├── ISetTopBoxControls.cs │ │ ├── IStateFeedback.cs │ │ ├── ITemperatureSensor.cs │ │ ├── ITransport.cs │ │ ├── ITvPresetsProvider.cs │ │ ├── IUiDisplayInfo.cs │ │ ├── IWarmingCooling.cs │ │ ├── LanguageLabel.cs │ │ ├── Template.cs │ │ └── eVolumeLevelUnits.cs │ ├── Devices/ │ │ ├── AudioControlListItemBase.cs │ │ ├── AudioInterfaces.cs │ │ ├── CameraListItem.cs │ │ ├── CodecInterfaces.cs │ │ ├── ConfigSnippetAttribute.cs │ │ ├── CrestronProcessor.cs │ │ ├── DescriptionAttribute.cs │ │ ├── DestinationListItem.cs │ │ ├── DeviceApiBase.cs │ │ ├── DeviceFeedbackExtensions.cs │ │ ├── DeviceJsonApi.cs │ │ ├── DeviceManager.cs │ │ ├── DisplayUiConstants.cs │ │ ├── EssentialsBridgeableDevice.cs │ │ ├── EssentialsDevice.cs │ │ ├── EssentialsDeviceFactory.cs │ │ ├── EssentialsPluginDevelopmentDeviceFactory.cs │ │ ├── EssentialsPluginDeviceFactory.cs │ │ ├── GenericIRController.cs │ │ ├── GenericMonitoredTcpDevice.cs │ │ ├── IAttachVideoStatus.cs │ │ ├── IAttachVideoStatusExtensions.cs │ │ ├── IDisplayUsage.cs │ │ ├── IDspPresets.cs │ │ ├── IHasFeedbacks.cs │ │ ├── IMakeModel.cs │ │ ├── IOnline.cs │ │ ├── IProjectorInterfaces.cs │ │ ├── IReconfigurableDevice.cs │ │ ├── IUsageTracking.cs │ │ ├── IrOutputPortController.cs │ │ ├── LevelControlListItem.cs │ │ ├── PduInterfaces.cs │ │ ├── PowerInterfaces.cs │ │ ├── PresentationDeviceType.cs │ │ ├── PresetListItem.cs │ │ ├── ProcessorExtensionDeviceFactory.cs │ │ ├── ReconfigurableDevice.cs │ │ ├── SmartObjectBaseTypes.cs │ │ ├── SourceListItem.cs │ │ └── VolumeDeviceChangeEventArgs.cs │ ├── Ethernet/ │ │ └── EthernetStatistics.cs │ ├── Extensions/ │ │ ├── IpAddressExtensions.cs │ │ ├── JsonExtensions.cs │ │ └── StringExtensions.cs │ ├── Factory/ │ │ ├── DeviceFactory.cs │ │ ├── DeviceFactoryWrapper.cs │ │ ├── IDeviceFactory.cs │ │ ├── IProcessorExtensionDeviceFactory.cs │ │ ├── ProcessorExtensionDeviceFactory.cs │ │ └── ReadyEventArgs.cs │ ├── Feedbacks/ │ │ ├── BoolFeedback.cs │ │ ├── BoolFeedbackOneShot.cs │ │ ├── BoolFeedbackPulseExtender.cs │ │ ├── BoolOutputLogicals.cs │ │ ├── FeedbackBase.cs │ │ ├── FeedbackCollection.cs │ │ ├── FeedbackEventArgs.cs │ │ ├── IntFeedback.cs │ │ ├── SerialFeedback.cs │ │ └── StringFeedback.cs │ ├── File/ │ │ └── FileIO.cs │ ├── Fusion/ │ │ ├── EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs │ │ ├── FusionCustomPropertiesBridge.cs │ │ ├── FusionEventHandlers.cs │ │ ├── FusionProcessorQueries.cs │ │ ├── FusionRviDataClasses.cs │ │ ├── IEssentialsRoomFusionController.cs │ │ ├── IEssentialsRoomFusionControllerFactory.cs │ │ ├── IEssentialsRoomFusionControllerPropertiesConfig.cs │ │ ├── IFusionHelpRequest.cs │ │ └── eFusionHelpResponse.cs │ ├── Global/ │ │ ├── EthernetAdapterInfo.cs │ │ ├── Global.cs │ │ ├── JobTimer.cs │ │ └── Scheduler.cs │ ├── InUseTracking/ │ │ ├── IInUseTracking.cs │ │ └── InUseTracking.cs │ ├── Interfaces/ │ │ ├── ILogStrings.cs │ │ └── ILogStringsWithLevel.cs │ ├── JoinMaps/ │ │ └── JoinMapBase.cs │ ├── License/ │ │ └── EssentialsLicenseManager.cs │ ├── Lighting/ │ │ ├── Lighting Interfaces.cs │ │ └── LightingScene.cs │ ├── Microphone Privacy/ │ │ ├── MicrophonePrivacyController.cs │ │ └── MicrophonePrivacyControllerConfig.cs │ ├── Monitoring/ │ │ ├── CrestronGenericBaseCommunicationMonitor.cs │ │ ├── GenericCommunicationMonitor.cs │ │ ├── Interfaces.cs │ │ ├── StatusMonitorBase.cs │ │ ├── StatusMonitorCollection.cs │ │ └── SystemMonitorController.cs │ ├── PartitionSensor/ │ │ ├── EssentialsPartitionController.cs │ │ └── IPartitionStateProvider.cs │ ├── PepperDash.Essentials.Core.csproj │ ├── PepperDash_Essentials_Core.csproj.DotSettings │ ├── Plugins/ │ │ ├── IPluginDeviceFactory.cs │ │ └── PluginLoader.cs │ ├── Presets/ │ │ ├── DevicePresets.cs │ │ ├── DevicePresetsView.cs │ │ ├── Interfaces.cs │ │ ├── PresetBase.cs │ │ ├── PresetChannel.cs │ │ └── PresetsListSubpageReferenceListItem.cs │ ├── Properties/ │ │ └── ControlSystem.cfg │ ├── Queues/ │ │ ├── ComsMessage.cs │ │ ├── GenericQueue.cs │ │ ├── IQueue.cs │ │ ├── IQueueMessage.cs │ │ ├── ProcessStringMessage.cs │ │ └── StringResponseProcessor.cs │ ├── Ramps and Increments/ │ │ ├── ActionIncrementer.cs │ │ ├── NumericalHelpers.cs │ │ └── UshortSigIncrementer.cs │ ├── Room/ │ │ ├── Behaviours/ │ │ │ └── RoomOnToDefaultSourceWhenOccupied.cs │ │ ├── Combining/ │ │ │ ├── EssentialsRoomCombiner.cs │ │ │ ├── EssentialsRoomCombinerPropertiesConfig.cs │ │ │ ├── IEssentialsRoomCombiner.cs │ │ │ └── RoomCombinationScenario.cs │ │ ├── Config/ │ │ │ ├── EssentialsDualDisplayRoomPropertiesConfig.cs │ │ │ ├── EssentialsHuddleRoomPropertiesConfig.cs │ │ │ ├── EssentialsHuddleVtc1PropertiesConfig.cs │ │ │ ├── EssentialsNDisplayRoomPropertiesConfig.cs │ │ │ ├── EssentialsPresentationPropertiesConfig.cs │ │ │ ├── EssentialsRoomConfig.cs │ │ │ ├── EssentialsRoomEmergencyConfig.cs │ │ │ ├── EssentialsRoomScheduledEventsConfig.cs │ │ │ ├── EssentialsTechRoomConfig.cs │ │ │ ├── EssentialsVolumeLevelConfig.cs │ │ │ └── SimplRoomPropertiesConfig.cs │ │ ├── EsentialsRoomEmergencyContactClosure.cs │ │ ├── EssentialsRoomBase.cs │ │ ├── IEssentialsRoom.cs │ │ ├── IRoomEventSchedule.cs │ │ ├── Interfaces.cs │ │ ├── Room.cs │ │ └── iOccupancyStatusProvider.cs │ ├── Routing/ │ │ ├── DummyRoutingInputsDevice.cs │ │ ├── Extensions.cs │ │ ├── ICardPortsDevice.cs │ │ ├── ICurrentSources.cs │ │ ├── IHasCurrentSourceInfoChange.cs │ │ ├── IInputSync.cs │ │ ├── IMatrixRouting.cs │ │ ├── IRmcRouting.cs │ │ ├── IRmcRoutingWithFeedback.cs │ │ ├── IRouting.cs │ │ ├── IRoutingFeedback.cs │ │ ├── IRoutingHasVideoInputSyncFeedbacks.cs │ │ ├── IRoutingInputSlot.cs │ │ ├── IRoutingInputs.cs │ │ ├── IRoutingInputsOutputs.cs │ │ ├── IRoutingNumeric.cs │ │ ├── IRoutingNumericWithFeedback.cs │ │ ├── IRoutingOutputSlot.cs │ │ ├── IRoutingOutputs.cs │ │ ├── IRoutingSink.cs │ │ ├── IRoutingSinkWithFeedback.cs │ │ ├── IRoutingSinkWithSwitching.cs │ │ ├── IRoutingSlot.cs │ │ ├── IRoutingSource.cs │ │ ├── IRoutingWithClear.cs │ │ ├── IRoutingWithFeedback.cs │ │ ├── ITxRouting.cs │ │ ├── ITxRoutingWithFeedback.cs │ │ ├── RouteDescriptor.cs │ │ ├── RouteDescriptorCollection.cs │ │ ├── RouteRequest.cs │ │ ├── RouteRequestQueueItem.cs │ │ ├── RouteSwitchDescriptor.cs │ │ ├── RoutingFeedbackManager.cs │ │ ├── RoutingInputPort.cs │ │ ├── RoutingInputPortWithVideoStatuses.cs │ │ ├── RoutingNumericEventArgs.cs │ │ ├── RoutingOutputPort.cs │ │ ├── RoutingPort.cs │ │ ├── RoutingPortCollection.cs │ │ ├── RoutingPortNames.cs │ │ ├── TieLine.cs │ │ ├── TieLineConfig.cs │ │ ├── eRoutingPortConnectionType.cs │ │ └── eRoutingSignalType.cs │ ├── Secrets/ │ │ ├── CrestronGlobalSecretsProvider.cs │ │ ├── CrestronLocalSecretsProvider.cs │ │ ├── CrestronSecret.cs │ │ ├── Interfaces.cs │ │ ├── SecretsManager.cs │ │ └── SecretsPropertiesConfig.cs │ ├── Shades/ │ │ ├── Shade Interfaces.cs │ │ └── ShadeBase.cs │ ├── SigHelper.cs │ ├── SmartObjects/ │ │ ├── SmartObjectDPad.cs │ │ ├── SmartObjectDynamicList.cs │ │ ├── SmartObjectHelperBase.cs │ │ ├── SmartObjectNumeric.cs │ │ └── SubpageReferencList/ │ │ ├── SourceListSubpageReferenceList.cs │ │ ├── SubpageReferenceList.cs │ │ └── SubpageReferenceListItem.cs │ ├── Timers/ │ │ ├── CountdownTimer.cs │ │ └── RetriggerableTimer.cs │ ├── Touchpanels/ │ │ ├── CrestronTouchpanelPropertiesConfig.cs │ │ ├── Interfaces.cs │ │ ├── Keyboards/ │ │ │ └── HabaneroKeyboardController.cs │ │ ├── ModalDialog.cs │ │ ├── Mpc3Touchpanel.cs │ │ └── TriListExtensions.cs │ ├── TriListBridges/ │ │ └── HandlerBridge.cs │ ├── UI/ │ │ └── TouchpanelBase.cs │ ├── UI PageManagers/ │ │ ├── BlurayPageManager.cs │ │ ├── PageManager.cs │ │ ├── SetTopBoxThreePanelPageManager.cs │ │ ├── SetTopBoxTwoPanelPageManager.cs │ │ └── SinglePageManager.cs │ ├── Utilities/ │ │ └── ActionSequence.cs │ ├── VideoStatus/ │ │ └── VideoStatusOutputs.cs │ ├── Web/ │ │ ├── EssentialsWebApi.cs │ │ ├── EssentialsWebApiFactory.cs │ │ ├── EssentialsWebApiHelpers.cs │ │ ├── EssentialsWebApiPropertiesConfig.cs │ │ └── RequestHandlers/ │ │ ├── AppDebugRequestHandler.cs │ │ ├── DebugSessionRequestHandler.cs │ │ ├── DefaultRequestHandler.cs │ │ ├── DevJsonRequestHandler.cs │ │ ├── DevListRequestHandler.cs │ │ ├── DevMethodsRequestHandler.cs │ │ ├── DevPropsRequestHandler.cs │ │ ├── DisableAllStreamDebugRequestHandler.cs │ │ ├── DoNotLoadConfigOnNextBootRequestHandler.cs │ │ ├── GetFeedbacksForDeviceRequestHandler.cs │ │ ├── GetJoinMapForBridgeKeyRequestHandler.cs │ │ ├── GetJoinMapForDeviceKeyRequestHandler.cs │ │ ├── GetRoutesHandler.cs │ │ ├── GetRoutingDevicesAndTieLinesHandler.cs │ │ ├── GetRoutingPortsHandler.cs │ │ ├── GetTieLinesRequestHandler.cs │ │ ├── GetTypesByFilterRequestHandler.cs │ │ ├── GetTypesRequestHandler.cs │ │ ├── LoadConfigRequestHandler.cs │ │ ├── LoginRequestHandler.cs │ │ ├── ReportVersionsRequestHandler.cs │ │ ├── RestartProgramRequestHandler.cs │ │ ├── ServeDebugAppRequestHandler.cs │ │ ├── SetDeviceStreamDebugRequestHandler.cs │ │ └── ShowConfigRequestHandler.cs │ └── app.config ├── PepperDash.Essentials.Devices.Common/ │ ├── Audio/ │ │ └── GenericAudioOut.cs │ ├── AudioCodec/ │ │ ├── AudioCodecBase.cs │ │ ├── Interfaces/ │ │ │ ├── IAudioCodecInfo.cs │ │ │ └── IHasAudioCodec.cs │ │ └── MockAC/ │ │ ├── MockAC.cs │ │ └── MockAcPropertiesConfig.cs │ ├── Cameras/ │ │ ├── CameraBase.cs │ │ ├── CameraVisca.cs │ │ ├── IHasCameraPresets.cs │ │ └── Interfaces/ │ │ ├── CameraSelectedEventArgs.cs │ │ ├── IAmFarEndCamera.cs │ │ ├── ICameraCapabilities.cs │ │ ├── IHasAutoFocusMode.cs │ │ ├── IHasCameraAutoMode.cs │ │ ├── IHasCameraControls.cs │ │ ├── IHasCameraFocusControl.cs │ │ ├── IHasCameraMute.cs │ │ ├── IHasCameraMuteWithUnmuteRequest.cs │ │ ├── IHasCameraOff.cs │ │ ├── IHasCameraPanControl.cs │ │ ├── IHasCameraPtzControl.cs │ │ ├── IHasCameraTiltControl.cs │ │ ├── IHasCameraZoomControl.cs │ │ ├── IHasCameras.cs │ │ ├── IHasCamerasWithControls.cs │ │ ├── IHasCodecCameras.cs │ │ ├── IHasFarEndCameraControl.cs │ │ └── eCameraControlMode.cs │ ├── Codec/ │ │ ├── Call.cs │ │ ├── Cisco/ │ │ │ ├── IPresenterTrack.cs │ │ │ └── ISpeakerTrack.cs │ │ ├── CodecActiveCallItem.cs │ │ ├── CodecDirectory.cs │ │ ├── CodecScheduleAwareness.cs │ │ ├── ContactMethod.cs │ │ ├── DirectoryContact.cs │ │ ├── DirectoryEventArgs.cs │ │ ├── DirectoryFolder.cs │ │ ├── DirectoryItem.cs │ │ ├── ICiscoCodecCameraConfig.cs │ │ ├── IHasCallHold.cs │ │ ├── IHasDirectoryHistoryStack.cs │ │ ├── IHasDoNotDisturb.cs │ │ ├── IHasExternalSourceSwitching.cs │ │ ├── IInvitableContact.cs │ │ ├── InvitableDirectoryContact.cs │ │ ├── Meeting.cs │ │ ├── MeetingEventArgs.cs │ │ ├── eCodecCallDirection.cs │ │ ├── eCodecCallStatus.cs │ │ ├── eCodecCallType.cs │ │ ├── eContactMethodCallType.cs │ │ ├── eContactMethodDevice.cs │ │ ├── eMeetingEventChangeType.cs │ │ ├── eMeetingPrivacy.cs │ │ ├── iCodecAudio.cs │ │ ├── iHasCallFavorites.cs │ │ ├── iHasCallHistory.cs │ │ ├── iHasContentSharing.cs │ │ ├── iHasDialer.cs │ │ ├── iHasDirectory.cs │ │ └── iHasScheduleAwareness.cs │ ├── DSP/ │ │ └── DspBase.cs │ ├── DeviceFactory.cs │ ├── Displays/ │ │ ├── BasicIrDisplay.cs │ │ ├── DisplayBase.cs │ │ ├── InputInterfaces.cs │ │ ├── MockDisplay.cs │ │ ├── MockDisplayInputs.cs │ │ ├── ScreenLiftController.cs │ │ ├── ScreenLiftControllerConfigProperties.cs │ │ ├── ScreenLiftRelaysConfig.cs │ │ ├── TwoWayDisplayBase.cs │ │ └── eScreenLiftControlMode.cs │ ├── Generic/ │ │ ├── GenericSink.cs │ │ └── GenericSource.cs │ ├── Lighting/ │ │ └── LightingBase.cs │ ├── PepperDash.Essentials.Devices.Common.csproj │ ├── Properties/ │ │ └── ControlSystem.cfg │ ├── Room/ │ │ ├── IEssentialsHuddleSpaceRoom.cs │ │ ├── IEssentialsHuddleVtc1Room.cs │ │ ├── IEssentialsRoomPropertiesConfig.cs │ │ └── IEssentialsTechRoom.cs │ ├── SetTopBox/ │ │ ├── IRSetTopBoxBase.cs │ │ ├── IRSetTopBoxBaseFactory.cs │ │ └── SetTopBoxPropertiesConfig.cs │ ├── Shades/ │ │ ├── RelayControlledShade.cs │ │ ├── ShadeBase.cs │ │ └── ShadeController.cs │ ├── SoftCodec/ │ │ ├── BlueJeansPc.cs │ │ ├── BlueJeansPcFactory.cs │ │ ├── GenericSoftCodec.cs │ │ ├── GenericSoftCodecFactory.cs │ │ └── GenericSoftCodecProperties.cs │ ├── Sources/ │ │ ├── InRoomPc.cs │ │ ├── InRoomPcFactory.cs │ │ ├── Laptop.cs │ │ └── LaptopFactory.cs │ ├── Streaming/ │ │ ├── AppleTV.cs │ │ ├── AppleTVFactory.cs │ │ ├── AppleTvIrCommands.cs │ │ ├── Roku.cs │ │ └── Roku2Factory.cs │ └── VideoCodec/ │ ├── CiscoCodec/ │ │ ├── CallHistoryDataClasses.cs │ │ ├── RoomPresets.cs │ │ ├── eCommandType.cs │ │ ├── eExternalSourceMode.cs │ │ └── eExternalSourceType.cs │ ├── CodecCommandWithLabel.cs │ ├── CodecPhonebookSyncState.cs │ ├── ConvertiblePreset.cs │ ├── Interfaces/ │ │ ├── CodecParticipants.cs │ │ ├── IHasCodecLayouts.cs │ │ ├── IHasCodecSelfview.cs │ │ ├── IHasMeetingInfo.cs │ │ ├── IHasMeetingLock.cs │ │ ├── IHasMeetingRecording.cs │ │ ├── IHasMeetingRecordingWithPrompt.cs │ │ ├── IHasParticipantAudioMute.cs │ │ ├── IHasParticipantPinUnpin.cs │ │ ├── IHasParticipantVideoMute.cs │ │ ├── IHasParticipants.cs │ │ ├── IHasPresentationOnlyMeeting.cs │ │ ├── IHasSelfviewPosition.cs │ │ ├── IHasSelfviewSize.cs │ │ ├── IHasStandbyMode.cs │ │ ├── IHasStartMeeting.cs │ │ ├── IHasVideoCodec.cs │ │ ├── IJoinCalls.cs │ │ ├── MeetingInfo.cs │ │ ├── MeetingInfoEventArgs.cs │ │ ├── Participant.cs │ │ └── iVideoCodecInfo.cs │ ├── MockVC/ │ │ ├── MockCodecDirectory.cs │ │ ├── MockVC.cs │ │ ├── MockVCCamera.cs │ │ └── MockVcPropertiesConfig.cs │ └── VideoCodecBase.cs ├── PepperDash.Essentials.MobileControl/ │ ├── AuthorizationResponse.cs │ ├── ClientSpecificUpdateRequest.cs │ ├── IDelayedConfiguration.cs │ ├── MessageToClients.cs │ ├── MobileControlAction.cs │ ├── MobileControlConfig.cs │ ├── MobileControlDeviceFactory.cs │ ├── MobileControlEssentialsConfig.cs │ ├── MobileControlFactory.cs │ ├── MobileControlSimplDeviceBridge.cs │ ├── MobileControlSystemController.cs │ ├── PepperDash.Essentials.MobileControl.csproj │ ├── RoomBridges/ │ │ ├── MobileControlBridgeBase.cs │ │ ├── MobileControlEssentialsRoomBridge.cs │ │ ├── MobileControlSIMPLRoomBridge.cs │ │ └── SourceDeviceMapDictionary.cs │ ├── Services/ │ │ └── MobileControlApiService.cs │ ├── Touchpanel/ │ │ ├── ITheme.cs │ │ ├── ITswAppControl.cs │ │ ├── ITswAppControlMessenger.cs │ │ ├── ITswZoomControlMessenger.cs │ │ ├── MobileControlTouchpanelController.cs │ │ ├── MobileControlTouchpanelProperties.cs │ │ └── ThemeMessenger.cs │ ├── TransmitMessage.cs │ ├── UserCodeChanged.cs │ ├── UserCodeChangedContent.cs │ ├── Utilities.cs │ ├── Volumes.cs │ ├── WebApiHandlers/ │ │ ├── ActionPathsHandler.cs │ │ ├── DeleteAllUiClientsHandler.cs │ │ ├── MobileAuthRequestHandler.cs │ │ ├── MobileInfoHandler.cs │ │ └── UiClientHandler.cs │ └── WebSocketServer/ │ ├── ConnectionClosedEventArgs.cs │ ├── DeviceInterfaceInfo.cs │ ├── JoinResponse.cs │ ├── JoinToken.cs │ ├── MobileControlWebsocketServer.cs │ ├── ServerTokenSecrets.cs │ ├── UiClient.cs │ ├── UiClientContext.cs │ ├── Version.cs │ └── WebSocketServerSecretProvider.cs └── PepperDash.Essentials.MobileControl.Messengers/ ├── ContentTypes.cs ├── DeviceTypeExtensions/ │ ├── DisplayBaseMessenger.cs │ ├── IChannelMessenger.cs │ ├── IColorMessenger.cs │ ├── IDPadMessenger.cs │ ├── IDvrMessenger.cs │ ├── IHasPowerMessenger.cs │ ├── INumericMessenger.cs │ ├── ISetTopBoxControlsMessenger.cs │ └── ITransportMessenger.cs ├── Messengers/ │ ├── AudioCodecBaseMessenger.cs │ ├── CameraBaseMessenger.cs │ ├── CurrentSourcesMessenger.cs │ ├── DeviceEventMessageBase.cs │ ├── DeviceInfoMessenger.cs │ ├── DeviceMessageBase.cs │ ├── DevicePresetsModelMessenger.cs │ ├── DeviceStateMessageBase.cs │ ├── DeviceVolumeMessenger.cs │ ├── GenericMessenger.cs │ ├── IBasicVideoMuteWithFeedbackMessenger.cs │ ├── ICommunicationMonitorMessenger.cs │ ├── IDspPresetsMessenger.cs │ ├── IEssentialsRoomCombinerMessenger.cs │ ├── IHasCamerasMessenger.cs │ ├── IHasCamerasWithControlMessenger.cs │ ├── IHasCurrentSourceInfoMessenger.cs │ ├── IHasInputsMessenger.cs │ ├── IHasPowerControlWithFeedbackMessenger.cs │ ├── IHasScheduleAwarenessMessenger.cs │ ├── IHumiditySensor.cs │ ├── ILevelControlsMessenger.cs │ ├── IMatrixRoutingMessenger.cs │ ├── IProjectorScreenLiftControlMessenger.cs │ ├── IRunRouteActionMessenger.cs │ ├── ISelectableItemsMessenger.cs │ ├── IShutdownPromptTimerMessenger.cs │ ├── ISwitchedOutputMessenger.cs │ ├── ITechPasswordMessenger.cs │ ├── ITemperatureSensorMessenger.cs │ ├── LightingBaseMessenger.cs │ ├── MessengerBase.cs │ ├── PressAndHoldHandler.cs │ ├── RoomEventScheduleMessenger.cs │ ├── SIMPLAtcMessenger.cs │ ├── SIMPLCameraMessenger.cs │ ├── SIMPLDirectRouteMessenger.cs │ ├── SIMPLRouteMessenger.cs │ ├── SIMPLVtcMessenger.cs │ ├── ShadeBaseMessenger.cs │ ├── SimplMessengerPropertiesConfig.cs │ ├── SystemMonitorMessenger.cs │ ├── TwoWayDisplayBaseMessenger.cs │ └── VideoCodecBaseMessenger.cs ├── MobileControlMessage.cs ├── MobileControlSimpleContent.cs ├── PepperDash.Essentials.MobileControl.Messengers.csproj └── SIMPLJoinMaps/ ├── MobileControlSIMPLRoomJoinMap.cs ├── MobileControlSIMPLRunDirectRouteActionJoinMap.cs ├── SIMPLAtcJoinMap.cs └── SIMPLVtcJoinMap.cs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .config/dotnet-tools.json ================================================ { "version": 1, "isRoot": true, "tools": { "csharpier": { "version": "1.2.4", "commands": [ "csharpier" ], "rollForward": false } } } ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: "[BUG]-" labels: bug assignees: '' --- **Was this bug identified in a specific build version?** Please note the build version where this bug was identified **Describe the bug** A clear and concise description of what the bug is. **Stacktrace** Include a stack trace of the exception if possible. ``` Paste stack trace here ``` **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: "[FEATURE]-" labels: enhancement assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] If this is a request for support for a new device or type, be as specific as possible and include any pertinent manufacturer and model information. **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/ISSUE_TEMPLATE/rfi_request.md ================================================ --- name: Request for Information about: Request specific information about capabilities of the framework title: "[RFI]-" labels: RFI assignees: '' --- **What is your request?** Please provide as much detail as possible. **What is the intended use case** - [ ] Essentials Standalone Application - [ ] Essentials + SIMPL Windows Hybrid **User Interface Requirements** - [ ] Not Applicable (logic only) - [ ] Crestron Smart Graphics Touchpanel - [ ] Cisco Touch10 - [ ] Mobile Control - [ ] Crestron CH5 Touchpanel interface **Additional context** Add any other context or screenshots about the request here. ================================================ FILE: .github/scripts/GenerateVersionNumber-2.0.0.ps1 ================================================ $latestVersion = [version]"2.0.0" $newVersion = [version]$latestVersion $phase = "" $newVersionString = "" switch -regex ($Env:GITHUB_REF) { '^refs\/pull\/*.' { $phase = 'beta'; $newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER } '^refs\/heads\/feature-2.0.0\/*.' { $phase = 'alpha' $newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER } 'development-2.0.0' { $phase = 'beta' $newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER } } Write-Output $newVersionString ================================================ FILE: .github/scripts/GenerateVersionNumber.ps1 ================================================ $latestVersions = $(git tag --merged origin/main) $latestVersion = [version]"0.0.0" Write-Host "GITHUB_REF: $($Env:GITHUB_REF)" Write-Host "GITHUB_HEAD_REF: $($Env:GITHUB_HEAD_REF)" Write-Host "GITHUB_BASE_REF: $($Env:GITHUB_BASE_REF)" Foreach ($version in $latestVersions) { Write-Host $version try { if (([version]$version) -ge $latestVersion) { $latestVersion = $version Write-Host "Setting latest version to: $latestVersion" } } catch { Write-Host "Unable to convert $($version). Skipping" continue; } } $newVersion = [version]$latestVersion $phase = "" $newVersionString = "" switch -regex ($Env:GITHUB_REF) { '^refs\/pull\/*.' { $splitRef = $Env:GITHUB_REF -split "/" $phase = "pr$($splitRef[2])" $newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $newVersion.Major, $newVersion.Minor, ($newVersion.Build + 1), $phase, $Env:GITHUB_RUN_NUMBER } '^refs\/heads\/main*.' { $newVersionString = "{0}.{1}.{2}" -f $newVersion.Major, $newVersion.Minor, $newVersion.Build } '^refs\/heads\/feature\/*.' { $phase = 'alpha' $newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $newVersion.Major, $newVersion.Minor, ($newVersion.Build + 1), $phase, $Env:GITHUB_RUN_NUMBER } '^refs\/heads\/release\/*.' { $splitRef = $Env:GITHUB_REF -split "/" $version = [version]($splitRef[-1] -replace "v", "") $phase = 'rc' $newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $version.Major, $version.Minor, $version.Build, $phase, $Env:GITHUB_RUN_NUMBER } '^refs\/heads\/development*.' { $phase = 'beta' $newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $newVersion.Major, $newVersion.Minor, ($newVersion.Build + 1), $phase, $Env:GITHUB_RUN_NUMBER } '^refs\/heads\/hotfix\/*.' { $phase = 'hotfix' $newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $newVersion.Major, $newVersion.Minor, ($newVersion.Build + 1), $phase, $Env:GITHUB_RUN_NUMBER } '^refs\/heads\/bugfix\/*.' { $phase = 'hotfix' $newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $newVersion.Major, $newVersion.Minor, ($newVersion.Build + 1), $phase, $Env:GITHUB_RUN_NUMBER } } Write-Output $newVersionString ================================================ FILE: .github/scripts/UpdateAssemblyVersion.ps1 ================================================ function Update-SourceVersion { Param ([string]$Version) #$fullVersion = $Version $baseVersion = [regex]::Match($Version, "(\d+.\d+.\d+).*").captures.groups[1].value $NewAssemblyVersion = ‘AssemblyVersion("‘ + $baseVersion + ‘.*")’ Write-Output "AssemblyVersion = $NewAssemblyVersion" $NewAssemblyInformationalVersion = ‘AssemblyInformationalVersion("‘ + $Version + ‘")’ Write-Output "AssemblyInformationalVersion = $NewAssemblyInformationalVersion" foreach ($o in $input) { Write-output $o.FullName $TmpFile = $o.FullName + “.tmp” get-content $o.FullName | ForEach-Object { $_ -replace ‘AssemblyVersion\(".*"\)’, $NewAssemblyVersion } | ForEach-Object { $_ -replace ‘AssemblyInformationalVersion\(".*"\)’, $NewAssemblyInformationalVersion } > $TmpFile move-item $TmpFile $o.FullName -force } } function Update-AllAssemblyInfoFiles ( $version ) { foreach ($file in “AssemblyInfo.cs”, “AssemblyInfo.vb” ) { get-childitem -Path $Env:GITHUB_WORKSPACE -recurse | Where-Object { $_.Name -eq $file } | Update-SourceVersion $version ; } } # validate arguments $r = [System.Text.RegularExpressions.Regex]::Match($args[0], "\d+\.\d+\.\d+.*"); if ($r.Success) { Write-Output "Updating Assembly Version to $args ..."; Update-AllAssemblyInfoFiles $args[0]; } else { Write-Output ” “; Write-Output “Error: Input version does not match x.y.z format!” Write-Output ” “; Write-Output "Unable to apply version to AssemblyInfo.cs files"; } ================================================ FILE: .github/scripts/ZipBuildOutput.ps1 ================================================ # Uncomment these for local testing # $Env:GITHUB_WORKSPACE = "C:\Working Directories\PD\essentials" # $Env:SOLUTION_FILE = "PepperDashEssentials" # $Env:VERSION = "0.0.0-buildType-test" # Sets the root directory for the operation $destination = "$($Env:GITHUB_HOME)\output" New-Item -ItemType Directory -Force -Path ($destination) Get-ChildItem ($destination) $exclusions = @(git submodule foreach --quiet 'echo $name') $exclusions += "Newtonsoft.Compact.Json.dll" # Trying to get any .json schema files (not currently working) # Gets any files with the listed extensions. Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.dll", "*.nuspec" | ForEach-Object { $allowed = $true; # Exclude any files in submodules foreach ($exclude in $exclusions) { if ((Split-Path $_.FullName -Parent).contains("$($exclude)")) { $allowed = $false; break; } } if ($allowed) { Write-Host "allowing $($_)" $_; } } | Copy-Item -Destination ($destination) -Force Write-Host "Getting matching files..." # Get any files from the output folder that match the following extensions Get-ChildItem -Path $destination | Where-Object { ($_.Extension -eq ".clz") -or ($_.Extension -eq ".cpz" -or ($_.Extension -eq ".cplz")) } | ForEach-Object { # Replace the extensions with dll and xml and create an array # Removed dll file capture, as previous step should capture all of them. Add if needed-> $($_ -replace "cpz|clz|cplz", "dll"), $filenames = @($($_ -replace "cpz|clz|cplz", "xml")) Write-Host "Filenames:" Write-Host $filenames if ($filenames.length -gt 0) { # Attempt to get the files and return them to the output directory Get-ChildItem -Recurse -Path "$($Env:GITHUB_WORKSPACE)" -include $filenames | Copy-Item -Destination ($destination) -Force } } Get-ChildItem -Path $destination\*.cpz | Rename-Item -NewName { "$($_.BaseName)-$($Env:VERSION)$($_.Extension)" } Compress-Archive -Path $destination -DestinationPath "$($Env:GITHUB_WORKSPACE)\$($Env:SOLUTION_FILE)-$($Env:VERSION).zip" -Force Write-Host "Output Contents post Zip" Get-ChildItem -Path $destination ================================================ FILE: .github/workflows/EssentialsPlugins-builds-4-series-caller.yml ================================================ name: Build PepperDash Essentials on: push: branches: - '**' jobs: getVersion: uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-getversion.yml@main secrets: inherit build-4Series: uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-4Series-builds.yml@main secrets: inherit needs: getVersion if: needs.getVersion.outputs.newVersion == 'true' with: newVersion: ${{ needs.getVersion.outputs.newVersion }} version: ${{ needs.getVersion.outputs.version }} tag: ${{ needs.getVersion.outputs.tag }} channel: ${{ needs.getVersion.outputs.channel }} bypassPackageCheck: true devToolsVersion: ${{ vars.ESSENTIALSDEVTOOLSVERSION }} ================================================ FILE: .github/workflows/publish-docs.yml ================================================ name: Publish Docs # Trigger the action on push to main on: push: branches: - main # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: actions: read pages: write id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false jobs: publish-docs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Dotnet Setup uses: actions/setup-dotnet@v4 with: dotnet-version: 8.x - run: dotnet tool update -g docfx - run: docfx ./docs/docfx.json - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: # Upload entire repository path: './docs/_site' - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ================================================ FILE: .gitignore ================================================ #ignore thumbnails created by windows Thumbs.db #Ignore files build by Visual Studio *.user *.aps *.pch *.vspscc *_i.c *_p.c *.ncb *.suo *.bak *.cache *.ilk *.log [Bb]in [Dd]ebug*/ *.sbr obj/ [Rr]elease*/ _ReSharper*/ SIMPLSharpLogs/ *.projectinfo essentials-framework/EssentialDMTestConfig/ output/ packages/ PepperDashEssentials-0.0.0-buildType-test.zip ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ [Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Coverlet is a free, cross platform Code Coverage Tool coverage*.json coverage*.xml coverage*.info # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/PepperDash_Essentials_Interfaces.csproj .DS_Store /._PepperDash.Essentials.sln .vscode/settings.json _site/ api/ *.DS_Store /._PepperDash.Essentials.4Series.sln dotnet ================================================ FILE: .gitmodules ================================================ ================================================ FILE: .releaserc.json ================================================ { "plugins": [ [ "@semantic-release/commit-analyzer", { "releaseRules": [ { "scope": "force-patch", "release": "patch" }, { "scope": "no-release", "release": false } ] } ], "@semantic-release/release-notes-generator", ["@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" } ], [ "@semantic-release/exec", { "verifyReleaseCmd": "echo \"newVersion=true\" >> $GITHUB_OUTPUT", "publishCmd": "echo \"version=${nextRelease.version}\" >> $GITHUB_OUTPUT && echo \"tag=${nextRelease.gitTag}\" >> $GITHUB_OUTPUT && echo \"type=${nextRelease.type}\" >> $GITHUB_OUTPUT && echo \"channel=${nextRelease.channel}\" >> $GITHUB_OUTPUT" } ] ], "branches": [ "main", {"name": "development", "prerelease": "beta", "channel": "beta"}, {"name": "release", "prerelease": "rc", "channel": "rc"}, { "name": "replace-me-feature-branch", "prerelease": "replace-me-prerelease", "channel": "replace-me-prerelease" } ] } ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": [ "ms-dotnettools.vscode-dotnet-runtime", "ms-dotnettools.csharp", "ms-dotnettools.csdevkit", "vivaxy.vscode-conventional-commits", "mhutchie.git-graph" ] } ================================================ FILE: CONTRIBUTING.md ================================================ # Contributors Guide Essentials is an open source project. If you are interested in making it better, there are many ways you can contribute. For example, you can: - Submit a bug report - Suggest a new feature - Provide feedback by commenting on feature requests/proposals - Propose a patch by submitting a pull request - Suggest or submit documentation improvements - Review outstanding pull requests - Answer questions from other users - Share the software with other users who are interested - Teach others to use the software ## Bugs and Feature Requests If you believe that you have found a bug or wish to propose a new feature, please first search the existing [issues] to see if it has already been reported. If you are unable to find an existing issue, consider using one of the provided templates to create a new issue and provide as many details as you can to assist in reproducing the bug or explaining your proposed feature. ## Patch Submission tips Patches should be submitted in the form of Pull Requests to the Essentials [repository] on GitHub. But first, consider the following tips to ensure a smooth process when submitting a patch: - Ensure that the patch compiles and does not break any build-time tests. - Be understanding, patient, and friendly; developers may need time to review your submissions before they can take action or respond. This does not mean your contribution is not valued. If your contribution has not received a response in a reasonable time, consider commenting with a polite inquiry for an update. - Limit your patches to the smallest reasonable change to achieve your intended goal. For example, do not make unnecessary indentation changes; but don't go out of your way to make the patch so minimal that it isn't easy to read, either. Consider the reviewer's perspective. - Before submission, please squash your commits to using a message that starts with the issue number and a description of the changes. - Isolate multiple patches from each other. If you wish to make several independent patches, do so in separate, smaller pull requests that can be reviewed more easily. - Be prepared to answer questions from reviewers. They may have further questions before accepting your patch, and may even propose changes. Please accept this feedback constructively, and not as a rejection of your proposed change. ## GitFlow Branch Model This repository adheres to the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model and is intitialized for GitFlow to make for consistent branch name prefixes. Please take time to familiarize yourself with this model. - `master` will contain the latest stable version of the framework and release builds will be created from tagged commits on `master`. - HotFix/Patch Pull Requests should target `master` as the base branch. - All other Pull Requests (bug fixes, enhancements, etc.) should target `development` as the base branch. - `release/vX.Y.X` branches will be used for release candidates when moving new features from `development` to `master`. Beta builds will be created from tagged commits on release candidate branches. ## Review - We welcome code reviews from anyone. A committer is required to formally accept and merge the changes. - Reviewers will be looking for things like threading issues, performance implications, API design, duplication of existing functionality, readability and code style, avoidance of bloat (scope-creep), etc. - Reviewers will likely ask questions to better understand your change. - Reviewers will make comments about changes to your patch: - MUST means that the change is required - SHOULD means that the change is suggested, further discussion on the subject may be required - COULD means that the change is optional ## Timeline and Managing Expectations As we continue to engage contributors and learn best practices for running a successful open source project, our processes and guidance will likely evolve. We will try to communicate expectations as we are able and to always be responsive. We hope that the community will share their suggestions for improving this engagement. Based on the level of initial interest we receive and the availability of resources to evaluate contributions, we anticipate the following: - We will initially prioritize pull requests that include small bug fixes and code that addresses potential vulnerabilities as well as pull requests that include improvements for processor language specifications because these require a reasonable amount of effort to evaluate and will help us exercise and revise our process for accepting contributions. In other words, we are going to start small in order to work out the kinks first. - We are committed to maintaining the integrity and security of our code base. In addition to the careful review the maintainers will give to code contributions to make sure they do not introduce new bugs or vulnerabilities, we will be trying to identify best practices to incorporate with our open source project so that contributors can have more control over whether their contributions are accepted. These might include things like style guides and requirements for tests and documentation to accompany some code contributions. As a result, it may take a long time for some contributions to be accepted. This does not mean we are ignoring them. - We are committed to integrating this GitHub project with our team's regular development work flow so that the open source project remains dynamic and relevant. This may affect our responsiveness and ability to accept pull requests quickly. This does not mean we are ignoring them. - Not all innovative ideas need to be accepted as pull requests into this GitHub project to be valuable to the community. There may be times when we recommend that you just share your code for some enhancement to Essentials from your own repository. As we identify and recognize extensions that are of general interest to Essentials, we may seek to incorporate them with our baseline. ## Legal Consistent with Section D.6. of the GitHub Terms of Service as of 2019, and the MIT license, the project maintainer for this project accepts contributions using the inbound=outbound model. When you submit a pull request to this repository (inbound), you are agreeing to license your contribution under the same terms as specified in [LICENSE] (outbound). This is an open source project. Contributions you make to this repository are completely voluntary. When you submit an issue, bug report, question, enhancement, pull request, etc., you are offering your contribution without expectation of payment, you expressly waive any future pay claims against PepperDash related to your contribution, and you acknowledge that this does not create an obligation on the part of PepperDash of any kind. Furthermore, your contributing to this project does not create an employer-employee relationship between the PepperDash and the contributor. [issues]: https://github.com/PepperDash/Essentials/issues [repository]: https://github.com/PepperDash/Essentials [LICENSE]: https://github.com/PepperDash/Essentials/blob/master/LICENSE.md ================================================ FILE: Crestron-Library-Usage-Analysis.md ================================================ # Crestron Library Usage Analysis - PepperDash Essentials This document provides a comprehensive analysis of Crestron classes and interfaces used throughout the PepperDash Essentials framework, organized by namespace and library component. ## Executive Summary The PepperDash Essentials framework extensively leverages Crestron SDK components across 100+ files, providing abstractions for: - Control system hardware (processors, touchpanels, IO devices) - Communication interfaces (Serial, TCP/IP, SSH, CEC, IR) - Device management and routing - User interface components and smart objects - System monitoring and diagnostics ## 1. Core Crestron Libraries ### 1.1 Crestron.SimplSharp **Primary Usage**: Foundational framework components, collections, and basic types. **Key Files**: - Multiple files across all projects use `Crestron.SimplSharp` namespaces - Provides basic C# runtime support for Crestron processors ### 1.2 Crestron.SimplSharpPro **Primary Usage**: Main hardware abstraction layer for Crestron devices. **Key Classes Used**: #### CrestronControlSystem - **File**: `/src/PepperDash.Essentials/ControlSystem.cs` - **Usage**: Base class for the main control system implementation - **Implementation**: `public class ControlSystem : CrestronControlSystem, ILoadConfig` #### Device (Base Class) - **Files**: 50+ files inherit from or use this class - **Key Implementations**: - `/src/PepperDash.Core/Device.cs` - Core device abstraction - `/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs` - Extended device base - `/src/PepperDash.Essentials.Core/Room/Room.cs` - Room device implementation - `/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs` - Processor device wrapper #### BasicTriList - **Files**: 30+ files use this class extensively - **Primary Usage**: Touchpanel communication and SIMPL bridging - **Key Files**: - `/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs` - Extension methods for signal handling - `/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs` - Bridge interface - `/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs` - UI dialog implementation #### BasicTriListWithSmartObject - **Files**: Multiple touchpanel and UI files - **Usage**: Enhanced touchpanel support with smart object integration - **Key Files**: - `/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs` - Interface definitions - `/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferenceList/SubpageReferenceList.cs` ## 2. Communication Hardware ### 2.1 Serial Communication (ComPort) **Primary Class**: `ComPort` **Key Files**: - `/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs` - `/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs` **Usage Pattern**: ```csharp public class ComPortController : Device, IBasicCommunicationWithStreamDebugging public static ComPort GetComPort(EssentialsControlPropertiesConfig config) ``` **Interface Support**: `IComPorts` - Used for devices that provide multiple COM ports ### 2.2 IR Communication (IROutputPort) **Primary Class**: `IROutputPort` **Key Files**: - `/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs` - `/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs` - `/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs` **Usage Pattern**: ```csharp public class IrOutputPortController : Device IROutputPort IrPort; public IrOutputPortController(string key, IROutputPort port, string irDriverFilepath) ``` ### 2.3 CEC Communication (ICec) **Primary Interface**: `ICec` **Key Files**: - `/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs` - `/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs` **Usage Pattern**: ```csharp public class CecPortController : Device, IBasicCommunicationWithStreamDebugging public static ICec GetCecPort(ControlPropertiesConfig config) ``` ## 3. Input/Output Hardware ### 3.1 Digital Input **Primary Interface**: `IDigitalInput` **Key Files**: - `/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs` - `/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs` **Usage Pattern**: ```csharp public List Inputs { get; private set; } void AddInput(IDigitalInput input) ``` ### 3.2 Versiport Support **Key Files**: - `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs` - `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs` - `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs` **Usage**: Provides flexible I/O port configuration for various signal types ## 4. Touchpanel Hardware ### 4.1 MPC3 Touchpanel **Primary Class**: `MPC3Basic` **Key File**: `/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs` **Usage Pattern**: ```csharp public class Mpc3TouchpanelController : Device readonly MPC3Basic _touchpanel; _touchpanel = processor.ControllerTouchScreenSlotDevice as MPC3Basic; ``` ### 4.2 TSW Series Support **Evidence**: References found in messenger files and mobile control components **Usage**: Integrated through mobile control messaging system for TSW touchpanel features ## 5. Timer and Threading ### 5.1 CTimer **Primary Class**: `CTimer` **Key File**: `/src/PepperDash.Core/PasswordManagement/PasswordManager.cs` **Usage Pattern**: ```csharp Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started")); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset")); ``` ## 6. Networking and Communication ### 6.1 Ethernet Communication **Libraries Used**: - `Crestron.SimplSharpPro.EthernetCommunication` - `Crestron.SimplSharp.Net.Utilities.EthernetHelper` **Key Files**: - `/src/PepperDash.Core/Comm/GenericTcpIpClient.cs` - `/src/PepperDash.Core/Comm/GenericTcpIpServer.cs` - `/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs` - `/src/PepperDash.Core/Comm/GenericSshClient.cs` - `/src/PepperDash.Core/Comm/GenericUdpServer.cs` **Usage Pattern**: ```csharp public class GenericTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect ``` ## 7. Device Management Libraries ### 7.1 DeviceSupport **Library**: `Crestron.SimplSharpPro.DeviceSupport` **Usage**: Core device support infrastructure used throughout the framework ### 7.2 DM (DigitalMedia) **Library**: `Crestron.SimplSharpPro.DM` **Usage**: Digital media routing and switching support **Evidence**: Found in routing configuration and DM output card references ## 8. User Interface Libraries ### 8.1 UI Components **Library**: `Crestron.SimplSharpPro.UI` **Usage**: User interface elements and touchpanel controls ### 8.2 Smart Objects **Key Files**: - `/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs` - `/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferenceList/SubpageReferenceList.cs` **Usage**: Advanced UI components with dynamic content ## 9. System Monitoring and Diagnostics ### 9.1 Diagnostics **Library**: `Crestron.SimplSharpPro.Diagnostics` **Usage**: System health monitoring and performance tracking ### 9.2 System Information **Key Files**: - `/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs` **Usage**: Provides system status, Ethernet information, and program details ## 10. Integration Patterns ### 10.1 SIMPL Bridging **Pattern**: Extensive use of `BasicTriList` for SIMPL integration **Files**: Bridge classes throughout the framework implement `LinkToApi` methods: ```csharp public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); ``` ### 10.2 Device Factory Pattern **Implementation**: Factory classes create hardware-specific implementations **Example**: `CommFactory.cs` provides communication device creation ### 10.3 Extension Methods **Pattern**: Extensive use of extension methods for Crestron classes **Example**: `TriListExtensions.cs` adds 30+ extension methods to `BasicTriList` ## 11. Signal Processing ### 11.1 Signal Types **Bool Signals**: Digital control and feedback **UShort Signals**: Analog values and numeric data **String Signals**: Text and configuration data **Implementation**: Comprehensive signal handling in `TriListExtensions.cs` ## 12. Error Handling and Logging **Pattern**: Consistent use of Crestron's Debug logging throughout **Examples**: ```csharp Debug.LogMessage(LogEventLevel.Information, "Device {0} is not a valid device", dc.PortDeviceKey); Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?"); ``` ## 13. Threading and Synchronization **Components**: - CTimer for time-based operations - Thread-safe collections and patterns - Event-driven programming models ## Conclusion The PepperDash Essentials framework demonstrates sophisticated integration with the Crestron ecosystem, leveraging: - **Core Infrastructure**: CrestronControlSystem, Device base classes - **Communication**: COM, IR, CEC, TCP/IP, SSH protocols - **Hardware Abstraction**: Touchpanels, I/O devices, processors - **User Interface**: Smart objects, signal processing, SIMPL bridging - **System Services**: Monitoring, diagnostics, device management This analysis shows that Essentials serves as a comprehensive middleware layer, abstracting Crestron hardware complexities while providing modern software development patterns and practices. --- *Generated: [Current Date]* *Framework Version: PepperDash Essentials (Based on codebase analysis)* ================================================ FILE: LICENSE.md ================================================ Copyright (c) <2020> PepperDash Technology Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: PepperDash.Essentials.4Series.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.33213.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Devices.Common", "src\PepperDash.Essentials.Devices.Common\PepperDash.Essentials.Devices.Common.csproj", "{53E204B7-97DD-441D-A96C-721DF014DF82}" ProjectSection(ProjectDependencies) = postProject {E5336563-1194-501E-BC4A-79AD9283EF90} = {E5336563-1194-501E-BC4A-79AD9283EF90} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials", "src\PepperDash.Essentials\PepperDash.Essentials.csproj", "{CB3B11BA-625C-4D35-B663-FDC5BE9A230E}" ProjectSection(ProjectDependencies) = postProject {E5336563-1194-501E-BC4A-79AD9283EF90} = {E5336563-1194-501E-BC4A-79AD9283EF90} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash.Essentials.Core", "src\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj", "{3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}" ProjectSection(ProjectDependencies) = postProject {E5336563-1194-501E-BC4A-79AD9283EF90} = {E5336563-1194-501E-BC4A-79AD9283EF90} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile Control", "Mobile Control", "{B24989D7-32B5-48D5-9AE1-5F3B17D25206}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash.Essentials.MobileControl", "src\PepperDash.Essentials.MobileControl\PepperDash.Essentials.MobileControl.csproj", "{F6D362DE-2256-44B1-927A-8CE4705D839A}" ProjectSection(ProjectDependencies) = postProject {E5336563-1194-501E-BC4A-79AD9283EF90} = {E5336563-1194-501E-BC4A-79AD9283EF90} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash.Essentials.MobileControl.Messengers", "src\PepperDash.Essentials.MobileControl.Messengers\PepperDash.Essentials.MobileControl.Messengers.csproj", "{B438694F-8FF7-464A-9EC8-10427374471F}" ProjectSection(ProjectDependencies) = postProject {E5336563-1194-501E-BC4A-79AD9283EF90} = {E5336563-1194-501E-BC4A-79AD9283EF90} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Essentials", "Essentials", "{AD98B742-8D85-481C-A69D-D8D8ABED39EA}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash.Core", "src\PepperDash.Core\PepperDash.Core.csproj", "{E5336563-1194-501E-BC4A-79AD9283EF90}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug 4.7.2|Any CPU = Debug 4.7.2|Any CPU Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {53E204B7-97DD-441D-A96C-721DF014DF82}.Debug 4.7.2|Any CPU.ActiveCfg = Debug 4.7.2|Any CPU {53E204B7-97DD-441D-A96C-721DF014DF82}.Debug 4.7.2|Any CPU.Build.0 = Debug 4.7.2|Any CPU {53E204B7-97DD-441D-A96C-721DF014DF82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {53E204B7-97DD-441D-A96C-721DF014DF82}.Debug|Any CPU.Build.0 = Debug|Any CPU {53E204B7-97DD-441D-A96C-721DF014DF82}.Release|Any CPU.ActiveCfg = Release|Any CPU {53E204B7-97DD-441D-A96C-721DF014DF82}.Release|Any CPU.Build.0 = Release|Any CPU {CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Debug 4.7.2|Any CPU.ActiveCfg = Debug 4.7.2|Any CPU {CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Debug 4.7.2|Any CPU.Build.0 = Debug 4.7.2|Any CPU {CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Debug|Any CPU.Build.0 = Debug|Any CPU {CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB3B11BA-625C-4D35-B663-FDC5BE9A230E}.Release|Any CPU.Build.0 = Release|Any CPU {3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Debug 4.7.2|Any CPU.ActiveCfg = Debug 4.7.2|Any CPU {3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Debug 4.7.2|Any CPU.Build.0 = Debug 4.7.2|Any CPU {3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D192FED-8FFC-4CB5-B5F7-BA307ABA254B}.Release|Any CPU.Build.0 = Release|Any CPU {F6D362DE-2256-44B1-927A-8CE4705D839A}.Debug 4.7.2|Any CPU.ActiveCfg = Debug|Any CPU {F6D362DE-2256-44B1-927A-8CE4705D839A}.Debug 4.7.2|Any CPU.Build.0 = Debug|Any CPU {F6D362DE-2256-44B1-927A-8CE4705D839A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F6D362DE-2256-44B1-927A-8CE4705D839A}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6D362DE-2256-44B1-927A-8CE4705D839A}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6D362DE-2256-44B1-927A-8CE4705D839A}.Release|Any CPU.Build.0 = Release|Any CPU {B438694F-8FF7-464A-9EC8-10427374471F}.Debug 4.7.2|Any CPU.ActiveCfg = Debug|Any CPU {B438694F-8FF7-464A-9EC8-10427374471F}.Debug 4.7.2|Any CPU.Build.0 = Debug|Any CPU {B438694F-8FF7-464A-9EC8-10427374471F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B438694F-8FF7-464A-9EC8-10427374471F}.Debug|Any CPU.Build.0 = Debug|Any CPU {B438694F-8FF7-464A-9EC8-10427374471F}.Release|Any CPU.ActiveCfg = Release|Any CPU {B438694F-8FF7-464A-9EC8-10427374471F}.Release|Any CPU.Build.0 = Release|Any CPU {E5336563-1194-501E-BC4A-79AD9283EF90}.Debug 4.7.2|Any CPU.ActiveCfg = Debug|Any CPU {E5336563-1194-501E-BC4A-79AD9283EF90}.Debug 4.7.2|Any CPU.Build.0 = Debug|Any CPU {E5336563-1194-501E-BC4A-79AD9283EF90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5336563-1194-501E-BC4A-79AD9283EF90}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5336563-1194-501E-BC4A-79AD9283EF90}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5336563-1194-501E-BC4A-79AD9283EF90}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {53E204B7-97DD-441D-A96C-721DF014DF82} = {AD98B742-8D85-481C-A69D-D8D8ABED39EA} {CB3B11BA-625C-4D35-B663-FDC5BE9A230E} = {AD98B742-8D85-481C-A69D-D8D8ABED39EA} {3D192FED-8FFC-4CB5-B5F7-BA307ABA254B} = {AD98B742-8D85-481C-A69D-D8D8ABED39EA} {F6D362DE-2256-44B1-927A-8CE4705D839A} = {B24989D7-32B5-48D5-9AE1-5F3B17D25206} {B438694F-8FF7-464A-9EC8-10427374471F} = {B24989D7-32B5-48D5-9AE1-5F3B17D25206} {E5336563-1194-501E-BC4A-79AD9283EF90} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6907A4BF-7201-47CF-AAB1-3597F3B8E1C3} EndGlobalSection EndGlobal ================================================ FILE: README.md ================================================ # PepperDash Essentials Framework (c) 2020 ## [Latest Release](https://github.com/PepperDash/Essentials/releases/latest) ## License Provided under MIT license ## Overview PepperDash Essentials is an open source Crestron framework that can be configured as a standalone program capable of running a wide variety of system designs and can also be utilized as a plug-in architecture to augment other Simpl# Pro and Simpl Windows programs. Essentials Framework is a collection of C# / Simpl# Pro libraries that can be utilized in several different manners. It is currently operating as a 100% configuration-driven system, and can be extended to add different workflows and behaviors, either through the addition of further device "types" or via the plug-in mechanism. The framework is a collection of "things" that are all related and interconnected, but in general do not have dependencies on each other. ## Minimum Requirements - Essentials Framework runs on any Crestron 3-series processor, **4-series** processor or Crestron's VC-4 platform. - To edit and compile the source, Microsoft Visual Studio 2008 Professional with SP1 is required. - Crestron's Simpl# Plugin is also required (must be obtained from Crestron). ## Dependencies The [PepperDash.Core](https://github.com/PepperDash/PepperDashCore) SIMPL# library is required. It is referenced via nuget. You must have nuget.exe installed and in the `PATH` environment variable to use the following command. Nuget.exe is available at [nuget.org](https://dist.nuget.org/win-x86-commandline/latest/nuget.exe). ### Installing Dependencies To install dependencies once nuget.exe is installed, run the following command: `nuget install .\packages.config -OutputDirectory .\packages -excludeVersion`. To verify that the packages installed correctly, open Essentials and make sure that all references are found, then try and build it. ### Installing Different versions of PepperDash Core If you need a different version of PepperDash Core, use the command `nuget install .\packages.config -OutputDirectory .\packages -excludeVersion -Version {versionToGet}`. Omitting the `-Version` option will pull the version indicated in the packages.config file. ## Utilization Essentials was originally conceptualized as a standalone application for running control system logic entirely in Simpl# Pro. It is primarily designed around accomplishing this goal, but during development, it became obvious that it could easily be leveraged to also serve as a partner application to one or more SIMPL Windows programs. Utilization of Essentials Framework falls into the following categories: 1. Standalone Control System Application for controlling one or more rooms. See [Standalone Use](https://github.com/PepperDash/Essentials/wiki/Standalone-Use#standalone-application) 2. Partner Application to a SIMPL Windows program. This allows for several useful advantages. See [SIMPL Windows Bridging](https://github.com/PepperDash/Essentials/wiki/SIMPL-Bridging#simpl-windows-bridging) - Dynamic device instantiation. Devices can be defined in configuration and instantiated at runtime and then bridged to a SIMPL Windows program via EISC. - Advanced logic. Some logic operations that cannot be affectively accomplished in SIMPL Windows (ex. JSON/XML serialization/deserialization, database operations, etc.) can be done in the Simpl# Pro environment and the necessary input and output bridged to a SIMPL Windows program via EISC. 3. Hybrid Application that may contain elements of both standalone control and SIMPL partner application integration. - There may be a use case where a device can only be defined in a single application, but that device may need to be interacted with from multiple applications. The device can be defined in an Essentials application, interacted with in that application and also bridged to one or more SIMPL Windows applications. ## Documentation For detailed documentation, see the [Wiki](https://github.com/PepperDash/EssentialsFramework/wiki). ## Support * Check out our [Discord Server](https://discord.gg/rWyeRH3K) ## How-To (Getting Started) See [Getting Started](https://github.com/PepperDash/Essentials/wiki/Get-started#how-to-get-started) ================================================ FILE: Sample Presets/SampleDirecTV.json ================================================ { "name": "Sample DirecTV List", "channels": [ { "name": "HBO", "IconUrl": "HBO", "Channel": "501" }, { "name": "HBO", "IconUrl": "HBO", "Channel": "501" }, { "name": "HBO", "IconUrl": "HBO", "Channel": "501" }, { "name": "HBO", "IconUrl": "HBO", "Channel": "501" }, { "name": "HBO", "IconUrl": "HBO", "Channel": "501" }, { "name": "HBO", "IconUrl": "HBO", "Channel": "501" } ] } ================================================ FILE: docs/docfx.json ================================================ { "$schema": "https://raw.githubusercontent.com/dotnet/docfx/main/schemas/docfx.schema.json", "metadata": [ { "src": [ { "src": "../", "files": [ "src/**/*.csproj" ] } ], "properties": { "TargetFramework": "net472" }, "dest": "api", "namespaceLayout": "nested", "outputFormat": "apiPage" } ], "build": { "content": [ { "files": [ "docs/**/*.{md,yml}", "api/**/*.{md,yml}", "index.md", "toc.yml" ], "exclude": [ "_site/**", ".github/**" ] } ], "resource": [ { "files": [ "docs/images/**" ] } ], "output": "_site", "template": [ "default", "modern" ], "globalMetadata": { "_appName": "PepperDash Essentials", "_appTitle": "PepperDash Essentials", "_enableSearch": true, "_appLogoPath": "docs/images/favicon-32x32.png", "_appFaviconPath": "docs/images/favicon.ico", "_disableToc": false, "_enableNewTab": true, "pdf": false } } } ================================================ FILE: docs/docs/CardFrame.md ================================================ { "key": "cardCage1", "uid": 1, "name": "Internal Card Cage", "type": "internalcardcage", "group": "cardCage", "properties": { "cards": { "1": "c3com3", "2": "c3com3", "3": "" } } }, ================================================ FILE: docs/docs/Get-started.md ================================================ # Get started --- [YouTube Video - Getting Started with PepperDash Essentials](https://youtu.be/FxEZtbpCwiQ) *** ## Get a CPZ ### Prerequisites * [VS Code](https://code.visualstudio.com/) * [.NET 9 SDK](https://dotnet.microsoft.com/en-us/download) * [Git](https://git-scm.com/) > Note: Essentials 2.x.x uses .NET Framework 4.7.2 currently. The .NET 9 SDK will build the project with the appropriate references ### Build From Source 1. Clone the repo: `git clone https://github.com/PepperDash/Essentials.git` 2. Open the folder in VS Code 3. Build using the dotnet CLI: `dotnet build` ### Download the latest release The latest release can be found on [Github](https://github.com/PepperDash/Essentials/releases/latest) ## How to Get Started 2. Using an SFTP client or Crestron Toolbox, load the downloaded (or built) cpz to the processor in program slot 1 1. If using SFTP, connect via SSH and start the program by sending console command `progload -p:1` 3. On first boot, the Essentials Application will build the necessary configuration folder structure in the user/program1/ path. 4. The application has some example configuration files included. Copy `/Program01/Example Configuration/EssentialsSpaceHuddleRoom/configurationFile-HuddleSpace-2-Source.json` to the `/User/Program1/` folder. 6. Reset the program via console `progreset -p:1`. The program will load the example configuration file. Once Essentials is running with a valid configuration, the following console commands can be used to see what's going on: * ```devlist:1``` * Print the list of devices in [{key}] {name} format * The key of a device can be used with the rest of the commands to get more information * `devprops:1 {deviceKey}` * Print the real-time property values of the device with key "display-1". * `devmethods:1 display-1` * Print the public methods available for the device with key "display-1". * `devjson:1 {"deviceKey":"display-1","methodName":"PowerOn", "params": []}` * Call the method `PowerOn()` on the device with key "display-1". Next: [Standalone use](~/docs/usage/Standalone-Use.md) ================================================ FILE: docs/docs/Home.md ================================================ # Welcome to PepperDash Essentials! PepperDash Essentials is an open-source framework for control systems, built on Crestron's Simpl# Pro framework. It can be configured as a standalone program capable of running a wide variety of system designs and can also be used to augment other Crestron programs. Essentials is a collection of C# libraries that can be used in many ways. It is a 100% configuration-driven framework that can be extended to add different workflows and behaviors, either through the addition of new device-types and classes, or via a plug-in mechanism. The framework is a collection of things that are all related and interconnected, but in general do not have strong dependencies on each other. --- ## Get started - [Download essentials build or clone repo](~/docs/Get-started.md) - [How to get started](~/docs/Get-started.md) - [YouTube Video Series Playlist](https://youtube.com/playlist?list=PLKOoNNwgPFZdV5wDEBDZxTHu1KROspaBu) - [Discord Server](https://discord.gg/6Vh3ssDdPs) Or use the links to the right to navigate our documentation. --- ## Benefits - Runs on Crestron 3-Series, **4-Series** and VC-4 Control System platforms - Reduced hardware overhead compared to S+ and Simpl solutions - Quick development cycle - Shared resources made easily available - More flexibility with less code - Configurable using simple JSON files - Is awesome --- ## Comment The Essentials wiki is clearly in-progress right now. Take a look at the links to the right. We are actively working on this documentation, so please be patient with us. If you have any comments on or suggestions for the documentation, please file an issue here, with as much detail as you can provide: Thanks! --- ## Collaboration Essentials is an open-source project and we encourage collaboration on this community project. For features that may not be useful to the greater community, or for just-plain learning, we want to remind developers to try writing plugins for Essentials. More information can be found here: [Plugins](~/docs/technical-docs/Plugins.md) ### Open-source-collaborative workflow The `main` branch always contain the latest stable version. The `development` branch is used for most development efforts. [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) will be used as the workflow for this collaborative project. To contribute, follow this process: 1. Fork this repository ([More Info](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks)) 2. Create a branch using standard GitFlow branch prefixes (feature/hotfix) followed by a descriptive name. - Example: `feature/add-awesomeness` or `hotfix/really-big-oops` - When working on a new feature or bugfix, branch from the `development` branch. When working on a hotfix, branch from `main`. 3. Make commits as necessary (often is better). And use concise, descriptive language, leveraging issue notation and/or [Closing Keywords](https://help.github.com/articles/closing-issues-using-keywords) to ensure any issues addressed by your work are referenced accordingly. 4. When the scope of the work for your branch is complete, make sure to rebase your branch in case further progress has been made since the repo was forked 5. Create a Pull Request to pull your branch into the appropriate branch in the main repository. 6. Your Pull Request will be reviewed by our team and evaluated for inclusion into the main repository. Next: [Get started](~/docs/Get-started.md) ================================================ FILE: docs/docs/Plugins-Deprecated.md ================================================ # Deprecated **Note : this entry is out of date - please see [Plugins](~/docs/technical-docs/Plugins.md)** ## What are Essentials Plugins? Plugins are SIMPL# Pro libraries that reference the Essentials Framework and can be loaded into an Essentials Application at runtime to extend functionality beyond what the Essentials Framework provides on its own. ## Why Use Plugins? Plugins are a way to extend or add new functionality to the Essentials Application without having to modify the actual Framework. In most cases, a plugin can be written to support a new device or behavior. Using plugins also limits the scope of understanding needed to work within the Essentials Framework. ## Should I use a Plugin? Essentials is meant to be a lightweight framework and an extensible basis for development. While some devices are included in the framework, mostly for the purposes of providing examples and developing and prototyping new device types, the bulk of new development is intended to take place in Plugins. Once a plugin adds new functionality that may be of benefit if shared across multiple plugins, it may make sense to port that common logic (base classes and/or interfaces) back into the framework to make it available to others. The thrust of future Essentials development is targeted towards building a library of plugins. ## How do Plugins Work? One or more plugins can be loaded to the /user/ProgramX/plugins as .dlls or .cplz packages. When the Essentials Application starts, it looks for any .cplz files, unzips them and then iterates any .dll assemblies in that folder and loads them. Once the plugin assemblies are loaded the Essentials Application will then attempt to load a configuration file and construct items as defined in the file. Those items can be defined in either the Essentials Framework or in any of the loaded plugin assemblies. ![Architecture drawing](~/docs/images/Plugin%20Load%20Sequence.png) ## What Must be Implemented in a Plugin for it to Work? All plugin assemblies must contain a static method called LoadPlugin(): ```cs public class SomeDevice : Device , IBridge //IBridge only needs to be implemented if using a bridge { // This string is used to define the minimum version of the // Essentials Framework required for this plugin public static string MinimumEssentialsFrameworkVersion = "1.4.23"; // This method gets called by the Essentials Framework when the application starts. // It is intended to be used to load the new Device type(s) specified in the plugin public static void LoadPlugin() { DeviceFactory.AddFactoryForType("typeName", FactoryMethod); // typeName should be the unique string that identifies the type of device to build, // FactoryMethod represents the method that takes a DevicConfig object as and argument // and returns an instance of the desired device type } // This is a factory method to construct a device and return it to be // added to the DeviceManager public static Device FactoryMethod(DeviceConfig dc) { return new SomeDevice(dc.key, dc.name, dc); } #region IBridge // This method is called by an EiscApi bridge instance and should call an extension method // defined in your plugin. Required for implementing IBridge public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey) { this.LinkToApiExt(trilist, joinStart, joinMapKey); } #endregion } ``` ## SIMPL Bridging Optionally, if your plugin device needs to be able to bridge to a SIMPL program over EISC, and there isn't already an existing bridge class in the Essentials Framework, you can write a new bridge class in your plugin. However, in order for the Essentials Application to be able to us that new bridge, the bridge must implement the IBridge interface with the required LinkToApi() Extension method. Often though, you may find that a bridge class already exists in the Essentials Framework that you can leverage. For example, if you were writing a plugin to support a new display model that isn't already in the Essentials Framework, you would define a class in your plugin that inherits from PepperDash.Essentials.Core.DisplayBase. If you're only implementing the standard display control functions such as power/input/volume control, then the existing bridge class `DisplayControllerBridge` can be used. If you needed to add additional functions to the bridge, then you would need to write your own bridge in the plugin. For additional info see the [SIMPL-Bridging article](~/docs/SIMPL-Bridging.md). ## Template Essentials Plugin Repository Fork this repository when starting a new plugin. The template repository uses the essentials-builds repository as a submodule. This allows the plugin to reference a specific build version of Essentials. You must make sure that you checkout the correct build of the Essentials-Builds repo that contains any dependencies that your plugin may rely on. [Essentials Plugin Template Repository](https://github.com/PepperDash/EssentialsPluginTemplate) ================================================ FILE: docs/docs/SIMPL-Bridging-Deprecated.md ================================================ # Deprecated **Note : this entry is out of date - please see [SIMPL Windows Bridging](~/docs/SIMPL-Bridging.md)** ## SIMPL Windows Bridging - Deprecated Essentials allows for devices defined within the SIMPL# Pro application to be bridged to a SIMPL Windows application over Ethernet Intersystem Communication (EISC). This allows a SIMPL Windows program to take advantage of some of the features of the SIMPL# Pro environment, without requiring the entire application to be written in C#. Some of the main advantages are: 1. The ability to instantiate devices from configuration. 1. The ability to leverage C# concepts to handle data intensive tasks (Serialization/Deserialization of JSON/XML, cyrptography, etc.). 1. The ability to reuse the same compiled SIMPL Windows program (regardless of target processor type) by offloading all the variables that may be room or hardware specific to Essentials. 1. The ability to handle multiple communciation types generically without changing the SIMPL Program (TCP/UDP/SSH/HTTP/HTTPS/CEC, etc.) 1. Much faster development cycle 1. Reduced processor overhead 1. Ability to easily share devices defined in Essentials between multiple other programs ## Implementation Bridges are devices that are defined within the devices array in the config file. They are unique devices with a specialized purpose; to act as a bridge between Essentials Devices and applications programmed traditionally in Simpl Windows. This is accomplished by instantiating a Three Series Intersystem Communication symbol within the bridge device, and linking its Boolean/Ushort/String inputs and outputs to actions on one or multiple Essentials device(s). The definition for which joins map to which actions is defined within the device to be bridged to in a class that derives from JoinMapBase. Let's consider the following Essentials Configuration: ```JSON { "template": { "roomInfo": [ {} ], "devices": [ { "key": "processor", "uid": 1, "type": "pro3", "name": "PRO3 w/o cards", "group": "processor", "supportedConfigModes": [ "essentials" ], "supportedSystemTypes": [ "hudType", "presType", "vtcType", "custom" ], "supportsCompliance": true, "properties": { "numberOfComPorts": 6, "numberOfIrPorts": 8, "numberOfRelays": 8, "numberOfDIOPorts": 8 } }, { "key": "panasonicDisplay01", "type": "PanasonicThefDisplay", "name": "Main Display", "group": "displays", "uid": 2, "properties": { "id": "01", "inputNumber": 1, "outputNumber": 1, "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 9600, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "controlPortDevKey": "processor", "method": "com" } } }, { "key": "vtcComPort", "uid": 3, "name": "VTC Coms", "group": "comm", "type": "genericComm", "properties": { "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 38400, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 2, "controlPortDevKey": "processor", "method": "com" } } }, { "key": "deviceBridge", "uid": 4, "name": "BridgeToDevices", "group": "api", "type": "eiscApi", "properties": { "control": { "tcpSshProperties": { "address": "127.0.0.2", "port": 0 }, "ipid": "03", "method": "ipidTcp" }, "devices": [ { "deviceKey": "panasonicDisplay01", "joinStart": 1 }, { "deviceKey": "vtcComPort", "joinStart": 51 } ] } } ] } } ``` We have four Essentials Devices configured: 1. Pro3 with a Key of "processor" 1. Panasonic Display with a Key of "panasonicDisplay01" 1. Com port with a Key of "vtcComPort" 1. Bridge with a Key of "deviceBridge" We want to have access to the com port for VTC Control from Simpl Windows and we want to control the display from Simpl Windows. To accomplish this, we have created a bridge device and added the devices to be bridged to the "devices" array on the bridge. As you can see we define the device key and the join start, which will determine which joins we will use on the resulting EISC to interact with the devices. In the Bridge control properties we defined ipid 03, and we will need a corresponding Ethernet System Intercommunication in the Simpl Windows program at ipid 03. Now that our devices have been built, we can refer to the device join maps to see which joins correspond to which actions. See below: ```cs namespace PepperDash.Essentials.Bridges { public class DisplayControllerJoinMap : JoinMapBase { #region Digitals /// /// Turns the display off and reports power off feedback /// public uint PowerOff { get; set; } /// /// Turns the display on and repots power on feedback /// public uint PowerOn { get; set; } /// /// Indicates that the display device supports two way communication when high /// public uint IsTwoWayDisplay { get; set; } /// /// Increments the volume while high /// public uint VolumeUp { get; set; } /// /// Decrements teh volume while high /// public uint VolumeDown { get; set; } /// /// Toggles the mute state. Feedback is high when volume is muted /// public uint VolumeMute { get; set; } /// /// Range of digital joins to select inputs and report current input as feedback /// public uint InputSelectOffset { get; set; } /// /// Range of digital joins to report visibility for input buttons /// public uint ButtonVisibilityOffset { get; set; } /// /// High if the device is online /// public uint IsOnline { get; set; } #endregion #region Analogs /// /// Analog join to set the input and report current input as feedback /// public uint InputSelect { get; set; } /// /// Sets the volume level and reports the current level as feedback /// public uint VolumeLevel { get; set; } #endregion #region Serials /// /// Reports the name of the display as defined in config as feedback /// public uint Name { get; set; } /// /// Range of serial joins that reports the names of the inputs as feedback /// public uint InputNamesOffset { get; set; } #endregion public DisplayControllerJoinMap() { // Digital IsOnline = 50; PowerOff = 1; PowerOn = 2; IsTwoWayDisplay = 3; VolumeUp = 5; VolumeDown = 6; VolumeMute = 7; ButtonVisibilityOffset = 40; InputSelectOffset = 10; // Analog InputSelect = 11; VolumeLevel = 5; // Serial Name = 1; InputNamesOffset = 10; } public override void OffsetJoinNumbers(uint joinStart) { var joinOffset = joinStart - 1; IsOnline = IsOnline + joinOffset; PowerOff = PowerOff + joinOffset; PowerOn = PowerOn + joinOffset; IsTwoWayDisplay = IsTwoWayDisplay + joinOffset; ButtonVisibilityOffset = ButtonVisibilityOffset + joinOffset; Name = Name + joinOffset; InputNamesOffset = InputNamesOffset + joinOffset; InputSelectOffset = InputSelectOffset + joinOffset; InputSelect = InputSelect + joinOffset; VolumeUp = VolumeUp + joinOffset; VolumeDown = VolumeDown + joinOffset; VolumeMute = VolumeMute + joinOffset; VolumeLevel = VolumeLevel + joinOffset; } } } ``` We know that the Panasonic Display uses the DisplayControllerJoinMap class and can see the join numbers that will give us access to functionality in the Device. IsOnline = 50 PowerOff = 1 PowerOn = 2 IsTwoWayDisplay = 3 VolumeUp = 5 VolumeDown = 6 VolumeMute = 7 ```cs namespace PepperDash.Essentials.Bridges { public class IBasicCommunicationJoinMap : JoinMapBase { #region Digitals /// /// Set High to connect, Low to disconnect /// public uint Connect { get; set; } /// /// Reports Connected State (High = Connected) /// public uint Connected { get; set; } #endregion #region Analogs /// /// Reports the connections status value /// public uint Status { get; set; } #endregion #region Serials /// /// Data back from port /// public uint TextReceived { get; set; } /// /// Sends data to the port /// public uint SendText { get; set; } /// /// Takes a JSON serialized string that sets a COM port's parameters /// public uint SetPortConfig { get; set; } #endregion public IBasicCommunicationJoinMap() { TextReceived = 1; SendText = 1; SetPortConfig = 2; Connect = 1; Connected = 1; Status = 1; } public override void OffsetJoinNumbers(uint joinStart) { var joinOffset = joinStart - 1; TextReceived = TextReceived + joinOffset; SendText = SendText + joinOffset; SetPortConfig = SetPortConfig + joinOffset; Connect = Connect + joinOffset; Connected = Connected + joinOffset; Status = Status + joinOffset; } } } ``` TextReceived = 1 SendText = 1 SetPortConfig = 2 Connect = 1 Connected = 1 Status = 1 Considering our Bridge config, we can see that the display controls will start at join 1, and the VTC Com port will start at join 51. The result is a single EISC that allows us to interact with our Essentials devices. To control diplay power from Simpl Windows, we would connect Digital Signals to joins 1 & 2 on the EISC to control Display Power On & Off. To utilize the com port device, we would connect Serial Signals (VTC_TX$ and VTC_RX$) to join 51 on the EISC. You can refer to our [Simpl Windows Bridging Example](https://github.com/PepperDash/EssentialsSIMPLWindowsBridgeExample) for a more complex example. Example device config: ## Notes 1. It is important to realize that there are no safety checks (yet) when assigning joinStarts in bridge configurations. If you were to put two devices on a bridge with overlapping joins, the most recently bridged join would overwrite previously bridged joins. For now it is on the programmer to ensure there are no conflicting join maps. 1. There is _no_ limit to the amount of times a device may be bridged to. You may have the same device on multiple bridges across multiple applications without problem. That being said, we recommend using common sense. Accessing a single com port for VTC control via multiple bridges may not be wise... 1. A bridge need not only bridge between applications on the same processor. A bridge may bridge to an application on a completely separate processor; simply define the ip address in the Bridge control properties accordingly. 1. For devices included in Essentials, you will be able to find defined join maps below. If you are building your own plugins, you will need to build the join map yourself. It would be beneficial to review the wiki entry on the [Feedback Class](~/docs/technical-docs/Feedback-Classes.md) for this. 1. When building plugins, we highly recommend reusing JoinMaps, as this will make code more easily interchangeable. For example; if you were to build a display plugin, we'd recommend you use/extend the existing DisplayControllerJoinMap. This way, you can swap plugins without needing any change on the Simpl Windows side. This is extremely powerful when maintaining Simpl Windows code bases for large deployments that may utilize differing equipment per room. If you can build a Simpl Windows program that interacts with established join maps, you can swap out the device via config without any change needed to Simpl Windows. 1. Related to item 5, you can use the same paradigm with respect to physical device communication. If you were to have a DSP device in some rooms communicating over RS232 and some via SSH, it would be trival to swap the device from a Com port to an SSH client in the Essentials Devicee Config and update the Bridge Config to brigde to the desired communication method. Again this would require no change on the Simpl Windows side as long as you maintain the same join Start in the Bridge Device Configuration. ## Common Use Cases 1. There are 10 conference rooms that all operate the same, but have hardware differences that are impossible to account for in SIMPL Windows. For example, each room might have a DM-MD8X8 chassis, but the input and output cards aren't all in the same order, or they might be different models but function the same. You can use Essentials with a unique configuration file for each hardware configuration. 1. You have a floor of conference rooms that all share some centralized hardware like DSP, AV Routing and a shared CEN-GWEXER gateway with multiple GLS-OIR-CSM-EX-BATT occupancy sensors. All the shared hardware can be defined in the Essentials configuration and bridged over an EISC to each program that needs access. The same device can even be exposed to multiple programs over different EISCs. 1. You have a SIMPL program that works for many room types, but because some rooms have different models of processors than others (CP3/CP3N/AV3/PRO3/DMPS3 variants), you have to maintain several versions of the program, compiled for each processor model to maintain access to features like the System Monitor slot. You can use Essentials running in a slot on a processor to expose the System Monitor and many other features of the processor, regardless of model. Now you only need to maintain a single SIMPL program defined for your most complex processor application (ex. PRO3) ## Device Type Join Maps ### AirMediaController > supports: AM-200, AM-300 ### AppleTvController > supports: IR control of Apple TV ### CameraControlBase > supports: any camera that derives from CameraBase ### DisplayController > supports: IR controlled displays, any two way display driver that derives from PepperDash.Essentials.Core.DisplayBase ### DmChasisController > supports: All DM-MD-8x8/16x16/32x32 chassis, with or w/o DM-CPU3 Card ### DmRmcController > supports: All DM-RMC devices ### DmTxController > supports: All Dm-Tx devices ### DmpsAudioOutputController > supports: Program, Aux1, Aux2 outputs of all DMPS3 Control Systems ### DmpsRoutingController > supports: Av routing for all DMPS3 Control Systems ### GenericRelayController > supports: Any relay port on a Crestron Control System or Dm Endpoint ### GenericLightingJoinMap > supports: Devices derived from PepperDash.Essentials.Core.Lighting.LightingBase ### GlsOccupancySensorBase > supports: Any Crestron GLS-Type Occupancy sensor - single/dual type ### HdMdxxxCEController > supports: HD-MD-400-C-E, HD-MD-300-C-E, HD-MD-200-C-E, HD-MD-200-C-1G-E-B/W ### IBasicCommunication > supports: Any COM Port on a Control System or Dm Endpoint device, TCP Client, SSH Client, or UDP Server ### IDigitalInput > supports: Any Digital Input on a Control System, or DM Endpoint device ### SystemMonitorController > supports: Exposing the system monitor slot for any Control System ## Example SIMPL Windows Program We've provided an [example program](https://github.com/PepperDash/EssentialsSIMPLWindowsBridgeExample) for SIMPL Windows that works with the provided example Essentials configuration file [SIMPLBridgeExample_configurationFile.json](https://github.com/PepperDash/Essentials/blob/main/PepperDashEssentials/Example%20Configuration/SIMPLBridging/SIMPLBridgeExample_configurationFile.json). Load Essentials and the example SIMPL program to two slots on the same processor and you can get a better idea of how to take advantage of SIMPL Windows bridging. Next: [Essentials architecture](~/docs/technical-docs/Arch-summary.md) ================================================ FILE: docs/docs/SIMPL-Bridging.md ================================================ # SIMPL Windows Bridging **Note : this entry is out of date - please see [SIMPL Windows Bridging - Updated](~/docs/usage/SIMPL-Bridging-Updated.md)** Essentials allows for devices defined within the SIMPL# Pro application to be bridged to a SIMPL Windows application over Ethernet Intersystem Communication (EISC). This allows a SIMPL Windows program to take advantage of some of the features of the SIMPL# Pro environment, without requiring the entire application to be written in C#. Some of the main advantages are: 1. The ability to instantiate devices from configuration. 1. The ability to leverage C# concepts to handle data intensive tasks (Serialization/Deserialization of JSON/XML, cyrptography, etc.). 1. The ability to reuse the same compiled SIMPL Windows program (regardless of target processor type) by offloading all the variables that may be room or hardware specific to Essentials. 1. The ability to handle multiple communciation types generically without changing the SIMPL Program (TCP/UDP/SSH/HTTP/HTTPS/CEC, etc.) 1. Much faster development cycle 1. Reduced processor overhead 1. Ability to easily share devices defined in Essentials between multiple other programs ## Implementation Bridges are devices that are defined within the devices array in the config file. They are unique devices with a specialized purpose; to act as a bridge between Essentials Devices and applications programmed traditionally in Simpl Windows. This is accomplished by instantiating a Three Series Intersystem Communication symbol within the bridge device, and linking its Boolean/Ushort/String inputs and outputs to actions on one or multiple Essentials device(s). The definition for which joins map to which actions is defined within the device to be bridged to in a class that derives from JoinMapBase. Let's consider the following Essentials Configuration: ```JSON { "template": { "roomInfo": [ {} ], "devices": [ { "key": "processor", "uid": 1, "type": "pro3", "name": "PRO3 w/o cards", "group": "processor", "supportedConfigModes": [ "essentials" ], "supportedSystemTypes": [ "hudType", "presType", "vtcType", "custom" ], "supportsCompliance": true, "properties": { "numberOfComPorts": 6, "numberOfIrPorts": 8, "numberOfRelays": 8, "numberOfDIOPorts": 8 } }, { "key": "panasonicDisplay01", "type": "PanasonicThefDisplay", "name": "Main Display", "group": "displays", "uid": 2, "properties": { "id": "01", "inputNumber": 1, "outputNumber": 1, "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 9600, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "controlPortDevKey": "processor", "method": "com" } } }, { "key": "vtcComPort", "uid": 3, "name": "VTC Coms", "group": "comm", "type": "genericComm", "properties": { "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 38400, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 2, "controlPortDevKey": "processor", "method": "com" } } }, { "key": "deviceBridge", "uid": 4, "name": "BridgeToDevices", "group": "api", "type": "eiscApi", "properties": { "control": { "tcpSshProperties": { "address": "127.0.0.2", "port": 0 }, "ipid": "03", "method": "ipidTcp" }, "devices": [ { "deviceKey": "panasonicDisplay01", "joinStart": 1 }, { "deviceKey": "vtcComPort", "joinStart": 51 } ] } } ] } } ``` We have four Essentials Devices configured: 1. Pro3 with a Key of "processor" 1. Panasonic Display with a Key of "panasonicDisplay01" 1. Com port with a Key of "vtcComPort" 1. Bridge with a Key of "deviceBridge" We want to have access to the com port for VTC Control from Simpl Windows and we want to control the display from Simpl Windows. To accomplish this, we have created a bridge device and added the devices to be bridged to the "devices" array on the bridge. As you can see we define the device key and the join start, which will determine which joins we will use on the resulting EISC to interact with the devices. In the Bridge control properties we defined ipid 03, and we will need a corresponding Ethernet System Intercommunication in the Simpl Windows program at ipid 03. Now that our devices have been built, we can refer to the device join maps to see which joins correspond to which actions. See below: ```cs namespace PepperDash.Essentials.Bridges { public class DisplayControllerJoinMap : JoinMapBase { #region Digitals /// /// Turns the display off and reports power off feedback /// public uint PowerOff { get; set; } /// /// Turns the display on and repots power on feedback /// public uint PowerOn { get; set; } /// /// Indicates that the display device supports two way communication when high /// public uint IsTwoWayDisplay { get; set; } /// /// Increments the volume while high /// public uint VolumeUp { get; set; } /// /// Decrements teh volume while high /// public uint VolumeDown { get; set; } /// /// Toggles the mute state. Feedback is high when volume is muted /// public uint VolumeMute { get; set; } /// /// Range of digital joins to select inputs and report current input as feedback /// public uint InputSelectOffset { get; set; } /// /// Range of digital joins to report visibility for input buttons /// public uint ButtonVisibilityOffset { get; set; } /// /// High if the device is online /// public uint IsOnline { get; set; } #endregion #region Analogs /// /// Analog join to set the input and report current input as feedback /// public uint InputSelect { get; set; } /// /// Sets the volume level and reports the current level as feedback /// public uint VolumeLevel { get; set; } #endregion #region Serials /// /// Reports the name of the display as defined in config as feedback /// public uint Name { get; set; } /// /// Range of serial joins that reports the names of the inputs as feedback /// public uint InputNamesOffset { get; set; } #endregion public DisplayControllerJoinMap() { // Digital IsOnline = 50; PowerOff = 1; PowerOn = 2; IsTwoWayDisplay = 3; VolumeUp = 5; VolumeDown = 6; VolumeMute = 7; ButtonVisibilityOffset = 40; InputSelectOffset = 10; // Analog InputSelect = 11; VolumeLevel = 5; // Serial Name = 1; InputNamesOffset = 10; } public override void OffsetJoinNumbers(uint joinStart) { var joinOffset = joinStart - 1; IsOnline = IsOnline + joinOffset; PowerOff = PowerOff + joinOffset; PowerOn = PowerOn + joinOffset; IsTwoWayDisplay = IsTwoWayDisplay + joinOffset; ButtonVisibilityOffset = ButtonVisibilityOffset + joinOffset; Name = Name + joinOffset; InputNamesOffset = InputNamesOffset + joinOffset; InputSelectOffset = InputSelectOffset + joinOffset; InputSelect = InputSelect + joinOffset; VolumeUp = VolumeUp + joinOffset; VolumeDown = VolumeDown + joinOffset; VolumeMute = VolumeMute + joinOffset; VolumeLevel = VolumeLevel + joinOffset; } } } ``` We know that the Panasonic Display uses the DisplayControllerJoinMap class and can see the join numbers that will give us access to functionality in the Device. IsOnline = 50 PowerOff = 1 PowerOn = 2 IsTwoWayDisplay = 3 VolumeUp = 5 VolumeDown = 6 VolumeMute = 7 ```cs namespace PepperDash.Essentials.Bridges { public class IBasicCommunicationJoinMap : JoinMapBase { #region Digitals /// /// Set High to connect, Low to disconnect /// public uint Connect { get; set; } /// /// Reports Connected State (High = Connected) /// public uint Connected { get; set; } #endregion #region Analogs /// /// Reports the connections status value /// public uint Status { get; set; } #endregion #region Serials /// /// Data back from port /// public uint TextReceived { get; set; } /// /// Sends data to the port /// public uint SendText { get; set; } /// /// Takes a JSON serialized string that sets a COM port's parameters /// public uint SetPortConfig { get; set; } #endregion public IBasicCommunicationJoinMap() { TextReceived = 1; SendText = 1; SetPortConfig = 2; Connect = 1; Connected = 1; Status = 1; } public override void OffsetJoinNumbers(uint joinStart) { var joinOffset = joinStart - 1; TextReceived = TextReceived + joinOffset; SendText = SendText + joinOffset; SetPortConfig = SetPortConfig + joinOffset; Connect = Connect + joinOffset; Connected = Connected + joinOffset; Status = Status + joinOffset; } } } ``` TextReceived = 1 SendText = 1 SetPortConfig = 2 Connect = 1 Connected = 1 Status = 1 Considering our Bridge config, we can see that the display controls will start at join 1, and the VTC Com port will start at join 51. The result is a single EISC that allows us to interact with our Essentials devices. To control diplay power from Simpl Windows, we would connect Digital Signals to joins 1 & 2 on the EISC to control Display Power On & Off. To utilize the com port device, we would connect Serial Signals (VTC_TX$ and VTC_RX$) to join 51 on the EISC. You can refer to our [Simpl Windows Bridging Example](https://github.com/PepperDash/EssentialsSIMPLWindowsBridgeExample) for a more complex example. Example device config: ## Notes 1. It is important to realize that there are no safety checks (yet) when assigning joinStarts in bridge configurations. If you were to put two devices on a bridge with overlapping joins, the most recently bridged join would overwrite previously bridged joins. For now it is on the programmer to ensure there are no conflicting join maps. 1. There is _no_ limit to the amount of times a device may be bridged to. You may have the same device on multiple bridges across multiple applications without problem. That being said, we recommend using common sense. Accessing a single com port for VTC control via multiple bridges may not be wise... 1. A bridge need not only bridge between applications on the same processor. A bridge may bridge to an application on a completely separate processor; simply define the ip address in the Bridge control properties accordingly. 1. For devices included in Essentials, you will be able to find defined join maps below. If you are building your own plugins, you will need to build the join map yourself. It would be beneficial to review the wiki entry on the [Feedback Class](~/docs/technical-docs/Feedback-Classes.md) for this. 1. When building plugins, we highly recommend reusing JoinMaps, as this will make code more easily interchangeable. For example; if you were to build a display plugin, we'd recommend you use/extend the existing DisplayControllerJoinMap. This way, you can swap plugins without needing any change on the Simpl Windows side. This is extremely powerful when maintaining Simpl Windows code bases for large deployments that may utilize differing equipment per room. If you can build a Simpl Windows program that interacts with established join maps, you can swap out the device via config without any change needed to Simpl Windows. 1. Related to item 5, you can use the same paradigm with respect to physical device communication. If you were to have a DSP device in some rooms communicating over RS232 and some via SSH, it would be trival to swap the device from a Com port to an SSH client in the Essentials Devicee Config and update the Bridge Config to brigde to the desired communication method. Again this would require no change on the Simpl Windows side as long as you maintain the same join Start in the Bridge Device Configuration. ## Common Use Cases 1. There are 10 conference rooms that all operate the same, but have hardware differences that are impossible to account for in SIMPL Windows. For example, each room might have a DM-MD8X8 chassis, but the input and output cards aren't all in the same order, or they might be different models but function the same. You can use Essentials with a unique configuration file for each hardware configuration. 1. You have a floor of conference rooms that all share some centralized hardware like DSP, AV Routing and a shared CEN-GWEXER gateway with multiple GLS-OIR-CSM-EX-BATT occupancy sensors. All the shared hardware can be defined in the Essentials configuration and bridged over an EISC to each program that needs access. The same device can even be exposed to multiple programs over different EISCs. 1. You have a SIMPL program that works for many room types, but because some rooms have different models of processors than others (CP3/CP3N/AV3/PRO3/DMPS3 variants), you have to maintain several versions of the program, compiled for each processor model to maintain access to features like the System Monitor slot. You can use Essentials running in a slot on a processor to expose the System Monitor and many other features of the processor, regardless of model. Now you only need to maintain a single SIMPL program defined for your most complex processor application (ex. PRO3) ## Device Type Join Maps ### AirMediaController > supports: AM-200, AM-300 ### AppleTvController > supports: IR control of Apple TV ### CameraControlBase > supports: any camera that derives from CameraBase ### DisplayController > supports: IR controlled displays, any two way display driver that derives from PepperDash.Essentials.Core.DisplayBase ### DmChasisController > supports: All DM-MD-8x8/16x16/32x32 chassis, with or w/o DM-CPU3 Card ### DmRmcController > supports: All DM-RMC devices ### DmTxController > supports: All Dm-Tx devices ### DmpsAudioOutputController > supports: Program, Aux1, Aux2 outputs of all DMPS3 Control Systems ### DmpsRoutingController > supports: Av routing for all DMPS3 Control Systems ### GenericRelayController > supports: Any relay port on a Crestron Control System or Dm Endpoint ### GenericLightingJoinMap > supports: Devices derived from PepperDash.Essentials.Core.Lighting.LightingBase ### GlsOccupancySensorBase > supports: Any Crestron GLS-Type Occupancy sensor - single/dual type ### HdMdxxxCEController > supports: HD-MD-400-C-E, HD-MD-300-C-E, HD-MD-200-C-E, HD-MD-200-C-1G-E-B/W ### IBasicCommunication > supports: Any COM Port on a Control System or Dm Endpoint device, TCP Client, SSH Client, or UDP Server ### IDigitalInput > supports: Any Digital Input on a Control System, or DM Endpoint device ### SystemMonitorController > supports: Exposing the system monitor slot for any Control System ## Example SIMPL Windows Program We've provided an [example program](https://github.com/PepperDash/EssentialsSIMPLWindowsBridgeExample) for SIMPL Windows that works with the provided example Essentials configuration file [SIMPLBridgeExample_configurationFile.json](https://github.com/PepperDash/Essentials/blob/main/PepperDashEssentials/Example%20Configuration/SIMPLBridging/SIMPLBridgeExample_configurationFile.json). Load Essentials and the example SIMPL program to two slots on the same processor and you can get a better idea of how to take advantage of SIMPL Windows bridging. Next: [Essentials architecture](~/docs/technical-docs/Arch-summary.md) ================================================ FILE: docs/docs/getting-started.md ================================================ # Getting Started ================================================ FILE: docs/docs/how-to/how-to-add-docs.md ================================================ # How to Add Documentation to Essentials This guide explains how to add new documentation articles to the Essentials docFx site. ## Overview The Essentials documentation uses [docFx](https://dotnet.github.io/docfx/) to generate a static documentation website. Documentation files are organized in a hierarchical structure with a table of contents (TOC) file that defines the site navigation. Documentation should be organized and written to fit into the [Diátaxis](https://diataxis.fr/start-here/) conceptual framework. ## Documentation Structure Documentation files are located in `/docs/docs/` and organized into the following subdirectories: - **how-to/** - Step-by-step guides and tutorials - **usage/** - Usage documentation for SIMPL bridging, standalone use, and hardware integration - **technical-docs/** - Technical documentation including architecture, plugins, and API references - **images/** - Image assets used in documentation ## Adding a New Document ### Step 1: Create Your Markdown File 1. Determine which category your document belongs to (how-to, usage, or technical-docs) 2. Create a new `.md` file in the appropriate subdirectory 3. Use a descriptive filename with hyphens (e.g., `my-new-feature.md`) **Example:** ```bash # For a how-to guide touch /docs/docs/how-to/configure-audio-settings.md # For usage documentation touch /docs/docs/usage/video-switcher-control.md # For technical documentation touch /docs/docs/technical-docs/custom-device-plugin.md ``` ### Step 2: Write Your Content Start your markdown file with a level 1 heading (`#`) that serves as the page title: ```markdown # Your Document Title Brief introduction to the topic. ## Section Heading Content goes here... ### Subsection More detailed content... ``` **Markdown Features:** - Use standard markdown syntax - Include code blocks with language specifiers (```csharp, ```json, etc.) - Add images: `![Alt text](../images/your-image.png)` - Link to other docs: `[Link text](../usage/related-doc.md)` ### Step 3: Add to Table of Contents Edit `/docs/docs/toc.yml` to add your new document to the navigation: ```yaml - name: How-to's items: - href: how-to/how-to-add-docs.md - href: how-to/your-new-doc.md # Add your document here ``` **TOC Structure:** - `name:` - Display name in the navigation menu - `href:` - Relative path to the markdown file - `items:` - Nested items for hierarchical navigation **Example with nested items:** ```yaml - name: Usage items: - name: SIMPL Bridging href: usage/SIMPL-Bridging-Updated.md items: - name: Your Sub-Topic href: usage/your-sub-topic.md ``` ### Step 4: Test Locally Build and preview the docFx site locally to verify your changes: ```bash # Navigate to the docs directory cd docs # Build the documentation docfx build # Serve the site locally docfx serve _site ``` Then open your browser to `http://localhost:8080` to view the site. ## Best Practices ### File Naming - Use lowercase with hyphens: `my-document-name.md` - Be descriptive but concise - Avoid special characters ### Content Guidelines - Start with a clear introduction - Use hierarchical headings (H1 → H2 → H3) - Include code examples where appropriate - Add images to illustrate complex concepts - Link to related documentation ### TOC Organization - Group related documents under the same parent - Order items logically (basic → advanced) - Keep the TOC hierarchy shallow (2-3 levels max) - Use clear, descriptive names for navigation items ## Common Issues ### Document Not Appearing - Verify the file path in `toc.yml` is correct and uses forward slashes - Ensure the markdown file exists in the specified location - Check for YAML syntax errors in `toc.yml` ### Images Not Loading - Verify image path is relative to the markdown file location - Use `../images/` for files in the images directory - Ensure image files are committed to the repository ### Broken Links - Use relative paths for internal links - Test all links after building the site - Use `.md` extension when linking to other documentation files ## Additional Resources - [docFx Documentation](https://dotnet.github.io/docfx/) - [Markdown Guide](https://www.markdownguide.org/) - [YAML Syntax](https://yaml.org/spec/1.2/spec.html) - [Diátaxis](https://diataxis.fr/start-here/) ================================================ FILE: docs/docs/technical-docs/Arch-1.md ================================================ # Essentials architecture ## Device and DeviceManager --- [YouTube Video - The Device Model in PepperDash Essentials](https://youtu.be/QF4vCQfOYGw) *** A `Device` (`PepperDash.Core.Device`) is a logical construct. It may represent a piece of hardware, a port, a socket, a collection of other devices/ports/constructs that define an operation, or any unit of logic that should be created at startup and exist independent of other devices. `DeviceManager` (`PepperDash.Essentials.Core.DeviceManager`) is the collection of all Devices. The collection of everything we control, and other business logic in a system. See the list below for what is typical in the device manager. ## Flat system design In Essentials, most everything we do is focused in one layer: The Devices layer. This layer interacts with the physical Crestron and other hardware and logical constructs underneath, and is designed so that we rarely act directly on the often-inconsistent hardware layer. The `DeviceManager` is responsible for containing all of the devices in this layer. Types of things in `DeviceManager`: * Rooms * Sources * Codecs, DSPs, displays, routing hardware * IR Ports, Com ports, SSh Clients, ... * Occupancy sensors and relay-driven devices * Logical devices that manage multiple devices and other business, like shade or lighting scene controllers * Fusion connectors to rooms A Device doesn't always represent a physical piece of hardware, but rather a logical construct that "does something" and is used by one or more other devices in the running program. For example, we create a room device, and its corresponding Fusion device, and that room has a Cisco codec device, with an attached SSh client device. All of these lie in a flat collection in the `DeviceManager`. > The `DeviceManager` is nothing more than a modified collection of things, and technically those things don't have to be Devices, but must at least implement the `IKeyed` (`PepperDash.Core.IKeyed`) interface (simply so items can be looked up by their key.) Items in the `DeviceManager` that are Devices are run through additional steps of [activation](~/docs/technical-docs/Arch-activate.md#2-pre-activation) at startup. This collection of devices is all interrelated by their string keys. In this flat design, we spin up devices, and then introduce them to their "coworkers and bosses" - the other devices and logical units that they will interact with - and get them all operating together to form a running unit. For example: A room configuration will contain a "VideoCodecKey" property and a "DefaultDisplayKey" property. The `DeviceManager` provides the room with the codec or displays having the appropriate keys. What the room does with those is dependent on its coding. > In the default Essentials routing scheme, the routing system gets the various devices involved in given route from `DeviceManager`, as they are discovered along the defined tie-lines. This is all done at route-time, on the fly, using only device and port keys. As soon as the routing operation is done, the whole process is released from memory. This is extremely-loose coupling between objects. This flat structure ensures that every device in a system exists in one place and may be shared and reused with relative ease. There is no hierarchy. ## Architecture drawing ![Architecture overview](~/docs/images/arch-overview.png) Next: [Configurable lifecycle](~/docs/technical-docs/Arch-lifecycle.md) ================================================ FILE: docs/docs/technical-docs/Arch-activate.md ================================================ # Essentials architecture: DeviceManager activation ## What is all this? The Essentials system architecture is a loose collection of "things" - generally real or logical Devices - that all need to relate to each other. In the interest of keeping Essentials extensible and flexible, we use an non-ordered collection of objects that should only have references to each other in the least-binding way possible. Meaning: Devices should be designed to be able to function without related objects present, and when they are present they should only retain loose reference to those other objects for memory management and later deconstruction as Essentials grows into a real-time configurable environment. In order to facilitate this loose coupling, Essentials devices go through five phases during the startup process: Construction; addition to `DeviceManager`; pre-activation; activation; post-activation. We will describe what is optimal behavior for each of the steps below: ### Classes Referenced * `PepperDash.Core.Device` * `PepperDash.Essentials.Core.EssentialsDevice` * `PepperDash.Essentials.Core.DeviceManager` * `PepperDash.Essentials.Core.Privacy.MicrophonePrivacyController` ## 1. Construction and addition to the DeviceManager In general, a device's constructor should only be used to get the "framework" of the device in place. All devices are constructed in this stage. Rooms and fusion bridges included. Simple devices like IR driver devices, and devices with no controls can be completely spun up in this phase. All devices are added to the `DeviceManager` after they are constructed, but may not be fully functional. ## 2. Pre-activation This stage is rarely used. It exists to allow an opportunity for any necessary logic to take place before the main activation phase. ## 3. Activation This stage is the main phase of startup, and where most devices will get up and running, if they need additional startup behavior defined. The developer will code an optional overridden `CustomActivate()` method on the device class. This is where hardware ports may be set up; signals and feedbacks linked; UI drivers fired up; rooms linked to their displays and codec... With the exception of early-designed devices, most new Essentials classes do all of their startup here, rather than in their constructors. Remember that in your `CustomActivate()` method, you cannot assume that a device you depend on is alive and running yet. It may be activating later. You _can_ depend on that device's existence, and link yourself to it, but it may not be functional yet. In general, there should be no conditions in any Essentials code that depend on device startup sequence and ordering. All rooms, devices, classes should be able to function without linked devices being alive, and respond appropriately when they do come to life. Any post-activation steps can be done in step four below - and should be avoided in general. If the `CustomActivate()` method is long, consider breaking it up into many smaller methods. This will enhance exception handling and debugging when things go wrong, with more-detailed stack traces, and makes for easier-to-read code. Note: It is best-practice in Essentials to not write arbitrarily-timed startup sequences to ensure that a "system" or room is functional. Rather, we encourage the developer to use various properties and conditions on devices to aggregate together "room is ready" statuses that can trigger further action. This ensures that all devices can be up and alive, allowing them to be debugged within a program that may otherwise be misbehaving - as well as not making users and expensive developers wait for code to start up! ```cs public override bool CustomActivate() { Debug.Console(0, this, "Final activation. Setting up actions and feedbacks"); SetupFunctions(); SetupFeedbacks(); EISC.SigChange += EISC_SigChange; ... } ``` ## 4. Post-activation This phase is used primarily to handle any logic in a device that might be dependent on another device, and we need to ensure that we have waited for the dependent device to be activated first. For example, if we look at the `MicrophonePrivacyController` class, this is a "virtual" device whose purpose is to control the mute state of microphones from one or more contact closure inputs as well as provide feedback via different colored LEDs as to the current mute state. This virtual-device doesn't actually represent any sort of physical hardware device, but rather relies on associating itself with other devices that represent digital inputs and relays as well as whatever device is responsible for preforming the actual muting of the microphones. We can see in the example below that during the `CustomActivate()` phase, we define a post-activation action via a lambda in `AddPostActivationAction()` that will execute during the post-activation phase. The purpose here is to check the state of the microphone mute and set the state of the relays that control the LEDs accordingly. We need to do this as a post-activation action because we need to make sure that the devices PrivacyDevice, RedLedRelay and GreenLedRelay are fully activated before we can attempt to interact with them. ### **Example** ```cs public override bool CustomActivate() { foreach (var i in Config.Inputs) { var input = DeviceManager.GetDeviceForKey(i.DeviceKey) as IDigitalInput; if(input != null) AddInput(input); } var greenLed = DeviceManager.GetDeviceForKey(Config.GreenLedRelay.DeviceKey) as GenericRelayDevice; if (greenLed != null) GreenLedRelay = greenLed; else Debug.Console(0, this, "Unable to add Green LED device"); var redLed = DeviceManager.GetDeviceForKey(Config.RedLedRelay.DeviceKey) as GenericRelayDevice; if (redLed != null) RedLedRelay = redLed; else Debug.Console(0, this, "Unable to add Red LED device"); AddPostActivationAction(() => { CheckPrivacyMode(); PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange; PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; }); initialized = true; return base.CustomActivate(); } void CheckPrivacyMode() { if (PrivacyDevice != null) { var privacyState = PrivacyDevice.PrivacyModeIsOnFeedback.BoolValue; if (privacyState) TurnOnRedLeds(); else TurnOnGreenLeds(); } } ``` ## Activation exceptions Each of the three activation phases operates in a try/catch block for each device. This way if one device has a fatal failure during activation, the failure will be logged and the system can continue to activate. This allows the developer to chase down multiple issues per load while testing, or to fix configuration omissions/errors as a group rather than one-at-a-time. A program can theoretically be fully-initialized and have many or all devices fail. We generally do not want to depend on exception handling to log device failures. Construction and activation code should have plenty of null checks, parameter validity checks, and debugging output to prevent exceptions from occurring. `String.IsEmptyOrNull(myString)` and `if(myObject == null)` are your friends. Invite them often. ## Interdependence In any real-world system, devices and business logic need to talk to each other, otherwise, what's the point of all this coding? When creating your classes and configuration, it is best practice to _try_ not to "plug" one device into another during construction or activation. For example your touchpanel controller class has a `Display1` property that holds the display-1 object. Rather, it may be better to refer to the device as it is stored in the `DeviceManager` when it's needed using the static `DeviceManager.GetDeviceForKey(key)` method to get a reference to the device, which can be cast using various interfaces/class types, and then interacted with. This prevents objects from being referenced in places where the developer may later forget to dereference them, causing memory leak. This will become more important as Essentials becomes more able to be reconfigured at runtime. As an example, [connection-based routing](~/docs/technical-docs/Connection-based-routing.md#essentials-connection-based-routing) uses these methods. When a route is requested, the collection of tielines and devices is searched for the devices and paths necessary to complete a route, but there are no devices or tie lines that are object-referenced in running code. It can all be torn down and reconfigured without any memory-management dereferencing, setting things to null. ## Device Initialization Once the `DeviceManager` has completed the activation phase cycle for all devices, the devices themselves can be initialized. The `EssentialsDevice` class subscribes to the `DeviceManager.AllDevicesActivated` event and invokes the virtual `Initialize()` method on `Device` in a separate thread. This allows all devices to concurrently initialize in parallel threads. The main task that should be undertaken in the `Initialize()` method for any 3rd party device class, it to begin communication with the device via its API. Ideally, no class that communicates with a 3rd party device outside the program should attempt to start communicating before this point. ### Example (from `PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.CiscoSparkCodec`) ```cs public override void Initialize() { var socket = Communication as ISocketStatus; if (socket != null) { socket.ConnectionChange += new EventHandler(socket_ConnectionChange); } Communication.Connect(); CommunicationMonitor.Start(); const string prefix = "xFeedback register "; CliFeedbackRegistrationExpression = prefix + "/Configuration" + Delimiter + prefix + "/Status/Audio" + Delimiter + prefix + "/Status/Call" + Delimiter + prefix + "/Status/Conference/Presentation" + Delimiter + prefix + "/Status/Cameras/SpeakerTrack" + Delimiter + prefix + "/Status/RoomAnalytics" + Delimiter + prefix + "/Status/RoomPreset" + Delimiter + prefix + "/Status/Standby" + Delimiter + prefix + "/Status/Video/Selfview" + Delimiter + prefix + "/Status/Video/Layout" + Delimiter + prefix + "/Status/Video/Input/MainVideoMute" + Delimiter + prefix + "/Bookings" + Delimiter + prefix + "/Event/CallDisconnect" + Delimiter + prefix + "/Event/Bookings" + Delimiter + prefix + "/Event/CameraPresetListUpdated" + Delimiter + prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter; } ``` ## The goal Robust C#-based system code should not depend on "order" or "time" to get running. We do not need to manage the order of our startup in this environment. Our Room class may come alive before our DSP and or Codec, and the Room is responsible for handling things when those devices become available. The UI layer is responsible for blocking the UI or providing status when the Room's requirements are coming alive, or if something has gone away. We use events or `Feedbacks` to notify dependents that other devices/classes are ready or not, but we do not prevent continued construction/activation of the system when many of these events don't happen, or don't happen in a timely fashion. This removes the need for startup management, which is often prolonged and consumes _tons_ of developer/installer time. A fully-loaded Essentials system may go through activation in several seconds, with all devices concurrently getting themselves going, where legacy code may take 10 minutes. When designing new Device-based classes, be it rooms, devices, port controllers, bridges, make them as independent as possible. They could exist alone in a program with no required partner objects, and just quietly exist without failing. We want the system to be fast and flexible, and keeping the interdependence between objects at a minimum improves this flexibility into the future. Next: [More architecture](~/docs/technical-docs/Arch-topics.md) ================================================ FILE: docs/docs/technical-docs/Arch-lifecycle.md ================================================ # Essentials Configurable System Lifecycle The diagram below describes how Essentials gets a program up and running. (The various activation phases are covered in more detail on the [next page](~/docs/technical-docs/Arch-activate.md)) ![Lifecycle](~/docs/images/lifecycle.png) Next: [Activation phases](~/docs/technical-docs/Arch-activate.md) ================================================ FILE: docs/docs/technical-docs/Arch-summary.md ================================================ # Essentials architecture ## Summary PepperDash Essentials is an open-source framework for control systems, built on Crestron's Simpl# Pro framework. It can be configured as a standalone program capable of running a wide variety of system designs and can also be used to augment other Crestron programs. Essentials is a collection of C# libraries that can be used in many ways. It is a 100% configuration-driven framework that can be extended to add different workflows and behaviors, either through the addition of new device-types and classes, or via a plug-in mechanism. The framework is a collection of things that are all related and interconnected, but in general do not have strong dependencies on each other. ## Framework Libraries The table below is a guide to understand the basic organization of code concepts within the various libraries that make up the architecture. ![Table](~/docs/images/arch-table.PNG) The diagram below shows the reference dependencies that exist between the different component libraries that make up the Essentials Framework. ![Architecture drawing](~/docs/images/arch-high-level.png) Next: [Architecture](~/docs/technical-docs/Arch-1.md) ================================================ FILE: docs/docs/technical-docs/Arch-topics.md ================================================ # Configuration topics Configuration is central to Essentials. On this page we will cover configuration-related topics, including the important concept of configure-first and some details about the config file process. ## Classes Referenced - `PepperDash.Essentials.Core.Config.DeviceConfig` ## Configure-first development ## Framework Libraries The table below is meant to serve as a guide to understand the basic organization of code concepts within the various libraries that make up the architecture. _Todo, try a text-based table:_ ![Table](~/docs/images/arch-table.PNG) The diagram below shows the reference dependencies that exist between the different component libraries that make up the Essentials Framework. ![Architecture drawing](~/docs/images/arch-high-level.png) ### Architecture #### Device and DeviceManager A `Device` is a logical construct. It may represent a piece of hardware, a port, a socket, a collection of other devices/ports/constructs that define an operation, or any unit of logic that should be created at startup and exist independent of other devices. `DeviceManager` is the collection of all Devices. The collection of everything we control on a system. **ADD SOME MORE HERE** #### Flat system design In Essentials, most everything we do is focused in one layer: The Devices layer. This layer interacts with the physical Crestron and other hardware and logical constructs underneath, and is designed so that we rarely act directly on the often-inconsistent hardware layer. The `DeviceManager` is responsible for containing all of the devices in this layer. Types of devices: - Rooms - Sources - Codecs, DSPs, displays, routing hardware - IR Ports, Com ports, SSh Clients, ... - Occupancy sensors and relay-driven devices - Logical devices that manage multiple devices and other business, like shade or lighting scene controllers - Fusion connectors to rooms A Device doesn't always represent a physical piece of hardware, but rather a logical construct that "does something" and is used by one or more other devices in the running program. For example, we create a room device, and its corresponding Fusion device, and that room has a Cisco codec device, with an attached SSh client device. All of these lie in a flat collection in the `DeviceManager`. > The `DeviceManager` is a modified collection of objects, and those objects don't have to inherit from Devices or EssentialsDevices, but must at least implement the `IKeyed` interface (so items can be looked up by their key.) Items in the `DeviceManager` that are Devices are run through additional steps of activation at startup. This collection of devices is all interrelated by their string keys. In this flat design, we spin up devices, and then introduce them to their "coworkers and bosses" - the other devices and logical units that they will interact with - and get them all operating together to form a running unit. For example: A room configuration will contain a "VideoCodecKey" property and a "DefaultDisplayKey" property. The `DeviceManager` provides the room with the codec or displays having the appropriate keys. What the room does with those is dependent on its coding. > In the default Essentials routing scheme, the routing system gets the various devices involved in given route from `DeviceManager`, as they are discovered along the defined tie-lines. This is all done at route-time, on the fly, using only device and port keys. As soon as the routing operation is done, the whole process is released from memory. This is extremely-loose coupling between objects. This flat structure ensures that every device in a system exists in one place and may be shared and reused with relative ease. There is no hierarchy. #### Architecture drawing ![Architecture overview](~/docs/images/arch-overview.png) #### Essentials Configurable System Lifecycle ![Lifecycle](~/docs/images/lifecycle.png) ### Activation phases additional topics and examples (OTHER DOCS) Concepts (link) Room and touchpanel activation (link) #### Configure first development One of the primary concepts that has been adopted and must be adhered to when writing for Essentials framework is the concept of "configure first." The simple version is: Write what you need to do in the related configuration file (and configuration tool) first, then write the code that runs from that configuration. This ensures that the running code can actually be configured in the "flat" structure of devices and rooms that Essentials uses. Often, code is written and tested first without consideration for configurability. Then, when a developer tries to make it configurable, they discover that the code as written doesn’t support it without complicated configuration files. This creates spaghetti code in tools that are written to generate configurations and tends to create tighter coupling between objects than we desire. Later, a modified version of the original program is desired, but because the code was written in such a specific fashion, the code is hard to refactor and extend. This causes the configuration tool and configuration files to become even more convoluted. The modern versions of configuration tools that are starting to come out are modular and componentized. We want to ensure as much re-use of these modules as possible, with extensions and added features added on, rather than complete rewrites of existing code. In our running systems, we want to ensure as much flexibility in design as possible, eliminating multiple classes with similar code. ### Configuration reader process At the heart of the Essentials framework is the configuration system. While not technically necessary for a system written with the Essentials framework, it is the preferred and, currently, the only way to build an Essentials system. The configuration file is JSON, and well-defined (but not well documented, yet). It is comprised of blocks: - info (object) Contains metadata about the config file - devices (array) Contains, well, the devices we intend to build and load - rooms (array, typically only one) Contains the rooms we need - sourceLists (object) Used by one or more rooms to represent list(s) of sources for those rooms - tieLines (array) Used by the routing system to discover routing between sources and displays In addition, a downloaded Portal config file will most likely be in a template/system form, meaning that the file contains two main objects, representing the template configuration and its system-level overrides. Other metadata, such as Portal UUIDs or URLs may be present. At startup, the configuration file is read, and a ReadyEvent is fired. Upon being ready, that configuration is loaded by the ConfigReader.LoadConfig() method. The template and system are merged into a single configuration object, and that object is then deserialized into configuration wrapper classes that define most of the structure of the program to be built. (Custom configuration objects were built to allow for better type handling rather than using JToken methods to parse out error-prone property names.) For example, a `DeviceConfig` object: ```cs namespace PepperDash.Essentials.Core.Config { public class DeviceConfig { [JsonProperty("key")] public string Key { get; set; } [JsonProperty("uid")] public int Uid { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("group")] public string Group { get; set; } [JsonProperty("type")] public string Type { get; set; } [JsonProperty("properties")] [JsonConverter(typeof(DevicePropertiesConverter))] public JToken Properties { get; set; } } } ``` _Every_ `Device` present must adhere to those five properties plus a properties object. The properties object will have its own deserialization helpers, depending on what its structure is. Once the ConfigReader has successfully read and deserialized the config file, then `ControlSystem.Load()` is called. This does the following in order: 1. Loads Devices 2. Loads TieLines 3. Loads Rooms 4. Loads LogoServer 5. Activation sequence This ordering ensures that all devices are at least present before building tie lines and rooms. Rooms can be built without their required devices being present. In principle, this could break from the loosely-coupled goal we have described, but it is the clearest way to build the system in code. The goal is still to build a room class that doesn't have functional dependencies on devices that may not be ready for use. In each device/room step, a device factory process is called. We call subsequent device factory methods in the various libraries that make up Essentials until one of them returns a functional device. This allows us to break up the factory process into individual libraries, and not have a huge list of types and build procedures. Here's part of the code: ```cs // Try local factories first var newDev = DeviceFactory.GetDevice(devConf); if (newDev == null) newDev = BridgeFactory.GetDevice(devConf); // Then associated library factories if (newDev == null) newDev = PepperDash.Essentials.Core.DeviceFactory.GetDevice(devConf); if (newDev == null) newDev = PepperDash.Essentials.Devices.Common.DeviceFactory.GetDevice(devConf); if (newDev == null) newDev = PepperDash.Essentials.DM.DeviceFactory.GetDevice(devConf); if (newDev == null) newDev = PepperDash.Essentials.Devices.Displays.DisplayDeviceFactory.GetDevice(devConf); ``` In each respective factory, or device constructor, the configuration's properties object is either converted to a config object or read from using `JToken` methods. This builds the device which may be ready to go, or may require activation as described above. A similar process is carried out for rooms, but as of now, the room types are so few that they are all handled in the `ControlSystem.LoadRooms()` method. _This process will soon be enhanced by a plug-in mechanism that will drill into dynamically-loaded DLLs and load types from factories in those libraries. This is where custom essentials systems will grow from._ After those five steps, the system will be running and ready to use. ================================================ FILE: docs/docs/technical-docs/Communication-Basics.md ================================================ # Unifying communication methods In networked A/V systems, devices can use many different methods of communication: COM ports, TCP/IP sockets, Telnet, SSH. Generally, the data protocol and commands that are sent and received using any of these methods are the same, and it is not necessary for a device to know the details of the communication method it is using. A Samsung MDC protocol display in room 1 using RS232 speaks the same language as another Samsung MDC does in the next room using TCP/IP. For these, and most cases where the device doesn't need to know its communication method, we introduce the `IBasicCommunication` interface. ## Classes Referenced * `PepperDash.Core.IBasicCommunication` * `PepperDash.Core.ISocketStatus` * `PepperDash.Core.GenericTcpIpClient` * `PepperDash.Core.GenericSshClient` * `PepperDash.Core.GenericSecureTcpIpClient` * `PepperDash.Essentials.Core.ComPortController` * `PepperDash.Essentials.Core.StatusMonitorBase` ## IBasicCommunication and ISocketStatus All common communication controllers will implement the `IBasicCommunication` interface, which is an extension of `ICommunicationReceiver`. This defines receive events, connection state properties, and send methods. Devices that need to use COM port, TCP, SSh or other similar communication will require an `IBasicCommunication` type object to be injected at construction time. ```cs /// /// An incoming communication stream /// public interface ICommunicationReceiver : IKeyed { event EventHandler BytesReceived; event EventHandler TextReceived; bool IsConnected { get; } void Connect(); void Disconnect(); } /// /// Represents a device that uses basic connection /// public interface IBasicCommunication : ICommunicationReceiver { void SendText(string text); void SendBytes(byte[] bytes); } /// /// For IBasicCommunication classes that have SocketStatus. GenericSshClient, /// GenericTcpIpClient /// public interface ISocketStatus : IBasicCommunication { event EventHandler ConnectionChange; SocketStatus ClientStatus { get; } } ``` ### Developing devices with communication Essentials uses dependency injection concepts in its start up phase. Simply, most devices use the same methods of communication, and are often communication-agnostic. During the build-from-configuration phase, the communication method device is instantiated, and then injected into the device that will use it. Since the communication device is of `IBasicCommunication`, the device controller receiving it knows that it can do things like listen for events, send text, or be notified when sockets change. ### Device Factory, Codec example ![Communication Device factory](~/docs/images/comm-device-factory.png) The DeviceManager will contain two new devices after this: The Cisco codec, and the codec's `GenericSshClient`. This enables easier debugging of the client using console methods. Some devices like this codec will also have a `StatusMonitorBase` device, for Fusion and other reporting. > `ComPortController` is `IBasicCommunication` as well, but methods like `Connect()` and `Disconnect()` do nothing on these types. #### ISocketStatus `PepperDash.Core.GenericTcpIpClient`, `GenericSshClient` and some other socket controllers implement `ISocketStatus`, which is an extension of `IBasicCommunication`. This interface reveals connection status properties and events. ```cs public interface ISocketStatus : IBasicCommunication { event EventHandler ConnectionChange; SocketStatus ClientStatus { get; } } ``` Classes that are using socket-based comms will need to check if the communication is `ISocketStatus` and link up to the `ConnectionChange` event for connection handling. ================================================ FILE: docs/docs/technical-docs/ConfigurationStructure.md ================================================ # Configuration Structure --- [YouTube Video - Configuring PepperDash Essentials](https://youtu.be/EK8Ti9a1o7s) *** The Essentials configuration structure is designed to allow minimum duplication of data across systems that share many similarities, which makes it ideally suited for applications where large numbers of duplicate room types must be deployed. At a high level, the idea is to define a template of all of the common configuration shared by a group of systems of the same type. Then individual differences per system instance can be defined in a system block that either add data missing in the template, or override the default values set in the template. ## Top Level Object Structure (Double Config) ```cs { // This object is deserialized to type PepperDash.Essentials.Core.Config.EssentialsConfig "system_url":"", // For Portal use only "template_url":"", // For Portal use only "template":{ // This object is deserialized to type PepperDash.Essentials.Core.EssentialsConfig // For most manually generated configuration, only define data here. Leave system empty }, "system":{ // This object is deserialized to type PepperDash.Essentials.Core.EssentialsConfig // Any data here will be overlayed on top of the data in template. In the case of duplicate values // the value in system will be overwrite any value in template } } ``` ## Object Structure for `template` and `system` (`PepperDash.Essentials.Core.EssentialsConfig`) ``` js { "info": { // This object is deserialized to type PepperDash.Essentials.Core.Config.InfoConfig // Contains information about the system/configuration }, "devices": [ // This object is deserialized to type List // An array of devices ], "rooms": [ // This object is deserialized to type List // An array of rooms. These are not automatically deserialized ], "tielines":[ // An array of tie lines that describe the connections between routing ports on devices ], "sourceLists":{ // This object is deserialized to type Dictionary> // An object that contains a collection }, "joinMaps":{ // This object is deserialized to type Dictionary where the value is a serialized class that inherits from JoinMapBase to be deserialized later // Used to define custom join maps for bridging devices to SIMPL } } ``` ## The Template and System Concept (Merging Configurations) In order to understand how and why we use a double configuration concept, it's important to understand the relationship between a Template and a System in Portal.  A System represents a physical installed group of hardware(either currently or in the future), acting together usually as part of a single control system program.  A system MUST inherit from a Template.  A Template represents the common elements of one or more systems. The idea being that configuration values that are common to all systems can be stored in the configuration for the template.  Then, any configuration values that are unique to a particular system cane be stored in the configuration of the System.  By "merging" the System configuration values over top of the Template configuration values, the resulting data contains all of the values that should be shared by each system that inherits from a common template, as well as the unique values for each individual system. Below is an example of a double configuration containing both template and system properties. ```JSON { "template": { "info": { "name": "Template Name", "description": "A 12 person conference room" }, "devices": [ ], "rooms": [ ] }, "system": { "info": { "name": "System Name", "myNewSystemProperty": "Some Value" }, "devices": [ ], "rooms": [ ] } } ``` Below is an example of the result of merging the above double configuration example into a single configuration. ```JSON { "info": { "name": "System Name", // Since this property existed in both the template and system, the system value replaces the template value after the merge "description": "A 12 person conference room", // This property existed only in the template and is unchanged after the merge "myNewSystemProperty": "Some Value" // This property existed only in the system and is unchanged after the merge }, "devices": [ ], "rooms": [ ] } ``` --- ## Device Object Structure The devices array is meant to hold a series of device objects.  The basic device object structure is defined below. ```JSON { "key": "someUniqueString", // *required* a unique string "name": "A friendly Name", // *required* a friendly name meant for display to users "type": "exampleType", // *required* the type identifier for this object. "group": "exampleGroup", // *required* the group identifier for this object. This really equates to a category for the device, // such as "lighting" or "displays" and may be deprecated in future in favor of "category" "uid":0, // *required* a unique numeric identifier for each device "properties": { // *required* an object where the configurable properties of the device are contained "control": { // an object to contain all of the properties to connect to and control the device "method": "ssh", // the control method used by this device "tcpSshProperties": { // contains the necessary properties for the specified method "address": "1.2.3.4", "port": 22, "username": "admin", "password": "uncrackablepassword" } }, "someCustomProperty": "I Love Tacos!" } // Do NOT add any custom data at the top level of the device object. All custom data must be in the properties object. } ``` Some additional details about specific properties that are important to note: * "key": This value needs to be unique in the array of devices objects * "uid": This value also needs to be unique for reasons related to configuration tools and template/system merging * "type": Think of this as a way to identify what specific module you might associate with this device.  In Essentials, this value is used to determine what class will be instantiated for the device (ex. "necmpsx" or "samsungMdc" for two types of displays) * "properties":  This object is used to store both specific and miscellaneous data about the device. * Specific data, like that shown above in the "control" object has a pre-defined structure. * Other data must be stored as objects or new properties inside the "properties" object such as "someCustomProperty" in the example above. * Do NOT add any additional properties at the top level of the device object.  All custom data must be in the "properties" object. ## The Device Properties.Control Object The control object inside properties has some reserved properties that are used by configuration tools and Essentials that require some caution. ```JSON { "properties": { // *required* an object where the configurable properties of the device are contained "control": { // an object to contain all of the properties to connect to and control the device // Example of the reserved properties for a socket based port (ssh, tcpIp, udp) "method": "ssh", // the control method used by this device "tcpSshProperties": { // contains the necessary properties for the specified method "address": "1.2.3.4", // IP Address or hostname "port": 22, "username": "admin", "password": "uncrackablepassword", "autoReconnect": true, // If true, the client will attempt to re-connect if the connection is broken externally "AutoReconnectIntervalMs": 2000 // The time between re-connection attempts }, // Example of the reserved properties for a Com port "method": "com", "controlPortNumber": 1, // The number of the com port on the device specified by controlPortDevKey "controlPortDevKey": "processor", // The key of the device where the com port is located "comParams": { // This object contains all of the com spec properties for the com port "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 9600, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 } } } } ``` --- ## Device Merging The following examples illustrate how the device key and uid properties affect how devices are merged together in a double configuration scenario.  In order for a template device and a system device to merge, they must have the same key and uid values ```JSON { "template": { "info": { "name": "Template Name", "description": "A 12 person conference room" }, "devices": [ { // This is the template device "key": "display-1", "name": "Display", "type": "samsungMdc", "group": "displays", "uid":0, "properties": { "control": { "method": "ssh", "tcpSshProperties": { "address": "", // Note that at the template level we won't know the actual IP address so this value is left empty "port": 22, "username": "admin", "password": "uncrackablepassword" } } } } ], "rooms": [ ] }, "system": { "info": { "name": "System Name", "myNewSystemProperty": "Some Value" }, "devices": [ { // This is the system device "key": "display-1", "uid":0, "properties": { "control": { "tcpSshProperties": { "address": "10.10.10.10" // Note that the actual IP address is specified at the system level } } } } ], "rooms": [ ] } } ``` Below is an example of the result of merging the above double configuration example into a single configuration.   ```JSON { "info": { "name": "System Name", "description": "A 12 person conference room", "myNewSystemProperty": "Some Value" }, "devices": [ { "key": "display-1", "name": "Display", "type": "samsungMdc", "group": "displays", "uid":0, "properties": { "control": { "method": "ssh", "tcpSshProperties": { "address": "10.10.10.10", // Note that the merged device object inherits all of the template // properties and overwrites the template address property with the system value "port": 22, "username": "admin", "password": "uncrackablepassword" } } } } ], "rooms": [ ] } ``` ================================================ FILE: docs/docs/technical-docs/Connection-Based-Routing.md ================================================ # Essentials connection-based routing ## TL;DR Routing is defined by a connection graph or a wiring diagram. Routable devices are sources, midpoints, or destinations. Devices are connected by tie lines. Tie lines represent the cables connecting devices, and have specific signal types (audio, video, audioVideo, secondaryAudio, usbInput, usbOutput). Routes are made by telling a destination to get a route from a source for a specific signal type. Combined signal types (e.g., audioVideo) are automatically split into separate routing operations. ## Summary Essentials routing is described by defining a graph of connections between devices in a system, typically in configuration. The audio, video and combination connections are like a wiring diagram. This graph is a collection of devices and tie lines, each tie line connecting a source device, source output port, destination device and destination input port. Tie lines are logically represented as a collection. When routes are to be executed, Essentials will use this connection graph to decide on routes from source to destination. A method call is made on a destination, which says "destination, find a way for source xyz to get to you." An algorithm analyzes the tie lines, instantly walking backwards from the destination, down every connection until it finds a complete path from the source. If a connected path is found, the algorithm then walks forward through all midpoints to the destination, executing switches as required until the full route is complete. The developer or configurer only needs to say "destination, get source xyz" and Essentials figures out how, regardless of what devices lie in between. ### Signal Type Handling When a combined signal type like `audioVideo` is requested, Essentials automatically splits it into two separate routing operations—one for audio and one for video. Each signal type is routed independently through the system, ensuring that: - Audio-only tie lines can be used for the audio portion - Video-only tie lines can be used for the video portion - AudioVideo tie lines can be used for both portions During path discovery, **only tie lines that support the requested signal type are considered**. For example, if a video route is requested, only tie lines with the video flag will be evaluated. This ensures signal compatibility throughout the entire routing chain. ### Port-Specific Routing The routing system supports routing to and from specific ports on devices. You can specify: - A specific input port on the destination device - A specific output port on the source device - Both specific ports for precise routing control When no specific ports are specified, the algorithm will automatically discover the appropriate ports based on available tie lines. ### Request Queuing All routing requests are processed sequentially through a queue. For devices that implement warming/cooling behavior (e.g., projectors), route requests are automatically held when a device is cooling down and executed once the device is ready. This prevents routing errors and ensures proper device state management. ### Classes Referenced * `PepperDash.Essentials.Core.Routing.IRoutingSource` * `PepperDash.Essentials.Core.Routing.IRoutingOutputs` * `PepperDash.Essentials.Core.Routing.IRoutingInputs` * `PepperDash.Essentials.Core.Routing.IRoutingInputsOutputs` * `PepperDash.Essentials.Core.Routing.IRoutingSinkNoSwitching` * `PepperDash.Essentials.Core.Routing.IRoutingSinkWithSwitching` ## Example system, a simple presentation system The diagram below shows the connections in a simple presentation system, with a few variations in connection paths. Example routes will be described following the diagram. Each visible line between ports on devices represents a tie line. A tie line connects an output port on one device to an input port on another device, for example: an HDMI port on a document camera to an HDMI input on a matrix switcher. A tie line has a signal type (audio, video, audioVideo, secondaryAudio, usbInput, or usbOutput) that determines what signals can travel through it. It is essentially a logical representation of a physical cable in a system. This diagram has 12 tie lines, and those tie lines are defined in the tieLines array in configuration. ![Routing system diagram](~/docs/images/routing-system-diagram.png) Let’s go through some examples of routing, using pseudo-code: 1. Method call: “Projector 1, show Doc cam.” Routing will walk backwards through DM-RMC-3 and DM-8x8 iterating through all “wired up” ports until it finds a path back to the Doc cam. Routing will then step back through all devices in the discovered chain, switching routes on those that are switchable: Doc cam: no switching; DM 8x8: route input 3 to output 3; DM-RMC-3: no switching; Projector 1: Select input HDMI In. Route is complete. 2. Method call: "Projector 2, show Laptop, video-only." Routing will walk backwards through DM-RMC-4, DM 8x8, DM-TX-1, iterating through all connected ports until it finds a connection to the laptop. During this search, only tie lines that support video signals are considered. Routing then steps back through all devices, switching video where it can: Laptop: No switching; DM-TX-1: Select HDMI in; DM 8x8: Route input 5 to output 4; DM-RMC-4: No switching; Projector 2: Select HDMI input. Route is complete. 3. Method call: "Amplifier, connect Laptop audio." Again walking backwards to Laptop, as in #2 above, but this time only tie lines supporting audio signals are evaluated. Switching will take place on DM-TX-1, DM 8x8, audio-only. 4. Very simple call: “Lobby display, show signage controller.” Routing will walk back on HDMI input 1 and immediately find the signage controller. It then does a switch to HDMI 1 on the display. All four of the above could be logically combined in a series of calls to define a possible “scene” in a room: Put Document camera on Projector 1, put Laptop on Projector 2 and the audio, put Signage on the Lobby display. They key takeaway is that the developer doesn’t need to define what is involved in making a certain route. The person configuring the system defines how it’s wired up, and the code only needs to tell a given destination to get a source, likely through configuration as well. All of the above routes can be defined in source list routing tables, covered elsewhere (**make link)**. --- ## Routing Algorithm Details ### Combined Signal Type Splitting When an `audioVideo` route is requested, the routing system automatically splits it into two independent routing operations: 1. **Audio Route**: Finds the best path for audio signals from source to destination 2. **Video Route**: Finds the best path for video signals from source to destination Each route can take a different physical path through the system. For example: - Video might travel: Laptop → DM-TX-1 → DM Matrix → Display - Audio might travel: Laptop → DM-TX-1 → DM Matrix → Audio Processor → Amplifier Both routes are discovered, stored, and executed independently. This allows for flexible system designs where audio and video follow different paths. The same splitting behavior occurs for `Video + SecondaryAudio` requests, where video and secondary audio are routed as separate operations. ### Signal Type Filtering At each step of the route discovery process, the algorithm filters tie lines based on the requested signal type: - **Video request**: Only considers tie lines with the `video` flag set - **Audio request**: Only considers tie lines with the `audio` flag set - **AudioVideo request**: Routes audio and video separately, each following their respective filtering rules If no tie line exists with the required signal type at any point in the chain, that path is rejected and the algorithm continues searching for an alternative route. If no valid path is found, the route request fails and no switching occurs. This filtering ensures that incompatible signal types never interfere with routing decisions. For example, an audio-only cable will never be selected when routing video, preventing misconfiguration errors. --- ### Definitions #### Ports Ports are logical representations of the input and output ports on a device. #### Source A source is a device at the beginning of a signal chain. For example, a set-top box, or a camera. Source devices typically have only output ports. Source devices in Essentials must implement `IRoutingOutputs` or `IRoutingSource` #### Midpoint A midpoint is a device in the middle of the signal chain. Typically a switcher, matrix or otherwise. Examples: DM chassis; DM-TX; DM-RMC; A video codec. These devices will have input and output ports. Midpoint devices must implement `IRoutingInputsOutputs`. Midpoints with switching must implement `IRouting`. #### Sink A sink is a device at the end of a full signal path. For example, a display, amplifier, encoder, etc. Sinks typically contain only input ports. They may or may not have switching, like a display with several inputs. Classes defining sink devices must implement `IRoutingSinkNoSwitching` or `IRoutingSinkWithSwitching`. #### Tie-line A tie-line is a logical representation of a physical cable connection between two devices. It has five properties that define how the tie-line connects two devices. ##### How Tie Line Types Are Determined The effective type of a tie line is determined by one of two methods: 1. **Automatic (Recommended)**: When no `type` property is specified in configuration, the tie line's type is automatically calculated as the **intersection** of signal types supported by both the source and destination ports. This ensures only compatible signals are considered for routing. Example: If a source port supports `AudioVideo` and the destination port supports `Audio`, the tie line will have type `Audio` (the only common type). 2. **Manual Override**: When the `type` property is explicitly set, it overrides the automatic calculation. This is useful when the physical cable supports fewer signal types than both ports are capable of. Example: Both ports support `AudioVideo`, but the cable only carries audio, so you set `"type": "audio"`. ##### Validation At startup, tie line configurations are validated to ensure: - Both ports exist on their respective devices - The source and destination ports have at least one common signal type - If a `type` override is specified, both ports must support that signal type Invalid tie lines will fail to build with descriptive error messages, preventing runtime routing issues. ##### Signal Types Tie lines support the following signal types: - `audio` - Audio-only signals - `video` - Video-only signals - `audioVideo` - Combined audio and video (automatically split during routing) - `secondaryAudio` - Secondary audio channel (e.g., program audio separate from microphone audio) - `usbInput` - USB input signals - `usbOutput` - USB output signals The `type` property determines which signals can travel through the tie line. During route discovery, only tie lines matching the requested signal type will be considered as valid paths. **Note**: In most cases, you should omit the `type` property and let the system automatically calculate it from the port capabilities. Only use it when you need to restrict the tie line to fewer signal types than the ports support or when needed for clarity. ##### Configuration Examples **Example 1: Automatic type calculation (recommended)** Connecting an HDMI cable between devices that both support audio and video. The `type` property is omitted, so the tie line will automatically support `AudioVideo`: ```json { "sourceKey": "ciscoSparkPlusCodec-1", "sourcePort": "HdmiOut1", "destinationKey": "display-1", "destinationPort": "HdmiIn1" } ``` **Example 2: Type override for cable limitations** Both devices support `AudioVideo`, but the physical cable only carries audio. The `type` property restricts routing to audio only: ```json { "sourceKey": "dmSwitcher-1", "sourcePort": "audioVideoOut1", "destinationKey": "amplifier-1", "destinationPort": "audioVideoIn1", "type": "audio" } ``` **Example 3: Mismatched port types (automatically handled)** Source only supports audio, destination supports both. No `type` needed—the tie line will automatically be `Audio`: ```json { "sourceKey": "audioProcessor-1", "sourcePort": "audioOut1", "destinationKey": "dmSwitcher-1", "destinationPort": "audioVideoIn1" } ``` **Invalid Example: Incompatible types** This configuration will **fail validation** at startup because the ports have no common signal types: ```json { "sourceKey": "audioProcessor-1", "sourcePort": "audioOut1", "destinationKey": "display-1", "destinationPort": "hdmiIn1", "type": "video" } ``` Error: `"Override type 'Video' is not supported by source port 'audioOut1' (type: Audio)"` ### Interfaces Todo: Define Interfaces IRouting, IRoutingOutputs, IRoutingInputs ================================================ FILE: docs/docs/technical-docs/Debugging.md ================================================ # Methods of Debugging 1. You can use Visual Studio step debugging - Pros: - Detailed real time debugging into with breakpoints and object inspection - Cons: - Doesn't really work remotely - On processors with Control Subnet, you must be connected to the CS interface to use step debugging. Often not practical or possible. - No logging - Using breakpoints stops the program and can interrupt system usage - Requires the running application to be built in debug mode, not release mode 2. You can use the Debug class features build into the PepperDash.Core library. - Pros: - Can be easily enabled from console - Allows for setting the level of verbosity - Works when troubleshooting remotely and doesn't require a connection to the CS interface of the processor. - Allows for logging to the Crestron error log or a custom log stored on removable media - Works regardless of build type setting (debug/release) - Can easily identify which class instance is generating console messages - Can use console commands to view the state of public properties on devices - Can use console commands to call methods on devices - Doesn't stop the program - Cons: - No detailed object inspection in real time - Only prints console statements already in code - When enabled at the highest level of verbosity, it can produce a significant amount of data in console. Can be hard to find messages easily. - No current mechanism to filter messages by device. (can be filtered by 3rd party tools easily, though) - Not very effective in debugging applications running on the VC-4 platform as only log messages get printed to the Syslog ## How to use the PepperDash.Core Debug Class The majority of interaction is done via console, preferably via an SSH session through Crestron Toolbox, PuTTy or any other suitable application. In code, the most useful method is `Debug.Console()` which has several overloads. All variations take an integer value for the level (0-2) as the first argument. Level 0 will ALWAYS print. Level 1 is for typical debug messages and level 2 is for verbose debugging. In cases where the overloads that accept a `Debug.ErrorLogLevel` parameter are used, the message will ALWAYS be logged, but will only print to console if the current debug level is the same or higher than the level set in the `Debug.Console()` statement. All statements printed to console are prefixed by a timestamp which can be greatly helpful in debugging order of operations. ```cs // The most basic use, sets the level (0) and the message to print. Debug.Console(0, "Hello World"); // prints: [timestamp]App 1:Hello World // The string parameter has a built in string.Format() that takes params object[] items string world = "World"; Debug.Console(0, "Hello {0}", world); // prints: [timestamp]App 1:Hello World // This overload takes an IKeyed as the second parameter and the resulting statement will // print the Key of the device in console to help identify the class instance the message // originated from Debug.Console(0, this, "Hello World"); // prints: [timestamp]App 1:[deviceKey]Hello World // Each of the above overloads has a corresponding variant that takes an argument to indicate // the level of error to log the message at as well as printing to console Debug.Console(0, Debug.ErrorLogLevel.Notice, "Hello World"); // prints: [timestamp]App 1:Hello World ``` ## Console Commands ### General Console Commands Below are is a non-exhaustive list of some of the Essentials specific console commands that allow interaction with the application at runtime. ### `help user` Will print the available console commands for each program slot. Console commands can be added and removed dynamically by Essentials and may vary by the version of Essentials that is running. This is the best place to start to determine the available commands registered for each instance of Essentials running on a processor. ### `reportversions:[slot]` Will print the running versions of all .dll libraries. Useful for determining the exact build version of the Essentials application and all plugins ### `gettypes:[slot] [searchString(optional)]` The `searchString` value is an optional parameter to filter the results. Will print all of the valid `type` values registered in the `DeviceFactory` for the running Essentials application. This helps when generating config structure and defining devices. Device types added by plugins will also be shown. ### `showconfig:[slot]` Will print out the merged config object ### `donotloadonnextboot:[slot] [true/false]` When the value is set to true, Essentials will pause when starting up, to allow for a developer to attach to the running process from an IDE for purposes of step debugging. Once attached, issuing the command `go:[slot]` will cause the configuration file to be read and the program to initialize. This value gets set to false when the `go` command is issues. ### DeviceManager Console Commands The following console commands all perform actions on devices that have been registered with the `PepperDash.Essentials.Core.DeviceManager` static class ### `Appdebug:[slot][0-2]` Gets or sets the current debug level where 0 is the lowest setting and 2 is the most verbose ### `getjoinmap:[slot] [bridgeKey][deviceKey (optional)] For use with SIMPL Bridging. Prints the join map for the specified bridge. If a device key is specified, only the joins for that device will be printed. Example: ```sh RMC3>appdebug:1 // Gets current level RMC3>AppDebug level = 0 RMC3>appdebug:1 1 // Sets level to 1 (all messages level 1 or lower will print) RMC3>[Application 1], Debug level set to 1 ``` ### `Devlist:[slot]` Gets the current list of devices from `DeviceManager` Prints in the form [deviceKey] deviceName Example: ```sh // Get the list of devices for program 1 RMC3>devlist:1 RMC3>[16:34:05.819]App 1:28 Devices registered with Device Mangager: [16:34:05.834]App 1: [cec-1] Tx 5 cec 1 [16:34:05.835]App 1: [cec-1-cec] [16:34:05.835]App 1: [cec-5] Rmc 1 cec 1 [16:34:05.836]App 1: [cec-5-cec] [16:34:05.836]App 1: [cec-6] Dm Chassis In 1 cec 1 [16:34:05.837]App 1: [cec-6-cec] [16:34:05.837]App 1: [cec-7] Dm Chassis Out 1 cec 1 [16:34:05.838]App 1: [cec-7-cec] [16:34:05.838]App 1: [comm-1] Generic comm 1 [16:34:05.838]App 1: [comm-1-com] [16:34:05.839]App 1: [comm-2] Rmc comm 1 [16:34:05.839]App 1: [comm-2-com] [16:34:05.840]App 1: [comm-3] Rmc comm 2 [16:34:05.840]App 1: [comm-3-com] [16:34:05.841]App 1: [dmMd8x8-1] DM-MD8x8 Chassis 1 [16:34:05.842]App 1: [dmRmc100C-1] DM-RMC-100-C Out 3 [16:34:05.843]App 1: [dmRmc200C-1] DM-RMC-200-C Out 2 [16:34:05.843]App 1: [dmRmc4kScalerC-1] DM-RMC-4K-SCALER-C Out 1 [16:34:05.844]App 1: [dmTx201C-1] DM-TX-201C 1 [16:34:05.845]App 1: [eisc-1A] [16:34:05.845]App 1: [gls-odt-1] GLS-ODT-CN 1 [16:34:05.846]App 1: [gls-oir-1] GLS-OIR-CN 1 [16:34:05.846]App 1: [processor] [16:34:05.847]App 1: [ssh-1] Generic SSH 1 [16:34:05.847]App 1: [ssh-1-ssh] [16:34:05.848]App 1: [systemMonitor] [16:34:05.848]App 1: [tcp-1] Generic TCP 1 [16:34:05.849]App 1: [tcp-1-tcp] ``` ### `Setdevicestreamdebug:[slot][devicekey][both/rx/tx/off]` Enables debug for communication on a single device Example: ```sh PRO3>setdevicestreamdebug:1 lights-1-com both [13:13:57.000]App 1:[lights-1-com] Sending 4 characters of text: 'test' PRO3>setdevicestreamdebug:1 lights-1-com off ``` ### `Devprops:[slot][devicekey]` Gets the list of public properties on the device with the corresponding `deviceKey` Example: ```sh // Get the properties on the device with Key 'cec-1-cec' // This device happens to be a CEC port on a DM-TX-201-C's HDMI input RMC3>devprops:1 cec-1-cec [ { "Name": "IsConnected", "Type": "Boolean", "Value": "True", "CanRead": true, "CanWrite": false }, { "Name": "Key", "Type": "String", "Value": "cec-1-cec", "CanRead": true, "CanWrite": true }, { "Name": "Name", "Type": "String", "Value": "", "CanRead": true, "CanWrite": true }, { "Name": "Enabled", "Type": "Boolean", "Value": "False", "CanRead": true, "CanWrite": true } ] RMC3> ``` ### `Devmethods:[slot][devicekey]` Gets the list of public methods available on the device Example: ```sh // Get the methods on the device with Key 'cec-1-cec' RMC3>devmethods:1 cec-1-cec [ { "Name": "SendText", "Params": [ { "Name": "text", "Type": "String" } ] }, { "Name": "SendBytes", "Params": [ { "Name": "bytes", "Type": "Byte[]" } ] }, { "Name": "SimulateReceive", "Params": [ { "Name": "s", "Type": "String" } ] }, //... Response abbreviated for clarity ... ] RMC3> ``` ### `Devjson:[slot][json formatted object {"devicekey", "methodname", "params"}]` Used in conjunction with devmethods, this command allows any of the public methods to be called from console and the appropriate arguments can be passed in to the method via a JSON object. This command is most useful for testing without access to hardware as it allows both simulated input and output for a device. Example: ```sh // This command will call the SendText(string text) method on the // device with the Key 'cec-1-cec' and pass in "hello world" as the // argument parameter. On this particular device, it would cause // the string to be sent via the CEC Transmit RMC3>devjson:1 {"deviceKey":"cec-1-cec", "methodName":"SendText", "params": ["hello world\r"]} // This command will call SimulateReceive(string text) on the device with Key 'cec-1-cec' // This would simulate receiving data on the CEC port of the DM-TX-201-C's HDMI input RMC3>devjson:1 {"deviceKey":"cec-1-cec", "methodName":"SimulateReceive", "params": ["hello citizen of Earth\r"]} ``` For additional examples, see this [file](https://github.com/PepperDash/Essentials/blob/main/devjson%20commands.json). ================================================ FILE: docs/docs/technical-docs/Feedback-Classes.md ================================================ # Feedback classes *** * [YouTube Video - Using Feedbacks in PepperDash Essentials](https://youtu.be/5GQVRKbD9Rk) *** The various Feedback classes are like "signals". They can enable various events, and are designed to be used where we need small data events to be sent without requiring custom handlers. ## Why Feedbacks? We have been writing "code" in an environment, Simpl, for years and have taken for granted the power that signals in that environment give us. With the release of the ability to develop in C#, we have been handed a massive set of tools to potentially make our lives better, but because of the age and limited scope of the .NET 3.5 Compact Framework, many of the things that have been very easy to do in the past have become challenging or bulky to write. Crestron classes have things called "Sigs", which are a less-functional version of the signal that we used in Simpl, but we have no ability to use our own Sigs around our own classes. This forces us to break out of the constraints and mindset of Simpl programming, but simultaneously keeps us partially bound to the "old way" of doing things. Signals as we have known them since Simpl came around are great. They allow a certain type of functional programming to be built, where things operate in solutions, and we are given a whole set of behaviors that we don't really have to think about: Something goes high, the next thing responds, something else happens, etc. With our older C# framework, it is most straightforward (and least-flexible) to take Sig transitions and handle them using very-flat and bulky coding techniques: Switch/case blocks, if/else blocks, slow dictionaries... In the Essentials environment (and in many other frameworks) these methods quickly reveal their flaws. Enter the Feedback. We want to define simple events that can be attached to various things - TP Sigs, EISC, event handlers - and maintain their own state. This simplifies the interface to various device classes, and allows us to define functional, simple classes with well-defined means of connecting them together. ### Feedbacks are similar to signals Feedbacks can: - Fire an event (OutputChange) - Be linked to one or more matching Crestron Sigs and update those Sigs - May contain complex computations to define the output value - Be put into test mode and have their value function overridden A Feedback is defined on a class using a C# construct called a `Func`. A `Func` is a small operation that returns a single value and is typically written in a lambda. The operation/expression in the `Func` is calculated when FireUpdate() is called on the Feedback. The result is then available for all objects listening to this Feedback. [Func documentation (MSDN)]() #### Creating Feedbacks The following `IntFeedback` returns the value of the `_VolumeLevel` field in this display class: ```cs public class MyDisplay { public IntFeedback VolumeLevelFeedback { get; private set; } ... public MyDisplay(...) { VolumeLevelFeedback = new IntFeedback(() => { return _VolumeLevel; }); ... ``` This BoolFeedback, adapted from the DmTx201Controller class, defines the `Func` first, and then creates the BoolFeedback using that `Func`. The value returned is true if the input is the digital-HDMI connection, and the TX hardware's VideoAttributes.HdcpActiveFeedback is true as well. ```cs public class MyTx { public BoolFeedback HdcpActiveFeedback { get; private set; } Func HdcpActiveFeedbackFunc = () => ActualVideoInput == DmTx200Base.eSourceSelection.Digital && tx.HdmiInput.VideoAttributes.HdcpActiveFeedback.BoolValue, ... public MyTx(...) { HdcpActiveFeedback = new BoolFeedback(HdcpActiveFeedbackFunc); ... ``` #### Triggering Feedback In your classes, when you need to update the objects listening to a Feedback, you will call MyFeedback.FireUpdate() inside your class. This will trigger the evaluation of the Func value, update any linked Sigs, and fire the OutputChange event. ```cs int _VolumeLevel; void ComDataChanged(string data) // volume=77 { if(data.StartsWith("volume=")) { _VolumeLevel = MyParseVolumeMethod(data); // get the level, 77 VolumeLevelFeedback.FireUpdate(); // all listeners updated ``` #### Using Feedbacks Feedbacks of the various types have BoolValue, IntValue, UShortValue, and StringValue properties that return the current value of the Feedback. ```cs if (MyTxDevice.HdcpActiveFeedback.BoolValue) { ... do something that needs to happen when HDCP is active ... ``` Feedbacks all share an OutputChange event, that fires an event with an empty EventArgs object. The event handler can go get the appropriate \*Value property when the event fires. The example below is a bit contrived, but explains the idea. ```cs ... MyDisplayDevice.VolumeLevelFeedback.OutputChange += MyDisplayVolumeHandler; ... } void MyDisplayVolumeHandler(object o, EventArgs a) { MobileControlServer.VolumeLevel = MyDisplayDevice.VolumeLevelFeedback.IntValue; ``` Feedbacks also have a LinkInputSig(\*InputSig sig) method that can directly trigger one or more Sigs on a Crestron device, without requiring an event handler. This is very useful for attaching states of our devices to Crestron touchpanels or EISCs, for example. The BoolFeedback class also has a LinkComplementInputSig(BoolInputSig sig) method that will invert the BoolFeedback's value to one or more attached Sigs. As well as updating upon change, the Feedback will set the Sig's value to the Feedback value upon calling the LinkInputSig method. This eliminates the need to walk through an object, property-by-property, and update several Sig values - as well as setting up to watch those values for changes. It is all handled in one step. ```cs public class MyClass { Tsw760 MyTp; MyDisplay Display; HookUpSigsMethod() { ... // changes to VolumeLevelFeedback will automatically propagate to UShortInputSig 123 // changes to HdcpActiveFeedback will propagate to BoolInputSig 456 // and these two panel Sigs are updated immediately as well. Display.VolumeLevelFeedback.LinkInputSig(MyTp.UshortInput[123]); MyHdcpDevice.HdcpActiveFeedback.LinkInputSig(MyTp.BoolInput[456]); ``` ================================================ FILE: docs/docs/technical-docs/Glossary-of-Terms.md ================================================ # Glossary of Terms **Assembly** An assembly is a file that is automatically generated by the compiler upon successful compilation of every . NET application. It can be either a Dynamic Link Library or an executable file. It is generated only once for an application and upon each subsequent compilation the assembly gets updated. **Device** A base class, defined in the PepperDash.Core library (`PepperDash.Core.Device`). It can represent a physical device, or a virtual device or behaviour. Generally, most new classes defined in the Essentials ecosystem should derive from Device. **DeviceManager** A static class (`PepperDash.Core.Essentials.DeviceManager`) that contains an unordered collection of Devices. Devices are added/registered to the DeviceManager and later can be retrieved as references by Key. **Essentials Application** A Crestron SIMPL# Pro application that is made up of the Essentials Framework and any optionally any number of Essentials Plugins **Essentials Framework** The collection of core libraries that make up the framework **Essentials Plugins** SIMPL# Pro libraries that reference the Essentials Framework and are loaded at runtime to add or extend functionality **IKeyed** An important interface defined in PepperDash.Core that requires a string property named Key, whose value must be unique. **PepperDash.Core** A SIMPL# utility library referenced by Essentials Framework. ================================================ FILE: docs/docs/technical-docs/Plugins.md ================================================ # What are Essentials Plugins? **Note : this entry updates a deprecated method - for information related to that deprecated method, see [Plugins - Deprecated](~/docs/Plugins-Deprecated.md)** *** * [YouTube Video - Loading Plugins in PepperDash Essentials](https://youtu.be/NA64iyNNAgE) * [YouTube Video - Build Your Own Plugin, Part 1](https://youtu.be/m2phC8g3Kfk) * [YouTube Video - Build Your Own Plugin, Part 2](https://youtu.be/2_PrWRk6Gy0) *** Plugins are SIMPL# Pro libraries that reference the Essentials Framework and can be loaded into an Essentials Application at runtime to extend functionality beyond what the Essentials Framework provides on its own. ## Why Use Plugins? Plugins are a way to extend or add new functionality to the Essentials Application without having to modify the actual Framework. In most cases, a plugin can be written to support a new device or behavior. Using plugins also limits the scope of understanding needed to work within the Essentials Framework. ## Should I use a Plugin? Essentials is meant to be a lightweight framework and an extensible basis for development. While some devices are included in the framework, mostly for the purposes of providing examples and developing and prototyping new device types, the bulk of new development is intended to take place in Plugins. Once a plugin adds new functionality that may be of benefit if shared across multiple plugins, it may make sense to port that common logic (base classes and/or interfaces) back into the framework to make it available to others. The thrust of future Essentials development is targeted towards building a library of plugins. ## How do Plugins Work? One or more plugins can be loaded to the /user/ProgramX/plugins as .dlls or .cplz packages. When the Essentials Application starts, it looks for any .cplz files, unzips them and then iterates any .dll assemblies in that folder and loads them. Once the plugin assemblies are loaded the Essentials Application will then attempt to load a configuration file and construct items as defined in the file. Those items can be defined in either the Essentials Framework or in any of the loaded plugin assemblies. ![Architecture drawing](~/docs/images/Plugin%20Load%20Sequence.png) ## What Must be Implemented in a Plugin for it to Work? All plugin assemblies must contain a class which inherits from ```EssentialsPluginDeviceFactory```, where `````` is a class which inherits from ```PepperDash.Essentials.Core.EssentialsDevice``` Within this class, we will define some metadata for the plugin and define which constructor to use for instantiating each class as defined by type. Note that multiple types can be loaded from the same plugin. ```cs using System; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Core; using System.Collections.Generic; namespace MyPlugin { public class SomeDeviceFactory : EssentialsPluginDeviceFactory { // This method defines metadata for the devices in the plugin public SomeDeviceFactory() { // This string is used to define the minimum version of the // Essentials Framework required for this plugin MinimumEssentialsFrameworkVersion = "1.5.0"; // This string is used to define all valid type names for // this plugin. This string is case insensitive TypeNames = new List { "SomeDevice" , "ThisNewDevice" }; } // This method instantiates new devices for the defined type // within the plugin public override EssentialsDevice BuildDevice(DeviceConfig dc) { // Deserialize the json properties for the loaded type to a new object var props = dc.Properties.ToObject(); // Return a newly instantiated device using the desired constructor // If no valid property data exists, return null with console print // describing the failure. if (props == null) { Debug.Console(0, "No valid property data for 'SomeDevice' - Verify Configuration."); Debug.Console(0, dc.Properties.ToString()); return null; } return new SomeDevice(dc.Key, dc.Name, props); } } public class OtherDeviceFactory : EssentialsPluginDeviceFactory { // This method defines metadata for the devices in the plugin public OtherDeviceFactory() { // This string is used to define the minimum version of the // Essentials Framework required for this plugin MinimumEssentialsFrameworkVersion = "1.5.0"; // This string is used to define all valid type names for // this plugin. This string is case insensitive TypeNames = new List { "OtherDevice", "ThisOtherDevice" }; } // This method instantiates new devices for the defined type // within the plugin public override EssentialsDevice BuildDevice(DeviceConfig dc) { // Deserialize the json properties for the loaded type to a new object var props = dc.Properties.ToObject(); // Return a newly instantiated device using the desired constructor // If no valid property data exists, return null with console print // describing the failure. if (props == null) { Debug.Console(0, "No valid property data for 'OtherDevice' - Verify Configuration."); Debug.Console(0, dc.Properties.ToString()); return null; } return new OtherDevice(dc.Key, dc.Name, props); } } } ``` ## SIMPL Bridging Optionally, if your plugin device needs to be able to bridge to a SIMPL program over EISC, and there isn't already an existing bridge class in the Essentials Framework, you can write a new bridge class in your plugin. However, in order for the Essentials Application to be able to us that new bridge, the bridge must implement the ```IBridgeAdvanced``` interface with the required ```LinkToApi()``` Extension method. If you are writing code for a bridgeable device, you should be inheriting from ```EssentialsBridgeableDevice```, which inherits from the already-required ```EssentialsDevice``` and implements ```IBridgeAdvanced```. Often though, you may find that a bridge class already exists in the Essentials Framework that you can leverage. For example, if you were writing a plugin to support a new display model that isn't already in the Essentials Framework, you would define a class in your plugin that inherits from PepperDash.Essentials.Core.DisplayBase. If you're only implementing the standard display control functions such as power/input/volume control, then the existing bridge class `DisplayControllerBridge` can be used. If you needed to add additional functions to the bridge, then you would need to write your own bridge in the plugin. For additional info see the [SIMPL-Bridging article](~/docs/SIMPL-Bridging.md). ## Template Essentials Plugin Repository Fork this repository when starting a new plugin. The template repository uses the essentials-builds repository as a submodule. This allows the plugin to reference a specific build version of Essentials. You must make sure that you checkout the correct build of the Essentials-Builds repo that contains any dependencies that your plugin may rely on. [Essentials Plugin Template Repository](https://github.com/PepperDash/EssentialsPluginTemplate) ================================================ FILE: docs/docs/technical-docs/Supported-Devices.md ================================================ # Essentials Framework Devices by Type ## Cameras * VISCA protocol * Cisco (via codec) * Zoom (via Zoom Room) ## Disc Player * Any IR disc player that implements standard RAD commands ## Displays * Any IR display that implements standard RAD commands * Samsung MDC protocol (commercial) * NEC Professional series flat panel * Avocor VTF * Panasonic TH series flat panels * Panasonic Projectors [(via plugin)](https://github.com/PepperDash/epi-display-panasonic-projectors) * LG Commercial series [(via plugin)](https://github.com/PepperDash/epi-display-lg) * Generic CEC control via HDMI [(via plugin)](https://github.com/PepperDash/epi-generic-cec-display) * Crestron Certified Driver Display [(via plugin)](https://github.com/batourin/epi-display-ccd) ## Lighting/Shading * Lutron Quantum * Somfy Shades (relay control) ## Power Controllers * Digital Logger ## Set Top Boxes * Any IR set top box that implements standard RAD commands ## Streaming Players * AppleTV (IR) * Roku (IR) ## Video Codecs * Cisco CE series (C/SX/RoomKit) * Zoom Room ## DSPs / Audio Codecs * BiAmp Tesira [(via plugin](https://github.com/PepperDash/epi-dsp-tesira) ## Crestron Devices * AM-200/300 Airmedia * All DM Chassis (8x8 * 128x128) * All DM input/output cards * All DMPS Processors * All DM Transmitter models (with COM/IR/Relay/CEC port access) * All DM Receiver models (with COM/IR/Relay/CEC port access) * DGE-100 * DM-DGE-200-C * DIN-8SW8 * CEN-IO-DIGIN-104 * CEN-RFGWEX/GWEXER * GLS-ODT/OIR-C-CN Occupancy Sensors * TSW-XXX series touchpanels * XPanel for SmartGraphics * Fusion Room and Assets ================================================ FILE: docs/docs/toc.yml ================================================ - name: Get Started With Essentials - href: ../index.md - href: Get-started.md - name: How-to's items: - name: How to add an article or doc page href: how-to/how-to-add-docs.md - name: Usage items: - href: usage/Standalone-Use.md - href: usage/SIMPL-Bridging-Updated.md items: - name: Join Maps href: usage/JoinMaps.md - name: Bridging to Hardware Resources href: usage/Bridging-To-Hardware-Resources.md items: - name: GenericComm Bridging href: usage/GenericComm.md - name: RelayOutput Bridging href: usage/RelayOutput.md - name: Digital Input Bridging href: usage/DigitalInput.md - name: IR Driver Bridging href: usage/IR-Driver-Bridging.md - name: Technical documentation items: - href: technical-docs/Arch-summary.md - name: Devices and DeviceManager href: technical-docs/Arch-1.md - name: Configurable lifecycle href: technical-docs/Arch-lifecycle.md - name: Activation phases href: technical-docs/Arch-activate.md - name: More href: technical-docs/Arch-topics.md - name: Plugins href: technical-docs/Plugins.md - name: Communication Basics href: technical-docs/Communication-Basics.md - name: Debugging href: technical-docs/Debugging.md - name: Feedback Classes href: technical-docs/Feedback-Classes.md - name: Connection Based Routing href: technical-docs/Connection-Based-Routing.md - name: Configuration Structure href: technical-docs/ConfigurationStructure.md - name: Supported Devices href: technical-docs/Supported-Devices.md - name: Glossary of Terms href: technical-docs/Glossary-of-Terms.md ================================================ FILE: docs/docs/usage/Bridging-To-Hardware-Resources.md ================================================ # Bridging to Hardware and Network Resources One of the most powerful features of Essentials is the ability to bridge SIMPL to and hardware resource to any piece of equipment instantiated inside of essentials. You can bridge directly to a comport on the processor just as easily as you can to the comport of an instantiated DM device. A simple change in the connection location of a display can be made with just a few keystrokes. This isn't restricted to comports either. Devices and direct connections can be linked to Digital Inputs, IR Ports, Relays, Comports, SSH, TCP/IP, UDP, and Cresnet resources. ## Examples Follow the links below for examples of bridging to hardware and network resources. **[GenericComm Bridging](~/docs/usage/GenericComm.md)** **[RelayOutput Bridging](~/docs/usage/RelayOutput.md)** **[Digital Input Bridging](~/docs/usage/DigitalInput.md)** **[Card Frame Bridging](~/docs/CardFrame.md)** ================================================ FILE: docs/docs/usage/DigitalInput.md ================================================ # DigitalInput Digital Inputs can be bridged directly to SIMPL from any device that is both inlcuded within essentials and has a relay. Consider the following example. ```JSON { "template": { "roomInfo": [ {} ], "devices": [ { "key": "processor", "uid": 0, "type": "pro3", "name": "pro3", "group": "processor", "supportedConfigModes": [ "compliance", "essentials" ], "supportedSystemTypes": [ "hudType", "presType", "vtcType", "custom" ], "supportsCompliance": true, "properties": {} }, { "key": "DigitalInput-1", "uid": 3, "name": "Digital Input 1", "group": "api", "type": "digitalInput", "properties": { "portDeviceKey" : "processor", "portNumber" : 1, "disablePullUpResistor" : true } }, { "key": "DigitalInput-2", "uid": 3, "name": "Digital Input 2", "group": "api", "type": "digitalInput", "properties": { "portDeviceKey" : "processor", "portNumber" : 2, "disablePullUpResistor" : true } }, { "key": "deviceBridge", "uid": 4, "name": "BridgeToDevices", "group": "api", "type": "eiscapiadv", "properties": { "control": { "tcpSshProperties": { "address": "127.0.0.2", "port": 0 }, "ipid": "03", "method": "ipidTcp" }, "devices": [ { "deviceKey": "DigitalInput-1", "joinStart": 1 }, { "deviceKey": "DigitalInput-2", "joinStart": 2 } ] } } ] } } ``` ## RelayOutput Configuration Explanation This configuration is meant for a Pro3 device, and instantiates two relay ports and links them to an eisc bridge to another processor slot on ipid 3. Let's break down the ```DigitalInput-1``` device. ```JSON { "key": "DigitalInput-1", "uid": 3, "name": "Digital Input 1", "group": "api", "type": "digitalInput", "properties": { "portDeviceKey" : "processor", "portNumber" : 1, "disablePullUpResistor" : true } } ``` **```Key```** The Key is a unique identifier for essentials. The key allows the device to be linked to other devices also defined by key. All Keys MUST be unique, as every device is added to a globally-accessible dictionary. If you have accidentally utilized the same key twice, Essentials will notify you during startup that there is an issue with the device. **```Uid```** The Uid is reserved for use with an PepperDash internal config generation tool, and is not useful to Essentials in any way. **```Name```** The Name a friendly name assigned to the device. Many devices pass this data to the bridge for utilization in SIMPL. **```Group```** Utilized in certain Essentials devices. In this case, the value is unimportant. **```Type```** The Type is the identifier for a specific type of device in Essentials. A list of all valid types can be reported by using the consolecommand ```gettypes``` in Essentials. In this case, the type is ```digitalInput```. This type is valid for any instance of a Relay Output. **```Properties```** These are the properties essential to the instantiation of the identified type. ### Properties There are two properties relevant to the instantiation of a relay device. **```portDeviceKey```** This property maps to the ```key``` of the device upon which the relay resides. **```portNumber```** This property maps to the number of the relay on the device you have mapped the relay device to. Even if the device has only a single relay, ```portNumber``` must be defined. **```disablePullUpResistor```** This is a boolean value, therefore it is a case-sensitive ```true``` or ```false``` utilized to determine if the pullup resistor on the digital input will be disabled or not. ### The JoinMap The joinmap for a ```digitalInput``` device is comprised of a single digital join. ```cs namespace PepperDash.Essentials.Core.Bridges { public class IDigitalInputJoinMap : JoinMapBaseAdvanced { [JoinName("InputState")] public JoinDataComplete InputState = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Room Email Url", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); public IDigitalInputJoinMap(uint joinStart) : base(joinStart, typeof(IDigitalInputJoinMap)) { } } } ``` ```InputState``` is a digital join that represents the feedback for the associated Digital Input Device. Its join is set to 1. ================================================ FILE: docs/docs/usage/GenericComm.md ================================================ # GenericComm One of the most common scenarios in control system development is utilizing RS232 to connect to a device. Essentials doesn't restrict you to connecting a native essentials device or plugin to the comport. You can directly access the comport, and even set baudrates on the fly if you so desire. Similarly you can instantiate one of several socket types in this manner and bridge them directly to SIMPL. Consider the following example. ```JSON { "template": { "roomInfo": [ {} ], "devices": [ { "key": "processor", "uid": 0, "type": "pro3", "name": "pro3", "group": "processor", "supportedConfigModes": [ "compliance", "essentials" ], "supportedSystemTypes": [ "hudType", "presType", "vtcType", "custom" ], "supportsCompliance": true, "properties": {} }, { "key": "Comport-1", "uid": 3, "name": "Comport 1", "group": "api", "type": "genericComm", "properties": { "control": { "method": "com", "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 115200, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "controlPortDevKey": "processor", } } }, { "key": "Comport-2", "uid": 3, "name": "Comport 2", "group": "api", "type": "genericComm", "properties": { "control": { "method": "ssh", "tcpSshProperties": { "address": "192.168.1.57", "port": 22, "username": "", "password": "", "autoReconnect": true, "autoReconnectIntervalMs": 10000 } } } }, { "key": "deviceBridge", "uid": 4, "name": "BridgeToDevices", "group": "api", "type": "eiscapiadv", "properties": { "control": { "tcpSshProperties": { "address": "127.0.0.2", "port": 0 }, "ipid": "03", "method": "ipidTcp" }, "devices": [ { "deviceKey": "Comport-1", "joinStart": 1 }, { "deviceKey": "Comport-2", "joinStart": 3 } ] } } ] } } ``` ## GenericComm Configuration Explanation This configuration is meant for a Pro3 device, and instantiates one comport and one SSH session and links them to an eisc bridge to another processor slot on ipid 3. Let's break down the ```Comport-1``` device. ```JSON { "key": "Comport-1", "uid": 3, "name": "Comport 1", "group": "comm", "type": "genericComm", "properties": { "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 115200, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "controlPortDevKey": "processor", "method": "com" } } } ``` **```Key```** The Key is a unique identifier for essentials. The key allows the device to be linked to other devices also defined by key. All Keys MUST be unique, as every device is added to a globally-accessible dictionary. If you have accidentally utilized the same key twice, Essentials will notify you during startup that there is an issue with the device. **```Uid```** The Uid is reserved for use with an PepperDash internal config generation tool, and is not useful to Essentials in any way. **```Name```** The Name a friendly name assigned to the device. Many devices pass this data to the bridge for utilization in SIMPL. **```Group```** Utilized in certain Essentials devices. In this case, the value is unimportant. **```Type```** The Type is the identifier for a specific type of device in Essentials. A list of all valid types can be reported by using the consolecommand ```gettypes``` in Essentials. In this case, the type is ```genericComm```. This type is valid for any instance of a serial-based communications channel such as a Serial Port, SSH, UDP, or standard TCP/IP Socket. **```Properties```** These are the properties essential to the instantiation of the identified type. #### Control The properties within this property are dependant on the type of genericComm you wish to instantiate. There is one common property for control of any type, and that is ```method```. The ```method``` property requires a string that maps to the following enumerations in Essentials : ```cs namespace PepperDash.Core { // Summary: // Crestron Control Methods for a comm object public enum eControlMethod { None = 0, Com = 1, IpId = 2, IpidTcp = 3, IR = 4, Ssh = 5, Tcpip = 6, Telnet = 7, Cresnet = 8, Cec = 9, Udp = 10, UdpClient = 11, } } ``` These enumerations are not case sensitive. Not all methods are valid for a ```genericComm``` device. For a comport, the only valid type would be ```Com```. For a direct network socket, valid options are ```Ssh```, ```Tcpip```, ```Telnet```, ```UdpClient```, and ```Udp```. ##### ComParams A ```Com``` device requires a ```comParams``` object to set the properties of the comport. The values of all properties are case-insensitive. ```JSON { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 115200, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 } ``` **Valid ```hardwareHandshake``` values are as follows** ```sh "None" "Rts" "Cts" "RtsCts" ``` **Valid ```parity``` values are as follows** ```sh "None" "Even" "Odd" "Mark" ``` **Valid ```protocol``` values are as follows** ```sh "RS232" "RS422" "RS485" ``` **Valid ```baudRate``` values are as follows** ```sh 300 600 1200 1800 2400 3600 4800 7200 9600 14400 19200 28800 38400 57600 115200 ``` **Valid ```dataBits``` values are as follows** ```sh 7 8 ``` **Valid ```softwareHandshake``` values are as follows** ```sh "None" "XON" "XONT" "XONR" ``` **Valid ```stopBits``` values are as follows** ```sh 1 2 ``` Additionally, a ```control``` object for a physical hardware port needs to map to that physical port. This is accomplished by utilizing the ```controlPortDevKey``` and ```port``` properties. **```controlPortDevKey```** This property maps to the ```key``` of the device upon which the port resides. **```port```** This property maps to the number of the port on the device you have mapped the relay device to. Even if the device has only a single port, ```port``` must be defined. ##### TcpSshParams A ```Ssh```, ```TcpIp```, ```UdpClient```, or ```Udp``` device requires a ```tcpSshProperties``` object to set the propeties of the socket. ```Json { "tcpSshProperties": { "address": "192.168.1.57", "port": 22, "username": "", "password": "", "autoReconnect": true, "autoReconnectIntervalMs": 10000 } } ``` **```address```** This is the IP address, hostname, or FQDN of the resource you wish to open a socket to. Use ```UdpClient``` for outbound UDP to a remote endpoint. Use ```Udp``` when you need Essentials to bind a local UDP listener. **```port```** This is the port you wish to utilize for the socket connection. Certain protocols require certain ports - ```Ssh``` being ```22``` and ```Telnet``` being ```23```. **```username```** This is the username (if required) for authentication to the device you are connecting to. Typcally only required for ```Ssh``` connections. **```password```** This is the password (if required) for authentication to the device you are connecting to. Typcally only required for ```Ssh``` connections. **```autoreconnect```** This is a boolean value, therefore it is a case-sensitive ```true``` or ```false``` utilized to determine if the socket will attempt to reconnect upon loss of connection. **```autoReconnectIntervalMs```** This is the duration of time, in Miliseconds, that the socket will wait before discrete connection attempts if ```autoreconnect``` is set to true. ##### The JoinMap The join map for a generic comms device is fairly simple. ```cs namespace PepperDash.Essentials.Core.Bridges { public class IBasicCommunicationJoinMap : JoinMapBaseAdvanced { [JoinName("TextReceived")] public JoinDataComplete TextReceived = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Text Received From Remote Device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("SendText")] public JoinDataComplete SendText = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Text Sent To Remote Device", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SetPortConfig")] public JoinDataComplete SetPortConfig = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Label = "Set Port Config", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("Connect")] public JoinDataComplete Connect = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Connect", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("Connected")] public JoinDataComplete Connected = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("Status")] public JoinDataComplete Status = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); public IBasicCommunicationJoinMap(uint joinStart) : base(joinStart, typeof(IBasicCommunicationJoinMap)) { } } } ``` ```TextReceived``` is a stream of strings received **FROM** the connected device. ```SendText``` is for any strings you wish to send **TO** the connected device. ```Connect``` connects to a remote socket device on the rising edge of the signal. ```Connected``` represents the current connection state. High for Connected, low for Disconnected. ```Status``` is an analog value that is representative of the connection states as reported by the SIMPL TCP/IP socket symbol. All of the preceeding joins are set to join ```1```. The second serial input join is reserved for ```2```. It allows you to send a ```comparams``` json object as a string, utilizing the same format mentioned previously in this document. Doing so will override the configured comport specifications. ================================================ FILE: docs/docs/usage/IR-Driver-Bridging.md ================================================ ## Legacy IR Driver Bridging ```json { "id": "1", "name": "Apple TV", "key": "appleTv-1", "type": "genericIrController", "uid": 3, "group": "devices", "properties": { "control": { "method": "ir", "irFile": "Apple_AppleTV_4th_Gen_Essentials.ir", "controlPortDevKey": "processor", "controlPortNumber": "1" } } } ``` ## Bridge Join Map IR Driver Bridging ```json { "id": "1", "name": "Apple TV", "key": "appleTv-1", "type": "genericIrController", "uid": 3, "group": "devices", "properties": { "control": { "method": "ir", "irFile": "Apple_AppleTV_4th_Gen_Essentials.ir", "controlPortDevKey": "processor", "controlPortNumber": "1", "useBridgeJoinMap": true } } } ``` Both methods will bridge the IR signals with `Standard Command` defined in the IR file. The `useBridgeJoinMap` property implements `GenericIrControllerJoinMap.cs` to standardized IR driver `Standard Command` signal joins. This allows users to swap IR drivers that implement `Standard Command` while bridging IR signals consistently between drivers. For example, when `useBridgeJoinMap` is present, channel up will be mapped to join-22 + device `joinstart` for any IR driver that has the signal marked as `Standard Command`. ## GenericIrControllerJoinMap (Example) ### Digitals | Join Number | Join Span | Description | Type | Capabilities | | ----------- | --------- | ----------- | ------------------- | ------------ | | 1 | 1 | PLAY | Digital | FromSIMPL | | 2 | 1 | STOP | Digital | FromSIMPL | | 3 | 1 | PAUSE | Digital | FromSIMPL | | 4 | 1 | FSCAN | Digital | FromSIMPL | | 5 | 1 | RSCAN | Digital | FromSIMPL | | 9 | 1 | POWER | Digital | FromSIMPL | | 10 | 1 | 0 | Digital | FromSIMPL | | 11 | 1 | 1 | Digital | FromSIMPL | | 12 | 1 | 2 | Digital | FromSIMPL | | 13 | 1 | 3 | Digital | FromSIMPL | | 14 | 1 | 4 | Digital | FromSIMPL | | 15 | 1 | 5 | Digital | FromSIMPL | | 16 | 1 | 6 | Digital | FromSIMPL | | 17 | 1 | 7 | Digital | FromSIMPL | | 18 | 1 | 8 | Digital | FromSIMPL | | 19 | 1 | 9 | Digital | FromSIMPL | | 21 | 1 | ENTER | Digital | FromSIMPL | | 22 | 1 | CH+ | Digital | FromSIMPL | | 23 | 1 | CH- | Digital | FromSIMPL | | 27 | 1 | POWER_ON | Digital | FromSIMPL | | 28 | 1 | POWER_OFF | Digital | FromSIMPL | | 30 | 1 | LAST | Digital | FromSIMPL | | 41 | 1 | BACK | Digital | FromSIMPL | | 42 | 1 | GUIDE | Digital | FromSIMPL | | 43 | 1 | INFO | Digital | FromSIMPL | | 44 | 1 | MENU | Digital | FromSIMPL | | 45 | 1 | UP_ARROW | Digital | FromSIMPL | | 46 | 1 | DN_ARROW | Digital | FromSIMPL | | 47 | 1 | LEFT_ARROW | Digital | FromSIMPL | | 48 | 1 | RIGHT_ARROW | Digital | FromSIMPL | | 49 | 1 | SELECT | Digital | FromSIMPL | | 54 | 1 | PAGE_UP | Digital | FromSIMPL | | 55 | 1 | PAGE_DOWN | Digital | FromSIMPL | | 61 | 1 | A | Digital | FromSIMPL | | 62 | 1 | B | Digital | FromSIMPL | | 63 | 1 | C | Digital | FromSIMPL | | 64 | 1 | D | Digital | FromSIMPL | ### Analogs | Join Number | Join Span | Description | Type | Capabilities | | ----------- | --------- | ----------- | ------------------- | ------------ | ### Serials | Join Number | Join Span | Description | Type | Capabilities | | ----------- | --------- | ----------- | ------------------- | ------------ | ================================================ FILE: docs/docs/usage/JoinMaps.md ================================================ # What is a Join Map? A join map is a class that defines the list of joins accessible to an `EssentialsBridgeableDevice` across an EISC Bridge. ## Why use a Join Map? A join map is necessary to bridge joins across an EISC bridge from Essentials to a SIMPL program. Join maps can be overriden in a configuration as necessary, but by default each device has a standard join map that publishes joins as a function of the joinOffset property of the device within a given Essentials Bridge. Join maps are reusable and extensible. Several join maps for standard device types already exist within Essentials, and those can be utilized for plugin creation without creation of a new join map. Utilizing standard join maps allows you to create a consistent API between device types that allows switching of devices via config without any new SIMPL or SIMPL#Pro code being written. ## How Join maps Work Whenever you instantiate a device and link that device to an EISC bridge utilizing your configuration in Essentials, the method `LinkToApi()` is called. This method matches various methods, feedbacks, and properties to joins on the EISC bridge in order to create a consistent API for communication to SIMPL. Whenever `LinkToApi()` is called, it creates a new instance of the device's joinMap class on demand. The constructor of that joinMap creates an object containing the join metadata, adds any configured join offsets to the standard join map, and adds all associated joins to a global join list that can be easily referenced from the command line. There are several components for each join within a join map. ```cs [JoinName("Online")] public JoinDataComplete Online = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Reports Online Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); ``` ### Attribute ```cs [JoinName("Online")] ``` If the attribute is present, the join data is added to the publically available list `Joins`. This can be used to "prebuild" functionality within a join map that you may not yet need. If you do not add this attribute (or simply comment it out), the join data will not be displayed whenever join data is printed using the `getjoinmap` command. ### JoinData ```cs JoinData() { JoinNumber = 1, JoinSpan = 1 }; ``` `JoinData` contains the pertinent information for the bridge. JoinData contains the information that the bridge utilizes to create each associated connection from the EISC to the methods, properties, and feedbacks associated with a device. `JoinNumber` is the 1-based index of the join you wish to tie to a given method, property, or feedback. This join, combined with the offset defined in the brdige's configuration for a device, will give you the SIMPL EISC join linked to the given data. `JoinSpan` determines a number of associated joins. Perhaps you have a list of Camera Presets, or a list of inputs. You can create one single join map entry and define the span of all associated join types. A `JoinData` object with a `JoinNumber` of 11 and a `JoinSpan` of 10 and a `joinOffset` of 0 is associated with joins 11-20 on the EISC. ### JoinMetadata ```cs JoinMetadata() { Label = "Reports Online Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital } ``` `JoinMetadata` provides the data reported when the `getjoinmap` command is used. `Label` is the description of the what this join does. `JoinCapabilities` is represented by an enum defining the direction that the data is flowing for this join. Appropriate values are: ```cs public enum eJoinCapabilities { None = 0, ToSIMPL = 1, FromSIMPL = 2, ToFromSIMPL = ToSIMPL | FromSIMPL } ``` `JoinType` is represented by an enum defining the data type in SIMPL. Appropriate values are: ```cs public enum eJoinType { None = 0, Digital = 1, Analog = 2, Serial = 4, DigitalAnalog = Digital | Analog, DigitalSerial = Digital | Serial, AnalogSerial = Analog | Serial, DigitalAnalogSerial = Digital | Analog | Serial } ``` ### JoinDataComplete ```chsarp JoinDataComplete(JoinData data, JoinMetadata metadata); ``` `JoinDataComplete` represents the `JoinData` and the `JoinMetadata` in a single object. You can call an instance of `JoinDataComplete` to report any information about a specific join. In a device bridge, you would utilize the `JoinNumber` property to link a feature from the plugin to the EISC API. ### Example Join Map This is the join map for `IBasicCommunication` Devices ```cs namespace PepperDash.Essentials.Core.Bridges { public class IBasicCommunicationJoinMap : JoinMapBaseAdvanced { [JoinName("TextReceived")] public JoinDataComplete TextReceived = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Text Received From Remote Device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("SendText")] public JoinDataComplete SendText = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Text Sent To Remote Device", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SetPortConfig")] public JoinDataComplete SetPortConfig = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Label = "Set Port Config", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("Connect")] public JoinDataComplete Connect = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Connect", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("Connected")] public JoinDataComplete Connected = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("Status")] public JoinDataComplete Status = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); public IBasicCommunicationJoinMap(uint joinStart) : base(joinStart, typeof(IBasicCommunicationJoinMap)) { } } } ``` ### Returning Data on Join Maps A mechanism for printing join maps to console from a running Essentials program is built in to Essentials. Given a single Generic Communication device with a `joinStart` of 11 and a key of "Com-1", defined on a bridge with a key of "Bridge-1" and IPID of A0, the command `getjoinmap Bridge-1 Com-1` would return: ```sh Join Map for device 'Com-1' on EISC 'Bridge-1': GenericComm: Digitals: Found 2 Digital Joins Join Number: '11' | JoinSpan: '1' | Label : 'Connect' | Type: 'Digital' | Capabilities : 'FromSimpl' Join Number: '11' | JoinSpan: '1' | Label : 'Connected' | Type: 'Digital' | Capabilities : 'ToSimpl' Analogs: Found 1 Analog Joins Join Number: '11' | JoinSpan: '1' | Label : 'Status' | Type: 'Analog' | Capabilities : 'ToSimpl' Serials: Found 3 Serial Joins Join Number: '11' | JoinSpan: '1' | Label : 'Text Received From Remote Device' | Type: 'Serial' | Capabilities : 'FromSimpl' Join Number: '11' | JoinSpan: '1' | Label : 'Text Sent To Remote Device' | Type: 'Serial' | Capabilities : 'ToSimpl' Join Number: '12' | JoinSpan: '1' | Label : 'Set Port Config' | Type: 'Serial' | Capabilities : 'FromSimpl' ``` ================================================ FILE: docs/docs/usage/RelayOutput.md ================================================ # RelayOutput Relays can be bridged directly to SIMPL from any device that is both inlcuded within essentials and has a relay. Consider the following example. ```JSON { "template": { "roomInfo": [ {} ], "devices": [ { "key": "processor", "uid": 0, "type": "pro3", "name": "pro3", "group": "processor", "supportedConfigModes": [ "compliance", "essentials" ], "supportedSystemTypes": [ "hudType", "presType", "vtcType", "custom" ], "supportsCompliance": true, "properties": {} }, { "key": "Relay-1", "uid": 3, "name": "Relay 1", "group": "api", "type": "relayOutput", "properties": { "portDeviceKey" : "processor", "portNumber" : 1 } }, { "key": "Relay-2", "uid": 3, "name": "Relay 2", "group": "api", "type": "relayOutput", "properties": { "portDeviceKey" : "processor", "portNumber" : 2 } }, { "key": "deviceBridge", "uid": 4, "name": "BridgeToDevices", "group": "api", "type": "eiscapiadv", "properties": { "control": { "tcpSshProperties": { "address": "127.0.0.2", "port": 0 }, "ipid": "03", "method": "ipidTcp" }, "devices": [ { "deviceKey": "Relay-1", "joinStart": 1 }, { "deviceKey": "Relay-2", "joinStart": 2 } ] } } ] } } ``` ## RelayOutput Configuration Explanation This configuration is meant for a Pro3 device, and instantiates two relay ports and links them to an eisc bridge to another processor slot on ipid 3. Let's break down the ```Relay-1``` device. ```JSON { "key": "Relay-1", "uid": 3, "name": "Relay 1", "group": "api", "type": "relayOutput", "properties": { "portDeviceKey" : "processor", "portNumber" : 1 } } ``` **```Key```** The Key is a unique identifier for essentials. The key allows the device to be linked to other devices also defined by key. All Keys MUST be unique, as every device is added to a globally-accessible dictionary. If you have accidentally utilized the same key twice, Essentials will notify you during startup that there is an issue with the device. **```Uid```** The Uid is reserved for use with an PepperDash internal config generation tool, and is not useful to Essentials in any way. **```Name```** The Name a friendly name assigned to the device. Many devices pass this data to the bridge for utilization in SIMPL. **```Group```** Utilized in certain Essentials devices. In this case, the value is unimportant. **```Type```** The Type is the identifier for a specific type of device in Essentials. A list of all valid types can be reported by using the consolecommand ```gettypes``` in Essentials. In this case, the type is ```relayOutput```. This type is valid for any instance of a Relay Output. **```Properties```** These are the properties essential to the instantiation of the identified type. ### Properties There are two properties relevant to the instantiation of a relay device. **```portDeviceKey```** This property maps to the ```key``` of the device upon which the relay resides. **```portNumber```** This property maps to the number of the relay on the device you have mapped the relay device to. Even if the device has only a single relay, ```portNumber``` must be defined. ### The JoinMap The joinmap for a ```relayOutput``` device is comprised of a single digital join. ```cs namespace PepperDash.Essentials.Core.Bridges { public class GenericRelayControllerJoinMap : JoinMapBaseAdvanced { [JoinName("Relay")] public JoinDataComplete Relay = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Device Relay State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); public GenericRelayControllerJoinMap(uint joinStart) : base(joinStart, typeof(GenericRelayControllerJoinMap)) { } } } ``` ```Relay``` is a digital join that represents both the trigger and the feedback for the associated relay device. Its join is set to 1. ================================================ FILE: docs/docs/usage/SIMPL-Bridging-Updated.md ================================================ # Use with SIMPL Windows *** * [YouTube Video - SIMPL Windows in PepperDash Essentials](https://youtu.be/P2jNzsfpgJE) *** Essentials allows for devices defined within the SIMPL# Pro application to be bridged to a SIMPL Windows application over Ethernet Intersystem Communication (EISC). This allows a SIMPL Windows program to take advantage of some of the features of the SIMPL# Pro environment, without requiring the entire application to be written in C#. Some of the main advantages are: 1. The ability to instantiate devices from configuration. 2. The ability to leverage C# concepts to handle data intensive tasks (Serialization/Deserialization of JSON/XML, cyrptography, etc.). 3. The ability to reuse the same compiled SIMPL Windows program (regardless of target processor type) by offloading all the variables that may be room or hardware specific to Essentials. 4. The ability to handle multiple communciation types generically without changing the SIMPL Program (TCP/UDP/SSH/HTTP/HTTPS/CEC, etc.) 5. Much faster development cycle 6. Reduced processor overhead 7. Ability to easily share devices defined in Essentials between multiple other programs ## Implementation Bridges are devices that are defined within the devices array in the config file. They are unique devices with a specialized purpose: to act as a bridge between Essentials Devices and applications programmed traditionally in SIMPL Windows. This is accomplished by instantiating a Three Series Intersystem Communication symbol within the bridge device, and linking its Boolean/Ushort/String inputs and outputs to actions on one or multiple Essentials device(s). The definition for which joins map to which actions is defined within the device to be bridged to in a class that derives from JoinMapBase. Let's consider the following Essentials Configuration: ```JSON { "template": { "roomInfo": [ {} ], "devices": [ { "key": "processor", "uid": 1, "type": "pro3", "name": "PRO3 w/o cards", "group": "processor", "supportedConfigModes": [ "essentials" ], "supportedSystemTypes": [ "hudType", "presType", "vtcType", "custom" ], "supportsCompliance": true, "properties": { "numberOfComPorts": 6, "numberOfIrPorts": 8, "numberOfRelays": 8, "numberOfDIOPorts": 8 } }, { "key": "panasonicDisplay01", "type": "PanasonicThefDisplay", "name": "Main Display", "group": "displays", "uid": 2, "properties": { "id": "01", "inputNumber": 1, "outputNumber": 1, "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 9600, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "controlPortDevKey": "processor", "method": "com" } } }, { "key": "vtcComPort", "uid": 3, "name": "VTC Coms", "group": "comm", "type": "genericComm", "properties": { "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 38400, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 2, "controlPortDevKey": "processor", "method": "com" } } }, { "key": "deviceBridge", "uid": 4, "name": "BridgeToDevices", "group": "api", "type": "eiscApi", "properties": { "control": { "tcpSshProperties": { "address": "127.0.0.2", "port": 0 }, "ipid": "03", "method": "ipidTcp" }, "devices": [ { "deviceKey": "panasonicDisplay01", "joinStart": 1 }, { "deviceKey": "vtcComPort", "joinStart": 51 } ] } } ] } } ``` We have four Essentials Devices configured: 1. Pro3 with a Key of "processor" 1. Panasonic Display with a Key of "panasonicDisplay01" 1. Com port with a Key of "vtcComPort" 1. Bridge with a Key of "deviceBridge" We want to have access to the com port for VTC Control from SIMPL Windows and we want to control the display from SIMPL Windows. To accomplish this, we have created a bridge device and added the devices to be bridged to the "devices" array on the bridge. As you can see we define the device key and the join start, which will determine which joins we will use on the resulting EISC to interact with the devices. In the Bridge control properties we defined ipid 03, and we will need a corresponding Ethernet System Intercommunication in the SIMPL Windows program at ipid 03. Now that our devices have been built, we can refer to the device join maps to see which joins correspond to which actions. See below: ```cs namespace PepperDash.Essentials.Core.Bridges { public class DisplayControllerJoinMap : JoinMapBaseAdvanced { [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("PowerOff")] public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("PowerOn")] public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Label = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("IsTwoWayDisplay")] public JoinDataComplete IsTwoWayDisplay = new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Label = "Is Two Way Display", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("VolumeUp")] public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Label = "Volume Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("VolumeLevel")] public JoinDataComplete VolumeLevel = new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Label = "Volume Level", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); [JoinName("VolumeDown")] public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata() { Label = "Volume Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("VolumeMute")] public JoinDataComplete VolumeMute = new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata() { Label = "Volume Mute", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("VolumeMuteOn")] public JoinDataComplete VolumeMuteOn = new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata() { Label = "Volume Mute On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("VolumeMuteOff")] public JoinDataComplete VolumeMuteOff = new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata() { Label = "Volume Mute Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("InputSelectOffset")] public JoinDataComplete InputSelectOffset = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 10 }, new JoinMetadata() { Label = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("InputNamesOffset")] public JoinDataComplete InputNamesOffset = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 10 }, new JoinMetadata() { Label = "Input Names Offset", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("InputSelect")] public JoinDataComplete InputSelect = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Label = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); [JoinName("ButtonVisibilityOffset")] public JoinDataComplete ButtonVisibilityOffset = new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 10 }, new JoinMetadata() { Label = "Button Visibility Offset", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalSerial }); [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData() { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata() { Label = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); public DisplayControllerJoinMap(uint joinStart) : base(joinStart, typeof(CameraControllerJoinMap)) { } } } ``` We know that the Panasonic Display uses the DisplayControllerJoinMap class and can see the join numbers that will give us access to functionality in the Device. IsOnline = 50 PowerOff = 1 PowerOn = 2 IsTwoWayDisplay = 3 VolumeUp = 5 VolumeDown = 6 VolumeMute = 7 ```cs namespace PepperDash.Essentials.Core.Bridges { public class IBasicCommunicationJoinMap : JoinMapBaseAdvanced { [JoinName("TextReceived")] public JoinDataComplete TextReceived = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Text Received From Remote Device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("SendText")] public JoinDataComplete SendText = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Text Sent To Remote Device", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SetPortConfig")] public JoinDataComplete SetPortConfig = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Label = "Set Port Config", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("Connect")] public JoinDataComplete Connect = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Connect", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("Connected")] public JoinDataComplete Connected = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("Status")] public JoinDataComplete Status = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Label = "Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); public IBasicCommunicationJoinMap(uint joinStart) : base(joinStart, typeof(IBasicCommunicationJoinMap)) { } } } ``` Considering our Bridge config, we can see that the display controls will start at join 1, and the VTC Com port will start at join 51. The result is a single EISC that allows us to interact with our Essentials devices. To control diplay power from SIMPL Windows, we would connect Digital Signals to joins 1 & 2 on the EISC to control Display Power On & Off. To utilize the com port device, we would connect Serial Signals (VTC_TX$ and VTC_RX$) to join 51 on the EISC. You can refer to our [SIMPL Windows Bridging Example](https://github.com/PepperDash/EssentialsSIMPLWindowsBridgeExample) for a more complex example. Example device config: ## Notes 1. It is important to realize that there are no safety checks (yet) when assigning joinStarts in bridge configurations. If you were to put two devices on a bridge with overlapping joins, the most recently bridged join would overwrite previously bridged joins. For now it is on the programmer to ensure there are no conflicting join maps. 2. There is _no_ limit to the amount of times a device may be bridged to. You may have the same device on multiple bridges across multiple applications without problem. That being said, we recommend using common sense. Accessing a single com port for VTC control via multiple bridges may not be wise... 3. A bridge need not only bridge between applications on the same processor. A bridge may bridge to an application on a completely separate processor; simply define the ip address in the Bridge control properties accordingly. 4. For devices included in Essentials, you will be able to find defined join maps below. If you are building your own plugins, you will need to build the join map yourself. It would be beneficial to review the wiki entry on the [Feedback Class](~/docs/technical-docs/Feedback-Classes.md) for this. 5. When building plugins, we highly recommend reusing JoinMaps, as this will make code more easily interchangeable. For example; if you were to build a display plugin, we'd recommend you use/extend the existing `DisplayControllerJoinMap`. This way, you can swap plugins without needing any change on the SIMPL Windows side. This is extremely powerful when maintaining SIMPL Windows code bases for large deployments that may utilize differing equipment per room. If you can build a SIMPL Windows program that interacts with established join maps, you can swap out the device via config without any change needed to SIMPL Windows. 6. Related to item 5, you can use the same paradigm with respect to physical device communication. If you were to have a DSP device in some rooms communicating over RS232 and some via SSH, it would be trival to swap the device from a Com port to an SSH client in the Essentials Devicee Config and update the Bridge Config to brigde to the desired communication method. Again this would require no change on the SIMPL Windows side as long as you maintain the same join Start in the Bridge Device Configuration. ## Common Use Cases 1. There are 10 conference rooms that all operate the same, but have hardware differences that are impossible to account for in SIMPL Windows. For example, each room might have a DM-MD8X8 chassis, but the input and output cards aren't all in the same order, or they might be different models but function the same. You can use Essentials with a unique configuration file for each hardware configuration. 2. You have a floor of conference rooms that all share some centralized hardware like DSP, AV Routing and a shared CEN-GWEXER gateway with multiple GLS-OIR-CSM-EX-BATT occupancy sensors. All the shared hardware can be defined in the Essentials configuration and bridged over an EISC to each program that needs access. The same device can even be exposed to multiple programs over different EISCs. 3. You have a SIMPL program that works for many room types, but because some rooms have different models of processors than others (CP3/CP3N/AV3/PRO3/DMPS3 variants), you have to maintain several versions of the program, compiled for each processor model to maintain access to features like the System Monitor slot. You can use Essentials running in a slot on a processor to expose the System Monitor and many other features of the processor, regardless of model. Now you only need to maintain a single SIMPL program defined for your most complex processor application (ex. PRO3) ## Join Map Documentation [Join Map Documentation](~/docs/usage/JoinMaps.md) ## Device Type Join Maps Please note that these joinmaps _may_ be using a deprecated implementation. The implementation is valid but nonetheless frowned upon for new features and plugins. ### AirMediaController > supports: AM-200, AM-300 ### AppleTvController > supports: IR control of Apple TV ### CameraControlBase > supports: any camera that derives from CameraBase ### DisplayController > supports: IR controlled displays, any two way display driver that derives from PepperDash.Essentials.Core.DisplayBase ### DmChasisController > supports: All DM-MD-8x8/16x16/32x32 chassis, with or w/o DM-CPU3 Card ### DmRmcController > supports: All DM-RMC devices ### DmTxController > supports: All Dm-Tx devices ### DmpsAudioOutputController > supports: Program, Aux1, Aux2 outputs of all DMPS3 Control Systems ### DmpsRoutingController > supports: Av routing for all DMPS3 Control Systems ### GenericRelayController > supports: Any relay port on a Crestron Control System or Dm Endpoint ### GenericLightingJoinMap > supports: Devices derived from PepperDash.Essentials.Core.Lighting.LightingBase ### GlsOccupancySensorBase > supports: Any Crestron GLS-Type Occupancy sensor - single/dual type ### HdMdxxxCEController > supports: HD-MD-400-C-E, HD-MD-300-C-E, HD-MD-200-C-E, HD-MD-200-C-1G-E-B/W ### IBasicCommunication > supports: Any COM Port on a Control System or Dm Endpoint device, TCP Client, SSH Client, or UDP Server ### IDigitalInput > supports: Any Digital Input on a Control System, or DM Endpoint device ### SystemMonitorController > supports: Exposing the system monitor slot for any Control System ## Example SIMPL Windows Program We've provided an [example program](https://github.com/PepperDash/EssentialsSIMPLWindowsBridgeExample) for SIMPL Windows that works with the provided example Essentials configuration file [SIMPLBridgeExample_configurationFile.json](https://github.com/PepperDash/Essentials/blob/main/PepperDashEssentials/Example%20Configuration/SIMPLBridging/SIMPLBridgeExample_configurationFile.json). Load Essentials and the example SIMPL program to two slots on the same processor and you can get a better idea of how to take advantage of SIMPL Windows bridging. Next: [Essentials architecture](~/docs/technical-docs/Arch-summary.md) ================================================ FILE: docs/docs/usage/Standalone-Use.md ================================================ # Stand-alone Application Essentials was originally designed as a standalone SIMPL# Pro control system application and has developed into a versatile, pluggable application. This page describes how to use our built-in room types for a completely self-contained "one-slot" control program. By defining devices and a room in a JSON configuration file, Essentials can control an entire AV control system for a room. A file can be manually created in an IDE such as Visual Studio Code, or it can be generated by a friendly web-based configuration tool on [PepperDash Portal](http://pepperdash.com/products/), or some other configuration tool application, both requiring no knowledge of JSON. These tools step a user through building the necessary devices and setting to achieve a full working room. ## Plugins ### Devices Essentials supports device plugins for communicating with various devices using both standard Crestron CIP communications, Cresnet, SSH, or other TCP/IP-based communication methods. See [the Plugins section](~/docs/technical-docs/Plugins.md) for more details ### Rooms In order to tie together equipment into a unit that comprises what devices are used in a room, Essentials supports Room plugins. These plugins are similar to device plugins, in that they're loaded at runtime and allow for customization of business logic and behavior. They're loaded into a different section of the Device Manager, and can reference devices created by device plugins using the device's key. See Also: [[Supported Devices|Supported-Devices]] Next: [Simpl Windows bridging](~/docs/usage/SIMPL-Bridging-Updated.md) ================================================ FILE: docs/index.md ================================================ # Welcome to PepperDash Essentials! PepperDash Essentials is an open-source framework for control systems, built on Crestron's Simpl# Pro framework. It can be configured as a standalone program capable of running a wide variety of system designs and can also be used to augment other Crestron programs. Essentials is a collection of C# libraries that can be used in many ways. It is a 100% configuration-driven framework that can be extended to add different workflows and behaviors, either through the addition of new device-types and classes, or via a plug-in mechanism. The framework is a collection of things that are all related and interconnected, but in general do not have strong dependencies on each other. --- ## Get started - [Download an Essentials build or clone the repo](~/docs/Get-started.md) - [Get started](~/docs/Get-started.md) - [YouTube Video Series Playlist](https://youtube.com/playlist?list=PLKOoNNwgPFZdV5wDEBDZxTHu1KROspaBu) - [Discord Server](https://discord.gg/6Vh3ssDdPs) Or use the links to the left to navigate our documentation. --- ## Benefits - Runs on Crestron 3-Series, **4-Series** and VC-4 Control System platforms - Reduced hardware overhead compared to S+ and Simpl solutions - Quick development cycle - Shared resources made easily available - More flexibility with less code - Configurable using simple JSON files --- ## Collaboration Essentials is an open-source project and we encourage collaboration on this community project. For features that may not be useful to the greater community, or for just-plain learning, we want to remind developers to try writing plugins for Essentials. More information can be found here: [Plugins](~/docs/technical-docs/Plugins.md) ### Open-source-collaborative workflow The `main` branch always contain the latest stable version. The `development` branch is used for most development efforts. [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) will be used as the workflow for this collaborative project. To contribute, follow this process: 1. Fork this repository ([More Info](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks)) 2. Create a branch using standard GitFlow branch prefixes (feature/hotfix) followed by a descriptive name. - Example: `feature/add-awesomeness` or `hotfix/really-big-oops` - When working on a new feature or bugfix, branch from the `development` branch. When working on a hotfix, branch from `main`. 3. Make commits as necessary (often is better). And use concise, descriptive language, leveraging issue notation and/or [Closing Keywords](https://help.github.com/articles/closing-issues-using-keywords) to ensure any issues addressed by your work are referenced accordingly. 4. When the scope of the work for your branch is complete, make sure to update your branch in case further progress has been made since the repo was forked 5. Create a Pull Request to pull your branch into the appropriate branch in the main repository. 6. Your Pull Request will be reviewed by our team and evaluated for inclusion into the main repository. Next: [Get started](~/docs/Get-started.md) ================================================ FILE: docs/toc.yml ================================================ - name: Docs href: docs/ - name: API href: api/ ================================================ FILE: src/Directory.Build.props ================================================ 2.29.0-local $(Version) PepperDash Technology PepperDash Technology PepperDash Essentials Copyright © 2025 https://github.com/PepperDash/Essentials git Crestron; 4series ../../output True LICENSE.md README.md True true ================================================ FILE: src/Directory.Build.targets ================================================ true build; true build; true build; $(TargetDir)$(TargetName).$(Version).$(TargetFramework).clz $(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz $(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz ================================================ FILE: src/PepperDash.Core/ComTextHelper.cs ================================================ using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace PepperDash.Core { /// /// Helper class for formatting communication text and byte data for debugging purposes. /// public class ComTextHelper { /// /// Gets escaped text for a byte array /// /// /// string with all bytes escaped public static string GetEscapedText(byte[] bytes) { return string.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); } /// /// Gets escaped text for a string /// /// /// string with all bytes escaped public static string GetEscapedText(string text) { var bytes = Encoding.GetEncoding(28591).GetBytes(text); return string.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); } /// /// Gets debug text for a string /// /// /// string with all non-printable characters escaped public static string GetDebugText(string text) { return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value)); } } } ================================================ FILE: src/PepperDash.Core/Comm/CommunicationGather.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Core { /// /// Defines the string event handler for line events on the gather /// /// public delegate void LineReceivedHandler(string text); /// /// Attaches to IBasicCommunication as a text gather /// public class CommunicationGather { /// /// Event that fires when a line is received from the IBasicCommunication source. /// The event merely contains the text, not an EventArgs type class. /// public event EventHandler LineReceived; /// /// The communication port that this gathers on /// public ICommunicationReceiver Port { get; private set; } /// /// Default false. If true, the delimiter will be included in the line output /// events /// public bool IncludeDelimiter { get; set; } /// /// For receive buffer /// StringBuilder ReceiveBuffer = new StringBuilder(); /// /// Delimiter, like it says! /// char Delimiter; string[] StringDelimiters; /// /// Constructor for using a char delimiter /// /// /// public CommunicationGather(ICommunicationReceiver port, char delimiter) { Port = port; Delimiter = delimiter; port.TextReceived += new EventHandler(Port_TextReceived); } /// /// Constructor for using a single string delimiter /// /// /// public CommunicationGather(ICommunicationReceiver port, string delimiter) :this(port, new string[] { delimiter} ) { } /// /// Constructor for using an array of string delimiters /// /// /// public CommunicationGather(ICommunicationReceiver port, string[] delimiters) { Port = port; StringDelimiters = delimiters; port.TextReceived += Port_TextReceivedStringDelimiter; } /// /// Stop method /// public void Stop() { Port.TextReceived -= Port_TextReceived; Port.TextReceived -= Port_TextReceivedStringDelimiter; } /// /// Handler for raw data coming from port /// void Port_TextReceived(object sender, GenericCommMethodReceiveTextArgs args) { var handler = LineReceived; if (handler != null) { ReceiveBuffer.Append(args.Text); var str = ReceiveBuffer.ToString(); var lines = str.Split(Delimiter); if (lines.Length > 0) { for (int i = 0; i < lines.Length - 1; i++) { string strToSend = null; if (IncludeDelimiter) strToSend = lines[i] + Delimiter; else strToSend = lines[i]; handler(this, new GenericCommMethodReceiveTextArgs(strToSend)); } ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]); } } } /// /// /// /// /// void Port_TextReceivedStringDelimiter(object sender, GenericCommMethodReceiveTextArgs args) { var handler = LineReceived; if (handler != null) { // Receive buffer should either be empty or not contain the delimiter // If the line does not have a delimiter, append the ReceiveBuffer.Append(args.Text); var str = ReceiveBuffer.ToString(); // Case: Receiving DEVICE get version\x0d\0x0a+OK "value":"1234"\x0d\x0a // RX: DEV // Split: (1) "DEV" // RX: I // Split: (1) "DEVI" // RX: CE get version // Split: (1) "DEVICE get version" // RX: \x0d\x0a+OK "value":"1234"\x0d\x0a // Split: (2) DEVICE get version, +OK "value":"1234" // Iterate the delimiters and fire an event for any matching delimiter foreach (var delimiter in StringDelimiters) { var lines = Regex.Split(str, delimiter); if (lines.Length == 1) continue; for (int i = 0; i < lines.Length - 1; i++) { string strToSend = null; if (IncludeDelimiter) strToSend = lines[i] + delimiter; else strToSend = lines[i]; handler(this, new GenericCommMethodReceiveTextArgs(strToSend, delimiter)); } ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]); } } } /// /// Deconstructor. Disconnects from port TextReceived events. /// ~CommunicationGather() { Stop(); } } } ================================================ FILE: src/PepperDash.Core/Comm/CommunicationStreamDebugging.cs ================================================ using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Core { /// /// Controls the ability to disable/enable debugging of TX/RX data sent to/from a device with a built in timer to disable /// public class CommunicationStreamDebugging { /// /// Device Key that this instance configures /// public string ParentDeviceKey { get; private set; } /// /// Timer to disable automatically if not manually disabled /// private CTimer DebugExpiryPeriod; /// /// Gets or sets the DebugSetting /// public eStreamDebuggingSetting DebugSetting { get; private set; } private uint _DebugTimeoutInMs; private const uint _DefaultDebugTimeoutMin = 30; /// /// Timeout in Minutes /// public uint DebugTimeoutMinutes { get { return _DebugTimeoutInMs / 60000; } } /// /// Gets or sets the RxStreamDebuggingIsEnabled /// public bool RxStreamDebuggingIsEnabled { get; private set; } /// /// Indicates that transmit stream debugging is enabled /// public bool TxStreamDebuggingIsEnabled { get; private set; } /// /// Constructor /// /// public CommunicationStreamDebugging(string parentDeviceKey) { ParentDeviceKey = parentDeviceKey; } /// /// Sets the debugging setting and if not setting to off, assumes the default of 30 mintues /// /// /// /// SetDebuggingWithDefaultTimeout method /// public void SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting setting) { if (setting == eStreamDebuggingSetting.Off) { DisableDebugging(); return; } SetDebuggingWithSpecificTimeout(setting, _DefaultDebugTimeoutMin); } /// /// Sets the debugging setting for the specified number of minutes /// /// /// /// /// SetDebuggingWithSpecificTimeout method /// public void SetDebuggingWithSpecificTimeout(eStreamDebuggingSetting setting, uint minutes) { if (setting == eStreamDebuggingSetting.Off) { DisableDebugging(); return; } _DebugTimeoutInMs = minutes * 60000; StopDebugTimer(); DebugExpiryPeriod = new CTimer((o) => DisableDebugging(), _DebugTimeoutInMs); if ((setting & eStreamDebuggingSetting.Rx) == eStreamDebuggingSetting.Rx) RxStreamDebuggingIsEnabled = true; if ((setting & eStreamDebuggingSetting.Tx) == eStreamDebuggingSetting.Tx) TxStreamDebuggingIsEnabled = true; Debug.SetDeviceDebugSettings(ParentDeviceKey, setting); } /// /// Disabled debugging /// private void DisableDebugging() { StopDebugTimer(); Debug.SetDeviceDebugSettings(ParentDeviceKey, eStreamDebuggingSetting.Off); } private void StopDebugTimer() { RxStreamDebuggingIsEnabled = false; TxStreamDebuggingIsEnabled = false; if (DebugExpiryPeriod == null) { return; } DebugExpiryPeriod.Stop(); DebugExpiryPeriod.Dispose(); DebugExpiryPeriod = null; } } } ================================================ FILE: src/PepperDash.Core/Comm/ControlPropertiesConfig.cs ================================================ using System; using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace PepperDash.Core { /// /// Represents a ControlPropertiesConfig /// public class ControlPropertiesConfig { /// /// The method of control /// [JsonProperty("method")] [JsonConverter(typeof(StringEnumConverter))] public eControlMethod Method { get; set; } /// /// The key of the device that contains the control port /// [JsonProperty("controlPortDevKey", NullValueHandling = NullValueHandling.Ignore)] public string ControlPortDevKey { get; set; } /// /// The number of the control port on the device specified by ControlPortDevKey /// [JsonProperty("controlPortNumber", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value public uint? ControlPortNumber { get; set; } /// /// The name of the control port on the device specified by ControlPortDevKey /// [JsonProperty("controlPortName", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value public string ControlPortName { get; set; } /// /// Properties for ethernet based communications /// [JsonProperty("tcpSshProperties", NullValueHandling = NullValueHandling.Ignore)] public TcpSshPropertiesConfig TcpSshProperties { get; set; } /// /// The filename and path for the IR file /// [JsonProperty("irFile", NullValueHandling = NullValueHandling.Ignore)] public string IrFile { get; set; } /// /// The IpId of a Crestron device /// [JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)] public string IpId { get; set; } /// /// Readonly uint representation of the IpId /// [JsonIgnore] public uint IpIdInt { get { return Convert.ToUInt32(IpId, 16); } } /// /// Char indicating end of line /// [JsonProperty("endOfLineChar", NullValueHandling = NullValueHandling.Ignore)] public char EndOfLineChar { get; set; } /// /// Defaults to Environment.NewLine; /// [JsonProperty("endOfLineString", NullValueHandling = NullValueHandling.Ignore)] public string EndOfLineString { get; set; } /// /// Indicates /// [JsonProperty("deviceReadyResponsePattern", NullValueHandling = NullValueHandling.Ignore)] public string DeviceReadyResponsePattern { get; set; } /// /// Used when communcating to programs running in VC-4 /// [JsonProperty("roomId", NullValueHandling = NullValueHandling.Ignore)] public string RoomId { get; set; } /// /// Constructor /// public ControlPropertiesConfig() { } } } ================================================ FILE: src/PepperDash.Core/Comm/EventArgs.cs ================================================ /*PepperDash Technology Corp. Copyright: 2017 ------------------------------------ ***Notice of Ownership and Copyright*** The material in which this notice appears is the property of PepperDash Technology Corporation, which claims copyright under the laws of the United States of America in the entire body of material and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part, of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited. PepperDash Technology Corporation reserves all rights under applicable laws. ------------------------------------ */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; namespace PepperDash.Core { /// /// Delegate for notifying of socket status changes /// /// public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client); /// /// EventArgs class for socket status changes /// public class GenericSocketStatusChageEventArgs : EventArgs { /// /// Gets or sets the Client /// public ISocketStatus Client { get; private set; } /// /// /// /// public GenericSocketStatusChageEventArgs(ISocketStatus client) { Client = client; } /// /// S+ Constructor /// public GenericSocketStatusChageEventArgs() { } } /// /// Delegate for notifying of TCP Server state changes /// /// public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state); /// /// EventArgs class for TCP Server state changes /// public class GenericTcpServerStateChangedEventArgs : EventArgs { /// /// Gets or sets the State /// public ServerState State { get; private set; } /// /// /// /// public GenericTcpServerStateChangedEventArgs(ServerState state) { State = state; } /// /// S+ Constructor /// public GenericTcpServerStateChangedEventArgs() { } } /// /// Delegate for TCP Server socket status changes /// /// /// /// public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus); /// /// EventArgs for TCP server socket status changes /// public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs { /// /// /// public object Socket { get; private set; } /// /// /// public uint ReceivedFromClientIndex { get; private set; } /// /// /// public SocketStatus ClientStatus { get; set; } /// /// /// /// /// public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus) { Socket = socket; ClientStatus = clientStatus; } /// /// /// /// /// /// public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus) { Socket = socket; ReceivedFromClientIndex = clientIndex; ClientStatus = clientStatus; } /// /// S+ Constructor /// public GenericTcpServerSocketStatusChangeEventArgs() { } } /// /// EventArgs for TCP server com method receive text /// public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs { /// /// /// public uint ReceivedFromClientIndex { get; private set; } /// /// /// public ushort ReceivedFromClientIndexShort { get { return (ushort)ReceivedFromClientIndex; } } /// /// Gets or sets the Text /// public string Text { get; private set; } /// /// /// /// public GenericTcpServerCommMethodReceiveTextArgs(string text) { Text = text; } /// /// /// /// /// public GenericTcpServerCommMethodReceiveTextArgs(string text, uint clientIndex) { Text = text; ReceivedFromClientIndex = clientIndex; } /// /// S+ Constructor /// public GenericTcpServerCommMethodReceiveTextArgs() { } } /// /// EventArgs for TCP server client ready for communication /// public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs { /// /// /// public bool IsReady; /// /// /// /// public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady) { IsReady = isReady; } /// /// S+ Constructor /// public GenericTcpServerClientReadyForcommunicationsEventArgs() { } } /// /// EventArgs for UDP connected /// public class GenericUdpConnectedEventArgs : EventArgs { /// /// /// public ushort UConnected; /// /// /// public bool Connected; /// /// Constructor /// public GenericUdpConnectedEventArgs() { } /// /// /// /// public GenericUdpConnectedEventArgs(ushort uconnected) { UConnected = uconnected; } /// /// /// /// public GenericUdpConnectedEventArgs(bool connected) { Connected = connected; } } } ================================================ FILE: src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; namespace PepperDash.Core { /// /// A class to handle secure TCP/IP communications with a server /// public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect { private const string SplusKey = "Uninitialized Secure Tcp _client"; /// /// Stream debugging /// public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// Fires when data is received from the server and returns it as a Byte array /// public event EventHandler BytesReceived; /// /// Fires when data is received from the server and returns it as text /// public event EventHandler TextReceived; #region GenericSecureTcpIpClient Events & Delegates /// /// /// //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; public event EventHandler ConnectionChange; /// /// Auto reconnect evant handler /// public event EventHandler AutoReconnectTriggered; /// /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. /// public event EventHandler TextReceivedQueueInvoke; /// /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. /// public event EventHandler ClientReadyForCommunications; #endregion #region GenricTcpIpClient properties private string _hostname; /// /// Address of server /// public string Hostname { get { return _hostname; } set { _hostname = value; if (_client != null) { _client.AddressClientConnectedTo = _hostname; } } } /// /// Gets or sets the Port /// public int Port { get; set; } /// /// S+ helper /// public ushort UPort { get { return Convert.ToUInt16(Port); } set { Port = Convert.ToInt32(value); } } /// /// Defaults to 2000 /// public int BufferSize { get; set; } /// /// Internal secure client /// private SecureTCPClient _client; /// /// Bool showing if socket is connected /// public bool IsConnected { get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } /// /// S+ helper for IsConnected /// public ushort UIsConnected { get { return (ushort)(IsConnected ? 1 : 0); } } /// /// _client socket status Read only /// public SocketStatus ClientStatus { get { return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; } } /// /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event /// and IsConnected would be true when this == 2. /// public ushort UStatus { get { return (ushort)ClientStatus; } } /// /// Status text shows the message associated with socket status /// public string ClientStatusText { get { return ClientStatus.ToString(); } } /// /// Connection failure reason /// public string ConnectionFailure { get { return ClientStatus.ToString(); } } /// /// Gets or sets the AutoReconnect /// public bool AutoReconnect { get; set; } /// /// S+ helper for AutoReconnect /// public ushort UAutoReconnect { get { return (ushort)(AutoReconnect ? 1 : 0); } set { AutoReconnect = value == 1; } } /// /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 /// public int AutoReconnectIntervalMs { get; set; } /// /// Flag Set only when the disconnect method is called. /// bool DisconnectCalledByUser; /// /// /// public bool Connected { get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } // private Timer for auto reconnect private CTimer RetryTimer; #endregion #region GenericSecureTcpIpClient properties /// /// Gets or sets the SharedKeyRequired /// public bool SharedKeyRequired { get; set; } /// /// S+ helper for requires shared key bool /// public ushort USharedKeyRequired { set { if (value == 1) SharedKeyRequired = true; else SharedKeyRequired = false; } } /// /// Gets or sets the SharedKey /// public string SharedKey { get; set; } /// /// flag to show the client is waiting for the server to send the shared key /// private bool WaitingForSharedKeyResponse { get; set; } /// /// Semaphore on connect method /// bool IsTryingToConnect; /// /// Gets or sets the IsReadyForCommunication /// public bool IsReadyForCommunication { get; set; } /// /// S+ helper for IsReadyForCommunication /// public ushort UIsReadyForCommunication { get { return (ushort)(IsReadyForCommunication ? 1 : 0); } } /// /// Bool Heartbeat Enabled flag /// public bool HeartbeatEnabled { get; set; } /// /// S+ helper for Heartbeat Enabled /// public ushort UHeartbeatEnabled { get { return (ushort)(HeartbeatEnabled ? 1 : 0); } set { HeartbeatEnabled = value == 1; } } /// /// Heartbeat String /// public string HeartbeatString { get; set; } //public int HeartbeatInterval = 50000; /// /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ /// public int HeartbeatInterval { get; set; } /// /// Simpl+ Heartbeat Analog value in seconds /// public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatInterval = (value * 1000); } } CTimer HeartbeatSendTimer; CTimer HeartbeatAckTimer; // Used to force disconnection on a dead connect attempt CTimer ConnectFailTimer; CTimer WaitForSharedKey; private int ConnectionCount; bool ProgramIsStopping; /// /// Queue lock /// CCriticalSection DequeueLock = new CCriticalSection(); /// /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before /// calling initialize. /// public int ReceiveQueueSize { get; set; } /// /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before /// calling initialize. /// private CrestronQueue MessageQueue; #endregion #region Constructors /// /// Constructor /// /// /// /// /// public GenericSecureTcpIpClient(string key, string address, int port, int bufferSize) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); Hostname = address; Port = port; BufferSize = bufferSize; AutoReconnectIntervalMs = 5000; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); } /// /// Contstructor that sets all properties by calling the initialize method with a config object. /// /// /// public GenericSecureTcpIpClient(string key, TcpClientConfigObject clientConfigObject) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; Initialize(clientConfigObject); } /// /// Default constructor for S+ /// public GenericSecureTcpIpClient() : base(SplusKey) { CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; } /// /// Initialize method /// public void Initialize(string key) { Key = key; } /// /// Initialize called by the constructor that accepts a client config object. Can be called later to reset properties of client. /// /// public void Initialize(TcpClientConfigObject config) { if (config == null) { Debug.Console(0, this, "Could not initialize client with key: {0}", Key); return; } try { Hostname = config.Control.TcpSshProperties.Address; Port = config.Control.TcpSshProperties.Port > 0 && config.Control.TcpSshProperties.Port <= 65535 ? config.Control.TcpSshProperties.Port : 80; AutoReconnect = config.Control.TcpSshProperties.AutoReconnect; AutoReconnectIntervalMs = config.Control.TcpSshProperties.AutoReconnectIntervalMs > 1000 ? config.Control.TcpSshProperties.AutoReconnectIntervalMs : 5000; SharedKey = config.SharedKey; SharedKeyRequired = config.SharedKeyRequired; HeartbeatEnabled = config.HeartbeatRequired; HeartbeatRequiredIntervalInSeconds = config.HeartbeatRequiredIntervalInSeconds > 0 ? config.HeartbeatRequiredIntervalInSeconds : (ushort)15; HeartbeatString = string.IsNullOrEmpty(config.HeartbeatStringToMatch) ? "heartbeat" : config.HeartbeatStringToMatch; BufferSize = config.Control.TcpSshProperties.BufferSize > 2000 ? config.Control.TcpSshProperties.BufferSize : 2000; ReceiveQueueSize = config.ReceiveQueueSize > 20 ? config.ReceiveQueueSize : 20; MessageQueue = new CrestronQueue(ReceiveQueueSize); } catch (Exception ex) { Debug.Console(0, this, "Exception initializing client with key: {0}\rException: {1}", Key, ex); } } #endregion /// /// Handles closing this up when the program shuts down /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing _client connection"); ProgramIsStopping = true; Disconnect(); } } /// /// Deactivate the client /// /// /// /// Deactivate method /// public override bool Deactivate() { if (_client != null) { _client.SocketStatusChange -= this.Client_SocketStatusChange; DisconnectClient(); } return true; } /// /// Connect method /// public void Connect() { ConnectionCount++; Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); if (IsConnected) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); return; } if (IsTryingToConnect) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); return; } try { IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } if (string.IsNullOrEmpty(Hostname)) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); return; } if (Port < 1 || Port > 65535) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); return; } if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); return; } // clean up previous client if (_client != null) { Disconnect(); } DisconnectCalledByUser = false; _client = new SecureTCPClient(Hostname, Port, BufferSize); _client.SocketStatusChange += Client_SocketStatusChange; if (HeartbeatEnabled) _client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); _client.AddressClientConnectedTo = Hostname; _client.PortNumber = Port; // SecureClient = c; //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); ConnectFailTimer = new CTimer(o => { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); if (IsTryingToConnect) { IsTryingToConnect = false; //if (ConnectionHasHungCallback != null) //{ // ConnectionHasHungCallback(); //} //SecureClient.DisconnectFromServer(); //CheckClosedAndTryReconnect(); } }, 30000); Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); _client.ConnectToServerAsync(o => { Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); if (ConnectFailTimer != null) { ConnectFailTimer.Stop(); } IsTryingToConnect = false; if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) { Debug.Console(2, this, "_client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); o.ReceiveDataAsync(Receive); if (SharedKeyRequired) { WaitingForSharedKeyResponse = true; WaitForSharedKey = new CTimer(timer => { Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup o.DisconnectFromServer(); //CheckClosedAndTryReconnect(); //OnClientReadyForcommunications(false); // Should send false event }, 15000); } else { //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key //required this is called by the shared key being negotiated if (IsReadyForCommunication == false) { OnClientReadyForcommunications(true); // Key not required } } } else { Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); CheckClosedAndTryReconnect(); } }); } catch (Exception ex) { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "_client connection exception: {0}", ex.Message); IsTryingToConnect = false; CheckClosedAndTryReconnect(); } } /// /// Disconnect method /// public void Disconnect() { this.LogVerbose("Disconnect Called"); DisconnectCalledByUser = true; // stop trying reconnects, if we are if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } if (_client != null) { DisconnectClient(); this.LogDebug("Disconnected"); } } /// /// DisconnectClient method /// public void DisconnectClient() { if (_client == null) return; Debug.Console(1, this, "Disconnecting client"); if (IsConnected) _client.DisconnectFromServer(); // close up client. ALWAYS use this when disconnecting. IsTryingToConnect = false; Debug.Console(2, this, "Disconnecting _client {0}", DisconnectCalledByUser ? ", Called by user" : ""); _client.SocketStatusChange -= Client_SocketStatusChange; _client.Dispose(); _client = null; if (ConnectFailTimer == null) return; ConnectFailTimer.Stop(); ConnectFailTimer.Dispose(); ConnectFailTimer = null; } #region Methods /// /// Called from Connect failure or Socket Status change if /// auto reconnect and socket disconnected (Not disconnected by user) /// void CheckClosedAndTryReconnect() { if (_client != null) { Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); Disconnect(); } if (!DisconnectCalledByUser && AutoReconnect) { var halfInterval = AutoReconnectIntervalMs / 2; var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } if (AutoReconnectTriggered != null) AutoReconnectTriggered(this, new EventArgs()); RetryTimer = new CTimer(o => Connect(), rndTime); } } /// /// Receive callback /// /// /// void Receive(SecureTCPClient client, int numBytes) { if (numBytes > 0) { string str = string.Empty; var handler = TextReceivedQueueInvoke; try { var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); Debug.Console(2, this, "_client Received:\r--------\r{0}\r--------", str); if (!string.IsNullOrEmpty(checkHeartbeat(str))) { if (SharedKeyRequired && str == "SharedKey:") { Debug.Console(2, this, "Server asking for shared key, sending"); SendText(SharedKey + "\n"); } else if (SharedKeyRequired && str == "Shared Key Match") { StopWaitForSharedKeyTimer(); Debug.Console(2, this, "Shared key confirmed. Ready for communication"); OnClientReadyForcommunications(true); // Successful key exchange } else { //var bytesHandler = BytesReceived; //if (bytesHandler != null) // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); var textHandler = TextReceived; if (textHandler != null) textHandler(this, new GenericCommMethodReceiveTextArgs(str)); if (handler != null) { MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(str)); } } } } catch (Exception ex) { Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); } if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) client.ReceiveDataAsync(Receive); //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. if (handler != null) { var gotLock = DequeueLock.TryEnter(); if (gotLock) CrestronInvoke.BeginInvoke((o) => DequeueEvent()); } } else //JAG added this as I believe the error return is 0 bytes like the server. See help when hover on ReceiveAsync { client.DisconnectFromServer(); } } /// /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. /// It will dequeue items as they are enqueued automatically. /// void DequeueEvent() { try { while (true) { // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. var message = MessageQueue.Dequeue(); var handler = TextReceivedQueueInvoke; if (handler != null) { handler(this, message); } } } catch (Exception e) { this.LogException(e, "DequeueEvent error"); } // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. if (DequeueLock != null) { DequeueLock.Leave(); } } void HeartbeatStart() { if (HeartbeatEnabled) { this.LogVerbose("Starting Heartbeat"); if (HeartbeatSendTimer == null) { HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); } if (HeartbeatAckTimer == null) { HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); } } } void HeartbeatStop() { if (HeartbeatSendTimer != null) { Debug.Console(2, this, "Stoping Heartbeat Send"); HeartbeatSendTimer.Stop(); HeartbeatSendTimer = null; } if (HeartbeatAckTimer != null) { Debug.Console(2, this, "Stoping Heartbeat Ack"); HeartbeatAckTimer.Stop(); HeartbeatAckTimer = null; } } void SendHeartbeat(object notused) { this.SendText(HeartbeatString); Debug.Console(2, this, "Sending Heartbeat"); } //private method to check heartbeat requirements and start or reset timer string checkHeartbeat(string received) { try { if (HeartbeatEnabled) { if (!string.IsNullOrEmpty(HeartbeatString)) { var remainingText = received.Replace(HeartbeatString, ""); var noDelimiter = received.Trim(new char[] { '\r', '\n' }); if (noDelimiter.Contains(HeartbeatString)) { if (HeartbeatAckTimer != null) { HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } else { HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); } Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); return remainingText; } } } } catch (Exception ex) { Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } return received; } void HeartbeatAckTimerFail(object o) { try { if (IsConnected) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); SendText("Heartbeat not received by server, closing connection"); CheckClosedAndTryReconnect(); } } catch (Exception ex) { ErrorLog.Error("Heartbeat timeout Error on _client: {0}, {1}", Key, ex); } } /// /// /// void StopWaitForSharedKeyTimer() { if (WaitForSharedKey != null) { WaitForSharedKey.Stop(); WaitForSharedKey = null; } } /// /// SendText method /// public void SendText(string text) { if (!string.IsNullOrEmpty(text)) { try { var bytes = Encoding.GetEncoding(28591).GetBytes(text); if (_client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) { _client.SendDataAsync(bytes, bytes.Length, (c, n) => { // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? if (n <= 0) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); } }); } } catch (Exception ex) { Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); } } } /// /// SendBytes method /// public void SendBytes(byte[] bytes) { if (bytes.Length > 0) { try { if (_client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) _client.SendData(bytes, bytes.Length); } catch (Exception ex) { Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); } } } /// /// SocketStatusChange Callback /// /// /// void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) { if (ProgramIsStopping) { ProgramIsStopping = false; return; } try { Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); OnConnectionChange(); // The client could be null or disposed by this time... if (_client == null || _client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { HeartbeatStop(); OnClientReadyForcommunications(false); // socket has gone low CheckClosedAndTryReconnect(); } } catch (Exception ex) { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); } } /// /// Helper for ConnectionChange event /// void OnConnectionChange() { var handler = ConnectionChange; if (handler == null) return; handler(this, new GenericSocketStatusChageEventArgs(this)); } /// /// Helper to fire ClientReadyForCommunications event /// void OnClientReadyForcommunications(bool isReady) { IsReadyForCommunication = isReady; if (IsReadyForCommunication) HeartbeatStart(); var handler = ClientReadyForCommunications; if (handler == null) return; handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); } #endregion } } ================================================ FILE: src/PepperDash.Core/Comm/GenericSecureTcpIpClient_ForServer.cs ================================================ /*PepperDash Technology Corp. JAG Copyright: 2017 ------------------------------------ ***Notice of Ownership and Copyright*** The material in which this notice appears is the property of PepperDash Technology Corporation, which claims copyright under the laws of the United States of America in the entire body of material and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part, of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited. PepperDash Technology Corporation reserves all rights under applicable laws. ------------------------------------ */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; namespace PepperDash.Core { /// /// Generic secure TCP/IP client for server /// public class GenericSecureTcpIpClient_ForServer : Device, IAutoReconnect { /// /// Band aid delegate for choked server /// internal delegate void ConnectionHasHungCallbackDelegate(); #region Events //public event EventHandler BytesReceived; /// /// Notifies of text received /// public event EventHandler TextReceived; /// /// Notifies of auto reconnect sequence triggered /// public event EventHandler AutoReconnectTriggered; /// /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. /// public event EventHandler TextReceivedQueueInvoke; /// /// Notifies of socket status change /// public event EventHandler ConnectionChange; /// /// This is something of a band-aid callback. If the client times out during the connection process, because the server /// is stuck, this will fire. It is intended to be used by the Server class monitor client, to help /// keep a watch on the server and reset it if necessary. /// internal ConnectionHasHungCallbackDelegate ConnectionHasHungCallback; /// /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. /// public event EventHandler ClientReadyForCommunications; #endregion #region Properties & Variables /// /// Address of server /// public string Hostname { get; set; } /// /// Gets or sets the Port /// public int Port { get; set; } /// /// S+ helper /// public ushort UPort { get { return Convert.ToUInt16(Port); } set { Port = Convert.ToInt32(value); } } /// /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class /// public bool SharedKeyRequired { get; set; } /// /// S+ helper for requires shared key bool /// public ushort USharedKeyRequired { set { if (value == 1) SharedKeyRequired = true; else SharedKeyRequired = false; } } /// /// Gets or sets the SharedKey /// public string SharedKey { get; set; } /// /// flag to show the client is waiting for the server to send the shared key /// private bool WaitingForSharedKeyResponse { get; set; } /// /// Gets or sets the BufferSize /// public int BufferSize { get; set; } /// /// Semaphore on connect method /// bool IsTryingToConnect; /// /// Bool showing if socket is connected /// public bool IsConnected { get { if (Client != null) return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; else return false; } } /// /// S+ helper for IsConnected /// public ushort UIsConnected { get { return (ushort)(IsConnected ? 1 : 0); } } /// /// Bool showing if socket is ready for communication after shared key exchange /// public bool IsReadyForCommunication { get; set; } /// /// S+ helper for IsReadyForCommunication /// public ushort UIsReadyForCommunication { get { return (ushort)(IsReadyForCommunication ? 1 : 0); } } /// /// Client socket status Read only /// public SocketStatus ClientStatus { get { if (Client != null) return Client.ClientStatus; else return SocketStatus.SOCKET_STATUS_NO_CONNECT; } } /// /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event /// and IsConnected would be true when this == 2. /// public ushort UStatus { get { return (ushort)ClientStatus; } } /// /// Status text shows the message associated with socket status /// public string ClientStatusText { get { return ClientStatus.ToString(); } } /// /// bool to track if auto reconnect should be set on the socket /// public bool AutoReconnect { get; set; } /// /// S+ helper for AutoReconnect /// public ushort UAutoReconnect { get { return (ushort)(AutoReconnect ? 1 : 0); } set { AutoReconnect = value == 1; } } /// /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 /// public int AutoReconnectIntervalMs { get; set; } /// /// Flag Set only when the disconnect method is called. /// bool DisconnectCalledByUser; /// /// private Timer for auto reconnect /// CTimer RetryTimer; /// /// /// public bool HeartbeatEnabled { get; set; } /// /// /// public ushort UHeartbeatEnabled { get { return (ushort)(HeartbeatEnabled ? 1 : 0); } set { HeartbeatEnabled = value == 1; } } /// /// /// public string HeartbeatString { get; set; } //public int HeartbeatInterval = 50000; /// /// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+ /// public int HeartbeatInterval { get; set; } /// /// Simpl+ Heartbeat Analog value in seconds /// public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatInterval = (value * 1000); } } CTimer HeartbeatSendTimer; CTimer HeartbeatAckTimer; /// /// Used to force disconnection on a dead connect attempt /// CTimer ConnectFailTimer; CTimer WaitForSharedKey; private int ConnectionCount; /// /// Internal secure client /// SecureTCPClient Client; bool ProgramIsStopping; /// /// Queue lock /// CCriticalSection DequeueLock = new CCriticalSection(); /// /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before /// calling initialize. /// public int ReceiveQueueSize { get; set; } /// /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before /// calling initialize. /// private CrestronQueue MessageQueue; #endregion #region Constructors /// /// Constructor /// /// /// /// /// public GenericSecureTcpIpClient_ForServer(string key, string address, int port, int bufferSize) : base(key) { CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); Hostname = address; Port = port; BufferSize = bufferSize; AutoReconnectIntervalMs = 5000; } /// /// Constructor for S+ /// public GenericSecureTcpIpClient_ForServer() : base("Uninitialized Secure Tcp Client For Server") { CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; } /// /// Contstructor that sets all properties by calling the initialize method with a config object. /// /// /// public GenericSecureTcpIpClient_ForServer(string key, TcpClientConfigObject clientConfigObject) : base(key) { CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); Initialize(clientConfigObject); } #endregion #region Methods /// /// Initialize method /// public void Initialize(string key) { Key = key; } /// /// Initialize called by the constructor that accepts a client config object. Can be called later to reset properties of client. /// /// public void Initialize(TcpClientConfigObject clientConfigObject) { try { if (clientConfigObject != null) { var TcpSshProperties = clientConfigObject.Control.TcpSshProperties; Hostname = TcpSshProperties.Address; AutoReconnect = TcpSshProperties.AutoReconnect; AutoReconnectIntervalMs = TcpSshProperties.AutoReconnectIntervalMs > 1000 ? TcpSshProperties.AutoReconnectIntervalMs : 5000; SharedKey = clientConfigObject.SharedKey; SharedKeyRequired = clientConfigObject.SharedKeyRequired; HeartbeatEnabled = clientConfigObject.HeartbeatRequired; HeartbeatRequiredIntervalInSeconds = clientConfigObject.HeartbeatRequiredIntervalInSeconds > 0 ? clientConfigObject.HeartbeatRequiredIntervalInSeconds : (ushort)15; HeartbeatString = string.IsNullOrEmpty(clientConfigObject.HeartbeatStringToMatch) ? "heartbeat" : clientConfigObject.HeartbeatStringToMatch; Port = TcpSshProperties.Port; BufferSize = TcpSshProperties.BufferSize > 2000 ? TcpSshProperties.BufferSize : 2000; ReceiveQueueSize = clientConfigObject.ReceiveQueueSize > 20 ? clientConfigObject.ReceiveQueueSize : 20; MessageQueue = new CrestronQueue(ReceiveQueueSize); } else { ErrorLog.Error("Could not initialize client with key: {0}", Key); } } catch { ErrorLog.Error("Could not initialize client with key: {0}", Key); } } /// /// Handles closing this up when the program shuts down /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing Client connection"); ProgramIsStopping = true; Disconnect(); } } /// /// Connect method /// public void Connect() { ConnectionCount++; Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); if (IsConnected) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); return; } if (IsTryingToConnect) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); return; } try { IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } if (string.IsNullOrEmpty(Hostname)) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); return; } if (Port < 1 || Port > 65535) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); return; } if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); return; } // clean up previous client if (Client != null) { Cleanup(); } DisconnectCalledByUser = false; Client = new SecureTCPClient(Hostname, Port, BufferSize); Client.SocketStatusChange += Client_SocketStatusChange; if (HeartbeatEnabled) Client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); Client.AddressClientConnectedTo = Hostname; Client.PortNumber = Port; // SecureClient = c; //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); ConnectFailTimer = new CTimer(o => { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); if (IsTryingToConnect) { IsTryingToConnect = false; //if (ConnectionHasHungCallback != null) //{ // ConnectionHasHungCallback(); //} //SecureClient.DisconnectFromServer(); //CheckClosedAndTryReconnect(); } }, 30000); Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); Client.ConnectToServerAsync(o => { Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); if (ConnectFailTimer != null) { ConnectFailTimer.Stop(); } IsTryingToConnect = false; if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) { Debug.Console(2, this, "Client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); o.ReceiveDataAsync(Receive); if (SharedKeyRequired) { WaitingForSharedKeyResponse = true; WaitForSharedKey = new CTimer(timer => { Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup o.DisconnectFromServer(); //CheckClosedAndTryReconnect(); //OnClientReadyForcommunications(false); // Should send false event }, 15000); } else { //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key //required this is called by the shared key being negotiated if (IsReadyForCommunication == false) { OnClientReadyForcommunications(true); // Key not required } } } else { Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); CheckClosedAndTryReconnect(); } }); } catch (Exception ex) { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Client connection exception: {0}", ex.Message); IsTryingToConnect = false; CheckClosedAndTryReconnect(); } } /// /// Disconnect method /// public void Disconnect() { this.LogVerbose("Disconnect Called"); DisconnectCalledByUser = true; if (IsConnected) { Client.DisconnectFromServer(); } if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } Cleanup(); } /// /// Internal call to close up client. ALWAYS use this when disconnecting. /// void Cleanup() { IsTryingToConnect = false; if (Client != null) { //SecureClient.DisconnectFromServer(); Debug.Console(2, this, "Disconnecting Client {0}", DisconnectCalledByUser ? ", Called by user" : ""); Client.SocketStatusChange -= Client_SocketStatusChange; Client.Dispose(); Client = null; } if (ConnectFailTimer != null) { ConnectFailTimer.Stop(); ConnectFailTimer.Dispose(); ConnectFailTimer = null; } } /// ff /// Called from Connect failure or Socket Status change if /// auto reconnect and socket disconnected (Not disconnected by user) /// void CheckClosedAndTryReconnect() { if (Client != null) { Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); Cleanup(); } if (!DisconnectCalledByUser && AutoReconnect) { var halfInterval = AutoReconnectIntervalMs / 2; var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } if(AutoReconnectTriggered != null) AutoReconnectTriggered(this, new EventArgs()); RetryTimer = new CTimer(o => Connect(), rndTime); } } /// /// Receive callback /// /// /// void Receive(SecureTCPClient client, int numBytes) { if (numBytes > 0) { string str = string.Empty; var handler = TextReceivedQueueInvoke; try { var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); Debug.Console(2, this, "Client Received:\r--------\r{0}\r--------", str); if (!string.IsNullOrEmpty(checkHeartbeat(str))) { if (SharedKeyRequired && str == "SharedKey:") { Debug.Console(2, this, "Server asking for shared key, sending"); SendText(SharedKey + "\n"); } else if (SharedKeyRequired && str == "Shared Key Match") { StopWaitForSharedKeyTimer(); Debug.Console(2, this, "Shared key confirmed. Ready for communication"); OnClientReadyForcommunications(true); // Successful key exchange } else { //var bytesHandler = BytesReceived; //if (bytesHandler != null) // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); var textHandler = TextReceived; if (textHandler != null) textHandler(this, new GenericTcpServerCommMethodReceiveTextArgs(str)); if (handler != null) { MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(str)); } } } } catch (Exception ex) { Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); } if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) client.ReceiveDataAsync(Receive); //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. if (handler != null) { var gotLock = DequeueLock.TryEnter(); if (gotLock) CrestronInvoke.BeginInvoke((o) => DequeueEvent()); } } else //JAG added this as I believe the error return is 0 bytes like the server. See help when hover on ReceiveAsync { client.DisconnectFromServer(); } } /// /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. /// It will dequeue items as they are enqueued automatically. /// void DequeueEvent() { try { while (true) { // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. var message = MessageQueue.Dequeue(); var handler = TextReceivedQueueInvoke; if (handler != null) { handler(this, message); } } } catch (Exception e) { this.LogException(e, "DequeueEvent error"); } // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. if (DequeueLock != null) { DequeueLock.Leave(); } } void HeartbeatStart() { if (HeartbeatEnabled) { Debug.Console(2, this, "Starting Heartbeat"); if (HeartbeatSendTimer == null) { HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); } if (HeartbeatAckTimer == null) { HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); } } } void HeartbeatStop() { if (HeartbeatSendTimer != null) { Debug.Console(2, this, "Stoping Heartbeat Send"); HeartbeatSendTimer.Stop(); HeartbeatSendTimer = null; } if (HeartbeatAckTimer != null) { Debug.Console(2, this, "Stoping Heartbeat Ack"); HeartbeatAckTimer.Stop(); HeartbeatAckTimer = null; } } void SendHeartbeat(object notused) { this.SendText(HeartbeatString); Debug.Console(2, this, "Sending Heartbeat"); } //private method to check heartbeat requirements and start or reset timer string checkHeartbeat(string received) { try { if (HeartbeatEnabled) { if (!string.IsNullOrEmpty(HeartbeatString)) { var remainingText = received.Replace(HeartbeatString, ""); var noDelimiter = received.Trim(new char[] { '\r', '\n' }); if (noDelimiter.Contains(HeartbeatString)) { if (HeartbeatAckTimer != null) { HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } else { HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); } Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); return remainingText; } } } } catch (Exception ex) { Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } return received; } void HeartbeatAckTimerFail(object o) { try { if (IsConnected) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); SendText("Heartbeat not received by server, closing connection"); CheckClosedAndTryReconnect(); } } catch (Exception ex) { ErrorLog.Error("Heartbeat timeout Error on Client: {0}, {1}", Key, ex); } } /// /// /// void StopWaitForSharedKeyTimer() { if (WaitForSharedKey != null) { WaitForSharedKey.Stop(); WaitForSharedKey = null; } } /// /// SendText method /// public void SendText(string text) { if (!string.IsNullOrEmpty(text)) { try { var bytes = Encoding.GetEncoding(28591).GetBytes(text); if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) { Client.SendDataAsync(bytes, bytes.Length, (c, n) => { // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? if (n <= 0) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); } }); } } catch (Exception ex) { Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); } } } /// /// SendBytes method /// public void SendBytes(byte[] bytes) { if (bytes.Length > 0) { try { if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) Client.SendData(bytes, bytes.Length); } catch (Exception ex) { Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); } } } /// /// SocketStatusChange Callback /// /// /// void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus) { if (ProgramIsStopping) { ProgramIsStopping = false; return; } try { Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); OnConnectionChange(); // The client could be null or disposed by this time... if (Client == null || Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { HeartbeatStop(); OnClientReadyForcommunications(false); // socket has gone low CheckClosedAndTryReconnect(); } } catch (Exception ex) { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); } } /// /// Helper for ConnectionChange event /// void OnConnectionChange() { var handler = ConnectionChange; if (handler != null) ConnectionChange(this, new GenericTcpServerSocketStatusChangeEventArgs(this, Client.ClientStatus)); } /// /// Helper to fire ClientReadyForCommunications event /// void OnClientReadyForcommunications(bool isReady) { IsReadyForCommunication = isReady; if (this.IsReadyForCommunication) { HeartbeatStart(); } var handler = ClientReadyForCommunications; if (handler != null) handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); } #endregion } } ================================================ FILE: src/PepperDash.Core/Comm/GenericSecureTcpIpServer.cs ================================================ /*PepperDash Technology Corp. JAG Copyright: 2017 ------------------------------------ ***Notice of Ownership and Copyright*** The material in which this notice appears is the property of PepperDash Technology Corporation, which claims copyright under the laws of the United States of America in the entire body of material and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part, of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited. PepperDash Technology Corporation reserves all rights under applicable laws. ------------------------------------ */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; namespace PepperDash.Core { /// /// Generic secure TCP/IP server /// public class GenericSecureTcpIpServer : Device { #region Events /// /// Event for Receiving text /// public event EventHandler TextReceived; /// /// Event for Receiving text. Once subscribed to this event the receive callback will start a thread that dequeues the messages and invokes the event on a new thread. /// It is not recommended to use both the TextReceived event and the TextReceivedQueueInvoke event. /// public event EventHandler TextReceivedQueueInvoke; /// /// Event for client connection socket status change /// public event EventHandler ClientConnectionChange; /// /// Event for Server State Change /// public event EventHandler ServerStateChange; /// /// For a server with a pre shared key, this will fire after the communication is established and the key exchange is complete. If no shared key, this will fire /// after connection is successful. Use this event to know when the client is ready for communication to avoid stepping on shared key. /// public event EventHandler ServerClientReadyForCommunications; /// /// A band aid event to notify user that the server has choked. /// public ServerHasChokedCallbackDelegate ServerHasChoked { get; set; } /// /// Delegate for ServerHasChokedCallbackDelegate /// public delegate void ServerHasChokedCallbackDelegate(); #endregion #region Properties/Variables /// /// Server listen lock /// CCriticalSection ServerCCSection = new CCriticalSection(); /// /// Queue lock /// CCriticalSection DequeueLock = new CCriticalSection(); /// /// Receive Queue size. Defaults to 20. Will set to 20 if QueueSize property is less than 20. Use constructor or set queue size property before /// calling initialize. /// public int ReceiveQueueSize { get; set; } /// /// Queue to temporarily store received messages with the source IP and Port info. Defaults to size 20. Use constructor or set queue size property before /// calling initialize. /// private CrestronQueue MessageQueue; /// /// A bandaid client that monitors whether the server is reachable /// GenericSecureTcpIpClient_ForServer MonitorClient; /// /// Timer to operate the bandaid monitor client in a loop. /// CTimer MonitorClientTimer; /// /// /// int MonitorClientFailureCount; /// /// Gets or sets the MonitorClientMaxFailureCount /// public int MonitorClientMaxFailureCount { get; set; } /// /// Text representation of the Socket Status enum values for the server /// public string Status { get { if (SecureServer != null) return SecureServer.State.ToString(); return ServerState.SERVER_NOT_LISTENING.ToString(); } } /// /// Bool showing if socket is connected /// public bool IsConnected { get { if (SecureServer != null) return (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED; return false; //return (Secure ? SecureServer != null : UnsecureServer != null) && //(Secure ? (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED : // (UnsecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED); } } /// /// S+ helper for IsConnected /// public ushort UIsConnected { get { return (ushort)(IsConnected ? 1 : 0); } } /// /// Bool showing if socket is connected /// public bool IsListening { get { if (SecureServer != null) return (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING; else return false; //return (Secure ? SecureServer != null : UnsecureServer != null) && //(Secure ? (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING : // (UnsecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING); } } /// /// S+ helper for IsConnected /// public ushort UIsListening { get { return (ushort)(IsListening ? 1 : 0); } } /// /// Max number of clients this server will allow for connection. Crestron max is 64. This number should be less than 65 /// public ushort MaxClients { get; set; } // should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable /// /// Number of clients currently connected. /// public ushort NumberOfClientsConnected { get { if (SecureServer != null) return (ushort)SecureServer.NumberOfClientsConnected; return 0; } } /// /// Gets or sets the Port /// public int Port { get; set; } /// /// S+ helper for Port /// public ushort UPort { get { return Convert.ToUInt16(Port); } set { Port = Convert.ToInt32(value); } } /// /// Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client /// public bool SharedKeyRequired { get; set; } /// /// S+ helper for requires shared key bool /// public ushort USharedKeyRequired { set { if (value == 1) SharedKeyRequired = true; else SharedKeyRequired = false; } } /// /// Gets or sets the SharedKey /// public string SharedKey { get; set; } /// /// Heartbeat Required bool sets whether server disconnects client if heartbeat is not received /// public bool HeartbeatRequired { get; set; } /// /// S+ Helper for Heartbeat Required /// public ushort UHeartbeatRequired { set { if (value == 1) HeartbeatRequired = true; else HeartbeatRequired = false; } } /// /// Gets or sets the HeartbeatRequiredIntervalMs /// public int HeartbeatRequiredIntervalMs { get; set; } /// /// Simpl+ Heartbeat Analog value in seconds /// public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } } /// /// Gets or sets the HeartbeatStringToMatch /// public string HeartbeatStringToMatch { get; set; } //private timers for Heartbeats per client Dictionary HeartbeatTimerDictionary = new Dictionary(); //flags to show the secure server is waiting for client at index to send the shared key List WaitingForSharedKey = new List(); List ClientReadyAfterKeyExchange = new List(); /// /// The connected client indexes /// public List ConnectedClientsIndexes = new List(); /// /// Gets or sets the BufferSize /// public int BufferSize { get; set; } /// /// Private flag to note that the server has stopped intentionally /// private bool ServerStopped { get; set; } //Servers SecureTCPServer SecureServer; /// /// /// bool ProgramIsStopping; #endregion #region Constructors /// /// constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. /// public GenericSecureTcpIpServer() : base("Uninitialized Secure TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); BufferSize = 2000; MonitorClientMaxFailureCount = 3; } /// /// constructor with debug key set at instantiation. Make sure to set all properties before listening. /// /// public GenericSecureTcpIpServer(string key) : base("Uninitialized Secure TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); BufferSize = 2000; MonitorClientMaxFailureCount = 3; Key = key; } /// /// Contstructor that sets all properties by calling the initialize method with a config object. This does set Queue size. /// /// public GenericSecureTcpIpServer(TcpServerConfigObject serverConfigObject) : base("Uninitialized Secure TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); BufferSize = 2000; MonitorClientMaxFailureCount = 3; Initialize(serverConfigObject); } #endregion #region Methods - Server Actions /// /// KillServer method /// public void KillServer() { ServerStopped = true; if (MonitorClient != null) { MonitorClient.Disconnect(); } DisconnectAllClientsForShutdown(); StopListening(); } /// /// Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+ /// /// /// /// Initialize method /// public void Initialize(string key) { Key = key; } /// /// Initialze the server /// /// public void Initialize(TcpServerConfigObject serverConfigObject) { try { if (serverConfigObject != null || string.IsNullOrEmpty(serverConfigObject.Key)) { Key = serverConfigObject.Key; MaxClients = serverConfigObject.MaxClients; Port = serverConfigObject.Port; SharedKeyRequired = serverConfigObject.SharedKeyRequired; SharedKey = serverConfigObject.SharedKey; HeartbeatRequired = serverConfigObject.HeartbeatRequired; HeartbeatRequiredIntervalInSeconds = serverConfigObject.HeartbeatRequiredIntervalInSeconds; HeartbeatStringToMatch = serverConfigObject.HeartbeatStringToMatch; BufferSize = serverConfigObject.BufferSize; ReceiveQueueSize = serverConfigObject.ReceiveQueueSize > 20 ? serverConfigObject.ReceiveQueueSize : 20; MessageQueue = new CrestronQueue(ReceiveQueueSize); } else { ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); } } catch { ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); } } /// /// Listen method /// public void Listen() { ServerCCSection.Enter(); try { if (Port < 1 || Port > 65535) { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': Invalid port", Key); ErrorLog.Warn(string.Format("Server '{0}': Invalid port", Key)); return; } if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': No Shared Key set", Key); ErrorLog.Warn(string.Format("Server '{0}': No Shared Key set", Key)); return; } if (SecureServer == null) { SecureServer = new SecureTCPServer(Port, MaxClients); if (HeartbeatRequired) SecureServer.SocketSendOrReceiveTimeOutInMs = (this.HeartbeatRequiredIntervalMs * 5); SecureServer.HandshakeTimeout = 30; SecureServer.SocketStatusChange += new SecureTCPServerSocketStatusChangeEventHandler(SecureServer_SocketStatusChange); } else { SecureServer.PortNumber = Port; } ServerStopped = false; // Start the listner SocketErrorCodes status = SecureServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback); if (status != SocketErrorCodes.SOCKET_OPERATION_PENDING) { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Error starting WaitForConnectionAsync {0}", status); } else { ServerStopped = false; } OnServerStateChange(SecureServer.State); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Secure Server Status: {0}, Socket Status: {1}", SecureServer.State, SecureServer.ServerSocketStatus); ServerCCSection.Leave(); } catch (Exception ex) { ServerCCSection.Leave(); ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); } } /// /// StopListening method /// public void StopListening() { try { Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Stopping Listener"); if (SecureServer != null) { SecureServer.Stop(); Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server State: {0}", SecureServer.State); OnServerStateChange(SecureServer.State); } ServerStopped = true; } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error stopping server. Error: {0}", ex); } } /// /// Disconnects Client /// /// /// /// DisconnectClient method /// public void DisconnectClient(uint client) { try { SecureServer.Disconnect(client); Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", client); } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", client, ex); } } /// /// DisconnectAllClientsForShutdown method /// public void DisconnectAllClientsForShutdown() { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting All Clients"); if (SecureServer != null) { SecureServer.SocketStatusChange -= SecureServer_SocketStatusChange; foreach (var index in ConnectedClientsIndexes.ToList()) // copy it here so that it iterates properly { var i = index; if (!SecureServer.ClientConnected(index)) continue; try { SecureServer.Disconnect(i); Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", i); } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", i, ex); } } Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server Status: {0}", SecureServer.ServerSocketStatus); } Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); ConnectedClientsIndexes.Clear(); if (!ProgramIsStopping) { OnConnectionChange(); OnServerStateChange(SecureServer.State); //State shows both listening and connected } // var o = new { }; } /// /// Broadcast text from server to all connected clients /// /// /// /// BroadcastText method /// public void BroadcastText(string text) { CCriticalSection CCBroadcast = new CCriticalSection(); CCBroadcast.Enter(); try { if (ConnectedClientsIndexes.Count > 0) { byte[] b = Encoding.GetEncoding(28591).GetBytes(text); foreach (uint i in ConnectedClientsIndexes) { if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(i))) { SocketErrorCodes error = SecureServer.SendDataAsync(i, b, b.Length, (x, y, z) => { }); if (error != SocketErrorCodes.SOCKET_OK && error != SocketErrorCodes.SOCKET_OPERATION_PENDING) this.LogVerbose("{error}", error); } } } CCBroadcast.Leave(); } catch (Exception ex) { CCBroadcast.Leave(); Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Broadcasting messages from server. Error: {0}", ex.Message); } } /// /// Not sure this is useful in library, maybe Pro?? /// /// /// /// /// SendTextToClient method /// public void SendTextToClient(string text, uint clientIndex) { try { byte[] b = Encoding.GetEncoding(28591).GetBytes(text); if (SecureServer != null && SecureServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) { if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) SecureServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); } } catch (Exception ex) { Debug.Console(2, this, "Error sending text to client. Text: {1}. Error: {0}", ex.Message, text); } } //private method to check heartbeat requirements and start or reset timer string checkHeartbeat(uint clientIndex, string received) { try { if (HeartbeatRequired) { if (!string.IsNullOrEmpty(HeartbeatStringToMatch)) { var remainingText = received.Replace(HeartbeatStringToMatch, ""); var noDelimiter = received.Trim(new char[] { '\r', '\n' }); if (noDelimiter.Contains(HeartbeatStringToMatch)) { if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); else { CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); } Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", HeartbeatStringToMatch, clientIndex); // Return Heartbeat SendTextToClient(HeartbeatStringToMatch, clientIndex); return remainingText; } } else { if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); else { CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); } Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", received, clientIndex); } } } catch (Exception ex) { Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } return received; } /// /// Get the IP Address for the client at the specifed index /// /// /// /// /// GetClientIPAddress method /// public string GetClientIPAddress(uint clientIndex) { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress Index: {0}", clientIndex); if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) { var ipa = this.SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress IPAddreess: {0}", ipa); return ipa; } else { return ""; } } #endregion #region Methods - HeartbeatTimer Callback void HeartbeatTimer_CallbackFunction(object o) { uint clientIndex = 99999; string address = string.Empty; try { clientIndex = (uint)o; address = SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Heartbeat not received for Client index {2} IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE {1}", address, string.IsNullOrEmpty(HeartbeatStringToMatch) ? "" : ("HeartbeatStringToMatch: " + HeartbeatStringToMatch), clientIndex); if (SecureServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) SendTextToClient("Heartbeat not received by server, closing connection", clientIndex); var discoResult = SecureServer.Disconnect(clientIndex); //Debug.Console(1, this, "{0}", discoResult); if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) { HeartbeatTimerDictionary[clientIndex].Stop(); HeartbeatTimerDictionary[clientIndex].Dispose(); HeartbeatTimerDictionary.Remove(clientIndex); } } catch (Exception ex) { ErrorLog.Error("{3}: Heartbeat timeout Error on Client Index: {0}, at address: {1}, error: {2}", clientIndex, address, ex.Message, Key); } } #endregion #region Methods - Socket Status Changed Callbacks /// /// Secure Server Socket Status Changed Callback /// /// /// /// void SecureServer_SocketStatusChange(SecureTCPServer server, uint clientIndex, SocketStatus serverSocketStatus) { try { // Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange Index:{0} status:{1} Port:{2} IP:{3}", clientIndex, serverSocketStatus, this.SecureServer.GetPortNumberServerAcceptedConnectionFromForSpecificClient(clientIndex), this.SecureServer.GetLocalAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); if (serverSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange ConnectedCLients: {0} ServerState: {1} Port: {2}", SecureServer.NumberOfClientsConnected, SecureServer.State, SecureServer.PortNumber); if (ConnectedClientsIndexes.Contains(clientIndex)) ConnectedClientsIndexes.Remove(clientIndex); if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex)) { HeartbeatTimerDictionary[clientIndex].Stop(); HeartbeatTimerDictionary[clientIndex].Dispose(); HeartbeatTimerDictionary.Remove(clientIndex); } if (ClientReadyAfterKeyExchange.Contains(clientIndex)) ClientReadyAfterKeyExchange.Remove(clientIndex); if (WaitingForSharedKey.Contains(clientIndex)) WaitingForSharedKey.Remove(clientIndex); if (SecureServer.MaxNumberOfClientSupported > SecureServer.NumberOfClientsConnected) { Listen(); } } } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Change Callback. Error: {0}", ex); } //Use a thread for this event so that the server state updates to listening while this event is processed. Listening must be added to the server state //after every client connection so that the server can check and see if it is at max clients. Due to this the event fires and server listening enum bit flag //is not set. Putting in a thread allows the state to update before this event processes so that the subscribers to this event get accurate isListening in the event. CrestronInvoke.BeginInvoke(o => onConnectionChange(clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)), null); } #endregion #region Methods Connected Callbacks /// /// Secure TCP Client Connected to Secure Server Callback /// /// /// void SecureConnectCallback(SecureTCPServer server, uint clientIndex) { try { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "ConnectCallback: IPAddress: {0}. Index: {1}. Status: {2}", server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); if (clientIndex != 0) { if (server.ClientConnected(clientIndex)) { if (!ConnectedClientsIndexes.Contains(clientIndex)) { ConnectedClientsIndexes.Add(clientIndex); } if (SharedKeyRequired) { if (!WaitingForSharedKey.Contains(clientIndex)) { WaitingForSharedKey.Add(clientIndex); } byte[] b = Encoding.GetEncoding(28591).GetBytes("SharedKey:"); server.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Sent Shared Key Request to client at {0}", server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); } else { OnServerClientReadyForCommunications(clientIndex); } if (HeartbeatRequired) { if (!HeartbeatTimerDictionary.ContainsKey(clientIndex)) { HeartbeatTimerDictionary.Add(clientIndex, new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs)); } } server.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback); } } else { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Client attempt faulty."); } } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Connect Callback. Error: {0}", ex); } // Rearm the listner SocketErrorCodes status = server.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback); if (status != SocketErrorCodes.SOCKET_OPERATION_PENDING) { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Socket status connect callback status {0}", status); if (status == SocketErrorCodes.SOCKET_CONNECTION_IN_PROGRESS) { // There is an issue where on a failed negotiation we need to stop and start the server. This should still leave connected clients intact. server.Stop(); Listen(); } } } #endregion #region Methods - Send/Receive Callbacks /// /// Secure Received Data Async Callback /// /// /// /// void SecureReceivedDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived) { if (numberOfBytesReceived > 0) { string received = "Nothing"; var handler = TextReceivedQueueInvoke; try { byte[] bytes = mySecureTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex); received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived); if (WaitingForSharedKey.Contains(clientIndex)) { received = received.Replace("\r", ""); received = received.Replace("\n", ""); if (received != SharedKey) { byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting"); Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Client at index {0} Shared key did not match the server, disconnecting client. Key: {1}", clientIndex, received); mySecureTCPServer.SendData(clientIndex, b, b.Length); mySecureTCPServer.Disconnect(clientIndex); return; } WaitingForSharedKey.Remove(clientIndex); byte[] success = Encoding.GetEncoding(28591).GetBytes("Shared Key Match"); mySecureTCPServer.SendDataAsync(clientIndex, success, success.Length, null); OnServerClientReadyForCommunications(clientIndex); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Client with index {0} provided the shared key and successfully connected to the server", clientIndex); } else if (!string.IsNullOrEmpty(checkHeartbeat(clientIndex, received))) { onTextReceived(received, clientIndex); if (handler != null) { MessageQueue.TryToEnqueue(new GenericTcpServerCommMethodReceiveTextArgs(received, clientIndex)); } } } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Receiving data: {0}. Error: {1}", received, ex); } if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback); //Check to see if there is a subscription to the TextReceivedQueueInvoke event. If there is start the dequeue thread. if (handler != null) { var gotLock = DequeueLock.TryEnter(); if (gotLock) CrestronInvoke.BeginInvoke((o) => DequeueEvent()); } } else { mySecureTCPServer.Disconnect(clientIndex); } } /// /// This method gets spooled up in its own thread an protected by a CCriticalSection to prevent multiple threads from running concurrently. /// It will dequeue items as they are enqueued automatically. /// void DequeueEvent() { try { while (true) { // Pull from Queue and fire an event. Block indefinitely until an item can be removed, similar to a Gather. var message = MessageQueue.Dequeue(); var handler = TextReceivedQueueInvoke; if (handler != null) { handler(this, message); } } } catch (Exception e) { this.LogException(e, "DequeueEvent error"); } // Make sure to leave the CCritical section in case an exception above stops this thread, or we won't be able to restart it. if (DequeueLock != null) { DequeueLock.Leave(); } } #endregion #region Methods - EventHelpers/Callbacks //Private Helper method to call the Connection Change Event void onConnectionChange(uint clientIndex, SocketStatus clientStatus) { if (clientIndex != 0) //0 is error not valid client change { var handler = ClientConnectionChange; if (handler != null) { handler(this, new GenericTcpServerSocketStatusChangeEventArgs(SecureServer, clientIndex, clientStatus)); } } } //Private Helper method to call the Connection Change Event void OnConnectionChange() { if (ProgramIsStopping) { return; } var handler = ClientConnectionChange; if (handler != null) { handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); } } //Private Helper Method to call the Text Received Event void onTextReceived(string text, uint clientIndex) { var handler = TextReceived; if (handler != null) handler(this, new GenericTcpServerCommMethodReceiveTextArgs(text, clientIndex)); } //Private Helper Method to call the Server State Change Event void OnServerStateChange(ServerState state) { if (ProgramIsStopping) { return; } var handler = ServerStateChange; if (handler != null) { handler(this, new GenericTcpServerStateChangedEventArgs(state)); } } /// /// Private Event Handler method to handle the closing of connections when the program stops /// /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) { ProgramIsStopping = true; // kill bandaid things if (MonitorClientTimer != null) MonitorClientTimer.Stop(); if (MonitorClient != null) MonitorClient.Disconnect(); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing server"); KillServer(); } } //Private event handler method to raise the event that the server is ready to send data after a successful client shared key negotiation void OnServerClientReadyForCommunications(uint clientIndex) { ClientReadyAfterKeyExchange.Add(clientIndex); var handler = ServerClientReadyForCommunications; if (handler != null) handler(this, new GenericTcpServerSocketStatusChangeEventArgs( this, clientIndex, SecureServer.GetServerSocketStatusForSpecificClient(clientIndex))); } #endregion #region Monitor Client /// /// Starts the monitor client cycle. Timed wait, then call RunMonitorClient /// void StartMonitorClient() { if (MonitorClientTimer != null) { return; } MonitorClientTimer = new CTimer(o => RunMonitorClient(), 60000); } /// /// /// void RunMonitorClient() { MonitorClient = new GenericSecureTcpIpClient_ForServer(Key + "-MONITOR", "127.0.0.1", Port, 2000); MonitorClient.SharedKeyRequired = this.SharedKeyRequired; MonitorClient.SharedKey = this.SharedKey; MonitorClient.ConnectionHasHungCallback = MonitorClientHasHungCallback; //MonitorClient.ConnectionChange += MonitorClient_ConnectionChange; MonitorClient.ClientReadyForCommunications += MonitorClient_IsReadyForComm; Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Starting monitor check"); MonitorClient.Connect(); // From here MonitorCLient either connects or hangs, MonitorClient will call back } /// /// /// void StopMonitorClient() { if (MonitorClient == null) return; MonitorClient.ClientReadyForCommunications -= MonitorClient_IsReadyForComm; MonitorClient.Disconnect(); MonitorClient = null; } /// /// On monitor connect, restart the operation /// void MonitorClient_IsReadyForComm(object sender, GenericTcpServerClientReadyForcommunicationsEventArgs args) { if (args.IsReady) { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Monitor client connection success. Disconnecting in 2s"); MonitorClientTimer.Stop(); MonitorClientTimer = null; MonitorClientFailureCount = 0; CrestronEnvironment.Sleep(2000); StopMonitorClient(); StartMonitorClient(); } } /// /// If the client hangs, add to counter and maybe fire the choke event /// void MonitorClientHasHungCallback() { MonitorClientFailureCount++; MonitorClientTimer.Stop(); MonitorClientTimer = null; StopMonitorClient(); if (MonitorClientFailureCount < MonitorClientMaxFailureCount) { Debug.Console(2, this, Debug.ErrorLogLevel.Warning, "Monitor client connection has hung {0} time{1}, maximum {2}", MonitorClientFailureCount, MonitorClientFailureCount > 1 ? "s" : "", MonitorClientMaxFailureCount); StartMonitorClient(); } else { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "\r***************************\rMonitor client connection has hung a maximum of {0} times. \r***************************", MonitorClientMaxFailureCount); var handler = ServerHasChoked; if (handler != null) handler(); // Some external thing is in charge here. Expected reset of program } } #endregion } } ================================================ FILE: src/PepperDash.Core/Comm/GenericSshClient.cs ================================================ using System; using System.Collections.Generic; using System.Text; using System.Threading; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using Org.BouncyCastle.Utilities; using PepperDash.Core.Logging; using Renci.SshNet; using Renci.SshNet.Common; namespace PepperDash.Core { /// /// SSH Client /// public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect { private const string SPlusKey = "Uninitialized SshClient"; /// /// Object to enable stream debugging /// public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// Event that fires when data is received. Delivers args with byte array /// public event EventHandler BytesReceived; /// /// Event that fires when data is received. Delivered as text. /// public event EventHandler TextReceived; /// /// Event when the connection status changes. /// public event EventHandler ConnectionChange; /// /// Gets or sets the Hostname /// public string Hostname { get; set; } /// /// Port on server /// public int Port { get; set; } /// /// Gets or sets the Username /// public string Username { get; set; } /// /// Gets or sets the Password /// public string Password { get; set; } /// /// True when the server is connected - when status == 2. /// public bool IsConnected { // returns false if no client or not connected get { return client != null && ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } /// /// S+ helper for IsConnected /// public ushort UIsConnected { get { return (ushort)(IsConnected ? 1 : 0); } } /// /// Socket status change event /// public SocketStatus ClientStatus { get { lock (_stateLock) { return _ClientStatus; } } private set { bool shouldFireEvent = false; lock (_stateLock) { if (_ClientStatus != value) { _ClientStatus = value; shouldFireEvent = true; } } // Fire event outside lock to avoid deadlock if (shouldFireEvent) OnConnectionChange(); } } private SocketStatus _ClientStatus; private bool _ConnectEnabled; /// /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event /// and IsConnected with be true when this == 2. /// public ushort UStatus { get { lock (_stateLock) { return (ushort)_ClientStatus; } } } /// /// Determines whether client will attempt reconnection on failure. Default is true /// public bool AutoReconnect { get; set; } /// /// Will be set and unset by connect and disconnect only /// public bool ConnectEnabled { get { lock (_stateLock) { return _ConnectEnabled; } } private set { lock (_stateLock) { _ConnectEnabled = value; } } } /// /// S+ helper for AutoReconnect /// public ushort UAutoReconnect { get { return (ushort)(AutoReconnect ? 1 : 0); } set { AutoReconnect = value == 1; } } /// /// Gets or sets the AutoReconnectIntervalMs /// public int AutoReconnectIntervalMs { get; set; } private SshClient client; private ShellStream shellStream; private readonly Timer reconnectTimer; //Lock object to prevent simulatneous connect/disconnect operations //private CCriticalSection connectLock = new CCriticalSection(); private readonly SemaphoreSlim connectLock = new SemaphoreSlim(1); // Thread-safety lock for state changes private readonly object _stateLock = new object(); private bool disconnectLogged = false; /// /// When true, turns off echo for the SSH session /// public bool DisableEcho { get; set; } /// /// Typical constructor. /// public GenericSshClient(string key, string hostname, int port, string username, string password) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); Key = key; Hostname = hostname; Port = port; Username = username; Password = password; AutoReconnectIntervalMs = 5000; reconnectTimer = new Timer(o => { if (ConnectEnabled) // Now thread-safe property access { Connect(); } }, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); } /// /// S+ Constructor - Must set all properties before calling Connect /// public GenericSshClient() : base(SPlusKey) { CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; reconnectTimer = new Timer(o => { if (ConnectEnabled) // Now thread-safe property access { Connect(); } }, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); } /// /// Handles closing this up when the program shuts down /// private void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) { if (client != null) { this.LogDebug("Program stopping. Closing connection"); Disconnect(); } } } /// /// Connect method /// public void Connect() { // Don't go unless everything is here if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535 || Username == null || Password == null) { this.LogError("Connect failed. Check hostname, port, username and password are set or not null"); return; } ConnectEnabled = true; try { connectLock.Wait(); if (IsConnected) { this.LogDebug("Connection already connected. Exiting Connect"); } else { this.LogDebug("Attempting connect"); // Cancel reconnect if running. StopReconnectTimer(); // Cleanup the old client if it already exists if (client != null) { this.LogDebug("Cleaning up disconnected client"); KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); } // This handles both password and keyboard-interactive (like on OS-X, 'nixes) KeyboardInteractiveAuthenticationMethod kauth = new KeyboardInteractiveAuthenticationMethod(Username); kauth.AuthenticationPrompt += new EventHandler(kauth_AuthenticationPrompt); PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password); this.LogDebug("Creating new SshClient"); ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth); client = new SshClient(connectionInfo); client.ErrorOccurred += Client_ErrorOccurred; //Attempt to connect ClientStatus = SocketStatus.SOCKET_STATUS_WAITING; try { client.Connect(); var modes = new Dictionary(); if (DisableEcho) { modes.Add(TerminalModes.ECHO, 0); } shellStream = client.CreateShellStream("PDTShell", 0, 0, 0, 0, 65534, modes); if (shellStream.DataAvailable) { // empty the buffer if there is data shellStream.Read(); } shellStream.DataReceived += Stream_DataReceived; this.LogInformation("Connected"); ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED; disconnectLogged = false; } catch (SshConnectionException e) { var ie = e.InnerException; // The details are inside!! if (ie is SocketException) { this.LogError("CONNECTION failure: Cannot reach host"); this.LogVerbose(ie, "Exception details: "); } if (ie is System.Net.Sockets.SocketException socketException) { this.LogError("Connection failure: Cannot reach {host} on {port}", Hostname, Port); this.LogVerbose(socketException, "SocketException details: "); } if (ie is SshAuthenticationException) { this.LogError("Authentication failure for username {userName}", Username); this.LogVerbose(ie, "AuthenticationException details: "); } else { this.LogError("Error on connect: {error}", ie.Message); this.LogVerbose(ie, "Exception details: "); } disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); } } catch (SshOperationTimeoutException ex) { this.LogWarning("Connection attempt timed out: {message}", ex.Message); disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); } } catch (Exception e) { this.LogError("Unhandled exception on connect: {error}", e.Message); this.LogVerbose(e, "Exception details: "); disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); } } } } finally { connectLock.Release(); } } /// /// Disconnect method /// public void Disconnect() { ConnectEnabled = false; // Stop trying reconnects, if we are StopReconnectTimer(); KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); } /// /// Kills the stream, cleans up the client and sets it to null /// private void KillClient(SocketStatus status) { KillStream(); try { if (client != null) { client.ErrorOccurred -= Client_ErrorOccurred; client.Disconnect(); client.Dispose(); client = null; ClientStatus = status; this.LogDebug("Disconnected"); } } catch (Exception ex) { this.LogException(ex, "Exception in Kill Client"); } } /// /// Kills the stream /// private void KillStream() { try { if (shellStream != null) { shellStream.DataReceived -= Stream_DataReceived; shellStream.Close(); shellStream.Dispose(); shellStream = null; this.LogDebug("Disconnected stream"); } } catch (Exception ex) { this.LogException(ex, "Exception in Kill Stream:{0}"); } } /// /// Handles the keyboard interactive authentication, should it be required. /// private void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e) { foreach (AuthenticationPrompt prompt in e.Prompts) if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1) prompt.Response = Password; } /// /// Handler for data receive on ShellStream. Passes data across to queue for line parsing. /// private void Stream_DataReceived(object sender, ShellDataEventArgs e) { if (((ShellStream)sender).Length <= 0L) { return; } var response = ((ShellStream)sender).Read(); var bytesHandler = BytesReceived; if (bytesHandler != null) { var bytes = Encoding.UTF8.GetBytes(response); this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; if (textHandler != null) { this.PrintReceivedText(response); textHandler(this, new GenericCommMethodReceiveTextArgs(response)); } } /// /// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange /// event /// private void Client_ErrorOccurred(object sender, ExceptionEventArgs e) { CrestronInvoke.BeginInvoke(o => { if (e.Exception is SshConnectionException || e.Exception is System.Net.Sockets.SocketException) this.LogError("Disconnected by remote"); else this.LogException(e.Exception, "Unhandled SSH client error"); try { connectLock.Wait(); KillClient(SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY); } finally { connectLock.Release(); } if (AutoReconnect && ConnectEnabled) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); } }); } /// /// Helper for ConnectionChange event /// private void OnConnectionChange() { ConnectionChange?.Invoke(this, new GenericSocketStatusChageEventArgs(this)); } #region IBasicCommunication Members /// /// Sends text to the server /// /// The text to send public void SendText(string text) { try { if (client != null && shellStream != null && IsConnected) { this.PrintSentText(text); shellStream.Write(text); shellStream.Flush(); } else { this.LogDebug("Client is null or disconnected. Cannot Send Text"); } } catch (ObjectDisposedException) { this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim()); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); StartReconnectTimer(); } catch (Exception ex) { this.LogException(ex, "Exception sending text: '{message}'", text); } } /// /// Sends Bytes to the server /// /// The bytes to send public void SendBytes(byte[] bytes) { try { if (client != null && shellStream != null && IsConnected) { this.PrintSentBytes(bytes); shellStream.Write(bytes, 0, bytes.Length); shellStream.Flush(); } else { this.LogDebug("Client is null or disconnected. Cannot Send Bytes"); } } catch (ObjectDisposedException ex) { this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes)); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); StartReconnectTimer(); } catch (Exception ex) { this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes)); } } #endregion /// /// Safely starts the reconnect timer with exception handling /// private void StartReconnectTimer() { try { reconnectTimer?.Change(AutoReconnectIntervalMs, System.Threading.Timeout.Infinite); } catch (ObjectDisposedException) { // Timer was disposed, ignore this.LogDebug("Attempted to start timer but it was already disposed"); } } /// /// Safely stops the reconnect timer with exception handling /// private void StopReconnectTimer() { try { reconnectTimer?.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); } catch (ObjectDisposedException) { // Timer was disposed, ignore this.LogDebug("Attempted to stop timer but it was already disposed"); } } /// /// Deactivate method - properly dispose of resources /// public override bool Deactivate() { try { this.LogDebug("Deactivating SSH client - disposing resources"); // Stop trying reconnects ConnectEnabled = false; StopReconnectTimer(); // Disconnect and cleanup client KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); // Dispose timer try { reconnectTimer?.Dispose(); } catch (ObjectDisposedException) { // Already disposed, ignore } // Dispose semaphore try { connectLock?.Dispose(); } catch (ObjectDisposedException) { // Already disposed, ignore } return base.Deactivate(); } catch (Exception ex) { this.LogException(ex, "Error during SSH client deactivation"); return false; } } } //***************************************************************************************************** //***************************************************************************************************** /// /// Represents a SshConnectionChangeEventArgs /// public class SshConnectionChangeEventArgs : EventArgs { /// /// Connection State /// public bool IsConnected { get; private set; } /// /// Gets or sets the UIsConnected /// public ushort UIsConnected { get { return (ushort)(Client.IsConnected ? 1 : 0); } } /// /// Gets or sets the Client /// public GenericSshClient Client { get; private set; } /// /// Gets or sets the Status /// public ushort Status { get { return Client.UStatus; } } /// /// S+ Constructor /// public SshConnectionChangeEventArgs() { } /// /// EventArgs class /// /// Connection State /// The Client public SshConnectionChangeEventArgs(bool isConnected, GenericSshClient client) { IsConnected = isConnected; Client = client; } } } ================================================ FILE: src/PepperDash.Core/Comm/GenericTcpIpClient.cs ================================================ using System; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using Newtonsoft.Json; namespace PepperDash.Core { /// /// A class to handle basic TCP/IP communications with a server /// public class GenericTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect { private const string SplusKey = "Uninitialized TcpIpClient"; /// /// Object to enable stream debugging /// public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// Fires when data is received from the server and returns it as a Byte array /// public event EventHandler BytesReceived; /// /// Fires when data is received from the server and returns it as text /// public event EventHandler TextReceived; /// /// /// //public event GenericSocketStatusChangeEventDelegate SocketStatusChange; public event EventHandler ConnectionChange; private string _hostname; /// /// Address of server /// public string Hostname { get { return _hostname; } set { _hostname = value; if (_client != null) { _client.AddressClientConnectedTo = _hostname; } } } /// /// Gets or sets the Port /// public int Port { get; set; } /// /// Another damn S+ helper because S+ seems to treat large port nums as signed ints /// which screws up things /// public ushort UPort { get { return Convert.ToUInt16(Port); } set { Port = Convert.ToInt32(value); } } /// /// Defaults to 2000 /// public int BufferSize { get; set; } /// /// The actual client class /// private TCPClient _client; /// /// Bool showing if socket is connected /// public bool IsConnected { get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } /// /// S+ helper for IsConnected /// public ushort UIsConnected { get { return (ushort)(IsConnected ? 1 : 0); } } /// /// _client socket status Read only /// public SocketStatus ClientStatus { get { return _client == null ? SocketStatus.SOCKET_STATUS_NO_CONNECT : _client.ClientStatus; } } /// /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event /// and IsConnected would be true when this == 2. /// public ushort UStatus { get { return (ushort)ClientStatus; } } /// /// Status text shows the message associated with socket status /// public string ClientStatusText { get { return ClientStatus.ToString(); } } /// /// Ushort representation of client status /// [Obsolete] public ushort UClientStatus { get { return (ushort)ClientStatus; } } /// /// Connection failure reason /// public string ConnectionFailure { get { return ClientStatus.ToString(); } } /// /// Gets or sets the AutoReconnect /// public bool AutoReconnect { get; set; } /// /// S+ helper for AutoReconnect /// public ushort UAutoReconnect { get { return (ushort)(AutoReconnect ? 1 : 0); } set { AutoReconnect = value == 1; } } /// /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 /// public int AutoReconnectIntervalMs { get; set; } /// /// Set only when the disconnect method is called /// bool DisconnectCalledByUser; /// /// /// public bool Connected { get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } //Lock object to prevent simulatneous connect/disconnect operations private CCriticalSection connectLock = new CCriticalSection(); // private Timer for auto reconnect private CTimer RetryTimer; /// /// Constructor /// /// unique string to differentiate between instances /// /// /// public GenericTcpIpClient(string key, string address, int port, int bufferSize) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; Hostname = address; Port = port; BufferSize = bufferSize; RetryTimer = new CTimer(o => { Reconnect(); }, Timeout.Infinite); } /// /// Constructor /// /// public GenericTcpIpClient(string key) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; RetryTimer = new CTimer(o => { Reconnect(); }, Timeout.Infinite); } /// /// Default constructor for S+ /// public GenericTcpIpClient() : base(SplusKey) { StreamDebugging = new CommunicationStreamDebugging(SplusKey); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; RetryTimer = new CTimer(o => { Reconnect(); }, Timeout.Infinite); } /// /// Initialize method /// public void Initialize(string key) { Key = key; } /// /// Handles closing this up when the program shuts down /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) { Debug.Console(1, this, "Program stopping. Closing connection"); Deactivate(); } } /// /// /// /// /// /// Deactivate method /// public override bool Deactivate() { RetryTimer.Stop(); RetryTimer.Dispose(); if (_client != null) { _client.SocketStatusChange -= this.Client_SocketStatusChange; DisconnectClient(); } return true; } /// /// Connect method /// public void Connect() { if (string.IsNullOrEmpty(Hostname)) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': No address set", Key); return; } if (Port < 1 || Port > 65535) { { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': Invalid port", Key); return; } } try { connectLock.Enter(); if (IsConnected) { Debug.Console(1, this, "Connection already connected. Exiting Connect()"); } else { //Stop retry timer if running RetryTimer.Stop(); _client = new TCPClient(Hostname, Port, BufferSize); _client.SocketStatusChange -= Client_SocketStatusChange; _client.SocketStatusChange += Client_SocketStatusChange; DisconnectCalledByUser = false; _client.ConnectToServerAsync(ConnectToServerCallback); } } finally { connectLock.Leave(); } } private void Reconnect() { if (_client == null) { return; } try { connectLock.Enter(); if (IsConnected || DisconnectCalledByUser == true) { Debug.Console(1, this, "Reconnect no longer needed. Exiting Reconnect()"); } else { Debug.Console(1, this, "Attempting reconnect now"); _client.ConnectToServerAsync(ConnectToServerCallback); } } finally { connectLock.Leave(); } } /// /// Disconnect method /// public void Disconnect() { try { connectLock.Enter(); DisconnectCalledByUser = true; // Stop trying reconnects, if we are RetryTimer.Stop(); DisconnectClient(); } finally { connectLock.Leave(); } } /// /// DisconnectClient method /// public void DisconnectClient() { if (_client != null) { Debug.Console(1, this, "Disconnecting client"); if (IsConnected) _client.DisconnectFromServer(); } } /// /// Callback method for connection attempt /// /// void ConnectToServerCallback(TCPClient c) { if (c.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { Debug.Console(0, this, "Server connection result: {0}", c.ClientStatus); WaitAndTryReconnect(); } else { Debug.Console(1, this, "Server connection result: {0}", c.ClientStatus); } } /// /// Disconnects, waits and attemtps to connect again /// void WaitAndTryReconnect() { CrestronInvoke.BeginInvoke(o => { try { connectLock.Enter(); if (!IsConnected && AutoReconnect && !DisconnectCalledByUser && _client != null) { DisconnectClient(); Debug.Console(1, this, "Attempting reconnect, status={0}", _client.ClientStatus); RetryTimer.Reset(AutoReconnectIntervalMs); } } finally { connectLock.Leave(); } }); } /// /// Recieves incoming data /// /// /// void Receive(TCPClient client, int numBytes) { if (client != null) { if (numBytes > 0) { var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); var bytesHandler = BytesReceived; if (bytesHandler != null) { this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; if (textHandler != null) { var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); this.PrintReceivedText(str); textHandler(this, new GenericCommMethodReceiveTextArgs(str)); } } client.ReceiveDataAsync(Receive); } } /// /// SendText method /// public void SendText(string text) { var bytes = Encoding.GetEncoding(28591).GetBytes(text); // Check debug level before processing byte array this.PrintSentText(text); if (_client != null) _client.SendData(bytes, bytes.Length); } /// /// SendEscapedText method /// public void SendEscapedText(string text) { var unescapedText = Regex.Replace(text, @"\\x([0-9a-fA-F][0-9a-fA-F])", s => { var hex = s.Groups[1].Value; return ((char)Convert.ToByte(hex, 16)).ToString(); }); SendText(unescapedText); } /// /// Sends Bytes to the server /// /// /// /// SendBytes method /// public void SendBytes(byte[] bytes) { this.PrintSentBytes(bytes); if (_client != null) _client.SendData(bytes, bytes.Length); } /// /// Socket Status Change Handler /// /// /// void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) { if (clientSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { Debug.Console(0, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); WaitAndTryReconnect(); } else { Debug.Console(1, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText); _client.ReceiveDataAsync(Receive); } var handler = ConnectionChange; if (handler != null) ConnectionChange(this, new GenericSocketStatusChageEventArgs(this)); } } /// /// Represents a TcpSshPropertiesConfig /// public class TcpSshPropertiesConfig { /// /// Address to connect to /// [JsonProperty(Required = Required.Always)] public string Address { get; set; } /// /// Port to connect to /// [JsonProperty(Required = Required.Always)] public int Port { get; set; } /// /// Username credential /// public string Username { get; set; } /// /// Gets or sets the Password /// public string Password { get; set; } /// /// Defaults to 32768 /// public int BufferSize { get; set; } /// /// Gets or sets the AutoReconnect /// public bool AutoReconnect { get; set; } /// /// Gets or sets the AutoReconnectIntervalMs /// public int AutoReconnectIntervalMs { get; set; } /// /// When true, turns off echo for the SSH session /// [JsonProperty("disableSshEcho")] public bool DisableSshEcho { get; set; } /// /// Default constructor /// public TcpSshPropertiesConfig() { BufferSize = 32768; AutoReconnect = true; AutoReconnectIntervalMs = 5000; Username = ""; Password = ""; DisableSshEcho = false; } } } ================================================ FILE: src/PepperDash.Core/Comm/GenericTcpIpClient_ForServer.cs ================================================ /*PepperDash Technology Corp. JAG Copyright: 2017 ------------------------------------ ***Notice of Ownership and Copyright*** The material in which this notice appears is the property of PepperDash Technology Corporation, which claims copyright under the laws of the United States of America in the entire body of material and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part, of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited. PepperDash Technology Corporation reserves all rights under applicable laws. ------------------------------------ */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; namespace PepperDash.Core { /// /// Generic TCP/IP client for server /// public class GenericTcpIpClient_ForServer : Device, IAutoReconnect { /// /// Band aid delegate for choked server /// internal delegate void ConnectionHasHungCallbackDelegate(); #region Events //public event EventHandler BytesReceived; /// /// Notifies of text received /// public event EventHandler TextReceived; /// /// Notifies of socket status change /// public event EventHandler ConnectionChange; /// /// This is something of a band-aid callback. If the client times out during the connection process, because the server /// is stuck, this will fire. It is intended to be used by the Server class monitor client, to help /// keep a watch on the server and reset it if necessary. /// internal ConnectionHasHungCallbackDelegate ConnectionHasHungCallback; /// /// For a client with a pre shared key, this will fire after the communication is established and the key exchange is complete. If you require /// a key and subscribe to the socket change event and try to send data on a connection the data sent will interfere with the key exchange and disconnect. /// public event EventHandler ClientReadyForCommunications; #endregion #region Properties & Variables /// /// Address of server /// public string Hostname { get; set; } /// /// Gets or sets the Port /// public int Port { get; set; } /// /// S+ helper /// public ushort UPort { get { return Convert.ToUInt16(Port); } set { Port = Convert.ToInt32(value); } } /// /// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class /// public bool SharedKeyRequired { get; set; } /// /// S+ helper for requires shared key bool /// public ushort USharedKeyRequired { set { if (value == 1) SharedKeyRequired = true; else SharedKeyRequired = false; } } /// /// Gets or sets the SharedKey /// public string SharedKey { get; set; } /// /// flag to show the client is waiting for the server to send the shared key /// private bool WaitingForSharedKeyResponse { get; set; } /// /// Gets or sets the BufferSize /// public int BufferSize { get; set; } /// /// Semaphore on connect method /// bool IsTryingToConnect; /// /// Bool showing if socket is connected /// public bool IsConnected { get { if (Client != null) return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; else return false; } } /// /// S+ helper for IsConnected /// public ushort UIsConnected { get { return (ushort)(IsConnected ? 1 : 0); } } /// /// Bool showing if socket is ready for communication after shared key exchange /// public bool IsReadyForCommunication { get; set; } /// /// S+ helper for IsReadyForCommunication /// public ushort UIsReadyForCommunication { get { return (ushort)(IsReadyForCommunication ? 1 : 0); } } /// /// Client socket status Read only /// public SocketStatus ClientStatus { get { if (Client != null) return Client.ClientStatus; else return SocketStatus.SOCKET_STATUS_NO_CONNECT; } } /// /// Contains the familiar Simpl analog status values. This drives the ConnectionChange event /// and IsConnected would be true when this == 2. /// public ushort UStatus { get { return (ushort)ClientStatus; } } /// /// Status text shows the message associated with socket status /// public string ClientStatusText { get { return ClientStatus.ToString(); } } /// /// bool to track if auto reconnect should be set on the socket /// public bool AutoReconnect { get; set; } /// /// S+ helper for AutoReconnect /// public ushort UAutoReconnect { get { return (ushort)(AutoReconnect ? 1 : 0); } set { AutoReconnect = value == 1; } } /// /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 /// public int AutoReconnectIntervalMs { get; set; } /// /// Flag Set only when the disconnect method is called. /// bool DisconnectCalledByUser; /// /// private Timer for auto reconnect /// CTimer RetryTimer; /// /// /// public bool HeartbeatEnabled { get; set; } /// /// /// public ushort UHeartbeatEnabled { get { return (ushort)(HeartbeatEnabled ? 1 : 0); } set { HeartbeatEnabled = value == 1; } } /// /// /// public string HeartbeatString = "heartbeat"; /// /// /// public int HeartbeatInterval = 50000; CTimer HeartbeatSendTimer; CTimer HeartbeatAckTimer; /// /// Used to force disconnection on a dead connect attempt /// CTimer ConnectFailTimer; CTimer WaitForSharedKey; private int ConnectionCount; /// /// Internal secure client /// TCPClient Client; bool ProgramIsStopping; #endregion #region Constructors /// /// Constructor /// /// /// /// /// public GenericTcpIpClient_ForServer(string key, string address, int port, int bufferSize) : base(key) { CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); Hostname = address; Port = port; BufferSize = bufferSize; AutoReconnectIntervalMs = 5000; } /// /// Constructor for S+ /// public GenericTcpIpClient_ForServer() : base("Uninitialized DynamicTcpClient") { CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; } #endregion #region Methods /// /// Initialize method /// public void Initialize(string key) { Key = key; } /// /// Handles closing this up when the program shuts down /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping || programEventType == eProgramStatusEventType.Paused) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing Client connection"); ProgramIsStopping = true; Disconnect(); } } /// /// Connect method /// public void Connect() { ConnectionCount++; Debug.Console(2, this, "Attempting connect Count:{0}", ConnectionCount); if (IsConnected) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already connected. Ignoring."); return; } if (IsTryingToConnect) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Already trying to connect. Ignoring."); return; } try { IsTryingToConnect = true; if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } if (string.IsNullOrEmpty(Hostname)) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No address set"); return; } if (Port < 1 || Port > 65535) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: Invalid port"); return; } if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) { Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "DynamicTcpClient: No Shared Key set"); return; } // clean up previous client if (Client != null) { Cleanup(); } DisconnectCalledByUser = false; Client = new TCPClient(Hostname, Port, BufferSize); Client.SocketStatusChange += Client_SocketStatusChange; if(HeartbeatEnabled) Client.SocketSendOrReceiveTimeOutInMs = (HeartbeatInterval * 5); Client.AddressClientConnectedTo = Hostname; Client.PortNumber = Port; // SecureClient = c; //var timeOfConnect = DateTime.Now.ToString("HH:mm:ss.fff"); ConnectFailTimer = new CTimer(o => { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Connect attempt has not finished after 30sec Count:{0}", ConnectionCount); if (IsTryingToConnect) { IsTryingToConnect = false; //if (ConnectionHasHungCallback != null) //{ // ConnectionHasHungCallback(); //} //SecureClient.DisconnectFromServer(); //CheckClosedAndTryReconnect(); } }, 30000); Debug.Console(2, this, "Making Connection Count:{0}", ConnectionCount); Client.ConnectToServerAsync(o => { Debug.Console(2, this, "ConnectToServerAsync Count:{0} Ran!", ConnectionCount); if (ConnectFailTimer != null) { ConnectFailTimer.Stop(); } IsTryingToConnect = false; if (o.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) { Debug.Console(2, this, "Client connected to {0} on port {1}", o.AddressClientConnectedTo, o.LocalPortNumberOfClient); o.ReceiveDataAsync(Receive); if (SharedKeyRequired) { WaitingForSharedKeyResponse = true; WaitForSharedKey = new CTimer(timer => { Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Shared key exchange timer expired. IsReadyForCommunication={0}", IsReadyForCommunication); // Debug.Console(1, this, "Connect attempt failed {0}", c.ClientStatus); // This is the only case where we should call DisconectFromServer...Event handeler will trigger the cleanup o.DisconnectFromServer(); //CheckClosedAndTryReconnect(); //OnClientReadyForcommunications(false); // Should send false event }, 15000); } else { //CLient connected and shared key is not required so just raise the ready for communication event. if Shared key //required this is called by the shared key being negotiated if (IsReadyForCommunication == false) { OnClientReadyForcommunications(true); // Key not required } } } else { Debug.Console(1, this, "Connect attempt failed {0}", o.ClientStatus); CheckClosedAndTryReconnect(); } }); } catch (Exception ex) { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Client connection exception: {0}", ex.Message); IsTryingToConnect = false; CheckClosedAndTryReconnect(); } } /// /// Disconnect method /// public void Disconnect() { this.LogVerbose("Disconnect Called"); DisconnectCalledByUser = true; if (IsConnected) { Client.DisconnectFromServer(); } if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } Cleanup(); } /// /// Internal call to close up client. ALWAYS use this when disconnecting. /// void Cleanup() { IsTryingToConnect = false; if (Client != null) { //SecureClient.DisconnectFromServer(); Debug.Console(2, this, "Disconnecting Client {0}", DisconnectCalledByUser ? ", Called by user" : ""); Client.SocketStatusChange -= Client_SocketStatusChange; Client.Dispose(); Client = null; } if (ConnectFailTimer != null) { ConnectFailTimer.Stop(); ConnectFailTimer.Dispose(); ConnectFailTimer = null; } } /// ff /// Called from Connect failure or Socket Status change if /// auto reconnect and socket disconnected (Not disconnected by user) /// void CheckClosedAndTryReconnect() { if (Client != null) { Debug.Console(2, this, "Cleaning up remotely closed/failed connection."); Cleanup(); } if (!DisconnectCalledByUser && AutoReconnect) { var halfInterval = AutoReconnectIntervalMs / 2; var rndTime = new Random().Next(-halfInterval, halfInterval) + AutoReconnectIntervalMs; Debug.Console(2, this, "Attempting reconnect in {0} ms, randomized", rndTime); if (RetryTimer != null) { RetryTimer.Stop(); RetryTimer = null; } RetryTimer = new CTimer(o => Connect(), rndTime); } } /// /// Receive callback /// /// /// void Receive(TCPClient client, int numBytes) { if (numBytes > 0) { string str = string.Empty; try { var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); Debug.Console(2, this, "Client Received:\r--------\r{0}\r--------", str); if (!string.IsNullOrEmpty(checkHeartbeat(str))) { if (SharedKeyRequired && str == "SharedKey:") { Debug.Console(2, this, "Server asking for shared key, sending"); SendText(SharedKey + "\n"); } else if (SharedKeyRequired && str == "Shared Key Match") { StopWaitForSharedKeyTimer(); Debug.Console(2, this, "Shared key confirmed. Ready for communication"); OnClientReadyForcommunications(true); // Successful key exchange } else { //var bytesHandler = BytesReceived; //if (bytesHandler != null) // bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); var textHandler = TextReceived; if (textHandler != null) textHandler(this, new GenericTcpServerCommMethodReceiveTextArgs(str)); } } } catch (Exception ex) { Debug.Console(1, this, "Error receiving data: {1}. Error: {0}", ex.Message, str); } } if (client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) client.ReceiveDataAsync(Receive); } void HeartbeatStart() { if (HeartbeatEnabled) { Debug.Console(2, this, "Starting Heartbeat"); if (HeartbeatSendTimer == null) { HeartbeatSendTimer = new CTimer(this.SendHeartbeat, null, HeartbeatInterval, HeartbeatInterval); } if (HeartbeatAckTimer == null) { HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); } } } void HeartbeatStop() { if (HeartbeatSendTimer != null) { Debug.Console(2, this, "Stoping Heartbeat Send"); HeartbeatSendTimer.Stop(); HeartbeatSendTimer = null; } if (HeartbeatAckTimer != null) { Debug.Console(2, this, "Stoping Heartbeat Ack"); HeartbeatAckTimer.Stop(); HeartbeatAckTimer = null; } } void SendHeartbeat(object notused) { this.SendText(HeartbeatString); Debug.Console(2, this, "Sending Heartbeat"); } //private method to check heartbeat requirements and start or reset timer string checkHeartbeat(string received) { try { if (HeartbeatEnabled) { if (!string.IsNullOrEmpty(HeartbeatString)) { var remainingText = received.Replace(HeartbeatString, ""); var noDelimiter = received.Trim(new char[] { '\r', '\n' }); if (noDelimiter.Contains(HeartbeatString)) { if (HeartbeatAckTimer != null) { HeartbeatAckTimer.Reset(HeartbeatInterval * 2); } else { HeartbeatAckTimer = new CTimer(HeartbeatAckTimerFail, null, (HeartbeatInterval * 2), (HeartbeatInterval * 2)); } Debug.Console(2, this, "Heartbeat Received: {0}, from Server", HeartbeatString); return remainingText; } } } } catch (Exception ex) { Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } return received; } void HeartbeatAckTimerFail(object o) { try { if (IsConnected) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "Heartbeat not received from Server...DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE"); SendText("Heartbeat not received by server, closing connection"); CheckClosedAndTryReconnect(); } } catch (Exception ex) { ErrorLog.Error("Heartbeat timeout Error on Client: {0}, {1}", Key, ex); } } /// /// /// void StopWaitForSharedKeyTimer() { if (WaitForSharedKey != null) { WaitForSharedKey.Stop(); WaitForSharedKey = null; } } /// /// SendText method /// public void SendText(string text) { if (!string.IsNullOrEmpty(text)) { try { var bytes = Encoding.GetEncoding(28591).GetBytes(text); if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) { Client.SendDataAsync(bytes, bytes.Length, (c, n) => { // HOW IN THE HELL DO WE CATCH AN EXCEPTION IN SENDING????? if (n <= 0) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "[{0}] Sent zero bytes. Was there an error?", this.Key); } }); } } catch (Exception ex) { Debug.Console(0, this, "Error sending text: {1}. Error: {0}", ex.Message, text); } } } /// /// SendBytes method /// public void SendBytes(byte[] bytes) { if (bytes.Length > 0) { try { if (Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED) Client.SendData(bytes, bytes.Length); } catch (Exception ex) { Debug.Console(0, this, "Error sending bytes. Error: {0}", ex.Message); } } } /// /// SocketStatusChange Callback /// /// /// void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) { if (ProgramIsStopping) { ProgramIsStopping = false; return; } try { Debug.Console(2, this, "Socket status change: {0} ({1})", client.ClientStatus, (ushort)(client.ClientStatus)); OnConnectionChange(); // The client could be null or disposed by this time... if (Client == null || Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { HeartbeatStop(); OnClientReadyForcommunications(false); // socket has gone low CheckClosedAndTryReconnect(); } } catch (Exception ex) { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Error in socket status change callback. Error: {0}\r\r{1}", ex, ex.InnerException); } } /// /// Helper for ConnectionChange event /// void OnConnectionChange() { var handler = ConnectionChange; if (handler != null) ConnectionChange(this, new GenericTcpServerSocketStatusChangeEventArgs(this, Client.ClientStatus)); } /// /// Helper to fire ClientReadyForCommunications event /// void OnClientReadyForcommunications(bool isReady) { IsReadyForCommunication = isReady; if (this.IsReadyForCommunication) { HeartbeatStart(); } var handler = ClientReadyForCommunications; if (handler != null) handler(this, new GenericTcpServerClientReadyForcommunicationsEventArgs(IsReadyForCommunication)); } #endregion } } ================================================ FILE: src/PepperDash.Core/Comm/GenericTcpIpServer.cs ================================================ /*PepperDash Technology Corp. JAG Copyright: 2017 ------------------------------------ ***Notice of Ownership and Copyright*** The material in which this notice appears is the property of PepperDash Technology Corporation, which claims copyright under the laws of the United States of America in the entire body of material and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part, of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited. PepperDash Technology Corporation reserves all rights under applicable laws. ------------------------------------ */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using PepperDash.Core.Logging; namespace PepperDash.Core { /// /// Generic TCP/IP server device /// public class GenericTcpIpServer : Device { #region Events /// /// Event for Receiving text /// public event EventHandler TextReceived; /// /// Event for client connection socket status change /// public event EventHandler ClientConnectionChange; /// /// Event for Server State Change /// public event EventHandler ServerStateChange; /// /// For a server with a pre shared key, this will fire after the communication is established and the key exchange is complete. If no shared key, this will fire /// after connection is successful. Use this event to know when the client is ready for communication to avoid stepping on shared key. /// public event EventHandler ServerClientReadyForCommunications; /// /// A band aid event to notify user that the server has choked. /// public ServerHasChokedCallbackDelegate ServerHasChoked { get; set; } /// /// Delegate for ServerHasChokedCallbackDelegate /// public delegate void ServerHasChokedCallbackDelegate(); #endregion #region Properties/Variables /// /// /// CCriticalSection ServerCCSection = new CCriticalSection(); /// /// A bandaid client that monitors whether the server is reachable /// GenericTcpIpClient_ForServer MonitorClient; /// /// Timer to operate the bandaid monitor client in a loop. /// CTimer MonitorClientTimer; /// /// /// int MonitorClientFailureCount; /// /// Gets or sets the MonitorClientMaxFailureCount /// public int MonitorClientMaxFailureCount { get; set; } /// /// Text representation of the Socket Status enum values for the server /// public string Status { get { if (myTcpServer != null) return myTcpServer.State.ToString(); return ServerState.SERVER_NOT_LISTENING.ToString(); } } /// /// Bool showing if socket is connected /// public bool IsConnected { get { if (myTcpServer != null) return (myTcpServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED; return false; //return (Secure ? SecureServer != null : UnsecureServer != null) && //(Secure ? (SecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED : // (UnsecureServer.State & ServerState.SERVER_CONNECTED) == ServerState.SERVER_CONNECTED); } } /// /// S+ helper for IsConnected /// public ushort UIsConnected { get { return (ushort)(IsConnected ? 1 : 0); } } /// /// Bool showing if socket is connected /// public bool IsListening { get { if (myTcpServer != null) return (myTcpServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING; else return false; //return (Secure ? SecureServer != null : UnsecureServer != null) && //(Secure ? (SecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING : // (UnsecureServer.State & ServerState.SERVER_LISTENING) == ServerState.SERVER_LISTENING); } } /// /// S+ helper for IsConnected /// public ushort UIsListening { get { return (ushort)(IsListening ? 1 : 0); } } /// /// The maximum number of clients. /// Should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable /// public ushort MaxClients { get; set; } /// /// Number of clients currently connected. /// public ushort NumberOfClientsConnected { get { if (myTcpServer != null) return (ushort)myTcpServer.NumberOfClientsConnected; return 0; } } /// /// Gets or sets the Port /// public int Port { get; set; } /// /// S+ helper for Port /// public ushort UPort { get { return Convert.ToUInt16(Port); } set { Port = Convert.ToInt32(value); } } /// /// Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client /// public bool SharedKeyRequired { get; set; } /// /// S+ helper for requires shared key bool /// public ushort USharedKeyRequired { set { if (value == 1) SharedKeyRequired = true; else SharedKeyRequired = false; } } /// /// Gets or sets the SharedKey /// public string SharedKey { get; set; } /// /// Heartbeat Required bool sets whether server disconnects client if heartbeat is not received /// public bool HeartbeatRequired { get; set; } /// /// S+ Helper for Heartbeat Required /// public ushort UHeartbeatRequired { set { if (value == 1) HeartbeatRequired = true; else HeartbeatRequired = false; } } /// /// Gets or sets the HeartbeatRequiredIntervalMs /// public int HeartbeatRequiredIntervalMs { get; set; } /// /// Simpl+ Heartbeat Analog value in seconds /// public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } } /// /// Gets or sets the HeartbeatStringToMatch /// public string HeartbeatStringToMatch { get; set; } //private timers for Heartbeats per client Dictionary HeartbeatTimerDictionary = new Dictionary(); //flags to show the secure server is waiting for client at index to send the shared key List WaitingForSharedKey = new List(); List ClientReadyAfterKeyExchange = new List(); /// /// The connected client indexes /// public List ConnectedClientsIndexes = new List(); /// /// Gets or sets the BufferSize /// public int BufferSize { get; set; } /// /// Private flag to note that the server has stopped intentionally /// private bool ServerStopped { get; set; } //Servers TCPServer myTcpServer; /// /// /// bool ProgramIsStopping; #endregion #region Constructors /// /// constructor S+ Does not accept a key. Use initialze with key to set the debug key on this device. If using with + make sure to set all properties manually. /// public GenericTcpIpServer() : base("Uninitialized Dynamic TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); BufferSize = 2000; MonitorClientMaxFailureCount = 3; } /// /// constructor with debug key set at instantiation. Make sure to set all properties before listening. /// /// public GenericTcpIpServer(string key) : base("Uninitialized Dynamic TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); BufferSize = 2000; MonitorClientMaxFailureCount = 3; Key = key; } /// /// Contstructor that sets all properties by calling the initialize method with a config object. /// /// public GenericTcpIpServer(TcpServerConfigObject serverConfigObject) : base("Uninitialized Dynamic TCP Server") { HeartbeatRequiredIntervalInSeconds = 15; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); BufferSize = 2000; MonitorClientMaxFailureCount = 3; Initialize(serverConfigObject); } #endregion #region Methods - Server Actions /// /// KillServer method /// public void KillServer() { ServerStopped = true; if (MonitorClient != null) { MonitorClient.Disconnect(); } DisconnectAllClientsForShutdown(); StopListening(); } /// /// Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+ /// /// /// /// Initialize method /// public void Initialize(string key) { Key = key; } /// /// Initialze with server configuration object /// /// public void Initialize(TcpServerConfigObject serverConfigObject) { try { if (serverConfigObject != null || string.IsNullOrEmpty(serverConfigObject.Key)) { Key = serverConfigObject.Key; MaxClients = serverConfigObject.MaxClients; Port = serverConfigObject.Port; SharedKeyRequired = serverConfigObject.SharedKeyRequired; SharedKey = serverConfigObject.SharedKey; HeartbeatRequired = serverConfigObject.HeartbeatRequired; HeartbeatRequiredIntervalInSeconds = serverConfigObject.HeartbeatRequiredIntervalInSeconds; HeartbeatStringToMatch = serverConfigObject.HeartbeatStringToMatch; BufferSize = serverConfigObject.BufferSize; } else { ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); } } catch { ErrorLog.Error("Could not initialize server with key: {0}", serverConfigObject.Key); } } /// /// Listen method /// public void Listen() { ServerCCSection.Enter(); try { if (Port < 1 || Port > 65535) { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': Invalid port", Key); ErrorLog.Warn(string.Format("Server '{0}': Invalid port", Key)); return; } if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired) { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Server '{0}': No Shared Key set", Key); ErrorLog.Warn(string.Format("Server '{0}': No Shared Key set", Key)); return; } if (IsListening) return; if (myTcpServer == null) { myTcpServer = new TCPServer(Port, MaxClients); if(HeartbeatRequired) myTcpServer.SocketSendOrReceiveTimeOutInMs = (this.HeartbeatRequiredIntervalMs * 5); // myTcpServer.HandshakeTimeout = 30; } else { KillServer(); myTcpServer.PortNumber = Port; } myTcpServer.SocketStatusChange -= TcpServer_SocketStatusChange; myTcpServer.SocketStatusChange += TcpServer_SocketStatusChange; ServerStopped = false; myTcpServer.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); OnServerStateChange(myTcpServer.State); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "TCP Server Status: {0}, Socket Status: {1}", myTcpServer.State, myTcpServer.ServerSocketStatus); // StartMonitorClient(); ServerCCSection.Leave(); } catch (Exception ex) { ServerCCSection.Leave(); ErrorLog.Error("{1} Error with Dynamic Server: {0}", ex.ToString(), Key); } } /// /// StopListening method /// public void StopListening() { try { Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Stopping Listener"); if (myTcpServer != null) { myTcpServer.Stop(); Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server State: {0}", myTcpServer.State); OnServerStateChange(myTcpServer.State); } ServerStopped = true; } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error stopping server. Error: {0}", ex); } } /// /// Disconnects Client /// /// /// /// DisconnectClient method /// public void DisconnectClient(uint client) { try { myTcpServer.Disconnect(client); Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", client); } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", client, ex); } } /// /// DisconnectAllClientsForShutdown method /// public void DisconnectAllClientsForShutdown() { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting All Clients"); if (myTcpServer != null) { myTcpServer.SocketStatusChange -= TcpServer_SocketStatusChange; foreach (var index in ConnectedClientsIndexes.ToList()) // copy it here so that it iterates properly { var i = index; if (!myTcpServer.ClientConnected(index)) continue; try { myTcpServer.Disconnect(i); Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected client index: {0}", i); } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Disconnecting client index: {0}. Error: {1}", i, ex); } } Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Server Status: {0}", myTcpServer.ServerSocketStatus); } Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Disconnected All Clients"); ConnectedClientsIndexes.Clear(); if (!ProgramIsStopping) { OnConnectionChange(); OnServerStateChange(myTcpServer.State); //State shows both listening and connected } // var o = new { }; } /// /// Broadcast text from server to all connected clients /// /// /// /// BroadcastText method /// public void BroadcastText(string text) { CCriticalSection CCBroadcast = new CCriticalSection(); CCBroadcast.Enter(); try { if (ConnectedClientsIndexes.Count > 0) { byte[] b = Encoding.GetEncoding(28591).GetBytes(text); foreach (uint i in ConnectedClientsIndexes) { if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(i))) { SocketErrorCodes error = myTcpServer.SendDataAsync(i, b, b.Length, (x, y, z) => { }); if (error != SocketErrorCodes.SOCKET_OK && error != SocketErrorCodes.SOCKET_OPERATION_PENDING) this.LogError("{error}",error.ToString()); } } } CCBroadcast.Leave(); } catch (Exception ex) { CCBroadcast.Leave(); Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Broadcasting messages from server. Error: {0}", ex.Message); } } /// /// Not sure this is useful in library, maybe Pro?? /// /// /// /// /// SendTextToClient method /// public void SendTextToClient(string text, uint clientIndex) { try { byte[] b = Encoding.GetEncoding(28591).GetBytes(text); if (myTcpServer != null && myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) { if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) myTcpServer.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); } } catch (Exception ex) { Debug.Console(2, this, "Error sending text to client. Text: {1}. Error: {0}", ex.Message, text); } } //private method to check heartbeat requirements and start or reset timer string checkHeartbeat(uint clientIndex, string received) { try { if (HeartbeatRequired) { if (!string.IsNullOrEmpty(HeartbeatStringToMatch)) { var remainingText = received.Replace(HeartbeatStringToMatch, ""); var noDelimiter = received.Trim(new char[] { '\r', '\n' }); if (noDelimiter.Contains(HeartbeatStringToMatch)) { if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); else { CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); } Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", HeartbeatStringToMatch, clientIndex); // Return Heartbeat SendTextToClient(HeartbeatStringToMatch, clientIndex); return remainingText; } } else { if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs); else { CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs); HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer); } Debug.Console(1, this, "Heartbeat Received: {0}, from client index: {1}", received, clientIndex); } } } catch (Exception ex) { Debug.Console(1, this, "Error checking heartbeat: {0}", ex.Message); } return received; } /// /// Gets the IP address based on the client index /// /// /// IP address of the client /// /// GetClientIPAddress method /// public string GetClientIPAddress(uint clientIndex) { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress Index: {0}", clientIndex); if (!SharedKeyRequired || (SharedKeyRequired && ClientReadyAfterKeyExchange.Contains(clientIndex))) { var ipa = this.myTcpServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "GetClientIPAddress IPAddreess: {0}", ipa); return ipa; } else { return ""; } } #endregion #region Methods - HeartbeatTimer Callback void HeartbeatTimer_CallbackFunction(object o) { uint clientIndex = 99999; string address = string.Empty; try { clientIndex = (uint)o; address = myTcpServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex); Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Heartbeat not received for Client index {2} IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE {1}", address, string.IsNullOrEmpty(HeartbeatStringToMatch) ? "" : ("HeartbeatStringToMatch: " + HeartbeatStringToMatch), clientIndex); if (myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) SendTextToClient("Heartbeat not received by server, closing connection", clientIndex); var discoResult = myTcpServer.Disconnect(clientIndex); //Debug.Console(1, this, "{0}", discoResult); if (HeartbeatTimerDictionary.ContainsKey(clientIndex)) { HeartbeatTimerDictionary[clientIndex].Stop(); HeartbeatTimerDictionary[clientIndex].Dispose(); HeartbeatTimerDictionary.Remove(clientIndex); } } catch (Exception ex) { ErrorLog.Error("{3}: Heartbeat timeout Error on Client Index: {0}, at address: {1}, error: {2}", clientIndex, address, ex.Message, Key); } } #endregion #region Methods - Socket Status Changed Callbacks /// /// Secure Server Socket Status Changed Callback /// /// /// /// void TcpServer_SocketStatusChange(TCPServer server, uint clientIndex, SocketStatus serverSocketStatus) { try { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SecureServerSocketStatusChange Index:{0} status:{1} Port:{2} IP:{3}", clientIndex, serverSocketStatus, this.myTcpServer.GetPortNumberServerAcceptedConnectionFromForSpecificClient(clientIndex), this.myTcpServer.GetLocalAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); if (serverSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED) { if (ConnectedClientsIndexes.Contains(clientIndex)) ConnectedClientsIndexes.Remove(clientIndex); if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex)) { HeartbeatTimerDictionary[clientIndex].Stop(); HeartbeatTimerDictionary[clientIndex].Dispose(); HeartbeatTimerDictionary.Remove(clientIndex); } if (ClientReadyAfterKeyExchange.Contains(clientIndex)) ClientReadyAfterKeyExchange.Remove(clientIndex); if (WaitingForSharedKey.Contains(clientIndex)) WaitingForSharedKey.Remove(clientIndex); } } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Change Callback. Error: {0}", ex); } onConnectionChange(clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); } #endregion #region Methods Connected Callbacks /// /// Secure TCP Client Connected to Secure Server Callback /// /// /// void TcpConnectCallback(TCPServer server, uint clientIndex) { try { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "ConnectCallback: IPAddress: {0}. Index: {1}. Status: {2}", server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), clientIndex, server.GetServerSocketStatusForSpecificClient(clientIndex)); if (clientIndex != 0) { if (server.ClientConnected(clientIndex)) { if (!ConnectedClientsIndexes.Contains(clientIndex)) { ConnectedClientsIndexes.Add(clientIndex); } if (SharedKeyRequired) { if (!WaitingForSharedKey.Contains(clientIndex)) { WaitingForSharedKey.Add(clientIndex); } byte[] b = Encoding.GetEncoding(28591).GetBytes("SharedKey:"); server.SendDataAsync(clientIndex, b, b.Length, (x, y, z) => { }); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Sent Shared Key Request to client at {0}", server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex)); } else { OnServerClientReadyForCommunications(clientIndex); } if (HeartbeatRequired) { if (!HeartbeatTimerDictionary.ContainsKey(clientIndex)) { HeartbeatTimerDictionary.Add(clientIndex, new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs)); } } server.ReceiveDataAsync(clientIndex, TcpServerReceivedDataAsyncCallback); } } else { Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Client attempt faulty."); if (!ServerStopped) { server.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); return; } } } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Socket Status Connect Callback. Error: {0}", ex); } //Debug.Console(1, this, Debug.ErrorLogLevel, "((((((Server State bitfield={0}; maxclient={1}; ServerStopped={2}))))))", // server.State, // MaxClients, // ServerStopped); if ((server.State & ServerState.SERVER_LISTENING) != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped) { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Waiting for next connection"); server.WaitForConnectionAsync(IPAddress.Any, TcpConnectCallback); } } #endregion #region Methods - Send/Receive Callbacks /// /// Secure Received Data Async Callback /// /// /// /// void TcpServerReceivedDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesReceived) { if (numberOfBytesReceived > 0) { string received = "Nothing"; try { byte[] bytes = myTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex); received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived); if (WaitingForSharedKey.Contains(clientIndex)) { received = received.Replace("\r", ""); received = received.Replace("\n", ""); if (received != SharedKey) { byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting"); Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Client at index {0} Shared key did not match the server, disconnecting client. Key: {1}", clientIndex, received); myTCPServer.SendData(clientIndex, b, b.Length); myTCPServer.Disconnect(clientIndex); return; } WaitingForSharedKey.Remove(clientIndex); byte[] success = Encoding.GetEncoding(28591).GetBytes("Shared Key Match"); myTCPServer.SendDataAsync(clientIndex, success, success.Length, null); OnServerClientReadyForCommunications(clientIndex); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Client with index {0} provided the shared key and successfully connected to the server", clientIndex); } else if (!string.IsNullOrEmpty(checkHeartbeat(clientIndex, received))) onTextReceived(received, clientIndex); } catch (Exception ex) { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error Receiving data: {0}. Error: {1}", received, ex); } if (myTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED) myTCPServer.ReceiveDataAsync(clientIndex, TcpServerReceivedDataAsyncCallback); } else { // If numberOfBytesReceived <= 0 myTCPServer.Disconnect(); } } #endregion #region Methods - EventHelpers/Callbacks //Private Helper method to call the Connection Change Event void onConnectionChange(uint clientIndex, SocketStatus clientStatus) { if (clientIndex != 0) //0 is error not valid client change { var handler = ClientConnectionChange; if (handler != null) { handler(this, new GenericTcpServerSocketStatusChangeEventArgs(myTcpServer, clientIndex, clientStatus)); } } } //Private Helper method to call the Connection Change Event void OnConnectionChange() { if (ProgramIsStopping) { return; } var handler = ClientConnectionChange; if (handler != null) { handler(this, new GenericTcpServerSocketStatusChangeEventArgs()); } } //Private Helper Method to call the Text Received Event void onTextReceived(string text, uint clientIndex) { var handler = TextReceived; if (handler != null) handler(this, new GenericTcpServerCommMethodReceiveTextArgs(text, clientIndex)); } //Private Helper Method to call the Server State Change Event void OnServerStateChange(ServerState state) { if (ProgramIsStopping) { return; } var handler = ServerStateChange; if (handler != null) { handler(this, new GenericTcpServerStateChangedEventArgs(state)); } } /// /// Private Event Handler method to handle the closing of connections when the program stops /// /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) { ProgramIsStopping = true; // kill bandaid things if (MonitorClientTimer != null) MonitorClientTimer.Stop(); if (MonitorClient != null) MonitorClient.Disconnect(); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Program stopping. Closing server"); KillServer(); } } //Private event handler method to raise the event that the server is ready to send data after a successful client shared key negotiation void OnServerClientReadyForCommunications(uint clientIndex) { ClientReadyAfterKeyExchange.Add(clientIndex); var handler = ServerClientReadyForCommunications; if (handler != null) handler(this, new GenericTcpServerSocketStatusChangeEventArgs( this, clientIndex, myTcpServer.GetServerSocketStatusForSpecificClient(clientIndex))); } #endregion #region Monitor Client /// /// Starts the monitor client cycle. Timed wait, then call RunMonitorClient /// void StartMonitorClient() { if (MonitorClientTimer != null) { return; } MonitorClientTimer = new CTimer(o => RunMonitorClient(), 60000); } /// /// /// void RunMonitorClient() { MonitorClient = new GenericTcpIpClient_ForServer(Key + "-MONITOR", "127.0.0.1", Port, 2000); MonitorClient.SharedKeyRequired = this.SharedKeyRequired; MonitorClient.SharedKey = this.SharedKey; MonitorClient.ConnectionHasHungCallback = MonitorClientHasHungCallback; //MonitorClient.ConnectionChange += MonitorClient_ConnectionChange; MonitorClient.ClientReadyForCommunications += MonitorClient_IsReadyForComm; Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Starting monitor check"); MonitorClient.Connect(); // From here MonitorCLient either connects or hangs, MonitorClient will call back } /// /// /// void StopMonitorClient() { if (MonitorClient == null) return; MonitorClient.ClientReadyForCommunications -= MonitorClient_IsReadyForComm; MonitorClient.Disconnect(); MonitorClient = null; } /// /// On monitor connect, restart the operation /// void MonitorClient_IsReadyForComm(object sender, GenericTcpServerClientReadyForcommunicationsEventArgs args) { if (args.IsReady) { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Monitor client connection success. Disconnecting in 2s"); MonitorClientTimer.Stop(); MonitorClientTimer = null; MonitorClientFailureCount = 0; CrestronEnvironment.Sleep(2000); StopMonitorClient(); StartMonitorClient(); } } /// /// If the client hangs, add to counter and maybe fire the choke event /// void MonitorClientHasHungCallback() { MonitorClientFailureCount++; MonitorClientTimer.Stop(); MonitorClientTimer = null; StopMonitorClient(); if (MonitorClientFailureCount < MonitorClientMaxFailureCount) { Debug.Console(2, this, Debug.ErrorLogLevel.Warning, "Monitor client connection has hung {0} time{1}, maximum {2}", MonitorClientFailureCount, MonitorClientFailureCount > 1 ? "s" : "", MonitorClientMaxFailureCount); StartMonitorClient(); } else { Debug.Console(2, this, Debug.ErrorLogLevel.Error, "\r***************************\rMonitor client connection has hung a maximum of {0} times.\r***************************", MonitorClientMaxFailureCount); var handler = ServerHasChoked; if (handler != null) handler(); // Some external thing is in charge here. Expected reset of program } } #endregion } } ================================================ FILE: src/PepperDash.Core/Comm/GenericUdpClient.cs ================================================ using System; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using ThreadingTimeout = System.Threading.Timeout; using NetSocketException = System.Net.Sockets.SocketException; namespace PepperDash.Core { /// /// A class to handle basic UDP communications to a remote endpoint /// public class GenericUdpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect { private const string SplusKey = "Uninitialized UdpClient"; private readonly object stateLock = new object(); private readonly Timer reconnectTimer; private UdpClient client; private CancellationTokenSource receiveCancellationTokenSource; private bool connectEnabled; private bool connectionRefusedLogged; private SocketStatus clientStatus = SocketStatus.SOCKET_STATUS_NO_CONNECT; /// /// Object to enable stream debugging /// public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// Fires when data is received from the remote endpoint and returns it as a byte array /// public event EventHandler BytesReceived; /// /// Fires when data is received from the remote endpoint and returns it as text /// public event EventHandler TextReceived; /// /// Fires when the socket status changes /// public event EventHandler ConnectionChange; /// /// Address of remote endpoint /// public string Hostname { get; set; } /// /// Port on remote endpoint /// public int Port { get; set; } /// /// Another S+ helper because large port numbers can be treated as signed ints /// public ushort UPort { get { return Convert.ToUInt16(Port); } set { Port = Convert.ToInt32(value); } } /// /// Defaults to 2000 /// public int BufferSize { get; set; } /// /// True when the local socket is created and associated with the configured remote endpoint /// public bool IsConnected { get { return ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } /// /// S+ helper for IsConnected /// public ushort UIsConnected { get { return (ushort)(IsConnected ? 1 : 0); } } /// /// The current socket status of the client /// public SocketStatus ClientStatus { get { lock (stateLock) { return clientStatus; } } private set { var shouldFireEvent = false; lock (stateLock) { if (clientStatus != value) { clientStatus = value; shouldFireEvent = true; } } if (shouldFireEvent) ConnectionChange?.Invoke(this, new GenericSocketStatusChageEventArgs(this)); } } /// /// Ushort representation of client status /// public ushort UStatus { get { return (ushort)ClientStatus; } } /// /// Gets or sets the AutoReconnect /// public bool AutoReconnect { get; set; } /// /// S+ helper for AutoReconnect /// public ushort UAutoReconnect { get { return (ushort)(AutoReconnect ? 1 : 0); } set { AutoReconnect = value == 1; } } /// /// Milliseconds to wait before attempting to reconnect. Defaults to 5000 /// public int AutoReconnectIntervalMs { get; set; } /// /// Constructor /// public GenericUdpClient(string key, string address, int port, int bufferSize) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; AutoReconnectIntervalMs = 5000; Hostname = address; Port = port; BufferSize = bufferSize; reconnectTimer = new Timer(o => { if (connectEnabled) Connect(); }, null, ThreadingTimeout.Infinite, ThreadingTimeout.Infinite); } /// /// Constructor for S+ /// public GenericUdpClient() : base(SplusKey) { StreamDebugging = new CommunicationStreamDebugging(SplusKey); CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; AutoReconnectIntervalMs = 5000; BufferSize = 2000; reconnectTimer = new Timer(o => { if (connectEnabled) Connect(); }, null, ThreadingTimeout.Infinite, ThreadingTimeout.Infinite); } /// /// Initialize method /// public void Initialize(string key) { Key = key; } private void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) { Debug.Console(1, this, "Program stopping. Closing connection"); Deactivate(); } } /// /// Deactivate method /// public override bool Deactivate() { Disconnect(); return true; } /// /// Connect method /// public void Connect() { if (string.IsNullOrEmpty(Hostname)) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpClient '{0}': No address set", Key); ClientStatus = SocketStatus.SOCKET_STATUS_NO_CONNECT; return; } if (Port < 1 || Port > 65535) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpClient '{0}': Invalid port", Key); ClientStatus = SocketStatus.SOCKET_STATUS_NO_CONNECT; return; } var hostname = Hostname; var port = Port; var bufferSize = BufferSize; UdpClient newClient = null; CancellationTokenSource newReceiveCancellationTokenSource = null; CancellationToken startReceiveToken = default(CancellationToken); var shouldStartReceive = false; lock (stateLock) { connectEnabled = true; if (client != null) return; } try { newReceiveCancellationTokenSource = new CancellationTokenSource(); newClient = new UdpClient(); newClient.Client.ReceiveBufferSize = bufferSize; newClient.Client.SendBufferSize = bufferSize; newClient.Connect(hostname, port); lock (stateLock) { if (!connectEnabled || client != null) { newClient.Close(); newReceiveCancellationTokenSource.Cancel(); newReceiveCancellationTokenSource.Dispose(); return; } receiveCancellationTokenSource = newReceiveCancellationTokenSource; client = newClient; ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED; reconnectTimer.Change(ThreadingTimeout.Infinite, ThreadingTimeout.Infinite); startReceiveToken = receiveCancellationTokenSource.Token; shouldStartReceive = true; } if (shouldStartReceive) StartReceive(startReceiveToken); } catch (Exception ex) { Debug.LogMessage(ex, "Error connecting UDP client {0}", this, Key); if (newClient != null) newClient.Close(); if (newReceiveCancellationTokenSource != null) { newReceiveCancellationTokenSource.Cancel(); newReceiveCancellationTokenSource.Dispose(); } lock (stateLock) { if (connectEnabled && client == null) { ClientStatus = SocketStatus.SOCKET_STATUS_NO_CONNECT; StartReconnectTimer(); } } } } /// /// Disconnect method /// public void Disconnect() { lock (stateLock) { connectEnabled = false; reconnectTimer.Change(ThreadingTimeout.Infinite, ThreadingTimeout.Infinite); CleanupClient(); ClientStatus = SocketStatus.SOCKET_STATUS_NO_CONNECT; } } /// /// SendText method /// public void SendText(string text) { this.PrintSentText(text); var bytes = Encoding.GetEncoding(28591).GetBytes(text); SendBytes(bytes); } /// /// SendBytes method /// public void SendBytes(byte[] bytes) { if (bytes == null) return; try { this.PrintSentBytes(bytes); if (!IsConnected || client == null) Connect(); var udpClient = client; if (!IsConnected || udpClient == null) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpClient '{0}': Cannot send bytes because the client is not connected", Key); return; } udpClient.Send(bytes, bytes.Length); } catch (Exception ex) { Debug.LogMessage(ex, "Error sending UDP bytes for {0}", this, Key); HandleDisconnected(); } } private void StartReceive(CancellationToken token) { Task.Run(async () => { while (!token.IsCancellationRequested) { try { var udpClient = client; if (udpClient == null) return; var result = await udpClient.ReceiveAsync().ConfigureAwait(false); var bytes = result.Buffer; if (bytes == null || bytes.Length == 0) continue; connectionRefusedLogged = false; var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); this.PrintReceivedBytes(bytes); this.PrintReceivedText(text); BytesReceived?.Invoke(this, new GenericCommMethodReceiveBytesArgs(bytes)); TextReceived?.Invoke(this, new GenericCommMethodReceiveTextArgs(text)); } catch (ObjectDisposedException) { return; } catch (InvalidOperationException) { return; } catch (NetSocketException ex) { if (ex.SocketErrorCode == SocketError.ConnectionRefused) { if (!connectionRefusedLogged) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpClient '{0}': Remote endpoint refused UDP traffic or is no longer listening", Key); connectionRefusedLogged = true; } HandleDisconnected(); return; } Debug.LogMessage(ex, "UDP receive error for {0}", this, Key); if (AutoReconnect) { HandleDisconnected(); return; } continue; } catch (Exception ex) { Debug.LogMessage(ex, "Unexpected UDP receive error for {0}", this, Key); if (AutoReconnect) { HandleDisconnected(); return; } continue; } } }, token); } private void HandleDisconnected() { lock (stateLock) { CleanupClient(); ClientStatus = SocketStatus.SOCKET_STATUS_NO_CONNECT; StartReconnectTimer(); } } private void StartReconnectTimer() { if (AutoReconnect && connectEnabled) reconnectTimer.Change(AutoReconnectIntervalMs, ThreadingTimeout.Infinite); } private void CleanupClient() { if (receiveCancellationTokenSource != null) { receiveCancellationTokenSource.Cancel(); receiveCancellationTokenSource.Dispose(); receiveCancellationTokenSource = null; } if (client != null) { client.Close(); client = null; } } } } ================================================ FILE: src/PepperDash.Core/Comm/GenericUdpServer.cs ================================================  using System; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using Newtonsoft.Json; using PepperDash.Core.Logging; namespace PepperDash.Core { /// /// Generic UDP Server device /// public class GenericUdpServer : Device, ISocketStatusWithStreamDebugging { private const string SplusKey = "Uninitialized Udp Server"; /// /// Object to enable stream debugging /// public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// /// public event EventHandler BytesReceived; /// /// /// public event EventHandler TextReceived; /// /// This event will fire when a message is dequeued that includes the source IP and Port info if needed to determine the source of the received data. /// public event EventHandler DataRecievedExtra; /// /// /// public event EventHandler ConnectionChange; /// /// /// public event EventHandler UpdateConnectionStatus; /// /// /// public SocketStatus ClientStatus { get { return Server.ServerStatus; } } /// /// /// public ushort UStatus { get { return (ushort)Server.ServerStatus; } } /// /// Address of server /// public string Hostname { get; set; } /// /// Port on server /// public int Port { get; set; } /// /// Another damn S+ helper because S+ seems to treat large port nums as signed ints /// which screws up things /// public ushort UPort { get { return Convert.ToUInt16(Port); } set { Port = Convert.ToInt32(value); } } /// /// Indicates that the UDP Server is enabled /// public bool IsConnected { get; private set; } /// /// Numeric value indicating /// public ushort UIsConnected { get { return IsConnected ? (ushort)1 : (ushort)0; } } /// /// Defaults to 2000 /// public int BufferSize { get; set; } /// /// The server /// public UDPServer Server { get; private set; } /// /// Constructor for S+. Make sure to set key, address, port, and buffersize using init method /// public GenericUdpServer() : base(SplusKey) { StreamDebugging = new CommunicationStreamDebugging(SplusKey); BufferSize = 5000; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); } /// /// /// /// /// /// /// public GenericUdpServer(string key, string address, int port, int bufferSize) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); Hostname = address; Port = port; BufferSize = bufferSize; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); } /// /// Call from S+ to initialize values /// /// /// /// /// /// Initialize method /// public void Initialize(string key, string address, ushort port) { Key = key; Hostname = address; UPort = port; } /// /// /// /// void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) { // Re-enable the server if the link comes back up and the status should be connected if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp && IsConnected) { Connect(); } } /// /// /// /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType != eProgramStatusEventType.Stopping) return; Debug.Console(1, this, "Program stopping. Disabling Server"); Disconnect(); } /// /// Connect method /// public void Connect() { if (Server == null) { try { var address = IPAddress.Parse(Hostname); Server = new UDPServer(address, Port, BufferSize); } catch (Exception ex) { this.LogError("Error parsing IP Address '{ipAddress}': message: {message}", Hostname, ex.Message); this.LogInformation("Creating UDPServer with default buffersize"); Server = new UDPServer(); } } if (string.IsNullOrEmpty(Hostname)) { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': No address set", Key); return; } if (Port < 1 || Port > 65535) { { Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericUdpServer '{0}': Invalid port", Key); return; } } var status = Server.EnableUDPServer(Hostname, Port); Debug.Console(2, this, "SocketErrorCode: {0}", status); if (status == SocketErrorCodes.SOCKET_OK) IsConnected = true; var handler = UpdateConnectionStatus; if (handler != null) handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); // Start receiving data Server.ReceiveDataAsync(Receive); } /// /// Disconnect method /// public void Disconnect() { if (Server != null) Server.DisableUDPServer(); IsConnected = false; var handler = UpdateConnectionStatus; if (handler != null) handler(this, new GenericUdpConnectedEventArgs(UIsConnected)); } /// /// Recursive method to receive data /// /// /// void Receive(UDPServer server, int numBytes) { Debug.Console(2, this, "Received {0} bytes", numBytes); try { if (numBytes <= 0) return; var sourceIp = Server.IPAddressLastMessageReceivedFrom; var sourcePort = Server.IPPortLastMessageReceivedFrom; var bytes = server.IncomingDataBuffer.Take(numBytes).ToArray(); var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); var dataRecivedExtra = DataRecievedExtra; if (dataRecivedExtra != null) dataRecivedExtra(this, new GenericUdpReceiveTextExtraArgs(str, sourceIp, sourcePort, bytes)); Debug.Console(2, this, "Bytes: {0}", bytes.ToString()); var bytesHandler = BytesReceived; if (bytesHandler != null) { this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; if (textHandler != null) { this.PrintReceivedText(str); textHandler(this, new GenericCommMethodReceiveTextArgs(str)); } } catch (Exception ex) { this.LogException(ex, "GenericUdpServer Receive error"); } finally { server.ReceiveDataAsync(Receive); } } /// /// General send method /// /// /// /// SendText method /// public void SendText(string text) { var bytes = Encoding.GetEncoding(28591).GetBytes(text); if (IsConnected && Server != null) { this.PrintSentText(text); Server.SendData(bytes, bytes.Length); } } /// /// /// /// /// /// SendBytes method /// public void SendBytes(byte[] bytes) { this.PrintSentBytes(bytes); if (IsConnected && Server != null) Server.SendData(bytes, bytes.Length); } } /// /// Represents a GenericUdpReceiveTextExtraArgs /// public class GenericUdpReceiveTextExtraArgs : EventArgs { /// /// /// public string Text { get; private set; } /// /// /// public string IpAddress { get; private set; } /// /// /// public int Port { get; private set; } /// /// /// public byte[] Bytes { get; private set; } /// /// /// /// /// /// /// public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes) { Text = text; IpAddress = ipAddress; Port = port; Bytes = bytes; } /// /// Stupid S+ Constructor /// public GenericUdpReceiveTextExtraArgs() { } } /// /// /// public class UdpServerPropertiesConfig { /// /// /// [JsonProperty(Required = Required.Always)] public string Address { get; set; } /// /// /// [JsonProperty(Required = Required.Always)] public int Port { get; set; } /// /// Defaults to 32768 /// public int BufferSize { get; set; } /// /// /// public UdpServerPropertiesConfig() { BufferSize = 32768; } } } ================================================ FILE: src/PepperDash.Core/Comm/StreamDebuggingExtensions.cs ================================================ using System; using Crestron.SimplSharp; namespace PepperDash.Core { /// /// Extension methods for stream debugging /// public static class StreamDebuggingExtensions { private static readonly string app = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? $"App {InitialParametersClass.ApplicationNumber}" : $"{InitialParametersClass.RoomId}"; /// /// Print the sent bytes to the console /// /// comms device /// bytes to print public static void PrintSentBytes(this IStreamDebugging comms, byte[] bytes) { if (!comms.StreamDebugging.TxStreamDebuggingIsEnabled) return; var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Sending {bytes.Length} bytes: '{ComTextHelper.GetEscapedText(bytes)}'"); } /// /// Print the received bytes to the console /// /// comms device /// bytes to print public static void PrintReceivedBytes(this IStreamDebugging comms, byte[] bytes) { if (!comms.StreamDebugging.RxStreamDebuggingIsEnabled) return; var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Received {bytes.Length} bytes: '{ComTextHelper.GetEscapedText(bytes)}'"); } /// /// Print the sent text to the console /// /// comms device /// text to print public static void PrintSentText(this IStreamDebugging comms, string text) { if (!comms.StreamDebugging.TxStreamDebuggingIsEnabled) return; var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Sending Text: '{ComTextHelper.GetDebugText(text)}'"); } /// /// Print the received text to the console /// /// comms device /// text to print public static void PrintReceivedText(this IStreamDebugging comms, string text) { if (!comms.StreamDebugging.RxStreamDebuggingIsEnabled) return; var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Received Text: '{ComTextHelper.GetDebugText(text)}'"); } } } ================================================ FILE: src/PepperDash.Core/Comm/TcpClientConfigObject.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Core { /// /// Represents a TcpClientConfigObject /// public class TcpClientConfigObject { /// /// TcpSsh Properties /// [JsonProperty("control")] public ControlPropertiesConfig Control { get; set; } /// /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic /// [JsonProperty("secure")] public bool Secure { get; set; } /// /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client /// [JsonProperty("sharedKeyRequired")] public bool SharedKeyRequired { get; set; } /// /// The shared key that must match on the server and client /// [JsonProperty("sharedKey")] public string SharedKey { get; set; } /// /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. /// heartbeats do not raise received events. /// [JsonProperty("heartbeatRequired")] public bool HeartbeatRequired { get; set; } /// /// The interval in seconds for the heartbeat from the client. If not received client is disconnected /// [JsonProperty("heartbeatRequiredIntervalInSeconds")] public ushort HeartbeatRequiredIntervalInSeconds { get; set; } /// /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. /// [JsonProperty("heartbeatStringToMatch")] public string HeartbeatStringToMatch { get; set; } /// /// Receive Queue size must be greater than 20 or defaults to 20 /// [JsonProperty("receiveQueueSize")] public int ReceiveQueueSize { get; set; } } } ================================================ FILE: src/PepperDash.Core/Comm/TcpServerConfigObject.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core { /// /// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities /// public class TcpServerConfigObject { /// /// Uique key /// public string Key { get; set; } /// /// Max Clients that the server will allow to connect. /// public ushort MaxClients { get; set; } /// /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic /// public bool Secure { get; set; } /// /// Port for the server to listen on /// public int Port { get; set; } /// /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client /// public bool SharedKeyRequired { get; set; } /// /// The shared key that must match on the server and client /// public string SharedKey { get; set; } /// /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. /// heartbeats do not raise received events. /// public bool HeartbeatRequired { get; set; } /// /// The interval in seconds for the heartbeat from the client. If not received client is disconnected /// public ushort HeartbeatRequiredIntervalInSeconds { get; set; } /// /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. /// public string HeartbeatStringToMatch { get; set; } /// /// Client buffer size. See Crestron help. defaults to 2000 if not greater than 2000 /// public int BufferSize { get; set; } /// /// Receive Queue size must be greater than 20 or defaults to 20 /// public int ReceiveQueueSize { get; set; } } } ================================================ FILE: src/PepperDash.Core/Comm/eControlMethods.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core { /// /// Crestron Control Methods for a comm object /// public enum eControlMethod { /// /// /// None = 0, /// /// RS232/422/485 /// Com, /// /// Crestron IpId (most Crestron ethernet devices) /// IpId, /// /// Crestron IpIdTcp (HD-MD series, etc.) /// IpidTcp, /// /// Crestron IR control /// IR, /// /// SSH client /// Ssh, /// /// TCP/IP client /// Tcpip, /// /// Telnet /// Telnet, /// /// Crestnet device /// Cresnet, /// /// CEC Control, via a DM HDMI port /// Cec, /// /// UDP Server /// Udp, /// /// UDP client /// UdpClient, /// /// HTTP client /// Http, /// /// HTTPS client /// Https, /// /// Websocket client /// Ws, /// /// Secure Websocket client /// Wss, /// /// Secure TCP/IP /// SecureTcpIp, /// /// Used when comms needs to be handled in SIMPL and bridged opposite the normal direction /// ComBridge, /// /// InfinetEX control /// InfinetEx } } ================================================ FILE: src/PepperDash.Core/Comm/eStreamDebuggingDataTypeSettings.cs ================================================ using System; namespace PepperDash.Core { /// /// The available settings for stream debugging data format types /// [Flags] public enum eStreamDebuggingDataTypeSettings { /// /// Debug data in byte format /// Bytes = 0, /// /// Debug data in text format /// Text = 1, /// /// Debug data in both byte and text formats /// Both = Bytes | Text } } ================================================ FILE: src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs ================================================ using System; namespace PepperDash.Core { /// /// The available settings for stream debugging /// [Flags] public enum eStreamDebuggingSetting { /// /// Debug off /// Off = 0, /// /// Debug received data /// Rx = 1, /// /// Debug transmitted data /// Tx = 2, /// /// Debug both received and transmitted data /// Both = Rx | Tx } } ================================================ FILE: src/PepperDash.Core/CommunicationExtras.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; using Newtonsoft.Json; namespace PepperDash.Core { /// /// An incoming communication stream /// public interface ICommunicationReceiver : IKeyed { /// /// Notifies of bytes received /// event EventHandler BytesReceived; /// /// Notifies of text received /// event EventHandler TextReceived; /// /// Indicates connection status /// [JsonProperty("isConnected")] bool IsConnected { get; } /// /// Connect to the device /// void Connect(); /// /// Disconnect from the device /// void Disconnect(); } /// /// Defines the contract for IBasicCommunication /// public interface IBasicCommunication : ICommunicationReceiver { /// /// Send text to the device /// /// void SendText(string text); /// /// Send bytes to the device /// /// void SendBytes(byte[] bytes); } /// /// Represents a device that implements IBasicCommunication and IStreamDebugging /// public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging { } /// /// Represents a device with stream debugging capablities /// public interface IStreamDebugging : IKeyed { /// /// Object to enable stream debugging /// [JsonProperty("streamDebugging")] CommunicationStreamDebugging StreamDebugging { get; } } /// /// For IBasicCommunication classes that have SocketStatus. GenericSshClient, /// GenericTcpIpClient /// public interface ISocketStatus : IBasicCommunication { /// /// Notifies of socket status changes /// event EventHandler ConnectionChange; /// /// The current socket status of the client /// [JsonProperty("clientStatus")] [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] SocketStatus ClientStatus { get; } } /// /// Describes a device that implements ISocketStatus and IStreamDebugging /// public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging { } /// /// Describes a device that can automatically attempt to reconnect /// public interface IAutoReconnect { /// /// Enable automatic recconnect /// [JsonProperty("autoReconnect")] bool AutoReconnect { get; set; } /// /// Interval in ms to attempt automatic recconnections /// [JsonProperty("autoReconnectIntervalMs")] int AutoReconnectIntervalMs { get; set; } } /// /// /// public enum eGenericCommMethodStatusChangeType { /// /// Connected /// Connected, /// /// Disconnected /// Disconnected } /// /// This delegate defines handler for IBasicCommunication status changes /// /// Device firing the status change /// public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status); /// /// /// public class GenericCommMethodReceiveBytesArgs : EventArgs { /// /// Gets or sets the Bytes /// public byte[] Bytes { get; private set; } /// /// /// /// public GenericCommMethodReceiveBytesArgs(byte[] bytes) { Bytes = bytes; } /// /// S+ Constructor /// public GenericCommMethodReceiveBytesArgs() { } } /// /// /// public class GenericCommMethodReceiveTextArgs : EventArgs { /// /// /// public string Text { get; private set; } /// /// /// public string Delimiter { get; private set; } /// /// /// /// public GenericCommMethodReceiveTextArgs(string text) { Text = text; } /// /// /// /// /// public GenericCommMethodReceiveTextArgs(string text, string delimiter) : this(text) { Delimiter = delimiter; } /// /// S+ Constructor /// public GenericCommMethodReceiveTextArgs() { } } } ================================================ FILE: src/PepperDash.Core/Config/PortalConfigReader.cs ================================================ using System; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Core.Config { /// /// Reads a Portal formatted config file /// public class PortalConfigReader { const string template = "template"; const string system = "system"; const string systemUrl = "system_url"; const string templateUrl = "template_url"; const string info = "info"; const string devices = "devices"; const string rooms = "rooms"; const string sourceLists = "sourceLists"; const string destinationLists = "destinationLists"; const string cameraLists = "cameraLists"; const string audioControlPointLists = "audioControlPointLists"; const string tieLines = "tieLines"; const string joinMaps = "joinMaps"; const string global = "global"; /// /// Reads the config file, checks if it needs a merge, merges and saves, then returns the merged Object. /// /// JObject of config file public static void ReadAndMergeFileIfNecessary(string filePath, string savePath) { try { if (!File.Exists(filePath)) { Debug.LogError( "ERROR: Configuration file not present. Please load file to {0} and reset program", filePath); } using (StreamReader fs = new StreamReader(filePath)) { var jsonObj = JObject.Parse(fs.ReadToEnd()); if(jsonObj[template] != null && jsonObj[system] != null) { // it's a double-config, merge it. var merged = MergeConfigs(jsonObj); if (jsonObj[systemUrl] != null) { merged[systemUrl] = jsonObj[systemUrl].Value(); } if (jsonObj[templateUrl] != null) { merged[templateUrl] = jsonObj[templateUrl].Value(); } jsonObj = merged; } using (StreamWriter fw = new StreamWriter(savePath)) { fw.Write(jsonObj.ToString(Formatting.Indented)); Debug.LogMessage(LogEventLevel.Debug, "JSON config merged and saved to {0}", savePath); } } } catch (Exception e) { Debug.LogMessage(e, "ERROR: Config load failed"); } } /// /// /// /// /// /// /// MergeConfigs method /// public static JObject MergeConfigs(JObject doubleConfig) { var system = JObject.FromObject(doubleConfig["system"]); var template = JObject.FromObject(doubleConfig["template"]); var merged = new JObject(); // Put together top-level objects if (system[info] != null) merged.Add(info, Merge(template[info], system[info], info)); else merged.Add(info, template[info]); merged.Add(devices, MergeArraysOnTopLevelProperty(template[devices] as JArray, system[devices] as JArray, "key", devices)); if (system[rooms] == null) merged.Add(rooms, template[rooms]); else merged.Add(rooms, MergeArraysOnTopLevelProperty(template[rooms] as JArray, system[rooms] as JArray, "key", rooms)); if (system[sourceLists] == null) merged.Add(sourceLists, template[sourceLists]); else merged.Add(sourceLists, Merge(template[sourceLists], system[sourceLists], sourceLists)); if (system[destinationLists] == null) merged.Add(destinationLists, template[destinationLists]); else merged.Add(destinationLists, Merge(template[destinationLists], system[destinationLists], destinationLists)); if (system[cameraLists] == null) merged.Add(cameraLists, template[cameraLists]); else merged.Add(cameraLists, Merge(template[cameraLists], system[cameraLists], cameraLists)); if (system[audioControlPointLists] == null) merged.Add(audioControlPointLists, template[audioControlPointLists]); else merged.Add(audioControlPointLists, Merge(template[audioControlPointLists], system[audioControlPointLists], audioControlPointLists)); // Template tie lines take precedence. Config tool doesn't do them at system // level anyway... if (template[tieLines] != null) merged.Add(tieLines, template[tieLines]); else if (system[tieLines] != null) merged.Add(tieLines, system[tieLines]); else merged.Add(tieLines, new JArray()); if (template[joinMaps] != null) merged.Add(joinMaps, template[joinMaps]); else merged.Add(joinMaps, new JObject()); if (system[global] != null) merged.Add(global, Merge(template[global], system[global], global)); else merged.Add(global, template[global]); //Debug.Console(2, "MERGED CONFIG RESULT: \x0d\x0a{0}", merged); return merged; } /// /// Merges the contents of a base and a delta array, matching the entries on a top-level property /// given by propertyName. Returns a merge of them. Items in the delta array that do not have /// a matched item in base array will not be merged. Non keyed system items will replace the template items. /// static JArray MergeArraysOnTopLevelProperty(JArray a1, JArray a2, string propertyName, string path) { var result = new JArray(); if (a2 == null || a2.Count == 0) // If the system array is null or empty, return the template array return a1; else if (a1 != null) { if (a2[0]["key"] == null) // If the first item in the system array has no key, overwrite the template array { // with the system array return a2; } else // The arrays are keyed, merge them by key { for (int i = 0; i < a1.Count(); i++) { var a1Dev = a1[i]; // Try to get a system device and if found, merge it onto template var a2Match = a2.FirstOrDefault(t => t[propertyName].Equals(a1Dev[propertyName]));// t.Value("uid") == tmplDev.Value("uid")); if (a2Match != null) { var mergedItem = Merge(a1Dev, a2Match, string.Format("{0}[{1}].", path, i));// Merge(JObject.FromObject(a1Dev), JObject.FromObject(a2Match)); result.Add(mergedItem); } else result.Add(a1Dev); } } } return result; } /// /// Helper for using with JTokens. Converts to JObject /// static JObject Merge(JToken t1, JToken t2, string path) { return Merge(JObject.FromObject(t1), JObject.FromObject(t2), path); } /// /// Merge o2 onto o1 /// /// /// /// static JObject Merge(JObject o1, JObject o2, string path) { foreach (var o2Prop in o2) { var propKey = o2Prop.Key; var o1Value = o1[propKey]; var o2Value = o2[propKey]; // if the property doesn't exist on o1, then add it. if (o1Value == null) { o1.Add(propKey, o2Value); } // otherwise merge them else { // Drill down var propPath = String.Format("{0}.{1}", path, propKey); try { if (o1Value is JArray) { if (o2Value is JArray) { o1Value.Replace(MergeArraysOnTopLevelProperty(o1Value as JArray, o2Value as JArray, "key", propPath)); } } else if (o2Prop.Value.HasValues && o1Value.HasValues) { o1Value.Replace(Merge(JObject.FromObject(o1Value), JObject.FromObject(o2Value), propPath)); } else { o1Value.Replace(o2Prop.Value); } } catch (Exception e) { Debug.LogError($"Cannot merge items at path {propPath}: \r{e}"); } } } return o1; } } } ================================================ FILE: src/PepperDash.Core/Conversion/Convert.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core { /// /// Represents a EncodingHelper /// public class EncodingHelper { /// /// ConvertUtf8ToAscii method /// public static string ConvertUtf8ToAscii(string utf8String) { return Encoding.ASCII.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); } /// /// ConvertUtf8ToUtf16 method /// public static string ConvertUtf8ToUtf16(string utf8String) { return Encoding.Unicode.GetString(Encoding.UTF8.GetBytes(utf8String), 0, utf8String.Length); } } } ================================================ FILE: src/PepperDash.Core/CoreInterfaces.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; using Serilog; namespace PepperDash.Core { /// /// Unique key interface to require a unique key for the class /// public interface IKeyed { /// /// Unique Key /// [JsonProperty("key")] string Key { get; } } /// /// Named Keyed device interface. Forces the device to have a Unique Key and a name. /// public interface IKeyName : IKeyed { /// /// Isn't it obvious :) /// [JsonProperty("name")] string Name { get; } } } ================================================ FILE: src/PepperDash.Core/Device.cs ================================================ using System; using System.Collections.Generic; using Serilog.Events; namespace PepperDash.Core { //********************************************************************************************************* /// /// Represents a Device /// public class Device : IKeyName { /// /// Unique Key /// public string Key { get; protected set; } /// /// Gets or sets the Name /// public string Name { get; protected set; } /// /// /// public bool Enabled { get; protected set; } List _PreActivationActions; List _PostActivationActions; /// /// /// public static Device DefaultDevice { get { return _DefaultDevice; } } static Device _DefaultDevice = new Device("Default", "Default"); /// /// Base constructor for all Devices. /// /// public Device(string key) { Key = key; if (key.Contains(".")) Debug.LogMessage(LogEventLevel.Information, "WARNING: Device key should not include '.'", this); Name = ""; } /// /// Constructor with key and name /// /// /// public Device(string key, string name) : this(key) { Name = name; } //public Device(DeviceConfig config) // : this(config.Key, config.Name) //{ // Config = config; //} /// /// Adds a pre activation action /// /// public void AddPreActivationAction(Action act) { if (_PreActivationActions == null) _PreActivationActions = new List(); _PreActivationActions.Add(act); } /// /// Adds a post activation action /// /// /// /// AddPostActivationAction method /// public void AddPostActivationAction(Action act) { if (_PostActivationActions == null) _PostActivationActions = new List(); _PostActivationActions.Add(act); } /// /// PreActivate method /// public void PreActivate() { if (_PreActivationActions != null) _PreActivationActions.ForEach(a => { try { a.Invoke(); } catch (Exception e) { Debug.LogMessage(e, "Error in PreActivationAction: " + e.Message, this); } }); } /// /// Activate method /// public bool Activate() { //if (_PreActivationActions != null) // _PreActivationActions.ForEach(a => a.Invoke()); var result = CustomActivate(); //if(result && _PostActivationActions != null) // _PostActivationActions.ForEach(a => a.Invoke()); return result; } /// /// PostActivate method /// public void PostActivate() { if (_PostActivationActions != null) _PostActivationActions.ForEach(a => { try { a.Invoke(); } catch (Exception e) { Debug.LogMessage(e, "Error in PostActivationAction: " + e.Message, this); } }); } /// /// Called in between Pre and PostActivationActions when Activate() is called. /// Override to provide addtitional setup when calling activation. Overriding classes /// do not need to call base.CustomActivate() /// /// true if device activated successfully. /// /// CustomActivate method /// public virtual bool CustomActivate() { return true; } /// /// Call to deactivate device - unlink events, etc. Overriding classes do not /// need to call base.Deactivate() /// /// public virtual bool Deactivate() { return true; } /// /// Call this method to start communications with a device. Overriding classes do not need to call base.Initialize() /// public virtual void Initialize() { } /// /// Helper method to check object for bool value false and fire an Action method /// /// Should be of type bool, others will be ignored /// Action to be run when o is false public void OnFalse(object o, Action a) { if (o is bool && !(bool)o) a(); } /// /// Returns a string representation of the object, including its key and name. /// /// The returned string is formatted as "{Key} - {Name}". If the Name property is /// null or empty, "---" is used in place of the name. /// A string that represents the object, containing the key and name in the format "{Key} - {Name}". /// /// ToString method /// public override string ToString() { return string.Format("{0} - {1}", Key, string.IsNullOrEmpty(Name) ? "---" : Name); } } } ================================================ FILE: src/PepperDash.Core/EthernetHelper.cs ================================================ using Crestron.SimplSharp; using Newtonsoft.Json; using Serilog.Events; namespace PepperDash.Core { /// /// Represents a EthernetHelper /// public class EthernetHelper { /// /// /// public static EthernetHelper LanHelper { get { if (_LanHelper == null) _LanHelper = new EthernetHelper(0); return _LanHelper; } } static EthernetHelper _LanHelper; // ADD OTHER HELPERS HERE /// /// Gets or sets the PortNumber /// public int PortNumber { get; private set; } private EthernetHelper(int portNumber) { PortNumber = portNumber; } /// /// /// [JsonProperty("linkActive")] public bool LinkActive { get { var status = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_LINK_STATUS, 0); Debug.LogMessage(LogEventLevel.Information, "LinkActive = {0}", status); return status == ""; } } /// /// /// [JsonProperty("dchpActive")] public bool DhcpActive { get { return CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, 0) == "ON"; } } /// /// /// [JsonProperty("hostname")] public string Hostname { get { return CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); } } /// /// /// [JsonProperty("ipAddress")] public string IPAddress { get { return CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); } } /// /// /// [JsonProperty("subnetMask")] public string SubnetMask { get { return CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 0); } } /// /// /// [JsonProperty("defaultGateway")] public string DefaultGateway { get { return CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); } } } } ================================================ FILE: src/PepperDash.Core/EventArgs.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core { /// /// Bool change event args /// public class BoolChangeEventArgs : EventArgs { /// /// Boolean state property /// public bool State { get; set; } /// /// Gets or sets the IntValue /// public ushort IntValue { get { return (ushort)(State ? 1 : 0); } } /// /// Gets or sets the Type /// public ushort Type { get; set; } /// /// Gets or sets the Index /// public ushort Index { get; set; } /// /// Constructor /// public BoolChangeEventArgs() { } /// /// Constructor overload /// /// /// public BoolChangeEventArgs(bool state, ushort type) { State = state; Type = type; } /// /// Constructor overload /// /// /// /// public BoolChangeEventArgs(bool state, ushort type, ushort index) { State = state; Type = type; Index = index; } } /// /// Represents a UshrtChangeEventArgs /// public class UshrtChangeEventArgs : EventArgs { /// /// Ushort change event args integer value /// public ushort IntValue { get; set; } /// /// Gets or sets the Type /// public ushort Type { get; set; } /// /// Gets or sets the Index /// public ushort Index { get; set; } /// /// Constructor /// public UshrtChangeEventArgs() { } /// /// Constructor overload /// /// /// public UshrtChangeEventArgs(ushort intValue, ushort type) { IntValue = intValue; Type = type; } /// /// Constructor overload /// /// /// /// public UshrtChangeEventArgs(ushort intValue, ushort type, ushort index) { IntValue = intValue; Type = type; Index = index; } } /// /// Represents a StringChangeEventArgs /// public class StringChangeEventArgs : EventArgs { /// /// String change event args value /// public string StringValue { get; set; } /// /// Gets or sets the Type /// public ushort Type { get; set; } /// /// Gets or sets the Index /// public ushort Index { get; set; } /// /// Constructor /// public StringChangeEventArgs() { } /// /// Constructor overload /// /// /// public StringChangeEventArgs(string stringValue, ushort type) { StringValue = stringValue; Type = type; } /// /// Constructor overload /// /// /// /// public StringChangeEventArgs(string stringValue, ushort type, ushort index) { StringValue = stringValue; Type = type; Index = index; } } } ================================================ FILE: src/PepperDash.Core/GenericRESTfulCommunications/Constants.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.GenericRESTfulCommunications { /// /// Constants /// public class GenericRESTfulConstants { /// /// Generic boolean change /// public const ushort BoolValueChange = 1; /// /// Generic Ushort change /// public const ushort UshrtValueChange = 101; /// /// Response Code Ushort change /// public const ushort ResponseCodeChange = 102; /// /// Generic String chagne /// public const ushort StringValueChange = 201; /// /// Response string change /// public const ushort ResponseStringChange = 202; /// /// Error string change /// public const ushort ErrorStringChange = 203; } } ================================================ FILE: src/PepperDash.Core/GenericRESTfulCommunications/GenericRESTfulClient.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.Net.Https; namespace PepperDash.Core.GenericRESTfulCommunications { /// /// Generic RESTful communication class /// public class GenericRESTfulClient { /// /// Boolean event handler /// public event EventHandler BoolChange; /// /// Ushort event handler /// public event EventHandler UshrtChange; /// /// String event handler /// public event EventHandler StringChange; /// /// Constructor /// public GenericRESTfulClient() { } /// /// Generic RESTful submit request /// /// /// /// /// /// /// public void SubmitRequest(string url, ushort port, ushort requestType, string contentType, string username, string password) { if (url.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) { SubmitRequestHttps(url, port, requestType, contentType, username, password); } else if (url.StartsWith("http:", StringComparison.OrdinalIgnoreCase)) { SubmitRequestHttp(url, port, requestType, contentType, username, password); } else { OnStringChange(string.Format("Invalid URL {0}", url), 0, GenericRESTfulConstants.ErrorStringChange); } } /// /// Private HTTP submit request /// /// /// /// /// /// /// private void SubmitRequestHttp(string url, ushort port, ushort requestType, string contentType, string username, string password) { try { HttpClient client = new HttpClient(); HttpClientRequest request = new HttpClientRequest(); HttpClientResponse response; client.KeepAlive = false; if(port >= 1 || port <= 65535) client.Port = port; else client.Port = 80; var authorization = ""; if (!string.IsNullOrEmpty(username)) authorization = EncodeBase64(username, password); if (!string.IsNullOrEmpty(authorization)) request.Header.SetHeaderValue("Authorization", authorization); if (!string.IsNullOrEmpty(contentType)) request.Header.ContentType = contentType; request.Url.Parse(url); request.RequestType = (Crestron.SimplSharp.Net.Http.RequestType)requestType; response = client.Dispatch(request); CrestronConsole.PrintLine(string.Format("SubmitRequestHttp Response[{0}]: {1}", response.Code, response.ContentString.ToString())); if (!string.IsNullOrEmpty(response.ContentString.ToString())) OnStringChange(response.ContentString.ToString(), 0, GenericRESTfulConstants.ResponseStringChange); if (response.Code > 0) OnUshrtChange((ushort)response.Code, 0, GenericRESTfulConstants.ResponseCodeChange); } catch (Exception e) { //var msg = string.Format("SubmitRequestHttp({0}, {1}, {2}) failed:{3}", url, port, requestType, e.Message); //CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); CrestronConsole.PrintLine(e.Message); OnStringChange(e.Message, 0, GenericRESTfulConstants.ErrorStringChange); } } /// /// Private HTTPS submit request /// /// /// /// /// /// /// private void SubmitRequestHttps(string url, ushort port, ushort requestType, string contentType, string username, string password) { try { HttpsClient client = new HttpsClient(); HttpsClientRequest request = new HttpsClientRequest(); HttpsClientResponse response; client.KeepAlive = false; client.HostVerification = false; client.PeerVerification = false; var authorization = ""; if (!string.IsNullOrEmpty(username)) authorization = EncodeBase64(username, password); if (!string.IsNullOrEmpty(authorization)) request.Header.SetHeaderValue("Authorization", authorization); if (!string.IsNullOrEmpty(contentType)) request.Header.ContentType = contentType; request.Url.Parse(url); request.RequestType = (Crestron.SimplSharp.Net.Https.RequestType)requestType; response = client.Dispatch(request); CrestronConsole.PrintLine(string.Format("SubmitRequestHttp Response[{0}]: {1}", response.Code, response.ContentString.ToString())); if(!string.IsNullOrEmpty(response.ContentString.ToString())) OnStringChange(response.ContentString.ToString(), 0, GenericRESTfulConstants.ResponseStringChange); if(response.Code > 0) OnUshrtChange((ushort)response.Code, 0, GenericRESTfulConstants.ResponseCodeChange); } catch (Exception e) { //var msg = string.Format("SubmitRequestHttps({0}, {1}, {2}, {3}, {4}) failed:{5}", url, port, requestType, username, password, e.Message); //CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); CrestronConsole.PrintLine(e.Message); OnStringChange(e.Message, 0, GenericRESTfulConstants.ErrorStringChange); } } /// /// Private method to encode username and password to Base64 string /// /// /// /// authorization private string EncodeBase64(string username, string password) { var authorization = ""; try { if (!string.IsNullOrEmpty(username)) { string base64String = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(string.Format("{0}:{1}", username, password))); authorization = string.Format("Basic {0}", base64String); } } catch (Exception e) { var msg = string.Format("EncodeBase64({0}, {1}) failed:\r{2}", username, password, e); CrestronConsole.PrintLine(msg); ErrorLog.Error(msg); return "" ; } return authorization; } /// /// Protected method to handle boolean change events /// /// /// /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; if (handler != null) { var args = new BoolChangeEventArgs(state, type); args.Index = index; BoolChange(this, args); } } /// /// Protected mehtod to handle ushort change events /// /// /// /// protected void OnUshrtChange(ushort value, ushort index, ushort type) { var handler = UshrtChange; if (handler != null) { var args = new UshrtChangeEventArgs(value, type); args.Index = index; UshrtChange(this, args); } } /// /// Protected method to handle string change events /// /// /// /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; StringChange(this, args); } } } } ================================================ FILE: src/PepperDash.Core/JsonStandardObjects/EventArgs and Constants.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.JsonStandardObjects { /// /// Constants for simpl modules /// public class JsonStandardDeviceConstants { /// /// Json object evaluated constant /// public const ushort JsonObjectEvaluated = 2; /// /// Json object changed constant /// public const ushort JsonObjectChanged = 104; } /// /// /// public class DeviceChangeEventArgs : EventArgs { /// /// Device change event args object /// public DeviceConfig Device { get; set; } /// /// Gets or sets the Type /// public ushort Type { get; set; } /// /// Gets or sets the Index /// public ushort Index { get; set; } /// /// Default constructor /// public DeviceChangeEventArgs() { } /// /// Constructor overload /// /// /// public DeviceChangeEventArgs(DeviceConfig device, ushort type) { Device = device; Type = type; } /// /// Constructor overload /// /// /// /// public DeviceChangeEventArgs(DeviceConfig device, ushort type, ushort index) { Device = device; Type = type; Index = index; } } } ================================================ FILE: src/PepperDash.Core/JsonStandardObjects/JsonToSimplDevice.cs ================================================ using System; using System.Linq; using Crestron.SimplSharp; using PepperDash.Core.JsonToSimpl; using Serilog.Events; namespace PepperDash.Core.JsonStandardObjects { /// /// Device class /// public class DeviceConfig { /// /// JSON config key property /// public string key { get; set; } /// /// JSON config name property /// public string name { get; set; } /// /// JSON config type property /// public string type { get; set; } /// /// JSON config properties /// public PropertiesConfig properties { get; set; } /// /// Bool change event handler /// public event EventHandler BoolChange; /// /// Ushort change event handler /// public event EventHandler UshrtChange; /// /// String change event handler /// public event EventHandler StringChange; /// /// Object change event handler /// public event EventHandler DeviceChange; /// /// Constructor /// public DeviceConfig() { properties = new PropertiesConfig(); } /// /// Initialize method /// /// /// /// /// Initialize method /// public void Initialize(string uniqueID, string deviceKey) { // S+ set EvaluateFb low OnBoolChange(false, 0, JsonStandardDeviceConstants.JsonObjectEvaluated); // validate parameters if (string.IsNullOrEmpty(uniqueID) || string.IsNullOrEmpty(deviceKey)) { Debug.LogMessage(LogEventLevel.Debug, "UniqueID ({0} or key ({1} is null or empty", uniqueID, deviceKey); // S+ set EvaluteFb high OnBoolChange(true, 0, JsonStandardDeviceConstants.JsonObjectEvaluated); return; } key = deviceKey; try { // get the file using the unique ID JsonToSimplMaster jsonMaster = J2SGlobal.GetMasterByFile(uniqueID); if (jsonMaster == null) { Debug.LogMessage(LogEventLevel.Debug, "Could not find JSON file with uniqueID {0}", uniqueID); return; } // get the device configuration using the key var devices = jsonMaster.JsonObject.ToObject().devices; var device = devices.FirstOrDefault(d => d.key.Equals(key)); if (device == null) { Debug.LogMessage(LogEventLevel.Debug, "Could not find device with key {0}", key); return; } OnObjectChange(device, 0, JsonStandardDeviceConstants.JsonObjectChanged); var index = devices.IndexOf(device); OnStringChange(string.Format("devices[{0}]", index), 0, JsonToSimplConstants.FullPathToArrayChange); } catch (Exception e) { var msg = string.Format("Device {0} lookup failed:\r{1}", key, e); CrestronConsole.PrintLine(msg); ErrorLog.Error(msg); } finally { // S+ set EvaluteFb high OnBoolChange(true, 0, JsonStandardDeviceConstants.JsonObjectEvaluated); } } #region EventHandler Helpers /// /// BoolChange event handler helper /// /// /// /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; if (handler != null) { var args = new BoolChangeEventArgs(state, type); args.Index = index; BoolChange(this, args); } } /// /// UshrtChange event handler helper /// /// /// /// protected void OnUshrtChange(ushort state, ushort index, ushort type) { var handler = UshrtChange; if (handler != null) { var args = new UshrtChangeEventArgs(state, type); args.Index = index; UshrtChange(this, args); } } /// /// StringChange event handler helper /// /// /// /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; StringChange(this, args); } } /// /// ObjectChange event handler helper /// /// /// /// protected void OnObjectChange(DeviceConfig device, ushort index, ushort type) { if (DeviceChange != null) { var args = new DeviceChangeEventArgs(device, type); args.Index = index; DeviceChange(this, args); } } #endregion EventHandler Helpers } } ================================================ FILE: src/PepperDash.Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.JsonStandardObjects { /* Convert JSON snippt to C#: http://json2csharp.com/# JSON Snippet: { "devices": [ { "key": "deviceKey", "name": "deviceName", "type": "deviceType", "properties": { "deviceId": 1, "enabled": true, "control": { "method": "methodName", "controlPortDevKey": "deviceControlPortDevKey", "controlPortNumber": 1, "comParams": { "baudRate": 9600, "dataBits": 8, "stopBits": 1, "parity": "None", "protocol": "RS232", "hardwareHandshake": "None", "softwareHandshake": "None", "pacing": 0 }, "tcpSshProperties": { "address": "172.22.1.101", "port": 23, "username": "user01", "password": "password01", "autoReconnect": false, "autoReconnectIntervalMs": 10000 } } } } ] } */ /// /// Represents a ComParamsConfig /// public class ComParamsConfig { /// /// Gets or sets the baudRate /// public int baudRate { get; set; } /// /// /// public int dataBits { get; set; } /// /// /// public int stopBits { get; set; } /// /// /// public string parity { get; set; } /// /// /// public string protocol { get; set; } /// /// /// public string hardwareHandshake { get; set; } /// /// /// public string softwareHandshake { get; set; } /// /// /// public int pacing { get; set; } // convert properties for simpl /// /// Gets or sets the simplBaudRate /// public ushort simplBaudRate { get { return Convert.ToUInt16(baudRate); } } /// /// Gets or sets the simplDataBits /// public ushort simplDataBits { get { return Convert.ToUInt16(dataBits); } } /// /// /// public ushort simplStopBits { get { return Convert.ToUInt16(stopBits); } } /// /// /// public ushort simplPacing { get { return Convert.ToUInt16(pacing); } } /// /// Constructor /// public ComParamsConfig() { } } /// /// Device TCP/SSH properties class /// public class TcpSshPropertiesConfig { /// /// /// public string address { get; set; } /// /// /// public int port { get; set; } /// /// /// public string username { get; set; } /// /// /// public string password { get; set; } /// /// /// public bool autoReconnect { get; set; } /// /// /// public int autoReconnectIntervalMs { get; set; } // convert properties for simpl /// /// Gets or sets the simplPort /// public ushort simplPort { get { return Convert.ToUInt16(port); } } /// /// Gets or sets the simplAutoReconnect /// public ushort simplAutoReconnect { get { return (ushort)(autoReconnect ? 1 : 0); } } /// /// /// public ushort simplAutoReconnectIntervalMs { get { return Convert.ToUInt16(autoReconnectIntervalMs); } } /// /// Constructor /// public TcpSshPropertiesConfig() { } } /// /// Device control class /// public class ControlConfig { /// /// /// public string method { get; set; } /// /// /// public string controlPortDevKey { get; set; } /// /// /// public int controlPortNumber { get; set; } /// /// /// public ComParamsConfig comParams { get; set; } /// /// /// public TcpSshPropertiesConfig tcpSshProperties { get; set; } // convert properties for simpl /// /// Gets or sets the simplControlPortNumber /// public ushort simplControlPortNumber { get { return Convert.ToUInt16(controlPortNumber); } } /// /// Constructor /// public ControlConfig() { comParams = new ComParamsConfig(); tcpSshProperties = new TcpSshPropertiesConfig(); } } /// /// Represents a PropertiesConfig /// public class PropertiesConfig { /// /// /// public int deviceId { get; set; } /// /// /// public bool enabled { get; set; } /// /// /// public ControlConfig control { get; set; } // convert properties for simpl /// /// Gets or sets the simplDeviceId /// public ushort simplDeviceId { get { return Convert.ToUInt16(deviceId); } } /// /// Gets or sets the simplEnabled /// public ushort simplEnabled { get { return (ushort)(enabled ? 1 : 0); } } /// /// Constructor /// public PropertiesConfig() { control = new ControlConfig(); } } /// /// Root device class /// public class RootObject { /// /// The collection of devices /// public List devices { get; set; } } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/Constants.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.JsonToSimpl { /// /// Constants for Simpl modules /// public class JsonToSimplConstants { /// /// /// public const ushort BoolValueChange = 1; /// /// /// public const ushort JsonIsValidBoolChange = 2; /// /// Reports the if the device is 3-series compatible /// public const ushort ProgramCompatibility3SeriesChange = 3; /// /// Reports the if the device is 4-series compatible /// public const ushort ProgramCompatibility4SeriesChange = 4; /// /// Reports the device platform enum value /// public const ushort DevicePlatformValueChange = 5; /// /// /// public const ushort UshortValueChange = 101; /// /// /// public const ushort StringValueChange = 201; /// /// /// public const ushort FullPathToArrayChange = 202; /// /// /// public const ushort ActualFilePathChange = 203; /// /// /// public const ushort FilenameResolvedChange = 204; /// /// /// public const ushort FilePathResolvedChange = 205; /// /// Reports the root directory change /// public const ushort RootDirectoryChange = 206; /// /// Reports the room ID change /// public const ushort RoomIdChange = 207; /// /// Reports the room name change /// public const ushort RoomNameChange = 208; } /// /// S+ values delegate /// public delegate void SPlusValuesDelegate(); /// /// S+ values wrapper /// public class SPlusValueWrapper { /// /// Gets or sets the ValueType /// public SPlusType ValueType { get; private set; } /// /// /// public ushort Index { get; private set; } /// /// /// public ushort BoolUShortValue { get; set; } /// /// /// public string StringValue { get; set; } /// /// /// public SPlusValueWrapper() {} /// /// /// /// /// public SPlusValueWrapper(SPlusType type, ushort index) { ValueType = type; Index = index; } } /// /// Enumeration of SPlusType values /// public enum SPlusType { /// /// Digital /// Digital, /// /// Analog /// Analog, /// /// String /// String } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/Global.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Serilog.Events; //using PepperDash.Core; namespace PepperDash.Core.JsonToSimpl { /// /// The global class to manage all the instances of JsonToSimplMaster /// public class J2SGlobal { static List Masters = new List(); /// /// Adds a file master. If the master's key or filename is equivalent to any existing /// master, this will fail /// /// New master to add /// /// /// AddMaster method /// public static void AddMaster(JsonToSimplMaster master) { if (master == null) throw new ArgumentNullException("master"); if (string.IsNullOrEmpty(master.UniqueID)) throw new InvalidOperationException("JSON Master cannot be added with a null UniqueId"); Debug.LogMessage(LogEventLevel.Debug, "JSON Global adding master {0}", master.UniqueID); if (Masters.Contains(master)) return; var existing = Masters.FirstOrDefault(m => m.UniqueID.Equals(master.UniqueID, StringComparison.OrdinalIgnoreCase)); if (existing == null) { Masters.Add(master); } else { var msg = string.Format("Cannot add JSON Master with unique ID '{0}'.\rID is already in use on another master.", master.UniqueID); CrestronConsole.PrintLine(msg); ErrorLog.Warn(msg); } } /// /// GetMasterByFile method /// public static JsonToSimplMaster GetMasterByFile(string file) { return Masters.FirstOrDefault(m => m.UniqueID.Equals(file, StringComparison.OrdinalIgnoreCase)); } } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs ================================================ using System; using System.Linq; using Newtonsoft.Json.Linq; using Serilog.Events; namespace PepperDash.Core.JsonToSimpl { /// /// Represents a JsonToSimplArrayLookupChild /// public class JsonToSimplArrayLookupChild : JsonToSimplChildObjectBase { /// /// /// public string SearchPropertyName { get; set; } /// /// /// public string SearchPropertyValue { get; set; } int ArrayIndex; /// /// For gt2.4.1 array lookups /// /// /// /// /// /// /// public void Initialize(string file, string key, string pathPrefix, string pathSuffix, string searchPropertyName, string searchPropertyValue) { base.Initialize(file, key, pathPrefix, pathSuffix); SearchPropertyName = searchPropertyName; SearchPropertyValue = searchPropertyValue; } /// /// For newer >=2.4.1 array lookups. /// /// /// /// /// /// /// /// public void InitializeWithAppend(string file, string key, string pathPrefix, string pathAppend, string pathSuffix, string searchPropertyName, string searchPropertyValue) { string pathPrefixWithAppend = (pathPrefix != null ? pathPrefix : "") + GetPathAppend(pathAppend); base.Initialize(file, key, pathPrefixWithAppend, pathSuffix); SearchPropertyName = searchPropertyName; SearchPropertyValue = searchPropertyValue; } //PathPrefix+ArrayName+[x]+path+PathSuffix /// /// /// /// /// protected override string GetFullPath(string path) { return string.Format("{0}[{1}].{2}{3}", PathPrefix == null ? "" : PathPrefix, ArrayIndex, path, PathSuffix == null ? "" : PathSuffix); } /// /// ProcessAll method /// /// public override void ProcessAll() { if (FindInArray()) base.ProcessAll(); } /// /// Provides the path append for GetFullPath /// /// string GetPathAppend(string a) { if (string.IsNullOrEmpty(a)) { return ""; } if (a.StartsWith(".")) { return a; } else { return "." + a; } } /// /// /// /// bool FindInArray() { if (Master == null) throw new InvalidOperationException("Cannot do operations before master is linked"); if (Master.JsonObject == null) throw new InvalidOperationException("Cannot do operations before master JSON has read"); if (PathPrefix == null) throw new InvalidOperationException("Cannot do operations before PathPrefix is set"); var token = Master.JsonObject.SelectToken(PathPrefix); if (token is JArray) { var array = token as JArray; try { var item = array.FirstOrDefault(o => { var prop = o[SearchPropertyName]; return prop != null && prop.Value() .Equals(SearchPropertyValue, StringComparison.OrdinalIgnoreCase); }); if (item == null) { Debug.LogMessage(LogEventLevel.Debug,"JSON Child[{0}] Array '{1}' '{2}={3}' not found: ", Key, PathPrefix, SearchPropertyName, SearchPropertyValue); this.LinkedToObject = false; return false; } this.LinkedToObject = true; ArrayIndex = array.IndexOf(item); OnStringChange(string.Format("{0}[{1}]", PathPrefix, ArrayIndex), 0, JsonToSimplConstants.FullPathToArrayChange); Debug.LogMessage(LogEventLevel.Debug, "JSON Child[{0}] Found array match at index {1}", Key, ArrayIndex); return true; } catch (Exception e) { Debug.LogMessage(e, "JSON Child[{key}] Array '{pathPrefix}' lookup error: '{searchPropertyName}={searchPropertyValue}'", null, Key, PathPrefix, SearchPropertyName, SearchPropertyValue, e); } } else { Debug.LogMessage(LogEventLevel.Debug, "JSON Child[{0}] Path '{1}' is not an array", Key, PathPrefix); } return false; } } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/JsonToSimplChildObjectBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; namespace PepperDash.Core.JsonToSimpl { /// /// Base class for JSON objects /// public abstract class JsonToSimplChildObjectBase : IKeyed { /// /// Notifies of bool change /// public event EventHandler BoolChange; /// /// Notifies of ushort change /// public event EventHandler UShortChange; /// /// Notifies of string change /// public event EventHandler StringChange; /// /// Delegate to get all values /// public SPlusValuesDelegate GetAllValuesDelegate { get; set; } /// /// Gets or sets the SetAllPathsDelegate /// public SPlusValuesDelegate SetAllPathsDelegate { get; set; } /// /// Gets or sets the Key /// public string Key { get; protected set; } /// /// This will be prepended to all paths to allow path swapping or for more organized /// sub-paths /// public string PathPrefix { get; protected set; } /// /// This is added to the end of all paths /// public string PathSuffix { get; protected set; } /// /// Gets or sets the LinkedToObject /// public bool LinkedToObject { get; protected set; } /// /// Reference to Master instance /// protected JsonToSimplMaster Master; /// /// Paths to boolean values in JSON structure /// protected Dictionary BoolPaths = new Dictionary(); /// /// Paths to numeric values in JSON structure /// protected Dictionary UshortPaths = new Dictionary(); /// /// Paths to string values in JSON structure /// protected Dictionary StringPaths = new Dictionary(); /// /// Call this before doing anything else /// /// /// /// /// public void Initialize(string masterUniqueId, string key, string pathPrefix, string pathSuffix) { Key = key; PathPrefix = pathPrefix; PathSuffix = pathSuffix; Master = J2SGlobal.GetMasterByFile(masterUniqueId); if (Master != null) Master.AddChild(this); else Debug.Console(1, "JSON Child [{0}] cannot link to master {1}", key, masterUniqueId); } /// /// Sets the path prefix for the object /// /// /// /// SetPathPrefix method /// public void SetPathPrefix(string pathPrefix) { PathPrefix = pathPrefix; } /// /// Set the JPath to evaluate for a given bool out index. /// public void SetBoolPath(ushort index, string path) { Debug.Console(1, "JSON Child[{0}] SetBoolPath {1}={2}", Key, index, path); if (path == null || path.Trim() == string.Empty) return; BoolPaths[index] = path; } /// /// SetUshortPath method /// public void SetUshortPath(ushort index, string path) { Debug.Console(1, "JSON Child[{0}] SetUshortPath {1}={2}", Key, index, path); if (path == null || path.Trim() == string.Empty) return; UshortPaths[index] = path; } /// /// SetStringPath method /// public void SetStringPath(ushort index, string path) { Debug.Console(1, "JSON Child[{0}] SetStringPath {1}={2}", Key, index, path); if (path == null || path.Trim() == string.Empty) return; StringPaths[index] = path; } /// /// ProcessAll method /// /// public virtual void ProcessAll() { if (!LinkedToObject) { Debug.Console(1, this, "Not linked to object in file. Skipping"); return; } if (SetAllPathsDelegate == null) { Debug.Console(1, this, "No SetAllPathsDelegate set. Ignoring ProcessAll"); return; } SetAllPathsDelegate(); foreach (var kvp in BoolPaths) ProcessBoolPath(kvp.Key); foreach (var kvp in UshortPaths) ProcessUshortPath(kvp.Key); foreach (var kvp in StringPaths) ProcessStringPath(kvp.Key); } /// /// Processes a bool property, converting to bool, firing off a BoolChange event /// void ProcessBoolPath(ushort index) { string response; if (Process(BoolPaths[index], out response)) OnBoolChange(response.Equals("true", StringComparison.OrdinalIgnoreCase), index, JsonToSimplConstants.BoolValueChange); else { } // OnBoolChange(false, index, JsonToSimplConstants.BoolValueChange); } // Processes the path to a ushort, converting to ushort if able, twos complement if necessary, firing off UshrtChange event void ProcessUshortPath(ushort index) { string response; if (Process(UshortPaths[index], out response)) { ushort val; try { val = Convert.ToInt32(response) < 0 ? (ushort)(Convert.ToInt16(response) + 65536) : Convert.ToUInt16(response); } catch { val = 0; } OnUShortChange(val, index, JsonToSimplConstants.UshortValueChange); } else { } // OnUShortChange(0, index, JsonToSimplConstants.UshortValueChange); } // Processes the path to a string property and fires of a StringChange event. void ProcessStringPath(ushort index) { string response; if (Process(StringPaths[index], out response)) OnStringChange(response, index, JsonToSimplConstants.StringValueChange); else { } // OnStringChange("", index, JsonToSimplConstants.StringValueChange); } /// /// Processes the given path. /// /// JPath formatted path to the desired property /// The string value of the property, or a default value if it /// doesn't exist /// This will return false in the case that EvaulateAllOnJsonChange /// is false and the path does not evaluate to a property in the incoming JSON. bool Process(string path, out string response) { path = GetFullPath(path); Debug.Console(1, "JSON Child[{0}] Processing {1}", Key, path); response = ""; if (Master == null) { Debug.Console(1, "JSONChild[{0}] cannot process without Master attached", Key); return false; } if (Master.JsonObject != null && path != string.Empty) { bool isCount = false; path = path.Trim(); if (path.EndsWith(".Count")) { path = path.Remove(path.Length - 6, 6); isCount = true; } try // Catch a strange cast error on a bad path { var t = Master.JsonObject.SelectToken(path); if (t != null) { // return the count of children objects - if any if (isCount) response = (t.HasValues ? t.Children().Count() : 0).ToString(); else response = t.Value(); Debug.Console(1, " ='{0}'", response); return true; } } catch { response = ""; } } // If the path isn't found, return this to determine whether to pass out the non-value or not. return false; } //************************************************************************************************ // Save-related functions /// /// Called from Master to read inputs and update their values in master JObject /// Callback should hit one of the following four methods /// public void UpdateInputsForMaster() { if (!LinkedToObject) { Debug.Console(1, this, "Not linked to object in file. Skipping"); return; } if (SetAllPathsDelegate == null) { Debug.Console(1, this, "No SetAllPathsDelegate set. Ignoring UpdateInputsForMaster"); return; } SetAllPathsDelegate(); var del = GetAllValuesDelegate; if (del != null) GetAllValuesDelegate(); } /// /// /// /// /// /// /// USetBoolValue method /// public void USetBoolValue(ushort key, ushort theValue) { SetBoolValue(key, theValue == 1); } /// /// /// /// /// /// /// SetBoolValue method /// public void SetBoolValue(ushort key, bool theValue) { if (BoolPaths.ContainsKey(key)) SetValueOnMaster(BoolPaths[key], new JValue(theValue)); } /// /// /// /// /// /// /// SetUShortValue method /// public void SetUShortValue(ushort key, ushort theValue) { if (UshortPaths.ContainsKey(key)) SetValueOnMaster(UshortPaths[key], new JValue(theValue)); } /// /// /// /// /// /// /// SetStringValue method /// public void SetStringValue(ushort key, string theValue) { if (StringPaths.ContainsKey(key)) SetValueOnMaster(StringPaths[key], new JValue(theValue)); } /// /// /// /// /// /// /// SetValueOnMaster method /// public void SetValueOnMaster(string keyPath, JValue valueToSave) { var path = GetFullPath(keyPath); try { Debug.Console(1, "JSON Child[{0}] Queueing value on master {1}='{2}'", Key, path, valueToSave); //var token = Master.JsonObject.SelectToken(path); //if (token != null) // The path exists in the file Master.AddUnsavedValue(path, valueToSave); } catch (Exception e) { Debug.Console(1, "JSON Child[{0}] Failed setting value for path '{1}'\r{2}", Key, path, e); } } /// /// Called during Process(...) to get the path to a given property. By default, /// returns PathPrefix+path+PathSuffix. Override to change the way path is built. /// protected virtual string GetFullPath(string path) { return (PathPrefix != null ? PathPrefix : "") + path + (PathSuffix != null ? PathSuffix : ""); } // Helpers for events //****************************************************************************************** /// /// Event helper /// /// /// /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; if (handler != null) { var args = new BoolChangeEventArgs(state, type); args.Index = index; BoolChange(this, args); } } //****************************************************************************************** /// /// Event helper /// /// /// /// protected void OnUShortChange(ushort state, ushort index, ushort type) { var handler = UShortChange; if (handler != null) { var args = new UshrtChangeEventArgs(state, type); args.Index = index; UShortChange(this, args); } } /// /// Event helper /// /// /// /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; StringChange(this, args); } } } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/JsonToSimplFileMaster.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json.Linq; namespace PepperDash.Core.JsonToSimpl { /// /// Represents a JSON file that can be read and written to /// public class JsonToSimplFileMaster : JsonToSimplMaster { /// /// Sets the filepath as well as registers this with the Global.Masters list /// public string Filepath { get; private set; } /// /// Gets or sets the ActualFilePath /// public string ActualFilePath { get; private set; } /// /// Gets or sets the Filename /// public string Filename { get; private set; } /// /// /// public string FilePathName { get; private set; } /*****************************************************************************************/ /** Privates **/ // The JSON file in JObject form // For gathering the incoming data object StringBuilderLock = new object(); // To prevent multiple same-file access static object FileLock = new object(); /*****************************************************************************************/ /// /// SIMPL+ default constructor. /// public JsonToSimplFileMaster() { } /// /// Read, evaluate and udpate status /// public void EvaluateFile(string filepath) { try { OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); var dirSeparator = Path.DirectorySeparatorChar; var dirSeparatorAlt = Path.AltDirectorySeparatorChar; var series = CrestronEnvironment.ProgramCompatibility; var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3)); OnBoolChange(is3Series, 0, JsonToSimplConstants.ProgramCompatibility3SeriesChange); var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4)); OnBoolChange(is4Series, 0, JsonToSimplConstants.ProgramCompatibility4SeriesChange); var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server; OnBoolChange(isServer, 0, JsonToSimplConstants.DevicePlatformValueChange); // get the roomID var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId; if (!string.IsNullOrEmpty(roomId)) { OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange); } // get the roomName var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName; if (!string.IsNullOrEmpty(roomName)) { OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange); } var rootDirectory = Directory.GetApplicationRootDirectory(); OnStringChange(rootDirectory, 0, JsonToSimplConstants.RootDirectoryChange); var splusPath = string.Empty; if (Regex.IsMatch(filepath, @"user", RegexOptions.IgnoreCase)) { if (is4Series) splusPath = Regex.Replace(filepath, "user", "user", RegexOptions.IgnoreCase); else if (isServer) splusPath = Regex.Replace(filepath, "user", "User", RegexOptions.IgnoreCase); else splusPath = filepath; } filepath = splusPath.Replace(dirSeparatorAlt, dirSeparator); Filepath = string.Format("{1}{0}{2}", dirSeparator, rootDirectory, filepath.TrimStart(dirSeparator, dirSeparatorAlt)); OnStringChange(string.Format("Attempting to evaluate {0}", Filepath), 0, JsonToSimplConstants.StringValueChange); if (string.IsNullOrEmpty(Filepath)) { OnStringChange(string.Format("Cannot evaluate file. JSON file path not set"), 0, JsonToSimplConstants.StringValueChange); CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set"); return; } // get file directory and name to search var fileDirectory = Path.GetDirectoryName(Filepath); var fileName = Path.GetFileName(Filepath); OnStringChange(string.Format("Checking '{0}' for '{1}'", fileDirectory, fileName), 0, JsonToSimplConstants.StringValueChange); Debug.Console(1, "Checking '{0}' for '{1}'", fileDirectory, fileName); if (Directory.Exists(fileDirectory)) { // get the directory info var directoryInfo = new DirectoryInfo(fileDirectory); // get the file to be read var actualFile = directoryInfo.GetFiles(fileName).FirstOrDefault(); if (actualFile == null) { var msg = string.Format("JSON file not found: {0}", Filepath); OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); CrestronConsole.PrintLine(msg); ErrorLog.Error(msg); return; } // \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json // \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json ActualFilePath = actualFile.FullName; OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); OnStringChange(string.Format("Actual JSON file is {0}", ActualFilePath), 0, JsonToSimplConstants.StringValueChange); Debug.Console(1, "Actual JSON file is {0}", ActualFilePath); Filename = actualFile.Name; OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange); OnStringChange(string.Format("JSON Filename is {0}", Filename), 0, JsonToSimplConstants.StringValueChange); Debug.Console(1, "JSON Filename is {0}", Filename); FilePathName = string.Format(@"{0}{1}", actualFile.DirectoryName, dirSeparator); OnStringChange(string.Format(@"{0}", actualFile.DirectoryName), 0, JsonToSimplConstants.FilePathResolvedChange); OnStringChange(string.Format(@"JSON File Path is {0}", actualFile.DirectoryName), 0, JsonToSimplConstants.StringValueChange); Debug.Console(1, "JSON File Path is {0}", FilePathName); var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII); JsonObject = JObject.Parse(json); foreach (var child in Children) child.ProcessAll(); OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); } else { OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange); Debug.Console(1, "'{0}' not found", fileDirectory); } } catch (Exception e) { var msg = string.Format("EvaluateFile Exception: Message\r{0}", e.Message); OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); CrestronConsole.PrintLine(msg); ErrorLog.Error(msg); var stackTrace = string.Format("EvaluateFile: Stack Trace\r{0}", e.StackTrace); OnStringChange(stackTrace, 0, JsonToSimplConstants.StringValueChange); CrestronConsole.PrintLine(stackTrace); ErrorLog.Error(stackTrace); } } /// /// Sets the debug level /// /// /// /// setDebugLevel method /// public void setDebugLevel(uint level) { Debug.SetDebugLevel(level); } /// /// Saves the values to the file /// public override void Save() { // this code is duplicated in the other masters!!!!!!!!!!!!! UnsavedValues = new Dictionary(); // Make each child update their values into master object foreach (var child in Children) { Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key); child.UpdateInputsForMaster(); } if (UnsavedValues == null || UnsavedValues.Count == 0) { Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID); return; } lock (FileLock) { Debug.Console(1, "Saving"); foreach (var path in UnsavedValues.Keys) { var tokenToReplace = JsonObject.SelectToken(path); if (tokenToReplace != null) {// It's found tokenToReplace.Replace(UnsavedValues[path]); Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path); } else // No token. Let's make one { //http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path); // JContainer jpart = JsonObject; // // walk down the path and find where it goes //#warning Does not handle arrays. // foreach (var part in path.Split('.')) // { // var openPos = part.IndexOf('['); // if (openPos > -1) // { // openPos++; // move to number // var closePos = part.IndexOf(']'); // var arrayName = part.Substring(0, openPos - 1); // get the name // var index = Convert.ToInt32(part.Substring(openPos, closePos - openPos)); // // Check if the array itself exists and add the item if so // if (jpart[arrayName] != null) // { // var arrayObj = jpart[arrayName] as JArray; // var item = arrayObj[index]; // if (item == null) // arrayObj.Add(new JObject()); // } // Debug.Console(0, "IGNORING MISSING ARRAY VALUE FOR NOW"); // continue; // } // // Build the // if (jpart[part] == null) // jpart.Add(new JProperty(part, new JObject())); // jpart = jpart[part] as JContainer; // } // jpart.Replace(UnsavedValues[path]); } } using (StreamWriter sw = new StreamWriter(ActualFilePath)) { try { sw.Write(JsonObject.ToString()); sw.Flush(); } catch (Exception e) { string err = string.Format("Error writing JSON file:\r{0}", e); Debug.Console(0, err); ErrorLog.Warn(err); return; } } } } } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/JsonToSimplFixedPathObject.cs ================================================  namespace PepperDash.Core.JsonToSimpl { /// /// Represents a JsonToSimplFixedPathObject /// public class JsonToSimplFixedPathObject : JsonToSimplChildObjectBase { /// /// Constructor /// public JsonToSimplFixedPathObject() { this.LinkedToObject = true; } } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/JsonToSimplGenericMaster.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using Newtonsoft.Json.Linq; namespace PepperDash.Core.JsonToSimpl { /// /// Represents a JsonToSimplGenericMaster /// public class JsonToSimplGenericMaster : JsonToSimplMaster { /*****************************************************************************************/ /** Privates **/ // The JSON file in JObject form // For gathering the incoming data object StringBuilderLock = new object(); // To prevent multiple same-file access static object WriteLock = new object(); /// /// Gets or sets the SaveCallback /// public Action SaveCallback { get; set; } /*****************************************************************************************/ /// /// SIMPL+ default constructor. /// public JsonToSimplGenericMaster() { } /// /// Loads in JSON and triggers evaluation on all children /// /// public void LoadWithJson(string json) { OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); try { JsonObject = JObject.Parse(json); foreach (var child in Children) child.ProcessAll(); OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); } catch (Exception e) { var msg = string.Format("JSON parsing failed:\r{0}", e); CrestronConsole.PrintLine(msg); ErrorLog.Error(msg); } } /// /// Loads JSON into JsonObject, but does not trigger evaluation by children /// /// /// /// SetJsonWithoutEvaluating method /// public void SetJsonWithoutEvaluating(string json) { try { JsonObject = JObject.Parse(json); } catch (Exception e) { Debug.Console(0, this, "JSON parsing failed:\r{0}", e); } } /// /// Save method /// /// public override void Save() { // this code is duplicated in the other masters!!!!!!!!!!!!! UnsavedValues = new Dictionary(); // Make each child update their values into master object foreach (var child in Children) { Debug.Console(1, this, "Master. checking child [{0}] for updates to save", child.Key); child.UpdateInputsForMaster(); } if (UnsavedValues == null || UnsavedValues.Count == 0) { Debug.Console(1, this, "Master. No updated values to save. Skipping"); return; } lock (WriteLock) { Debug.Console(1, this, "Saving"); foreach (var path in UnsavedValues.Keys) { var tokenToReplace = JsonObject.SelectToken(path); if (tokenToReplace != null) {// It's found tokenToReplace.Replace(UnsavedValues[path]); Debug.Console(1, this, "Master Updating '{0}'", path); } else // No token. Let's make one { Debug.Console(1, "Master Cannot write value onto missing property: '{0}'", path); } } } if (SaveCallback != null) SaveCallback(JsonObject.ToString()); else Debug.Console(0, this, "WARNING: No save callback defined."); } } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/JsonToSimplMaster.cs ================================================ using System; using System.Collections.Generic; using System.IO; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace PepperDash.Core.JsonToSimpl { /// /// Abstract base class for JsonToSimpl interactions /// public abstract class JsonToSimplMaster : IKeyed { /// /// Notifies of bool change /// public event EventHandler BoolChange; /// /// Notifies of ushort change /// public event EventHandler UshrtChange; /// /// Notifies of string change /// public event EventHandler StringChange; /// /// A collection of associated child modules /// protected List Children = new List(); /*****************************************************************************************/ /// /// Mirrors the Unique ID for now. /// public string Key { get { return UniqueID; } } /// /// Gets or sets the UniqueID /// public string UniqueID { get; protected set; } /// /// Merely for use in debug messages /// public string DebugName { get { return _DebugName; } set { if (DebugName == null) _DebugName = ""; else _DebugName = value; } } string _DebugName = ""; /// /// Gets or sets the PathPrefix /// public string PathPrefix { get; set; } /// /// This is added to the end of all paths /// public string PathSuffix { get; set; } /// /// Enables debugging output to the console. Certain error messages will be logged to the /// system's error log regardless of this setting /// public bool DebugOn { get; set; } /// /// Ushort helper for Debug property /// public ushort UDebug { get { return (ushort)(DebugOn ? 1 : 0); } set { DebugOn = (value == 1); CrestronConsole.PrintLine("JsonToSimpl debug={0}", DebugOn); } } /// /// Gets or sets the JsonObject /// public JObject JsonObject { get; protected set; } /*****************************************************************************************/ /** Privates **/ // The JSON file in JObject form // For gathering the incoming data protected Dictionary UnsavedValues = new Dictionary(); /*****************************************************************************************/ /// /// SIMPL+ default constructor. /// public JsonToSimplMaster() { } /// /// Sets up class - overriding methods should always call this. /// /// public virtual void Initialize(string uniqueId) { UniqueID = uniqueId; J2SGlobal.AddMaster(this); // Should not re-add } /// /// Adds a child "module" to this master /// /// /// /// AddChild method /// public void AddChild(JsonToSimplChildObjectBase child) { if (!Children.Contains(child)) { Children.Add(child); } } /// /// AddUnsavedValue method /// public void AddUnsavedValue(string path, JValue value) { if (UnsavedValues.ContainsKey(path)) { Debug.Console(0, "Master[{0}] WARNING - Attempt to add duplicate value for path '{1}'.\r Ingoring. Please ensure that path does not exist on multiple modules.", UniqueID, path); } else UnsavedValues.Add(path, value); //Debug.Console(0, "Master[{0}] Unsaved size={1}", UniqueID, UnsavedValues.Count); } /// /// Saves the file /// public abstract void Save(); /// /// /// public static class JsonFixes { /// /// Deserializes a string into a JObject /// /// /// public static JObject ParseObject(string json) { #if NET6_0 using (var reader = new JsonTextReader(new System.IO.StringReader(json))) #else using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json))) #endif { var startDepth = reader.Depth; var obj = JObject.Load(reader); if (startDepth != reader.Depth) throw new JsonSerializationException("Unenclosed json found"); return obj; } } /// /// Deserializes a string into a JArray /// /// /// /// /// ParseArray method /// public static JArray ParseArray(string json) { #if NET6_0 using (var reader = new JsonTextReader(new System.IO.StringReader(json))) #else using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json))) #endif { var startDepth = reader.Depth; var obj = JArray.Load(reader); if (startDepth != reader.Depth) throw new JsonSerializationException("Unenclosed json found"); return obj; } } } /// /// Helper event /// /// /// /// protected void OnBoolChange(bool state, ushort index, ushort type) { if (BoolChange != null) { var args = new BoolChangeEventArgs(state, type); args.Index = index; BoolChange(this, args); } } /// /// Helper event /// /// /// /// protected void OnUshrtChange(ushort state, ushort index, ushort type) { if (UshrtChange != null) { var args = new UshrtChangeEventArgs(state, type); args.Index = index; UshrtChange(this, args); } } /// /// Helper event /// /// /// /// protected void OnStringChange(string value, ushort index, ushort type) { if (StringChange != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; StringChange(this, args); } } } } ================================================ FILE: src/PepperDash.Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json.Linq; using PepperDash.Core.Config; namespace PepperDash.Core.JsonToSimpl { /// /// Portal File Master /// public class JsonToSimplPortalFileMaster : JsonToSimplMaster { /// /// Sets the filepath as well as registers this with the Global.Masters list /// public string PortalFilepath { get; private set; } /// /// Gets or sets the ActualFilePath /// public string ActualFilePath { get; private set; } /*****************************************************************************************/ /** Privates **/ // To prevent multiple same-file access object StringBuilderLock = new object(); static object FileLock = new object(); /*****************************************************************************************/ /// /// SIMPL+ default constructor. /// public JsonToSimplPortalFileMaster() { } /// /// Read, evaluate and udpate status /// public void EvaluateFile(string portalFilepath) { PortalFilepath = portalFilepath; OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); if (string.IsNullOrEmpty(PortalFilepath)) { CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set"); return; } // Resolve possible wildcarded filename // If the portal file is xyz.json, then // the file we want to check for first will be called xyz.local.json var localFilepath = Path.ChangeExtension(PortalFilepath, "local.json"); Debug.Console(0, this, "Checking for local file {0}", localFilepath); var actualLocalFile = GetActualFileInfoFromPath(localFilepath); if (actualLocalFile != null) { ActualFilePath = actualLocalFile.FullName; OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); } // If the local file does not exist, then read the portal file xyz.json // and create the local. else { Debug.Console(1, this, "Local JSON file not found {0}\rLoading portal JSON file", localFilepath); var actualPortalFile = GetActualFileInfoFromPath(portalFilepath); if (actualPortalFile != null) { var newLocalPath = Path.ChangeExtension(actualPortalFile.FullName, "local.json"); // got the portal file, hand off to the merge / save method PortalConfigReader.ReadAndMergeFileIfNecessary(actualPortalFile.FullName, newLocalPath); ActualFilePath = newLocalPath; OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); } else { var msg = string.Format("Portal JSON file not found: {0}", PortalFilepath); Debug.Console(1, this, msg); ErrorLog.Error(msg); return; } } // At this point we should have a local file. Do it. Debug.Console(1, "Reading local JSON file {0}", ActualFilePath); string json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII); try { JsonObject = JObject.Parse(json); foreach (var child in Children) child.ProcessAll(); OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); } catch (Exception e) { var msg = string.Format("JSON parsing failed:\r{0}", e); CrestronConsole.PrintLine(msg); ErrorLog.Error(msg); return; } } /// /// Returns the FileInfo object for a given path, with possible wildcards /// /// /// FileInfo GetActualFileInfoFromPath(string path) { var dir = Path.GetDirectoryName(path); var localFilename = Path.GetFileName(path); var directory = new DirectoryInfo(dir); // search the directory for the file w/ wildcards return directory.GetFiles(localFilename).FirstOrDefault(); } /// /// /// /// /// /// setDebugLevel method /// public void setDebugLevel(uint level) { Debug.SetDebugLevel(level); } /// /// /// public override void Save() { // this code is duplicated in the other masters!!!!!!!!!!!!! UnsavedValues = new Dictionary(); // Make each child update their values into master object foreach (var child in Children) { Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key); child.UpdateInputsForMaster(); } if (UnsavedValues == null || UnsavedValues.Count == 0) { Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID); return; } lock (FileLock) { Debug.Console(1, "Saving"); foreach (var path in UnsavedValues.Keys) { var tokenToReplace = JsonObject.SelectToken(path); if (tokenToReplace != null) {// It's found tokenToReplace.Replace(UnsavedValues[path]); Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path); } else // No token. Let's make one { //http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path); } } using (StreamWriter sw = new StreamWriter(ActualFilePath)) { try { sw.Write(JsonObject.ToString()); sw.Flush(); } catch (Exception e) { string err = string.Format("Error writing JSON file:\r{0}", e); Debug.Console(0, err); ErrorLog.Warn(err); return; } } } } } } ================================================ FILE: src/PepperDash.Core/Logging/CrestronEnricher.cs ================================================ using Crestron.SimplSharp; using Serilog.Core; using Serilog.Events; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Core.Logging { /// /// Represents a CrestronEnricher /// public class CrestronEnricher : ILogEventEnricher { static readonly string _appName; static CrestronEnricher() { switch (CrestronEnvironment.DevicePlatform) { case eDevicePlatform.Appliance: _appName = $"App {InitialParametersClass.ApplicationNumber}"; break; case eDevicePlatform.Server: _appName = $"{InitialParametersClass.RoomId}"; break; } } /// /// Enrich method /// public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { var property = propertyFactory.CreateProperty("App", _appName); logEvent.AddOrUpdateProperty(property); } } } ================================================ FILE: src/PepperDash.Core/Logging/Debug.cs ================================================ using System; using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronDataStore; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronLogger; using Newtonsoft.Json; using PepperDash.Core.Logging; using Serilog; using Serilog.Context; using Serilog.Core; using Serilog.Events; using Serilog.Formatting.Compact; using Serilog.Formatting.Json; using Serilog.Templates; namespace PepperDash.Core { /// /// public static class Debug { private static readonly string LevelStoreKey = "ConsoleDebugLevel"; private static readonly string WebSocketLevelStoreKey = "WebsocketDebugLevel"; private static readonly string ErrorLogLevelStoreKey = "ErrorLogDebugLevel"; private static readonly string FileLevelStoreKey = "FileDebugLevel"; private static readonly Dictionary _logLevels = new Dictionary() { {0, LogEventLevel.Information }, {3, LogEventLevel.Warning }, {4, LogEventLevel.Error }, {5, LogEventLevel.Fatal }, {1, LogEventLevel.Debug }, {2, LogEventLevel.Verbose }, }; private static ILogger _logger; private static readonly LoggingLevelSwitch _consoleLogLevelSwitch; private static readonly LoggingLevelSwitch _websocketLogLevelSwitch; private static readonly LoggingLevelSwitch _errorLogLevelSwitch; private static readonly LoggingLevelSwitch _fileLogLevelSwitch; /// /// Gets the minimum log level for the websocket sink. /// public static LogEventLevel WebsocketMinimumLogLevel { get { return _websocketLogLevelSwitch.MinimumLevel; } } private static readonly DebugWebsocketSink _websocketSink; /// /// Gets the websocket sink for debug logging. /// public static DebugWebsocketSink WebsocketSink { get { return _websocketSink; } } /// /// Describes the folder location where a given program stores it's debug level memory. By default, the /// file written will be named appNdebug where N is 1-10. /// public static string OldFilePathPrefix = @"\nvram\debug\"; /// /// Describes the new folder location where a given program stores it's debug level memory. By default, the /// file written will be named appNdebug where N is 1-10. /// public static string NewFilePathPrefix = @"\user\debug\"; /// /// The name of the file containing the current debug settings. /// public static string FileName = string.Format(@"app{0}Debug.json", InitialParametersClass.ApplicationNumber); /// /// Gets or sets the Level /// public static int Level { get; private set; } /// /// Gets or sets the DoNotLoadConfigOnNextBoot /// public static bool DoNotLoadConfigOnNextBoot { get; private set; } private static DebugContextCollection _contexts; private const int SaveTimeoutMs = 30000; /// /// Indicates whether the system is running on an appliance. /// public static bool IsRunningOnAppliance = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance; /// /// Gets or sets the PepperDashCoreVersion /// public static string PepperDashCoreVersion { get; private set; } private static CTimer _saveTimer; /// /// When true, the IncludedExcludedKeys dict will contain keys to include. /// When false (default), IncludedExcludedKeys will contain keys to exclude. /// private static bool _excludeAllMode; private static readonly Dictionary IncludedExcludedKeys; private static readonly LoggerConfiguration _defaultLoggerConfiguration; private static LoggerConfiguration _loggerConfiguration; /// /// Gets the logger configuration for the debug logging. /// public static LoggerConfiguration LoggerConfiguration => _loggerConfiguration; static Debug() { CrestronDataStoreStatic.InitCrestronDataStore(); var defaultConsoleLevel = GetStoredLogEventLevel(LevelStoreKey); var defaultWebsocketLevel = GetStoredLogEventLevel(WebSocketLevelStoreKey); var defaultErrorLogLevel = GetStoredLogEventLevel(ErrorLogLevelStoreKey); var defaultFileLogLevel = GetStoredLogEventLevel(FileLevelStoreKey); _consoleLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultConsoleLevel); _websocketLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultWebsocketLevel); _errorLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultErrorLogLevel); _fileLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultFileLogLevel); _websocketSink = new DebugWebsocketSink(new JsonFormatter(renderMessage: true)); var logFilePath = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? $@"{Directory.GetApplicationRootDirectory()}{Path.DirectorySeparatorChar}user{Path.DirectorySeparatorChar}debug{Path.DirectorySeparatorChar}app{InitialParametersClass.ApplicationNumber}{Path.DirectorySeparatorChar}global-log.log" : $@"{Directory.GetApplicationRootDirectory()}{Path.DirectorySeparatorChar}user{Path.DirectorySeparatorChar}debug{Path.DirectorySeparatorChar}room{InitialParametersClass.RoomId}{Path.DirectorySeparatorChar}global-log.log"; CrestronConsole.PrintLine($"Saving log files to {logFilePath}"); var errorLogTemplate = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? "{@t:fff}ms [{@l:u4}]{#if Key is not null}[{Key}]{#end} {@m}{#if @x is not null}\r\n{@x}{#end}" : "[{@t:yyyy-MM-dd HH:mm:ss.fff}][{@l:u4}][{App}]{#if Key is not null}[{Key}]{#end} {@m}{#if @x is not null}\r\n{@x}{#end}"; _defaultLoggerConfiguration = new LoggerConfiguration() .MinimumLevel.Verbose() .Enrich.FromLogContext() .Enrich.With(new CrestronEnricher()) .WriteTo.Sink(new DebugConsoleSink(new ExpressionTemplate("[{@t:yyyy-MM-dd HH:mm:ss.fff}][{@l:u4}][{App}]{#if Key is not null}[{Key}]{#end} {@m}{#if @x is not null}\r\n{@x}{#end}")), levelSwitch: _consoleLogLevelSwitch) .WriteTo.Sink(_websocketSink, levelSwitch: _websocketLogLevelSwitch) .WriteTo.Sink(new DebugErrorLogSink(new ExpressionTemplate(errorLogTemplate)), levelSwitch: _errorLogLevelSwitch) .WriteTo.File(new RenderedCompactJsonFormatter(), logFilePath, rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Debug, retainedFileCountLimit: CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? 7 : 14, levelSwitch: _fileLogLevelSwitch ); try { if (InitialParametersClass.NumberOfRemovableDrives > 0) { CrestronConsole.PrintLine("{0} RM Drive(s) Present. Initializing CrestronLogger", InitialParametersClass.NumberOfRemovableDrives); _defaultLoggerConfiguration.WriteTo.Sink(new DebugCrestronLoggerSink()); } else CrestronConsole.PrintLine("No RM Drive(s) Present. Not using Crestron Logger"); } catch (Exception e) { CrestronConsole.PrintLine("Initializing of CrestronLogger failed: {0}", e); } // Instantiate the root logger _loggerConfiguration = _defaultLoggerConfiguration; _logger = _loggerConfiguration.CreateLogger(); // Get the assembly version and print it to console and the log GetVersion(); string msg = $"[App {InitialParametersClass.ApplicationNumber}] Using PepperDash_Core v{PepperDashCoreVersion}"; if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) { msg = $"[Room {InitialParametersClass.RoomId}] Using PepperDash_Core v{PepperDashCoreVersion}"; } CrestronConsole.PrintLine(msg); LogMessage(LogEventLevel.Information, msg); IncludedExcludedKeys = new Dictionary(); if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro) { // Add command to console CrestronConsole.AddNewConsoleCommand(SetDoNotLoadOnNextBootFromConsole, "donotloadonnextboot", "donotloadonnextboot:P [true/false]: Should the application load on next boot", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug", "appdebug:P [0-5]: Sets the application's console debug message level", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(ShowDebugLog, "appdebuglog", "appdebuglog:P [all] Use \"all\" for full log.", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(s => CrestronLogger.Clear(false), "appdebugclear", "appdebugclear:P Clears the current custom log", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(SetDebugFilterFromConsole, "appdebugfilter", "appdebugfilter [params]", ConsoleAccessLevelEnum.AccessOperator); } CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; LoadMemory(); var context = _contexts.GetOrCreateItem("DEFAULT"); Level = context.Level; DoNotLoadConfigOnNextBoot = context.DoNotLoadOnNextBoot; if (DoNotLoadConfigOnNextBoot) CrestronConsole.PrintLine(string.Format("Program {0} will not load config after next boot. Use console command go:{0} to load the config manually", InitialParametersClass.ApplicationNumber)); _errorLogLevelSwitch.MinimumLevelChanged += (sender, args) => { LogMessage(LogEventLevel.Information, "Error log debug level set to {minimumLevel}", _errorLogLevelSwitch.MinimumLevel); }; // Set initial error log level based on platform && stored level. If appliance, use stored level, otherwise default to verbose SetErrorLogMinimumDebugLevel(CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? _errorLogLevelSwitch.MinimumLevel : LogEventLevel.Verbose); } /// /// UpdateLoggerConfiguration method /// public static void UpdateLoggerConfiguration(LoggerConfiguration config) { _loggerConfiguration = config; _logger = config.CreateLogger(); } /// /// ResetLoggerConfiguration method /// public static void ResetLoggerConfiguration() { _loggerConfiguration = _defaultLoggerConfiguration; _logger = _loggerConfiguration.CreateLogger(); } private static LogEventLevel GetStoredLogEventLevel(string levelStoreKey) { try { var result = CrestronDataStoreStatic.GetLocalIntValue(levelStoreKey, out int logLevel); if (result != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) { CrestronConsole.Print($"Unable to retrieve stored log level for {levelStoreKey}.\r\nError: {result}.\r\nSetting level to {LogEventLevel.Information}\r\n"); CrestronDataStoreStatic.SetLocalIntValue(levelStoreKey, levelStoreKey == ErrorLogLevelStoreKey ? (int)LogEventLevel.Warning : (int)LogEventLevel.Information); return levelStoreKey == ErrorLogLevelStoreKey ? LogEventLevel.Warning : LogEventLevel.Information; } if (logLevel < 0 || logLevel > 5) { CrestronConsole.PrintLine($"Stored Log level not valid for {levelStoreKey}: {logLevel}. Setting level to {LogEventLevel.Information}"); return LogEventLevel.Information; } CrestronConsole.PrintLine($"Stored log level for {levelStoreKey} is {logLevel}"); return (LogEventLevel)logLevel; } catch (Exception ex) { CrestronConsole.PrintLine($"Exception retrieving log level for {levelStoreKey}: {ex.Message}"); return LogEventLevel.Information; } } private static void GetVersion() { var assembly = Assembly.GetExecutingAssembly(); var ver = assembly .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); if (ver != null && ver.Length > 0) { if (ver[0] is AssemblyInformationalVersionAttribute verAttribute) { PepperDashCoreVersion = verAttribute.InformationalVersion; } } else { var version = assembly.GetName().Version; PepperDashCoreVersion = version.ToString(); } } /// /// Used to save memory when shutting down /// /// static void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) { Log.CloseAndFlush(); if (_saveTimer != null) { _saveTimer.Stop(); _saveTimer = null; } LogMessage(LogEventLevel.Information, "Saving debug settings"); SaveMemory(); } } /// /// Callback for console command /// /// /// /// SetDebugFromConsole method /// public static void SetDebugFromConsole(string levelString) { try { if (levelString.Trim() == "?") { CrestronConsole.ConsoleCommandResponse( "Used to set the minimum level of debug messages:\r\n" + "Usage: appdebug:P [sink] [level]\r\n" + " sink: console (default), errorlog, file, all\r\n" + " all: sets all sinks to the specified level\r\n" + " level: 0-5 or LogEventLevel name\r\n" + $"{_logLevels[0]} = 0\r\n" + $"{_logLevels[1]} = 1\r\n" + $"{_logLevels[2]} = 2\r\n" + $"{_logLevels[3]} = 3\r\n" + $"{_logLevels[4]} = 4\r\n" + $"{_logLevels[5]} = 5"); return; } if (string.IsNullOrEmpty(levelString.Trim())) { CrestronConsole.ConsoleCommandResponse("Console log level = {0}\r\n", _consoleLogLevelSwitch.MinimumLevel); CrestronConsole.ConsoleCommandResponse("File log level = {0}\r\n", _fileLogLevelSwitch.MinimumLevel); CrestronConsole.ConsoleCommandResponse("Error log level = {0}\r\n", _errorLogLevelSwitch.MinimumLevel); return; } // Parse tokens: first token is sink (defaults to console), second token is level var tokens = levelString.Trim().Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); string sinkName; string levelToken; if (tokens.Length == 1) { // Single token - assume it's a level for console sink sinkName = "console"; levelToken = tokens[0]; } else if (tokens.Length == 2) { // Two tokens - first is sink, second is level sinkName = tokens[0].ToLowerInvariant(); levelToken = tokens[1]; } else { CrestronConsole.ConsoleCommandResponse("Usage: appdebug:P [sink] [level]"); return; } // Parse the level using the same logic as before LogEventLevel level; if (int.TryParse(levelToken, out var levelInt)) { if (levelInt < 0 || levelInt > 5) { CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelToken} to valid log level. If using a number, value must be between 0-5"); return; } if (!_logLevels.TryGetValue((uint)levelInt, out level)) { level = LogEventLevel.Information; CrestronConsole.ConsoleCommandResponse($"{levelInt} not valid. Setting level to {level}"); } } else if (Enum.TryParse(levelToken, true, out level)) { // Successfully parsed as LogEventLevel enum } else { CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelToken} to valid log level"); return; } // Set the level for the specified sink switch (sinkName) { case "console": SetDebugLevel(level); break; case "errorlog": SetErrorLogMinimumDebugLevel(level); break; case "file": SetFileMinimumDebugLevel(level); break; case "all": SetDebugLevel(level); SetErrorLogMinimumDebugLevel(level); SetFileMinimumDebugLevel(level); break; default: CrestronConsole.ConsoleCommandResponse($"Error: Unknown sink '{sinkName}'. Valid sinks: console, errorlog, file"); break; } } catch { CrestronConsole.ConsoleCommandResponse("Usage: appdebug:P [sink] [level]"); } } /// /// Sets the debug level /// /// Valid values 0-5 /// /// SetDebugLevel method /// public static void SetDebugLevel(uint level) { if (!_logLevels.TryGetValue(level, out var logLevel)) { logLevel = LogEventLevel.Information; CrestronConsole.ConsoleCommandResponse($"{level} not valid. Setting level to {logLevel}"); SetDebugLevel(logLevel); } SetDebugLevel(logLevel); } /// /// SetDebugLevel method /// public static void SetDebugLevel(LogEventLevel level) { _consoleLogLevelSwitch.MinimumLevel = level; CrestronConsole.ConsoleCommandResponse("[Application {0}] Debug level set to {1}\r\n", InitialParametersClass.ApplicationNumber, _consoleLogLevelSwitch.MinimumLevel); CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int)level}"); var err = CrestronDataStoreStatic.SetLocalIntValue(LevelStoreKey, (int)level); CrestronConsole.ConsoleCommandResponse($"Store result: {err}:{(int)level}"); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) CrestronConsole.PrintLine($"Error saving console debug level setting: {err}"); } /// /// SetWebSocketMinimumDebugLevel method /// public static void SetWebSocketMinimumDebugLevel(LogEventLevel level) { _websocketLogLevelSwitch.MinimumLevel = level; var err = CrestronDataStoreStatic.SetLocalUintValue(WebSocketLevelStoreKey, (uint)level); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) LogMessage(LogEventLevel.Information, "Error saving websocket debug level setting: {erro}", err); LogMessage(LogEventLevel.Information, "Websocket debug level set to {0}", _websocketLogLevelSwitch.MinimumLevel); } /// /// SetErrorLogMinimumDebugLevel method /// public static void SetErrorLogMinimumDebugLevel(LogEventLevel level) { _errorLogLevelSwitch.MinimumLevel = level; CrestronConsole.ConsoleCommandResponse("[Application {0}] Error log level set to {1}\r\n", InitialParametersClass.ApplicationNumber, _errorLogLevelSwitch.MinimumLevel); CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int)level}"); var err = CrestronDataStoreStatic.SetLocalIntValue(ErrorLogLevelStoreKey, (int)level); CrestronConsole.ConsoleCommandResponse($"Store result: {err}:{(int)level}"); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) CrestronConsole.PrintLine($"Error saving error log debug level setting: {err}"); } /// /// SetFileMinimumDebugLevel method /// public static void SetFileMinimumDebugLevel(LogEventLevel level) { _fileLogLevelSwitch.MinimumLevel = level; CrestronConsole.ConsoleCommandResponse("[Application {0}] File log level set to {1}\r\n", InitialParametersClass.ApplicationNumber, _fileLogLevelSwitch.MinimumLevel); CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int)level}"); var err = CrestronDataStoreStatic.SetLocalIntValue(FileLevelStoreKey, (int)level); CrestronConsole.ConsoleCommandResponse($"Store result: {err}:{(int)level}"); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) CrestronConsole.PrintLine($"Error saving file debug level setting: {err}"); } /// /// Callback for console command /// /// /// /// SetDoNotLoadOnNextBootFromConsole method /// public static void SetDoNotLoadOnNextBootFromConsole(string stateString) { try { if (string.IsNullOrEmpty(stateString.Trim())) { CrestronConsole.ConsoleCommandResponse("DoNotLoadOnNextBoot = {0}", DoNotLoadConfigOnNextBoot); return; } SetDoNotLoadConfigOnNextBoot(bool.Parse(stateString)); } catch { CrestronConsole.ConsoleCommandResponse("Usage: donotloadonnextboot:P [true/false]"); } } /// /// Callback for console command /// /// /// /// SetDebugFilterFromConsole method /// public static void SetDebugFilterFromConsole(string items) { var str = items.Trim(); if (str == "?") { CrestronConsole.ConsoleCommandResponse("Usage:\r APPDEBUGFILTER key1 key2 key3....\r " + "+all: at beginning puts filter into 'default include' mode\r" + " All keys that follow will be excluded from output.\r" + "-all: at beginning puts filter into 'default exclude all' mode.\r" + " All keys that follow will be the only keys that are shown\r" + "+nokey: Enables messages with no key (default)\r" + "-nokey: Disables messages with no key.\r" + "(nokey settings are independent of all other settings)"); return; } var keys = Regex.Split(str, @"\s*"); foreach (var keyToken in keys) { var lkey = keyToken.ToLower(); if (lkey == "+all") { IncludedExcludedKeys.Clear(); _excludeAllMode = false; } else if (lkey == "-all") { IncludedExcludedKeys.Clear(); _excludeAllMode = true; } //else if (lkey == "+nokey") //{ // ExcludeNoKeyMessages = false; //} //else if (lkey == "-nokey") //{ // ExcludeNoKeyMessages = true; //} else { string key; if (lkey.StartsWith("-")) { key = lkey.Substring(1); // if in exclude all mode, we need to remove this from the inclusions if (_excludeAllMode) { if (IncludedExcludedKeys.ContainsKey(key)) IncludedExcludedKeys.Remove(key); } // otherwise include all mode, add to the exclusions else { IncludedExcludedKeys[key] = new object(); } } else if (lkey.StartsWith("+")) { key = lkey.Substring(1); // if in exclude all mode, we need to add this as inclusion if (_excludeAllMode) { IncludedExcludedKeys[key] = new object(); } // otherwise include all mode, remove this from exclusions else { if (IncludedExcludedKeys.ContainsKey(key)) IncludedExcludedKeys.Remove(key); } } } } } /// /// sets the settings for a device or creates a new entry /// /// /// /// public static void SetDeviceDebugSettings(string deviceKey, object settings) { _contexts.SetDebugSettingsForKey(deviceKey, settings); SaveMemoryOnTimeout(); } /// /// Gets the device settings for a device by key or returns null /// /// /// /// /// GetDeviceDebugSettingsForKey method /// public static object GetDeviceDebugSettingsForKey(string deviceKey) { return _contexts.GetDebugSettingsForKey(deviceKey); } /// /// Sets the flag to prevent application starting on next boot /// /// public static void SetDoNotLoadConfigOnNextBoot(bool state) { DoNotLoadConfigOnNextBoot = state; _contexts.GetOrCreateItem("DEFAULT").DoNotLoadOnNextBoot = state; SaveMemoryOnTimeout(); CrestronConsole.ConsoleCommandResponse("[Application {0}], Do Not Load Config on Next Boot set to {1}", InitialParametersClass.ApplicationNumber, DoNotLoadConfigOnNextBoot); } /// /// ShowDebugLog method /// public static void ShowDebugLog(string s) { var loglist = CrestronLogger.PrintTheLog(s.ToLower() == "all"); foreach (var l in loglist) CrestronConsole.ConsoleCommandResponse(l + CrestronEnvironment.NewLine); } /// /// Log an Exception as an Error /// /// Exception to log /// Message template /// Optional IKeyed device. If provided, the Key of the device will be added to the log message /// Args to put into message template /// /// LogMessage method /// public static void LogMessage(Exception ex, string message, IKeyed device = null, params object[] args) { using (LogContext.PushProperty("Key", device?.Key)) { _logger.Error(ex, message, args); } } /// /// Log a message /// /// Level to log at /// Message template /// Optional IKeyed device. If provided, the Key of the device will be added to the log message /// Args to put into message template public static void LogMessage(LogEventLevel level, string message, IKeyed device = null, params object[] args) { using (LogContext.PushProperty("Key", device?.Key)) { _logger.Write(level, message, args); } } /// /// Logs a message at the specified log level. /// /// Level to log at /// Message template /// Args to put into message template public static void LogMessage(LogEventLevel level, string message, params object[] args) { _logger.Write(level, message, args); } /// /// LogMessage method /// public static void LogMessage(LogEventLevel level, Exception ex, string message, params object[] args) { _logger.Write(level, ex, message, args); } /// /// LogMessage method /// public static void LogMessage(LogEventLevel level, IKeyed keyed, string message, params object[] args) { LogMessage(level, message, keyed, args); } /// /// LogMessage method /// public static void LogMessage(LogEventLevel level, Exception ex, IKeyed device, string message, params object[] args) { using (LogContext.PushProperty("Key", device?.Key)) { _logger.Write(level, ex, message, args); } } #region Explicit methods for logging levels /// /// LogVerbose method /// public static void LogVerbose(IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Verbose, message, args); } } /// /// LogVerbose method /// public static void LogVerbose(Exception ex, IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Verbose, ex, message, args); } } /// /// LogVerbose method /// public static void LogVerbose(string message, params object[] args) { _logger.Write(LogEventLevel.Verbose, message, args); } /// /// LogVerbose method /// public static void LogVerbose(Exception ex, string message, params object[] args) { _logger.Write(LogEventLevel.Verbose, ex, message, args); } /// /// LogDebug method /// public static void LogDebug(IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Debug, message, args); } } /// /// LogDebug method /// public static void LogDebug(Exception ex, IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Debug, ex, message, args); } } /// /// LogDebug method /// public static void LogDebug(string message, params object[] args) { _logger.Write(LogEventLevel.Debug, message, args); } /// /// LogDebug method /// public static void LogDebug(Exception ex, string message, params object[] args) { _logger.Write(LogEventLevel.Debug, ex, null, message, args); } /// /// LogInformation method /// public static void LogInformation(IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Information, message, args); } } /// /// LogInformation method /// public static void LogInformation(Exception ex, IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Information, ex, message, args); } } /// /// LogInformation method /// public static void LogInformation(string message, params object[] args) { _logger.Write(LogEventLevel.Information, message, args); } /// /// LogInformation method /// public static void LogInformation(Exception ex, string message, params object[] args) { _logger.Write(LogEventLevel.Information, ex, message, args); } /// /// LogWarning method /// public static void LogWarning(IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Warning, message, args); } } /// /// LogWarning method /// public static void LogWarning(Exception ex, IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Warning, ex, message, args); } } /// /// LogWarning method /// public static void LogWarning(string message, params object[] args) { _logger.Write(LogEventLevel.Warning, message, args); } /// /// LogWarning method /// public static void LogWarning(Exception ex, string message, params object[] args) { _logger.Write(LogEventLevel.Warning, ex, message, args); } /// /// LogError method /// public static void LogError(IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Error, message, args); } } /// /// LogError method /// public static void LogError(Exception ex, IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Error, ex, message, args); } } /// /// LogError method /// public static void LogError(string message, params object[] args) { _logger.Write(LogEventLevel.Error, message, args); } /// /// LogError method /// public static void LogError(Exception ex, string message, params object[] args) { _logger.Write(LogEventLevel.Error, ex, message, args); } /// /// LogFatal method /// public static void LogFatal(IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Fatal, message, args); } } /// /// LogFatal method /// public static void LogFatal(Exception ex, IKeyed keyed, string message, params object[] args) { using (LogContext.PushProperty("Key", keyed?.Key)) { _logger.Write(LogEventLevel.Fatal, ex, message, args); } } /// /// LogFatal method /// public static void LogFatal(string message, params object[] args) { _logger.Write(LogEventLevel.Fatal, message, args); } /// /// LogFatal method /// public static void LogFatal(Exception ex, string message, params object[] args) { _logger.Write(LogEventLevel.Fatal, ex, message, args); } #endregion private static void LogMessage(uint level, string format, params object[] items) { if (!_logLevels.ContainsKey(level)) return; var logLevel = _logLevels[level]; LogMessage(logLevel, format, items); } private static void LogMessage(uint level, IKeyed keyed, string format, params object[] items) { if (!_logLevels.ContainsKey(level)) return; var logLevel = _logLevels[level]; LogMessage(logLevel, keyed, format, items); } /// /// Prints message to console if current debug level is equal to or higher than the level of this message. /// Uses CrestronConsole.PrintLine. /// /// /// Console format string /// Object parameters [Obsolete("Use LogMessage methods. Will be removed in 2.2.0 and later versions")] public static void Console(uint level, string format, params object[] items) { LogMessage(level, format, items); //if (IsRunningOnAppliance) //{ // CrestronConsole.PrintLine("[{0}]App {1} Lvl {2}:{3}", DateTime.Now.ToString("HH:mm:ss.fff"), // InitialParametersClass.ApplicationNumber, // level, // string.Format(format, items)); //} } /// /// Logs to Console when at-level, and all messages to error log, including device key /// [Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")] public static void Console(uint level, IKeyed dev, string format, params object[] items) { LogMessage(level, dev, format, items); //if (Level >= level) // Console(level, "[{0}] {1}", dev.Key, message); } /// /// Prints message to console if current debug level is equal to or higher than the level of this message. Always sends message to Error Log. /// Uses CrestronConsole.PrintLine. /// [Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")] public static void Console(uint level, IKeyed dev, ErrorLogLevel errorLogLevel, string format, params object[] items) { LogMessage(level, dev, format, items); } /// /// Logs to Console when at-level, and all messages to error log /// [Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")] public static void Console(uint level, ErrorLogLevel errorLogLevel, string format, params object[] items) { LogMessage(level, format, items); } /// /// Logs to both console and the custom user log (not the built-in error log). If appdebug level is set at /// or above the level provided, then the output will be written to both console and the log. Otherwise /// it will only be written to the log. /// [Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")] public static void ConsoleWithLog(uint level, string format, params object[] items) { LogMessage(level, format, items); // var str = string.Format(format, items); //if (Level >= level) // CrestronConsole.PrintLine("App {0}:{1}", InitialParametersClass.ApplicationNumber, str); // CrestronLogger.WriteToLog(str, level); } /// /// Logs to both console and the custom user log (not the built-in error log). If appdebug level is set at /// or above the level provided, then the output will be written to both console and the log. Otherwise /// it will only be written to the log. /// [Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")] public static void ConsoleWithLog(uint level, IKeyed dev, string format, params object[] items) { LogMessage(level, dev, format, items); // var str = string.Format(format, items); // CrestronLogger.WriteToLog(string.Format("[{0}] {1}", dev.Key, str), level); } /// /// Prints to log and error log /// /// /// [Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")] public static void LogError(ErrorLogLevel errorLogLevel, string str) { switch (errorLogLevel) { case ErrorLogLevel.Error: LogMessage(LogEventLevel.Error, str); break; case ErrorLogLevel.Warning: LogMessage(LogEventLevel.Warning, str); break; case ErrorLogLevel.Notice: LogMessage(LogEventLevel.Information, str); break; } } /// /// Writes the memory object after timeout /// static void SaveMemoryOnTimeout() { Console(0, "Saving debug settings"); if (_saveTimer == null) _saveTimer = new CTimer(o => { _saveTimer = null; SaveMemory(); }, SaveTimeoutMs); else _saveTimer.Reset(SaveTimeoutMs); } /// /// Writes the memory - use SaveMemoryOnTimeout /// static void SaveMemory() { //var dir = @"\NVRAM\debug"; //if (!Directory.Exists(dir)) // Directory.Create(dir); var fileName = GetMemoryFileName(); LogMessage(LogEventLevel.Information, "Loading debug settings file from {fileName}", fileName); using (var sw = new StreamWriter(fileName)) { var json = JsonConvert.SerializeObject(_contexts); sw.Write(json); sw.Flush(); } } /// /// /// static void LoadMemory() { var file = GetMemoryFileName(); if (File.Exists(file)) { using (var sr = new StreamReader(file)) { var json = sr.ReadToEnd(); _contexts = JsonConvert.DeserializeObject(json); if (_contexts != null) { LogMessage(LogEventLevel.Debug, "Debug memory restored from file"); return; } } } _contexts = new DebugContextCollection(); } /// /// Helper to get the file path for this app's debug memory /// static string GetMemoryFileName() { if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) { // CheckForMigration(); return string.Format(@"\user\debugSettings\program{0}", InitialParametersClass.ApplicationNumber); } return string.Format("{0}{1}user{1}debugSettings{1}{2}.json", Directory.GetApplicationRootDirectory(), Path.DirectorySeparatorChar, InitialParametersClass.RoomId); } /// /// Enumeration of ErrorLogLevel values /// public enum ErrorLogLevel { /// /// Error /// Error, /// /// Warning /// Warning, /// /// Notice /// Notice, /// /// None /// None, } } } ================================================ FILE: src/PepperDash.Core/Logging/DebugConsoleSink.cs ================================================ using Crestron.SimplSharp; using Serilog.Configuration; using Serilog; using Serilog.Core; using Serilog.Events; using Serilog.Formatting; using Serilog.Formatting.Json; using System.IO; using System.Text; namespace PepperDash.Core { /// /// Represents a DebugConsoleSink /// public class DebugConsoleSink : ILogEventSink { private readonly ITextFormatter _textFormatter; /// /// Emit method /// public void Emit(LogEvent logEvent) { if (!Debug.IsRunningOnAppliance) return; /*string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}"; if(logEvent.Properties.TryGetValue("Key",out var value) && value is ScalarValue sv && sv.Value is string rawValue) { message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue,3}]: {logEvent.RenderMessage()}"; }*/ var buffer = new StringWriter(new StringBuilder(256)); _textFormatter.Format(logEvent, buffer); var message = buffer.ToString(); CrestronConsole.PrintLine(message); } public DebugConsoleSink(ITextFormatter formatProvider ) { _textFormatter = formatProvider ?? new JsonFormatter(); } } public static class DebugConsoleSinkExtensions { /// /// DebugConsoleSink method /// public static LoggerConfiguration DebugConsoleSink( this LoggerSinkConfiguration loggerConfiguration, ITextFormatter formatProvider = null) { return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider)); } } } ================================================ FILE: src/PepperDash.Core/Logging/DebugContext.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; namespace PepperDash.Core { /// /// Represents a debugging context /// [Obsolete("DebugContext is no longer supported and will be removed in a future release.")] public class DebugContext { /// /// Describes the folder location where a given program stores it's debug level memory. By default, the /// file written will be named appNdebug where N is 1-10. /// public string Key { get; private set; } /// /// The name of the file containing the current debug settings. /// //string FileName = string.Format(@"\nvram\debug\app{0}Debug.json", InitialParametersClass.ApplicationNumber); DebugContextSaveData SaveData; int SaveTimeoutMs = 30000; CTimer SaveTimer; static List Contexts = new List(); /// /// Creates or gets a debug context /// /// /// /// /// GetDebugContext method /// public static DebugContext GetDebugContext(string key) { var context = Contexts.FirstOrDefault(c => c.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); if (context == null) { context = new DebugContext(key); Contexts.Add(context); } return context; } /// /// Do not use. For S+ access. /// public DebugContext() { } DebugContext(string key) { Key = key; if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro) { // Add command to console CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug", "appdebug:P [0-2]: Sets the application's console debug message level", ConsoleAccessLevelEnum.AccessOperator); } CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; LoadMemory(); } /// /// Used to save memory when shutting down /// /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) { if (SaveTimer != null) { SaveTimer.Stop(); SaveTimer = null; } Console(0, "Saving debug settings"); SaveMemory(); } } /// /// Callback for console command /// /// /// /// SetDebugFromConsole method /// public void SetDebugFromConsole(string levelString) { try { if (string.IsNullOrEmpty(levelString.Trim())) { CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", SaveData.Level); return; } SetDebugLevel(Convert.ToInt32(levelString)); } catch { CrestronConsole.PrintLine("Usage: appdebug:P [0-2]"); } } /// /// Sets the debug level /// /// Valid values 0 (no debug), 1 (critical), 2 (all messages) /// /// SetDebugLevel method /// public void SetDebugLevel(int level) { if (level <= 2) { SaveData.Level = level; SaveMemoryOnTimeout(); CrestronConsole.PrintLine("[Application {0}], Debug level set to {1}", InitialParametersClass.ApplicationNumber, SaveData.Level); } } /// /// Prints message to console if current debug level is equal to or higher than the level of this message. /// Uses CrestronConsole.PrintLine. /// /// /// Console format string /// Object parameters public void Console(uint level, string format, params object[] items) { if (SaveData.Level >= level) CrestronConsole.PrintLine("App {0}:{1}", InitialParametersClass.ApplicationNumber, string.Format(format, items)); } /// /// Console method /// public void Console(uint level, IKeyed dev, string format, params object[] items) { if (SaveData.Level >= level) Console(level, "[{0}] {1}", dev.Key, string.Format(format, items)); } /// /// /// /// /// /// /// /// public void Console(uint level, IKeyed dev, Debug.ErrorLogLevel errorLogLevel, string format, params object[] items) { if (SaveData.Level >= level) { var str = string.Format("[{0}] {1}", dev.Key, string.Format(format, items)); Console(level, str); LogError(errorLogLevel, str); } } /// /// /// /// /// /// /// public void Console(uint level, Debug.ErrorLogLevel errorLogLevel, string format, params object[] items) { if (SaveData.Level >= level) { var str = string.Format(format, items); Console(level, str); LogError(errorLogLevel, str); } } /// /// /// /// /// /// /// LogError method /// public void LogError(Debug.ErrorLogLevel errorLogLevel, string str) { string msg = string.Format("App {0}:{1}", InitialParametersClass.ApplicationNumber, str); switch (errorLogLevel) { case Debug.ErrorLogLevel.Error: ErrorLog.Error(msg); break; case Debug.ErrorLogLevel.Warning: ErrorLog.Warn(msg); break; case Debug.ErrorLogLevel.Notice: ErrorLog.Notice(msg); break; } } /// /// Writes the memory object after timeout /// void SaveMemoryOnTimeout() { if (SaveTimer == null) SaveTimer = new CTimer(o => { SaveTimer = null; SaveMemory(); }, SaveTimeoutMs); else SaveTimer.Reset(SaveTimeoutMs); } /// /// Writes the memory - use SaveMemoryOnTimeout /// void SaveMemory() { using (StreamWriter sw = new StreamWriter(GetMemoryFileName())) { var json = JsonConvert.SerializeObject(SaveData); sw.Write(json); sw.Flush(); } } /// /// /// void LoadMemory() { var file = GetMemoryFileName(); if (File.Exists(file)) { using (StreamReader sr = new StreamReader(file)) { var data = JsonConvert.DeserializeObject(sr.ReadToEnd()); if (data != null) { SaveData = data; Debug.Console(1, "Debug memory restored from file"); return; } else SaveData = new DebugContextSaveData(); } } } /// /// Helper to get the file path for this app's debug memory /// string GetMemoryFileName() { return string.Format(@"\NVRAM\debugSettings\program{0}-{1}", InitialParametersClass.ApplicationNumber, Key); } } /// /// /// public class DebugContextSaveData { /// /// /// public int Level { get; set; } } } ================================================ FILE: src/PepperDash.Core/Logging/DebugCrestronLoggerSink.cs ================================================ using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronLogger; using Serilog.Core; using Serilog.Events; namespace PepperDash.Core.Logging { /// /// Represents a DebugCrestronLoggerSink /// public class DebugCrestronLoggerSink : ILogEventSink { /// /// Emit method /// public void Emit(LogEvent logEvent) { if (!Debug.IsRunningOnAppliance) return; string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}"; if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue) { message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue}]: {logEvent.RenderMessage()}"; } CrestronLogger.WriteToLog(message, (uint)logEvent.Level); } public DebugCrestronLoggerSink() { CrestronLogger.Initialize(1, LoggerModeEnum.RM); } } } ================================================ FILE: src/PepperDash.Core/Logging/DebugErrorLogSink.cs ================================================ using Crestron.SimplSharp; using Serilog.Core; using Serilog.Events; using Serilog.Formatting; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Core.Logging { /// /// Represents a DebugErrorLogSink /// public class DebugErrorLogSink : ILogEventSink { private ITextFormatter _formatter; private Dictionary> _errorLogMap = new Dictionary> { { LogEventLevel.Verbose, (msg) => ErrorLog.Notice(msg) }, {LogEventLevel.Debug, (msg) => ErrorLog.Notice(msg) }, {LogEventLevel.Information, (msg) => ErrorLog.Notice(msg) }, {LogEventLevel.Warning, (msg) => ErrorLog.Warn(msg) }, {LogEventLevel.Error, (msg) => ErrorLog.Error(msg) }, {LogEventLevel.Fatal, (msg) => ErrorLog.Error(msg) } }; /// /// Emit method /// public void Emit(LogEvent logEvent) { string message; if (_formatter == null) { var programId = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? $"App {InitialParametersClass.ApplicationNumber}" : $"Room {InitialParametersClass.RoomId}"; message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}]{logEvent.RenderMessage()}"; if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue) { message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}][{rawValue}]: {logEvent.RenderMessage()}"; } } else { var buffer = new StringWriter(new StringBuilder(256)); _formatter.Format(logEvent, buffer); message = buffer.ToString(); } if(!_errorLogMap.TryGetValue(logEvent.Level, out var handler)) { return; } handler(message); } public DebugErrorLogSink(ITextFormatter formatter = null) { _formatter = formatter; } } } ================================================ FILE: src/PepperDash.Core/Logging/DebugExtensions.cs ================================================ using System; using Serilog.Events; using Log = PepperDash.Core.Debug; namespace PepperDash.Core.Logging { public static class DebugExtensions { /// /// LogException method /// public static void LogException(this IKeyed device, Exception ex, string message, params object[] args) { Log.LogMessage(ex, message, device: device, args); } /// /// LogVerbose method /// public static void LogVerbose(this IKeyed device, Exception ex, string message, params object[] args) { Log.LogVerbose(ex, device, message, args); } /// /// LogVerbose method /// public static void LogVerbose(this IKeyed device, string message, params object[] args) { Log.LogVerbose(device, message, args); } /// /// LogDebug method /// public static void LogDebug(this IKeyed device, Exception ex, string message, params object[] args) { Log.LogDebug(ex, device, message, args); } /// /// LogDebug method /// public static void LogDebug(this IKeyed device, string message, params object[] args) { Log.LogDebug(device, message, args); } /// /// LogInformation method /// public static void LogInformation(this IKeyed device, Exception ex, string message, params object[] args) { Log.LogInformation(ex, device, message, args); } /// /// LogInformation method /// public static void LogInformation(this IKeyed device, string message, params object[] args) { Log.LogInformation(device, message, args); } /// /// LogWarning method /// public static void LogWarning(this IKeyed device, Exception ex, string message, params object[] args) { Log.LogWarning(ex, device, message, args); } /// /// LogWarning method /// public static void LogWarning(this IKeyed device, string message, params object[] args) { Log.LogWarning(device, message, args); } /// /// LogError method /// public static void LogError(this IKeyed device, Exception ex, string message, params object[] args) { Log.LogError(ex, device, message, args); } /// /// LogError method /// public static void LogError(this IKeyed device, string message, params object[] args) { Log.LogError(device, message, args); } /// /// LogFatal method /// public static void LogFatal(this IKeyed device, Exception ex, string message, params object[] args) { Log.LogFatal(ex, device, message, args); } /// /// LogFatal method /// public static void LogFatal(this IKeyed device, string message, params object[] args) { Log.LogFatal(device, message, args); } } } ================================================ FILE: src/PepperDash.Core/Logging/DebugMemory.cs ================================================ using System.Collections.Generic; using Crestron.SimplSharp; using Newtonsoft.Json; namespace PepperDash.Core.Logging { /// /// Represents a DebugContextCollection /// public class DebugContextCollection { /// /// To prevent threading issues with the DeviceDebugSettings collection /// private readonly CCriticalSection _deviceDebugSettingsLock; [JsonProperty("items")] private readonly Dictionary _items; /// /// Collection of the debug settings for each device where the dictionary key is the device key /// [JsonProperty("deviceDebugSettings")] private Dictionary DeviceDebugSettings { get; set; } /// /// Default constructor /// public DebugContextCollection() { _deviceDebugSettingsLock = new CCriticalSection(); DeviceDebugSettings = new Dictionary(); _items = new Dictionary(); } /// /// Sets the level of a given context item, and adds that item if it does not /// exist /// /// /// /// /// SetLevel method /// public void SetLevel(string contextKey, int level) { if (level < 0 || level > 2) return; GetOrCreateItem(contextKey).Level = level; } /// /// Gets a level or creates it if not existing /// /// /// /// /// GetOrCreateItem method /// public DebugContextItem GetOrCreateItem(string contextKey) { if (!_items.ContainsKey(contextKey)) _items[contextKey] = new DebugContextItem { Level = 0 }; return _items[contextKey]; } /// /// sets the settings for a device or creates a new entry /// /// /// /// /// /// SetDebugSettingsForKey method /// public void SetDebugSettingsForKey(string deviceKey, object settings) { try { _deviceDebugSettingsLock.Enter(); if (DeviceDebugSettings.ContainsKey(deviceKey)) { DeviceDebugSettings[deviceKey] = settings; } else DeviceDebugSettings.Add(deviceKey, settings); } finally { _deviceDebugSettingsLock.Leave(); } } /// /// Gets the device settings for a device by key or returns null /// /// /// /// /// GetDebugSettingsForKey method /// public object GetDebugSettingsForKey(string deviceKey) { return DeviceDebugSettings[deviceKey]; } } /// /// Contains information about /// public class DebugContextItem { /// /// The level of debug messages to print /// [JsonProperty("level")] public int Level { get; set; } /// /// Property to tell the program not to intitialize when it boots, if desired /// [JsonProperty("doNotLoadOnNextBoot")] public bool DoNotLoadOnNextBoot { get; set; } } } ================================================ FILE: src/PepperDash.Core/Logging/DebugWebsocketSink.cs ================================================ using System; using Serilog; using Serilog.Core; using Serilog.Events; using Serilog.Configuration; using WebSocketSharp.Server; using Crestron.SimplSharp; using WebSocketSharp; using System.Security.Authentication; using WebSocketSharp.Net; using System.Security.Cryptography.X509Certificates; using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Operators; using Org.BouncyCastle.Math; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; using Serilog.Formatting; using Serilog.Formatting.Json; namespace PepperDash.Core { /// /// Represents a DebugWebsocketSink /// public class DebugWebsocketSink : ILogEventSink { private HttpServer _httpsServer; private string _path = "/debug/join/"; private const string _certificateName = "selfCres"; private const string _certificatePassword = "cres12345"; private static string CertPath => $"{Path.DirectorySeparatorChar}user{Path.DirectorySeparatorChar}{_certificateName}.pfx"; public int Port { get { if (_httpsServer == null) return 0; return _httpsServer.Port; } } public string Url { get { if (_httpsServer == null || !_httpsServer.IsListening) return ""; var service = _httpsServer.WebSocketServices[_path]; if (service == null) return ""; // Use CSLAN IP if available, otherwise fallback to primary IP. This ensures we provide a reachable URL in dual-stack environments. var cslanIp = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 1); if (!string.IsNullOrEmpty(cslanIp) && cslanIp != "Invalid Value") return $"wss://{cslanIp}:{_httpsServer.Port}{service.Path}"; else return $"wss://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{_httpsServer.Port}{service.Path}"; } } /// /// Gets or sets the IsRunning /// public bool IsRunning { get => _httpsServer?.IsListening ?? false; } private readonly ITextFormatter _textFormatter; /// /// Initializes a new instance of the class with the specified text formatter. /// /// This constructor initializes the WebSocket sink and ensures that a certificate is /// available for secure communication. If the required certificate does not exist, it will be created /// automatically. Additionally, the sink is configured to stop the server when the program is /// stopping. /// The text formatter used to format log messages. If null, a default JSON formatter is used. public DebugWebsocketSink(ITextFormatter formatProvider) { _textFormatter = formatProvider ?? new JsonFormatter(); if (!File.Exists(CertPath)) CreateCert(); try { CrestronEnvironment.ProgramStatusEventHandler += type => { if (type == eProgramStatusEventType.Stopping) StopServer(); }; } catch { // CrestronEnvironment is not available in test / dev environments — safe to skip. } } private static void CreateCert() { // NOTE: This method is called from the constructor, which is itself called during Debug's static // constructor before _logger is assigned. Do NOT call any Debug.Log* methods here — use // CrestronConsole.PrintLine only, to avoid a NullReferenceException that would poison the Debug type. try { var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0); CrestronConsole.PrintLine(string.Format("CreateCert: DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress)); var subjectName = string.Format("CN={0}.{1}", hostName, domainName); var fqdn = string.Format("{0}.{1}", hostName, domainName); var random = new SecureRandom(); // Generate RSA 2048 key pair var keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(new KeyGenerationParameters(random, 2048)); var keyPair = keyPairGenerator.GenerateKeyPair(); // Build certificate var certGenerator = new X509V3CertificateGenerator(); certGenerator.SetSerialNumber(BigInteger.ValueOf(Math.Abs(DateTime.UtcNow.Ticks))); certGenerator.SetIssuerDN(new X509Name(subjectName)); certGenerator.SetSubjectDN(new X509Name(subjectName)); certGenerator.SetNotBefore(DateTime.UtcNow); certGenerator.SetNotAfter(DateTime.UtcNow.AddYears(2)); certGenerator.SetPublicKey(keyPair.Public); // Extended Key Usage: server + client auth certGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, false, new ExtendedKeyUsage(new[] { KeyPurposeID.id_kp_serverAuth, KeyPurposeID.id_kp_clientAuth })); // Subject Alternative Names: DNS + IP System.Net.IPAddress parsedIp; if (System.Net.IPAddress.TryParse(ipAddress, out parsedIp)) { certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(new GeneralName[] { new GeneralName(GeneralName.DnsName, fqdn), new GeneralName(GeneralName.IPAddress, ipAddress) })); } else { certGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(new GeneralName(GeneralName.DnsName, fqdn))); } // Sign with SHA256withRSA var signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", keyPair.Private, random); var certificate = certGenerator.Generate(signatureFactory); // Export as PKCS12/PFX var pkcs12Store = new Pkcs12StoreBuilder().Build(); var certEntry = new X509CertificateEntry(certificate); pkcs12Store.SetCertificateEntry(_certificateName, certEntry); pkcs12Store.SetKeyEntry(_certificateName, new AsymmetricKeyEntry(keyPair.Private), new[] { certEntry }); var separator = Path.DirectorySeparatorChar; var outputPath = string.Format("{0}user{1}{2}.pfx", separator, separator, _certificateName); using (var ms = new MemoryStream()) { var passwordChars = _certificatePassword.ToCharArray(); try { pkcs12Store.Save(ms, passwordChars, random); } finally { Array.Clear(passwordChars, 0, passwordChars.Length); } File.WriteAllBytes(outputPath, ms.ToArray()); } CrestronConsole.PrintLine(string.Format("CreateCert: Certificate written to {0}", outputPath)); } catch (Exception ex) { CrestronConsole.PrintLine(string.Format("WSS CreateCert Failed: {0}\r\n{1}", ex.Message, ex.StackTrace)); } } /// /// Emit method /// public void Emit(LogEvent logEvent) { if (_httpsServer == null || !_httpsServer.IsListening) return; var sw = new StringWriter(); _textFormatter.Format(logEvent, sw); _httpsServer.WebSocketServices.Broadcast(sw.ToString()); } /// /// Starts the WebSocket server on the specified port and configures it with the appropriate certificate. /// /// This method initializes the WebSocket server and binds it to the specified port. It /// also applies the server's certificate for secure communication. Ensure that the port is not already in use /// and that the certificate file is accessible. /// The port number on which the WebSocket server will listen. Must be a valid, non-negative port number. public void StartServerAndSetPort(int port) { Debug.LogInformation("Starting Websocket Server on port: {0}", port); Start(port, CertPath, _certificatePassword); } private static X509Certificate2 LoadOrRecreateCert(string certPath, string certPassword) { if (!File.Exists(certPath)) CreateCert(); try { return LoadCertFromBouncyCastle(certPath, certPassword); } catch (Exception ex) { // Cert is corrupt or was written by an incompatible tool — delete and regenerate once. CrestronConsole.PrintLine(string.Format("SSL cert load failed ({0}); regenerating...", ex.Message)); try { File.Delete(certPath); } catch { } CreateCert(); return LoadCertFromBouncyCastle(certPath, certPassword); } } /// /// Loads a PKCS#12 file written by BouncyCastle and returns an with /// private key attached. /// The PFX is parsed and re-encoded by BouncyCastle (ensuring format compatibility), then passed as /// raw bytes to so neither RSACryptoServiceProvider nor the /// EphemeralKeySet flag (unsupported on the Crestron/Mono runtime) is needed. /// private static X509Certificate2 LoadCertFromBouncyCastle(string certPath, string certPassword) { var passwordChars = certPassword.ToCharArray(); try { using (var stream = File.OpenRead(certPath)) { var store = new Pkcs12StoreBuilder().Build(); store.Load(stream, passwordChars); // Re-encode through BouncyCastle to guarantee PKCS#12 format compatibility, // then hand raw bytes to X509Certificate2 — no RSACryptoServiceProvider needed. using (var ms = new MemoryStream()) { store.Save(ms, passwordChars, new SecureRandom()); var cert = new X509Certificate2(ms.ToArray(), certPassword); if (!cert.HasPrivateKey) throw new InvalidOperationException( string.Format("Certificate loaded from '{0}' does not contain a private key and cannot be used as a server certificate.", certPath)); return cert; } } } finally { Array.Clear(passwordChars, 0, passwordChars.Length); } } private void Start(int port, string certPath = "", string certPassword = "") { try { _httpsServer = new HttpServer(port, true); if (!string.IsNullOrWhiteSpace(certPath)) { Debug.LogInformation("Assigning SSL Configuration"); _httpsServer.SslConfiguration.ServerCertificate = LoadOrRecreateCert(certPath, certPassword); _httpsServer.SslConfiguration.ClientCertificateRequired = false; _httpsServer.SslConfiguration.CheckCertificateRevocation = false; _httpsServer.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12; //this is just to test, you might want to actually validate _httpsServer.SslConfiguration.ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { Debug.LogInformation("HTTPS ClientCerticateValidation Callback triggered"); return true; }; } Debug.LogInformation("Adding Debug Client Service"); _httpsServer.AddWebSocketService(_path); Debug.LogInformation("Assigning Log Info"); _httpsServer.Log.Level = LogLevel.Trace; _httpsServer.Log.Output = WriteWebSocketInternalLog; Debug.LogInformation("Starting"); _httpsServer.Start(); Debug.LogInformation("Ready"); } catch (Exception ex) { Debug.LogError(ex, "WebSocket Failed to start {0}", ex.Message); Debug.LogVerbose("Stack Trace:\r{0}", ex.StackTrace); // Null out the server so callers can detect failure via IsRunning / Url null guards. _httpsServer = null; } } /// /// StopServer method /// public void StopServer() { Debug.LogInformation("Stopping Websocket Server"); try { if (_httpsServer == null || !_httpsServer.IsListening) { return; } // Prevent close-sequence internal websocket logs from re-entering the logging pipeline. _httpsServer.Log.Output = (d, s) => { }; var serviceHost = _httpsServer.WebSocketServices[_path]; if (serviceHost == null) { _httpsServer.Stop(); _httpsServer = null; return; } serviceHost.Sessions.Broadcast("Server is stopping"); foreach (var session in serviceHost.Sessions.Sessions) { if (session?.Context?.WebSocket != null && session.Context.WebSocket.IsAlive) { session.Context.WebSocket.Close(1001, "Server is stopping"); } } _httpsServer.Stop(); _httpsServer = null; } catch (Exception ex) { Debug.LogError(ex, "WebSocket Failed to stop gracefully {0}", ex.Message); Debug.LogVerbose("Stack Trace\r\n{0}", ex.StackTrace); } } private static void WriteWebSocketInternalLog(LogData data, string supplemental) { try { if (data == null) { return; } var message = string.IsNullOrWhiteSpace(data.Message) ? "" : data.Message; var details = string.IsNullOrWhiteSpace(supplemental) ? string.Empty : string.Format(" | details: {0}", supplemental); // Use direct console output to avoid recursive log sink calls. CrestronConsole.PrintLine(string.Format("WS[{0}] {1} | message: {2}{3}", data.Level, data.Date, message, details)); } catch { // Never throw from websocket log callback. } } } public static class DebugWebsocketSinkExtensions { /// /// DebugWebsocketSink method /// public static LoggerConfiguration DebugWebsocketSink( this LoggerSinkConfiguration loggerConfiguration, ITextFormatter formatProvider = null) { return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider)); } } /// /// Represents a DebugClient /// public class DebugClient : WebSocketBehavior { private DateTime _connectionTime; public TimeSpan ConnectedDuration { get { if (Context.WebSocket.IsAlive) { return DateTime.Now - _connectionTime; } else { return new TimeSpan(0); } } } public DebugClient() { Debug.Console(0, "DebugClient Created"); } protected override void OnOpen() { base.OnOpen(); var url = Context.WebSocket.Url; Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WebSocket Connection from: {0}", url); _connectionTime = DateTime.Now; } protected override void OnMessage(MessageEventArgs e) { base.OnMessage(e); Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data); } protected override void OnClose(CloseEventArgs e) { base.OnClose(e); Debug.Console(0, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Closing: {0} reason: {1}", e.Code, e.Reason); } protected override void OnError(WebSocketSharp.ErrorEventArgs e) { base.OnError(e); Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message); } } } ================================================ FILE: src/PepperDash.Core/Network/DiscoveryThings.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core { /// /// Not in use /// public static class NetworkComm { /// /// Not in use /// static NetworkComm() { } } } ================================================ FILE: src/PepperDash.Core/PasswordManagement/Config.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.PasswordManagement { /// /// JSON password configuration /// public class PasswordConfig { /// /// Password object configured password /// public string password { get; set; } /// /// Constructor /// public PasswordConfig() { } } } ================================================ FILE: src/PepperDash.Core/PasswordManagement/Constants.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.PasswordManagement { /// /// Constants /// public class PasswordManagementConstants { /// /// Generic boolean value change constant /// public const ushort BoolValueChange = 1; /// /// Evaluated boolean change constant /// public const ushort PasswordInitializedChange = 2; /// /// Update busy change const /// public const ushort PasswordUpdateBusyChange = 3; /// /// Password is valid change constant /// public const ushort PasswordValidationChange = 4; /// /// Password LED change constant /// public const ushort PasswordLedFeedbackChange = 5; /// /// Generic ushort value change constant /// public const ushort UshrtValueChange = 101; /// /// Password count /// public const ushort PasswordManagerCountChange = 102; /// /// Password selecte index change constant /// public const ushort PasswordSelectIndexChange = 103; /// /// Password length /// public const ushort PasswordLengthChange = 104; /// /// Generic string value change constant /// public const ushort StringValueChange = 201; } } ================================================ FILE: src/PepperDash.Core/PasswordManagement/PasswordClient.cs ================================================ using System; namespace PepperDash.Core.PasswordManagement { /// /// Represents a PasswordClient /// public class PasswordClient { /// /// Password selected /// public string Password { get; set; } /// /// Password selected key /// public ushort Key { get; set; } /// /// Used to build the password entered by the user /// public string PasswordToValidate { get; set; } /// /// Boolean event /// public event EventHandler BoolChange; /// /// Ushort event /// public event EventHandler UshrtChange; /// /// String event /// public event EventHandler StringChange; /// /// Constructor /// public PasswordClient() { PasswordManager.PasswordChange += new EventHandler(PasswordManager_PasswordChange); } /// /// Initialize method /// public void Initialize() { OnBoolChange(false, 0, PasswordManagementConstants.PasswordInitializedChange); Password = ""; PasswordToValidate = ""; OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange); } /// /// Retrieve password by index /// /// /// /// GetPasswordByIndex method /// public void GetPasswordByIndex(ushort key) { OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); Key = key; var pw = PasswordManager.Passwords[Key]; if (pw == null) { OnUshrtChange(0, 0, PasswordManagementConstants.PasswordLengthChange); return; } Password = pw; OnUshrtChange((ushort)Password.Length, 0, PasswordManagementConstants.PasswordLengthChange); OnUshrtChange(key, 0, PasswordManagementConstants.PasswordSelectIndexChange); } /// /// Password validation method /// /// /// /// ValidatePassword method /// public void ValidatePassword(string password) { if (string.IsNullOrEmpty(password)) return; if (string.Equals(Password, password)) OnBoolChange(true, 0, PasswordManagementConstants.PasswordValidationChange); else OnBoolChange(false, 0, PasswordManagementConstants.PasswordValidationChange); ClearPassword(); } /// /// Builds the user entered passwrod string, will attempt to validate the user entered /// password against the selected password when the length of the 2 are equal /// /// /// /// BuildPassword method /// public void BuildPassword(string data) { PasswordToValidate = String.Concat(PasswordToValidate, data); OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange); if (PasswordToValidate.Length == Password.Length) ValidatePassword(PasswordToValidate); } /// /// ClearPassword method /// public void ClearPassword() { PasswordToValidate = ""; OnBoolChange(false, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange); } /// /// Protected boolean change event handler /// /// /// /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; if (handler != null) { var args = new BoolChangeEventArgs(state, type); args.Index = index; BoolChange(this, args); } } /// /// Protected ushort change event handler /// /// /// /// protected void OnUshrtChange(ushort value, ushort index, ushort type) { var handler = UshrtChange; if (handler != null) { var args = new UshrtChangeEventArgs(value, type); args.Index = index; UshrtChange(this, args); } } /// /// Protected string change event handler /// /// /// /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; StringChange(this, args); } } /// /// If password changes while selected change event will be notifed and update the client /// /// /// protected void PasswordManager_PasswordChange(object sender, StringChangeEventArgs args) { //throw new NotImplementedException(); if (Key == args.Index) { //PasswordSelectedKey = args.Index; //PasswordSelected = args.StringValue; GetPasswordByIndex(args.Index); } } } } ================================================ FILE: src/PepperDash.Core/PasswordManagement/PasswordManager.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; namespace PepperDash.Core.PasswordManagement { /// /// Represents a PasswordManager /// public class PasswordManager { /// /// Public dictionary of known passwords /// public static Dictionary Passwords = new Dictionary(); /// /// Private dictionary, used when passwords are updated /// private Dictionary _passwords = new Dictionary(); /// /// Timer used to wait until password changes have stopped before updating the dictionary /// CTimer PasswordTimer; /// /// Timer length /// public long PasswordTimerElapsedMs = 5000; /// /// Boolean event /// public event EventHandler BoolChange; /// /// Ushort event /// public event EventHandler UshrtChange; /// /// String event /// public event EventHandler StringChange; /// /// Event to notify clients of an updated password at the specified index (uint) /// public static event EventHandler PasswordChange; /// /// Constructor /// public PasswordManager() { } /// /// Initialize password manager /// public void Initialize() { if (Passwords == null) Passwords = new Dictionary(); if (_passwords == null) _passwords = new Dictionary(); OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange); } /// /// Updates password stored in the dictonary /// /// /// /// /// UpdatePassword method /// public void UpdatePassword(ushort key, string password) { // validate the parameters if (key > 0 && string.IsNullOrEmpty(password)) { Debug.Console(1, string.Format("PasswordManager.UpdatePassword: key [{0}] or password are not valid", key, password)); return; } try { // if key exists, update the value if(_passwords.ContainsKey(key)) _passwords[key] = password; // else add the key & value else _passwords.Add(key, password); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: _password[{0}] = {1}", key, _passwords[key])); if (PasswordTimer == null) { PasswordTimer = new CTimer((o) => PasswordTimerElapsed(), PasswordTimerElapsedMs); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started")); OnBoolChange(true, 0, PasswordManagementConstants.PasswordUpdateBusyChange); } else { PasswordTimer.Reset(PasswordTimerElapsedMs); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset")); } } catch (Exception e) { var msg = string.Format("PasswordManager.UpdatePassword key-value[{0}, {1}] failed:\r{2}", key, password, e); Debug.Console(1, msg); } } /// /// CTimer callback function /// private void PasswordTimerElapsed() { try { PasswordTimer.Stop(); Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: CTimer Stopped")); OnBoolChange(false, 0, PasswordManagementConstants.PasswordUpdateBusyChange); foreach (var pw in _passwords) { // if key exists, continue if (Passwords.ContainsKey(pw.Key)) { Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: pw.key[{0}] = {1}", pw.Key, pw.Value)); if (Passwords[pw.Key] != _passwords[pw.Key]) { Passwords[pw.Key] = _passwords[pw.Key]; Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: Updated Password[{0} = {1}", pw.Key, Passwords[pw.Key])); OnPasswordChange(Passwords[pw.Key], (ushort)pw.Key, PasswordManagementConstants.StringValueChange); } } // else add the key & value else { Passwords.Add(pw.Key, pw.Value); } } OnUshrtChange((ushort)Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); } catch (Exception e) { var msg = string.Format("PasswordManager.PasswordTimerElapsed failed:\r{0}", e); Debug.Console(1, msg); } } /// /// Method to change the default timer value, (default 5000ms/5s) /// /// /// /// PasswordTimerMs method /// public void PasswordTimerMs(ushort time) { PasswordTimerElapsedMs = Convert.ToInt64(time); } /// /// Helper method for debugging to see what passwords are in the lists /// public void ListPasswords() { Debug.Console(0, "PasswordManager.ListPasswords:\r"); foreach (var pw in Passwords) Debug.Console(0, "Passwords[{0}]: {1}\r", pw.Key, pw.Value); Debug.Console(0, "\n"); foreach (var pw in _passwords) Debug.Console(0, "_passwords[{0}]: {1}\r", pw.Key, pw.Value); } /// /// Protected boolean change event handler /// /// /// /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; if (handler != null) { var args = new BoolChangeEventArgs(state, type); args.Index = index; BoolChange(this, args); } } /// /// Protected ushort change event handler /// /// /// /// protected void OnUshrtChange(ushort value, ushort index, ushort type) { var handler = UshrtChange; if (handler != null) { var args = new UshrtChangeEventArgs(value, type); args.Index = index; UshrtChange(this, args); } } /// /// Protected string change event handler /// /// /// /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; StringChange(this, args); } } /// /// Protected password change event handler /// /// /// /// protected void OnPasswordChange(string value, ushort index, ushort type) { var handler = PasswordChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; PasswordChange(this, args); } } } } ================================================ FILE: src/PepperDash.Core/PepperDash.Core.csproj ================================================  Library PepperDash.Core PepperDashCore net472 true en bin\$(Configuration)\ False True PepperDash Core PepperDash Technologies git https://github.com/PepperDash/PepperDashCore crestron;4series; false $(Version) true full TRACE;DEBUG;SERIES4 pdbonly bin\4Series\$(Configuration)\PepperDashCore.xml ================================================ FILE: src/PepperDash.Core/PepperDashCore.build/net472/PepperDashCore.props ================================================ 2.0.0-local PepperDash Technologies PepperDash Technologies PepperDash Essentials Copyright © 2025 git Crestron; 4series ../../output LICENSE.md README.md ================================================ FILE: src/PepperDash.Core/PepperDashCore.build/net472/PepperDashCore.targets ================================================ true build; true build; true build; $(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz $(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz > doNotUse ================================================ FILE: src/PepperDash.Core/Properties/ControlSystem.cfg ================================================  MC3 SSH
ssh 10.0.0.15
Program01 Internal Flash
================================================ FILE: src/PepperDash.Core/SystemInfo/EventArgs and Constants.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.SystemInfo { /// /// Constants /// public class SystemInfoConstants { /// /// /// public const ushort BoolValueChange = 1; /// /// /// public const ushort CompleteBoolChange = 2; /// /// /// public const ushort BusyBoolChange = 3; /// /// /// public const ushort UshortValueChange = 101; /// /// /// public const ushort StringValueChange = 201; /// /// /// public const ushort ConsoleResponseChange = 202; /// /// /// public const ushort ProcessorUptimeChange = 203; /// /// /// public const ushort ProgramUptimeChange = 204; /// /// /// public const ushort ObjectChange = 301; /// /// /// public const ushort ProcessorConfigChange = 302; /// /// /// public const ushort EthernetConfigChange = 303; /// /// /// public const ushort ControlSubnetConfigChange = 304; /// /// /// public const ushort ProgramConfigChange = 305; } /// /// Represents a ProcessorChangeEventArgs /// public class ProcessorChangeEventArgs : EventArgs { /// /// /// public ProcessorInfo Processor { get; set; } /// /// /// public ushort Type { get; set; } /// /// /// public ushort Index { get; set; } /// /// Constructor /// public ProcessorChangeEventArgs() { } /// /// Constructor overload /// public ProcessorChangeEventArgs(ProcessorInfo processor, ushort type) { Processor = processor; Type = type; } /// /// Constructor /// public ProcessorChangeEventArgs(ProcessorInfo processor, ushort type, ushort index) { Processor = processor; Type = type; Index = index; } } /// /// Represents a EthernetChangeEventArgs /// public class EthernetChangeEventArgs : EventArgs { /// /// /// public EthernetInfo Adapter { get; set; } /// /// /// public ushort Type { get; set; } /// /// /// public ushort Index { get; set; } /// /// Constructor /// public EthernetChangeEventArgs() { } /// /// Constructor overload /// /// /// public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type) { Adapter = ethernet; Type = type; } /// /// Constructor overload /// /// /// /// public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type, ushort index) { Adapter = ethernet; Type = type; Index = index; } } /// /// Represents a ControlSubnetChangeEventArgs /// public class ControlSubnetChangeEventArgs : EventArgs { /// /// /// public ControlSubnetInfo Adapter { get; set; } /// /// /// public ushort Type { get; set; } /// /// /// public ushort Index { get; set; } /// /// Constructor /// public ControlSubnetChangeEventArgs() { } /// /// Constructor overload /// public ControlSubnetChangeEventArgs(ControlSubnetInfo controlSubnet, ushort type) { Adapter = controlSubnet; Type = type; } /// /// Constructor overload /// public ControlSubnetChangeEventArgs(ControlSubnetInfo controlSubnet, ushort type, ushort index) { Adapter = controlSubnet; Type = type; Index = index; } } /// /// Represents a ProgramChangeEventArgs /// public class ProgramChangeEventArgs : EventArgs { /// /// /// public ProgramInfo Program { get; set; } /// /// /// public ushort Type { get; set; } /// /// /// public ushort Index { get; set; } /// /// Constructor /// public ProgramChangeEventArgs() { } /// /// Constructor overload /// /// /// public ProgramChangeEventArgs(ProgramInfo program, ushort type) { Program = program; Type = type; } /// /// Constructor overload /// /// /// /// public ProgramChangeEventArgs(ProgramInfo program, ushort type, ushort index) { Program = program; Type = type; Index = index; } } } ================================================ FILE: src/PepperDash.Core/SystemInfo/SystemInfoConfig.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.SystemInfo { /// /// Processor info class /// public class ProcessorInfo { /// /// /// public string Model { get; set; } /// /// /// public string SerialNumber { get; set; } /// /// /// public string Firmware { get; set; } /// /// /// public string FirmwareDate { get; set; } /// /// /// public string OsVersion { get; set; } /// /// /// public string RuntimeEnvironment { get; set; } /// /// /// public string DevicePlatform { get; set; } /// /// /// public string ModuleDirectory { get; set; } /// /// /// public string LocalTimeZone { get; set; } /// /// /// public string ProgramIdTag { get; set; } /// /// Constructor /// public ProcessorInfo() { } } /// /// Ethernet info class /// public class EthernetInfo { /// /// /// public ushort DhcpIsOn { get; set; } /// /// /// public string Hostname { get; set; } /// /// /// public string MacAddress { get; set; } /// /// /// public string IpAddress { get; set; } /// /// /// public string Subnet { get; set; } /// /// /// public string Gateway { get; set; } /// /// /// public string Dns1 { get; set; } /// /// /// public string Dns2 { get; set; } /// /// /// public string Dns3 { get; set; } /// /// /// public string Domain { get; set; } /// /// Constructor /// public EthernetInfo() { } } /// /// Control subnet info class /// public class ControlSubnetInfo { /// /// /// public ushort Enabled { get; set; } /// /// /// public ushort IsInAutomaticMode { get; set; } /// /// /// public string MacAddress { get; set; } /// /// /// public string IpAddress { get; set; } /// /// /// public string Subnet { get; set; } /// /// /// public string RouterPrefix { get; set; } /// /// Constructor /// public ControlSubnetInfo() { } } /// /// Program info class /// public class ProgramInfo { /// /// /// public string Name { get; set; } /// /// /// public string Header { get; set; } /// /// /// public string System { get; set; } /// /// /// public string ProgramIdTag { get; set; } /// /// /// public string CompileTime { get; set; } /// /// /// public string Database { get; set; } /// /// /// public string Environment { get; set; } /// /// /// public string Programmer { get; set; } /// /// Constructor /// public ProgramInfo() { } } } ================================================ FILE: src/PepperDash.Core/SystemInfo/SystemInfoToSimpl.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.SystemInfo { /// /// System Info class /// public class SystemInfoToSimpl { /// /// Notifies of bool change /// public event EventHandler BoolChange; /// /// Notifies of string change /// public event EventHandler StringChange; /// /// Notifies of processor change /// public event EventHandler ProcessorChange; /// /// Notifies of ethernet change /// public event EventHandler EthernetChange; /// /// Notifies of control subnet change /// public event EventHandler ControlSubnetChange; /// /// Notifies of program change /// public event EventHandler ProgramChange; /// /// Constructor /// public SystemInfoToSimpl() { } /// /// Gets the current processor info /// public void GetProcessorInfo() { OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange); try { var processor = new ProcessorInfo(); processor.Model = InitialParametersClass.ControllerPromptName; processor.SerialNumber = CrestronEnvironment.SystemInfo.SerialNumber; processor.ModuleDirectory = InitialParametersClass.ProgramDirectory.ToString(); processor.ProgramIdTag = InitialParametersClass.ProgramIDTag; processor.DevicePlatform = CrestronEnvironment.DevicePlatform.ToString(); processor.OsVersion = CrestronEnvironment.OSVersion.Version.ToString(); processor.RuntimeEnvironment = CrestronEnvironment.RuntimeEnvironment.ToString(); processor.LocalTimeZone = CrestronEnvironment.GetTimeZone().Offset; // Does not return firmware version matching a "ver" command // returns the "ver -v" 'CAB' version // example return ver -v: // RMC3 Cntrl Eng [v1.503.3568.25373 (Oct 09 2018), #4001E302] @E-00107f4420f0 // Build: 14:05:46 Oct 09 2018 (3568.25373) // Cab: 1.503.0070 // Applications: 1.0.6855.21351 // Updater: 1.4.24 // Bootloader: 1.22.00 // RMC3-SetupProgram: 1.003.0011 // IOPVersion: FPGA [v09] slot:7 // PUF: Unknown //Firmware = CrestronEnvironment.OSVersion.Firmware; //Firmware = InitialParametersClass.FirmwareVersion; // Use below logic to get actual firmware ver, not the 'CAB' returned by the above // matches console return of a "ver" and on SystemInfo page // example return ver: // RMC3 Cntrl Eng [v1.503.3568.25373 (Oct 09 2018), #4001E302] @E-00107f4420f0 var response = ""; CrestronConsole.SendControlSystemCommand("ver", ref response); processor.Firmware = ParseConsoleResponse(response, "Cntrl Eng", "[", "("); processor.FirmwareDate = ParseConsoleResponse(response, "Cntrl Eng", "(", ")"); OnProcessorChange(processor, 0, SystemInfoConstants.ProcessorConfigChange); } catch (Exception e) { var msg = string.Format("GetProcessorInfo failed: {0}", e.Message); CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); } OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange); } /// /// GetEthernetInfo method /// public void GetEthernetInfo() { OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange); var adapter = new EthernetInfo(); try { // get lan adapter id var adapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); // get lan adapter info var dhcpState = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterId); if (!string.IsNullOrEmpty(dhcpState)) adapter.DhcpIsOn = (ushort)(dhcpState.ToLower().Contains("on") ? 1 : 0); adapter.Hostname = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterId); adapter.MacAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterId); adapter.IpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterId); adapter.Subnet = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterId); adapter.Gateway = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterId); adapter.Domain = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterId); // returns comma seperate list of dns servers with trailing comma // example return: "8.8.8.8 (DHCP),8.8.4.4 (DHCP)," string dns = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterId); if (dns.Contains(",")) { string[] dnsList = dns.Split(','); for (var i = 0; i < dnsList.Length; i++) { if(i == 0) adapter.Dns1 = !string.IsNullOrEmpty(dnsList[0]) ? dnsList[0] : "0.0.0.0"; if(i == 1) adapter.Dns2 = !string.IsNullOrEmpty(dnsList[1]) ? dnsList[1] : "0.0.0.0"; if(i == 2) adapter.Dns3 = !string.IsNullOrEmpty(dnsList[2]) ? dnsList[2] : "0.0.0.0"; } } else { adapter.Dns1 = !string.IsNullOrEmpty(dns) ? dns : "0.0.0.0"; adapter.Dns2 = "0.0.0.0"; adapter.Dns3 = "0.0.0.0"; } OnEthernetInfoChange(adapter, 0, SystemInfoConstants.EthernetConfigChange); } catch (Exception e) { var msg = string.Format("GetEthernetInfo failed: {0}", e.Message); CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); } OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange); } /// /// GetControlSubnetInfo method /// public void GetControlSubnetInfo() { OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange); var adapter = new ControlSubnetInfo(); try { // get cs adapter id var adapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); if (!adapterId.Equals(EthernetAdapterType.EthernetUnknownAdapter)) { adapter.Enabled = 1; adapter.IsInAutomaticMode = (ushort)(CrestronEthernetHelper.IsControlSubnetInAutomaticMode ? 1 : 0); adapter.MacAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterId); adapter.IpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterId); adapter.Subnet = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterId); adapter.RouterPrefix = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CONTROL_SUBNET_ROUTER_PREFIX, adapterId); } } catch (Exception e) { adapter.Enabled = 0; adapter.IsInAutomaticMode = 0; adapter.MacAddress = "NA"; adapter.IpAddress = "NA"; adapter.Subnet = "NA"; adapter.RouterPrefix = "NA"; var msg = string.Format("GetControlSubnetInfo failed: {0}", e.Message); CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); } OnControlSubnetInfoChange(adapter, 0, SystemInfoConstants.ControlSubnetConfigChange); OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange); } /// /// Gets the program info by index /// /// /// /// GetProgramInfoByIndex method /// public void GetProgramInfoByIndex(ushort index) { if (index < 1 || index > 10) return; OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange); var program = new ProgramInfo(); try { var response = ""; CrestronConsole.SendControlSystemCommand(string.Format("progcomments:{0}", index), ref response); // no program loaded or running if (response.Contains("Bad or Incomplete Command")) { program.Name = ""; program.System = ""; program.Programmer = ""; program.CompileTime = ""; program.Database = ""; program.Environment = ""; } else { // SIMPL returns program.Name = ParseConsoleResponse(response, "Program File", ":", "\x0D"); program.System = ParseConsoleResponse(response, "System Name", ":", "\x0D"); program.ProgramIdTag = ParseConsoleResponse(response, "Friendly Name", ":", "\x0D"); program.Programmer = ParseConsoleResponse(response, "Programmer", ":", "\x0D"); program.CompileTime = ParseConsoleResponse(response, "Compiled On", ":", "\x0D"); program.Database = ParseConsoleResponse(response, "CrestronDB", ":", "\x0D"); program.Environment = ParseConsoleResponse(response, "Source Env", ":", "\x0D"); // S# returns if (program.System.Length == 0) program.System = ParseConsoleResponse(response, "Application Name", ":", "\x0D"); if (program.Database.Length == 0) program.Database = ParseConsoleResponse(response, "PlugInVersion", ":", "\x0D"); if (program.Environment.Length == 0) program.Environment = ParseConsoleResponse(response, "Program Tool", ":", "\x0D"); } OnProgramChange(program, index, SystemInfoConstants.ProgramConfigChange); } catch (Exception e) { var msg = string.Format("GetProgramInfoByIndex failed: {0}", e.Message); CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); } OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange); } /// /// RefreshProcessorUptime method /// public void RefreshProcessorUptime() { try { string response = ""; CrestronConsole.SendControlSystemCommand("uptime", ref response); var uptime = ParseConsoleResponse(response, "running for", "running for", "\x0D"); OnStringChange(uptime, 0, SystemInfoConstants.ProcessorUptimeChange); } catch (Exception e) { var msg = string.Format("RefreshProcessorUptime failed:\r{0}", e.Message); CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); } } /// /// Gets the program uptime, by index, and passes it to S+ /// /// /// /// RefreshProgramUptimeByIndex method /// public void RefreshProgramUptimeByIndex(int index) { try { string response = ""; CrestronConsole.SendControlSystemCommand(string.Format("proguptime:{0}", index), ref response); string uptime = ParseConsoleResponse(response, "running for", "running for", "\x0D"); OnStringChange(uptime, (ushort)index, SystemInfoConstants.ProgramUptimeChange); } catch (Exception e) { var msg = string.Format("RefreshProgramUptimebyIndex({0}) failed:\r{1}", index, e.Message); CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); } } /// /// Sends command to console, passes response back using string change event /// /// /// /// SendConsoleCommand method /// public void SendConsoleCommand(string cmd) { if (string.IsNullOrEmpty(cmd)) return; string response = ""; CrestronConsole.SendControlSystemCommand(cmd, ref response); if (!string.IsNullOrEmpty(response)) { if (response.EndsWith("\x0D\\x0A")) response.Trim('\n'); OnStringChange(response, 0, SystemInfoConstants.ConsoleResponseChange); } } /// /// private method to parse console messages /// /// /// /// /// /// private string ParseConsoleResponse(string data, string line, string dataStart, string dataEnd) { var response = ""; if (string.IsNullOrEmpty(data) || string.IsNullOrEmpty(line) || string.IsNullOrEmpty(dataStart) || string.IsNullOrEmpty(dataEnd)) return response; try { var linePos = data.IndexOf(line); var startPos = data.IndexOf(dataStart, linePos) + dataStart.Length; var endPos = data.IndexOf(dataEnd, startPos); response = data.Substring(startPos, endPos - startPos).Trim(); } catch (Exception e) { var msg = string.Format("ParseConsoleResponse failed: {0}", e.Message); CrestronConsole.PrintLine(msg); //ErrorLog.Error(msg); } return response; } /// /// Protected boolean change event handler /// /// /// /// protected void OnBoolChange(bool state, ushort index, ushort type) { var handler = BoolChange; if (handler != null) { var args = new BoolChangeEventArgs(state, type); args.Index = index; BoolChange(this, args); } } /// /// Protected string change event handler /// /// /// /// protected void OnStringChange(string value, ushort index, ushort type) { var handler = StringChange; if (handler != null) { var args = new StringChangeEventArgs(value, type); args.Index = index; StringChange(this, args); } } /// /// Protected processor config change event handler /// /// /// /// protected void OnProcessorChange(ProcessorInfo processor, ushort index, ushort type) { var handler = ProcessorChange; if (handler != null) { var args = new ProcessorChangeEventArgs(processor, type); args.Index = index; ProcessorChange(this, args); } } /// /// Ethernet change event handler /// /// /// /// protected void OnEthernetInfoChange(EthernetInfo ethernet, ushort index, ushort type) { var handler = EthernetChange; if (handler != null) { var args = new EthernetChangeEventArgs(ethernet, type); args.Index = index; EthernetChange(this, args); } } /// /// Control Subnet change event handler /// /// /// /// protected void OnControlSubnetInfoChange(ControlSubnetInfo ethernet, ushort index, ushort type) { var handler = ControlSubnetChange; if (handler != null) { var args = new ControlSubnetChangeEventArgs(ethernet, type); args.Index = index; ControlSubnetChange(this, args); } } /// /// Program change event handler /// /// /// /// protected void OnProgramChange(ProgramInfo program, ushort index, ushort type) { var handler = ProgramChange; if (handler != null) { var args = new ProgramChangeEventArgs(program, type); args.Index = index; ProgramChange(this, args); } } } } ================================================ FILE: src/PepperDash.Core/Web/BouncyCertificate.cs ================================================ using Crestron.SimplSharp; using System; using System.Collections.Generic; using System.IO; using System.Linq; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Prng; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.X509; using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; using X509KeyStorageFlags = System.Security.Cryptography.X509Certificates.X509KeyStorageFlags; using X509ContentType = System.Security.Cryptography.X509Certificates.X509ContentType; using Org.BouncyCastle.Crypto.Operators; using BigInteger = Org.BouncyCastle.Math.BigInteger; using X509Certificate = Org.BouncyCastle.X509.X509Certificate; namespace PepperDash.Core { /// /// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/ /// internal class BouncyCertificate { public string CertificatePassword { get; set; } = "password"; public X509Certificate2 LoadCertificate(string issuerFileName, string password) { // We need to pass 'Exportable', otherwise we can't get the private key. var issuerCertificate = new X509Certificate2(issuerFileName, password, X509KeyStorageFlags.Exportable); return issuerCertificate; } /// /// IssueCertificate method /// public X509Certificate2 IssueCertificate(string subjectName, X509Certificate2 issuerCertificate, string[] subjectAlternativeNames, KeyPurposeID[] usages) { // It's self-signed, so these are the same. var issuerName = issuerCertificate.Subject; var random = GetSecureRandom(); var subjectKeyPair = GenerateKeyPair(random, 2048); var issuerKeyPair = DotNetUtilities.GetKeyPair(issuerCertificate.PrivateKey); var serialNumber = GenerateSerialNumber(random); var issuerSerialNumber = new BigInteger(issuerCertificate.GetSerialNumber()); const bool isCertificateAuthority = false; var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, subjectAlternativeNames, issuerName, issuerKeyPair, issuerSerialNumber, isCertificateAuthority, usages); return ConvertCertificate(certificate, subjectKeyPair, random); } /// /// CreateCertificateAuthorityCertificate method /// public X509Certificate2 CreateCertificateAuthorityCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages) { // It's self-signed, so these are the same. var issuerName = subjectName; var random = GetSecureRandom(); var subjectKeyPair = GenerateKeyPair(random, 2048); // It's self-signed, so these are the same. var issuerKeyPair = subjectKeyPair; var serialNumber = GenerateSerialNumber(random); var issuerSerialNumber = serialNumber; // Self-signed, so it's the same serial number. const bool isCertificateAuthority = true; var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, subjectAlternativeNames, issuerName, issuerKeyPair, issuerSerialNumber, isCertificateAuthority, usages); return ConvertCertificate(certificate, subjectKeyPair, random); } /// /// CreateSelfSignedCertificate method /// public X509Certificate2 CreateSelfSignedCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages) { // It's self-signed, so these are the same. var issuerName = subjectName; var random = GetSecureRandom(); var subjectKeyPair = GenerateKeyPair(random, 2048); // It's self-signed, so these are the same. var issuerKeyPair = subjectKeyPair; var serialNumber = GenerateSerialNumber(random); var issuerSerialNumber = serialNumber; // Self-signed, so it's the same serial number. const bool isCertificateAuthority = false; var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber, subjectAlternativeNames, issuerName, issuerKeyPair, issuerSerialNumber, isCertificateAuthority, usages); return ConvertCertificate(certificate, subjectKeyPair, random); } private SecureRandom GetSecureRandom() { // Since we're on Windows, we'll use the CryptoAPI one (on the assumption // that it might have access to better sources of entropy than the built-in // Bouncy Castle ones): var randomGenerator = new CryptoApiRandomGenerator(); var random = new SecureRandom(randomGenerator); return random; } private X509Certificate GenerateCertificate(SecureRandom random, string subjectName, AsymmetricCipherKeyPair subjectKeyPair, BigInteger subjectSerialNumber, string[] subjectAlternativeNames, string issuerName, AsymmetricCipherKeyPair issuerKeyPair, BigInteger issuerSerialNumber, bool isCertificateAuthority, KeyPurposeID[] usages) { var certificateGenerator = new X509V3CertificateGenerator(); certificateGenerator.SetSerialNumber(subjectSerialNumber); var issuerDN = new X509Name(issuerName); certificateGenerator.SetIssuerDN(issuerDN); // Note: The subject can be omitted if you specify a subject alternative name (SAN). var subjectDN = new X509Name(subjectName); certificateGenerator.SetSubjectDN(subjectDN); // Our certificate needs valid from/to values. var notBefore = DateTime.UtcNow.Date; var notAfter = notBefore.AddYears(2); certificateGenerator.SetNotBefore(notBefore); certificateGenerator.SetNotAfter(notAfter); // The subject's public key goes in the certificate. certificateGenerator.SetPublicKey(subjectKeyPair.Public); AddAuthorityKeyIdentifier(certificateGenerator, issuerDN, issuerKeyPair, issuerSerialNumber); AddSubjectKeyIdentifier(certificateGenerator, subjectKeyPair); //AddBasicConstraints(certificateGenerator, isCertificateAuthority); if (usages != null && usages.Any()) AddExtendedKeyUsage(certificateGenerator, usages); if (subjectAlternativeNames != null && subjectAlternativeNames.Any()) AddSubjectAlternativeNames(certificateGenerator, subjectAlternativeNames); // Set the signature algorithm. This is used to generate the thumbprint which is then signed // with the issuer's private key. We'll use SHA-256, which is (currently) considered fairly strong. const string signatureAlgorithm = "SHA256WithRSA"; // The certificate is signed with the issuer's private key. ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerKeyPair.Private, random); var certificate = certificateGenerator.Generate(signatureFactory); return certificate; } /// /// The certificate needs a serial number. This is used for revocation, /// and usually should be an incrementing index (which makes it easier to revoke a range of certificates). /// Since we don't have anywhere to store the incrementing index, we can just use a random number. /// /// /// private BigInteger GenerateSerialNumber(SecureRandom random) { var serialNumber = BigIntegers.CreateRandomInRange( BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); return serialNumber; } /// /// Generate a key pair. /// /// The random number generator. /// The key length in bits. For RSA, 2048 bits should be considered the minimum acceptable these days. /// private AsymmetricCipherKeyPair GenerateKeyPair(SecureRandom random, int strength) { var keyGenerationParameters = new KeyGenerationParameters(random, strength); var keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); var subjectKeyPair = keyPairGenerator.GenerateKeyPair(); return subjectKeyPair; } /// /// Add the Authority Key Identifier. According to http://www.alvestrand.no/objectid/2.5.29.35.html, this /// identifies the public key to be used to verify the signature on this certificate. /// In a certificate chain, this corresponds to the "Subject Key Identifier" on the *issuer* certificate. /// The Bouncy Castle documentation, at http://www.bouncycastle.org/wiki/display/JA1/X.509+Public+Key+Certificate+and+Certification+Request+Generation, /// shows how to create this from the issuing certificate. Since we're creating a self-signed certificate, we have to do this slightly differently. /// /// /// /// /// private void AddAuthorityKeyIdentifier(X509V3CertificateGenerator certificateGenerator, X509Name issuerDN, AsymmetricCipherKeyPair issuerKeyPair, BigInteger issuerSerialNumber) { var authorityKeyIdentifierExtension = new AuthorityKeyIdentifier( SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKeyPair.Public), new GeneralNames(new GeneralName(issuerDN)), issuerSerialNumber); certificateGenerator.AddExtension( X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifierExtension); } /// /// Add the "Subject Alternative Names" extension. Note that you have to repeat /// the value from the "Subject Name" property. /// /// /// private void AddSubjectAlternativeNames(X509V3CertificateGenerator certificateGenerator, IEnumerable subjectAlternativeNames) { var subjectAlternativeNamesExtension = new DerSequence( subjectAlternativeNames.Select(name => new GeneralName(GeneralName.DnsName, name)) .ToArray()); certificateGenerator.AddExtension( X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension); } /// /// Add the "Extended Key Usage" extension, specifying (for example) "server authentication". /// /// /// private void AddExtendedKeyUsage(X509V3CertificateGenerator certificateGenerator, KeyPurposeID[] usages) { certificateGenerator.AddExtension( X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(usages)); } /// /// Add the "Basic Constraints" extension. /// /// /// private void AddBasicConstraints(X509V3CertificateGenerator certificateGenerator, bool isCertificateAuthority) { certificateGenerator.AddExtension( X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCertificateAuthority)); } /// /// Add the Subject Key Identifier. /// /// /// private void AddSubjectKeyIdentifier(X509V3CertificateGenerator certificateGenerator, AsymmetricCipherKeyPair subjectKeyPair) { var subjectKeyIdentifierExtension = new SubjectKeyIdentifier( SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public)); certificateGenerator.AddExtension( X509Extensions.SubjectKeyIdentifier.Id, false, subjectKeyIdentifierExtension); } private X509Certificate2 ConvertCertificate(X509Certificate certificate, AsymmetricCipherKeyPair subjectKeyPair, SecureRandom random) { // Now to convert the Bouncy Castle certificate to a .NET certificate. // See http://web.archive.org/web/20100504192226/http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx // ...but, basically, we create a PKCS12 store (a .PFX file) in memory, and add the public and private key to that. var store = new Pkcs12StoreBuilder().Build(); // What Bouncy Castle calls "alias" is the same as what Windows terms the "friendly name". string friendlyName = certificate.SubjectDN.ToString(); // Add the certificate. var certificateEntry = new X509CertificateEntry(certificate); store.SetCertificateEntry(friendlyName, certificateEntry); // Add the private key. store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry }); // Convert it to an X509Certificate2 object by saving/loading it from a MemoryStream. // It needs a password. Since we'll remove this later, it doesn't particularly matter what we use. var stream = new MemoryStream(); store.Save(stream, CertificatePassword.ToCharArray(), random); var convertedCertificate = new X509Certificate2(stream.ToArray(), CertificatePassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); return convertedCertificate; } /// /// WriteCertificate method /// public void WriteCertificate(X509Certificate2 certificate, string outputDirectory, string certName) { // This password is the one attached to the PFX file. Use 'null' for no password. // Create PFX (PKCS #12) with private key try { var pfx = certificate.Export(X509ContentType.Pfx, CertificatePassword); File.WriteAllBytes(string.Format("{0}.pfx", Path.Combine(outputDirectory, certName)), pfx); } catch (Exception ex) { CrestronConsole.PrintLine(string.Format("Failed to write x509 cert pfx\r\n{0}", ex.Message)); } // Create Base 64 encoded CER (public key only) using (var writer = new StreamWriter($"{Path.Combine(outputDirectory, certName)}.cer", false)) { try { var contents = string.Format("-----BEGIN CERTIFICATE-----\r\n{0}\r\n-----END CERTIFICATE-----", Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)); writer.Write(contents); } catch (Exception ex) { CrestronConsole.PrintLine(string.Format("Failed to write x509 cert cer\r\n{0}", ex.Message)); } } } /// /// AddCertToStore method /// public bool AddCertToStore(X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl) { bool bRet = false; try { var store = new System.Security.Cryptography.X509Certificates.X509Store(st, sl); store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite); store.Add(cert); store.Close(); bRet = true; } catch (Exception ex) { CrestronConsole.PrintLine(string.Format("AddCertToStore Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace)); } return bRet; } } } ================================================ FILE: src/PepperDash.Core/Web/RequestHandlers/DefaultRequestHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; namespace PepperDash.Core.Web.RequestHandlers { /// /// Represents a DefaultRequestHandler /// public class DefaultRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// public DefaultRequestHandler() : base(true) { } } } ================================================ FILE: src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace PepperDash.Core.Web.RequestHandlers { public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler { private readonly Dictionary> _handlers; protected readonly bool EnableCors; /// /// Constructor /// protected WebApiBaseRequestAsyncHandler(bool enableCors) { EnableCors = enableCors; _handlers = new Dictionary> { {"CONNECT", HandleConnect}, {"DELETE", HandleDelete}, {"GET", HandleGet}, {"HEAD", HandleHead}, {"OPTIONS", HandleOptions}, {"PATCH", HandlePatch}, {"POST", HandlePost}, {"PUT", HandlePut}, {"TRACE", HandleTrace} }; } /// /// Constructor /// protected WebApiBaseRequestAsyncHandler() : this(false) { } /// /// Handles CONNECT method requests /// /// protected virtual async Task HandleConnect(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles DELETE method requests /// /// protected virtual async Task HandleDelete(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles GET method requests /// /// protected virtual async Task HandleGet(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles HEAD method requests /// /// protected virtual async Task HandleHead(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles OPTIONS method requests /// /// protected virtual async Task HandleOptions(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles PATCH method requests /// /// protected virtual async Task HandlePatch(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles POST method requests /// /// protected virtual async Task HandlePost(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles PUT method requests /// /// protected virtual async Task HandlePut(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles TRACE method requests /// /// protected virtual async Task HandleTrace(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Process request /// /// /// /// ProcessRequest method /// public void ProcessRequest(HttpCwsContext context) { if (!_handlers.TryGetValue(context.Request.HttpMethod, out Func handler)) { return; } if (EnableCors) { context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); } var handlerTask = handler(context); handlerTask.GetAwaiter().GetResult(); } } } ================================================ FILE: src/PepperDash.Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp.WebScripting; namespace PepperDash.Core.Web.RequestHandlers { /// /// CWS Base Handler, implements IHttpCwsHandler /// public abstract class WebApiBaseRequestHandler : IHttpCwsHandler { private readonly Dictionary> _handlers; protected readonly bool EnableCors; /// /// Constructor /// protected WebApiBaseRequestHandler(bool enableCors) { EnableCors = enableCors; _handlers = new Dictionary> { {"CONNECT", HandleConnect}, {"DELETE", HandleDelete}, {"GET", HandleGet}, {"HEAD", HandleHead}, {"OPTIONS", HandleOptions}, {"PATCH", HandlePatch}, {"POST", HandlePost}, {"PUT", HandlePut}, {"TRACE", HandleTrace} }; } /// /// Constructor /// protected WebApiBaseRequestHandler() : this(false) { } /// /// Handles CONNECT method requests /// /// protected virtual void HandleConnect(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles DELETE method requests /// /// protected virtual void HandleDelete(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles GET method requests /// /// protected virtual void HandleGet(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles HEAD method requests /// /// protected virtual void HandleHead(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles OPTIONS method requests /// /// protected virtual void HandleOptions(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles PATCH method requests /// /// protected virtual void HandlePatch(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles POST method requests /// /// protected virtual void HandlePost(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles PUT method requests /// /// protected virtual void HandlePut(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles TRACE method requests /// /// protected virtual void HandleTrace(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Process request /// /// /// /// ProcessRequest method /// public void ProcessRequest(HttpCwsContext context) { Action handler; if (!_handlers.TryGetValue(context.Request.HttpMethod, out handler)) { return; } if (EnableCors) { context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); } handler(context); } } } ================================================ FILE: src/PepperDash.Core/Web/WebApiServer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core.Logging; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Core.Web { /// /// Web API server /// public class WebApiServer : IKeyName { private const string SplusKey = "Uninitialized Web API Server"; private const string DefaultName = "Web API Server"; private const string DefaultBasePath = "/api"; private const uint DebugTrace = 0; private const uint DebugInfo = 1; private const uint DebugVerbose = 2; private readonly CCriticalSection _serverLock = new CCriticalSection(); private HttpCwsServer _server; /// /// Gets or sets the Key /// public string Key { get; private set; } /// /// Gets or sets the Name /// public string Name { get; private set; } /// /// Gets or sets the BasePath /// public string BasePath { get; private set; } /// /// Gets or sets the IsRegistered /// public bool IsRegistered { get; private set; } //public IHttpCwsHandler HttpRequestHandler //{ // get { return _server.HttpRequestHandler; } // set // { // if (_server == null) return; // _server.HttpRequestHandler = value; // } //} //public event EventHandler ReceivedRequestEvent //{ // add { _server.ReceivedRequestEvent += new HttpCwsRequestEventHandler(value); } // remove { _server.ReceivedRequestEvent -= new HttpCwsRequestEventHandler(value); } //} /// /// Constructor for S+. Make sure to set necessary properties using init method /// public WebApiServer() : this(SplusKey, DefaultName, null) { } /// /// Constructor /// /// /// public WebApiServer(string key, string basePath) : this(key, DefaultName, basePath) { } /// /// Constructor /// /// /// /// public WebApiServer(string key, string name, string basePath) { Key = key; Name = string.IsNullOrEmpty(name) ? DefaultName : name; BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; if (_server == null) _server = new HttpCwsServer(BasePath); _server.AuthenticateAllRoutes = false; _server.setProcessName(Key); _server.HttpRequestHandler = new DefaultRequestHandler(); CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } /// /// Program status event handler /// /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType != eProgramStatusEventType.Stopping) return; this.LogInformation("Program stopping. stopping server"); Stop(); } /// /// Ethernet event handler /// /// void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) { // Re-enable the server if the link comes back up and the status should be connected if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp && IsRegistered) { this.LogInformation("Ethernet link up. Server is alreedy registered."); return; } this.LogInformation("Ethernet link up. Starting server"); Start(); } /// /// Initialize method /// public void Initialize(string key, string basePath) { Key = key; BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; } /// /// Adds a route to CWS /// public void AddRoute(HttpCwsRoute route) { if (route == null) { this.LogWarning("Failed to add route, route parameter is null"); return; } _server.Routes.Add(route); } /// /// Removes a route from CWS /// /// public void RemoveRoute(HttpCwsRoute route) { if (route == null) { this.LogWarning("Failed to remove route, route parameter is null"); return; } _server.Routes.Remove(route); } /// /// Sets the fallback request handler that is invoked when no registered route /// matches an incoming request. Must be called before . /// /// The handler to use as the server-level fallback. public void SetFallbackHandler(IHttpCwsHandler handler) { if (handler == null) { this.LogWarning("SetFallbackHandler: handler parameter is null, ignoring"); return; } _server.HttpRequestHandler = handler; } /// /// GetRouteCollection method /// public HttpCwsRouteCollection GetRouteCollection() { return _server.Routes; } /// /// Starts CWS instance /// public void Start() { try { _serverLock.Enter(); if (_server == null) { this.LogWarning("Server is null, unable to start"); return; } if (IsRegistered) { this.LogWarning("Server has already been started"); return; } IsRegistered = _server.Register(); this.LogInformation("Starting server, registration {registrationResult}", IsRegistered ? "was successful" : "failed"); } catch (Exception ex) { this.LogError("Start Exception Message: {message}", ex.Message); this.LogDebug(ex, "Start Exception StackTrace"); } finally { _serverLock.Leave(); } } /// /// Stop method /// public void Stop() { try { _serverLock.Enter(); if (_server == null) { this.LogWarning("Server is null or has already been stopped"); return; } IsRegistered = _server.Unregister() == false; this.LogInformation("Stopping server, unregistration {unregistrationResult}", IsRegistered ? "failed" : "was successful"); _server.Dispose(); _server = null; } catch (Exception ex) { this.LogError("Server Stop Exception Message: {message}", ex.Message); this.LogDebug(ex, "Server Stop Exception StackTrace"); } finally { _serverLock.Leave(); } } /// /// Received request handler /// /// /// This is here for development and testing /// /// /// public void ReceivedRequestEventHandler(object sender, HttpCwsRequestEventArgs args) { try { var j = JsonConvert.SerializeObject(args.Context, Formatting.Indented); this.LogVerbose("RecieveRequestEventHandler Context:\x0d\x0a{0}", j); } catch (Exception ex) { this.LogError("ReceivedRequestEventHandler Exception Message: {message}", ex.Message); this.LogDebug(ex, "ReceivedRequestEventHandler Exception StackTrace: {stackTrace}", ex.StackTrace); } } } } ================================================ FILE: src/PepperDash.Core/WebApi/Presets/Preset.cs ================================================ using System; namespace PepperDash.Core.WebApi.Presets { /// /// Represents a Preset /// public class Preset { /// /// ID of preset /// public int Id { get; set; } /// /// Gets or sets the UserId /// public int UserId { get; set; } /// /// Gets or sets the RoomTypeId /// public int RoomTypeId { get; set; } /// /// Gets or sets the PresetName /// public string PresetName { get; set; } /// /// Gets or sets the PresetNumber /// public int PresetNumber { get; set; } /// /// Gets or sets the Data /// public string Data { get; set; } /// /// Constructor /// public Preset() { PresetName = ""; PresetNumber = 1; Data = "{}"; } } /// /// Represents a PresetReceivedEventArgs /// public class PresetReceivedEventArgs : EventArgs { /// /// True when the preset is found /// public bool LookupSuccess { get; private set; } /// /// Gets or sets the ULookupSuccess /// public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } } /// /// Gets or sets the Preset /// public Preset Preset { get; private set; } /// /// For Simpl+ /// public PresetReceivedEventArgs() { } /// /// Constructor /// /// /// public PresetReceivedEventArgs(Preset preset, bool success) { LookupSuccess = success; Preset = preset; } } } ================================================ FILE: src/PepperDash.Core/WebApi/Presets/User.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Core.WebApi.Presets { /// /// /// public class User { /// /// /// public int Id { get; set; } /// /// Gets or sets the ExternalId /// public string ExternalId { get; set; } /// /// Gets or sets the FirstName /// public string FirstName { get; set; } /// /// Gets or sets the LastName /// public string LastName { get; set; } } /// /// /// public class UserReceivedEventArgs : EventArgs { /// /// True when user is found /// public bool LookupSuccess { get; private set; } /// /// Gets or sets the ULookupSuccess /// public ushort ULookupSuccess { get { return (ushort)(LookupSuccess ? 1 : 0); } } /// /// Gets or sets the User /// public User User { get; private set; } /// /// For Simpl+ /// public UserReceivedEventArgs() { } /// /// Constructor /// /// /// public UserReceivedEventArgs(User user, bool success) { LookupSuccess = success; User = user; } } /// /// Represents a UserAndRoomMessage /// public class UserAndRoomMessage { /// /// /// public int UserId { get; set; } /// /// Gets or sets the RoomTypeId /// public int RoomTypeId { get; set; } /// /// Gets or sets the PresetNumber /// public int PresetNumber { get; set; } } } ================================================ FILE: src/PepperDash.Core/WebApi/Presets/WebApiPasscodeClient.cs ================================================ using System; using Crestron.SimplSharp; // For Basic SIMPL# Classes using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.Net.Https; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core.JsonToSimpl; namespace PepperDash.Core.WebApi.Presets { /// /// Passcode client for the WebApi /// [Obsolete("WebApiPasscodeClient is no longer supported and will be removed in a future release.")] public class WebApiPasscodeClient : IKeyed { /// /// Notifies when user received /// public event EventHandler UserReceived; /// /// Notifies when Preset received /// public event EventHandler PresetReceived; /// /// Gets or sets the Key /// public string Key { get; private set; } //string JsonMasterKey; /// /// An embedded JsonToSimpl master object. /// JsonToSimplGenericMaster J2SMaster; string UrlBase; string DefaultPresetJsonFilePath; User CurrentUser; Preset CurrentPreset; /// /// SIMPL+ can only execute the default constructor. If you have variables that require initialization, please /// use an Initialize method /// public WebApiPasscodeClient() { } /// /// Initializes the instance /// /// /// /// /// public void Initialize(string key, string jsonMasterKey, string urlBase, string defaultPresetJsonFilePath) { Key = key; //JsonMasterKey = jsonMasterKey; UrlBase = urlBase; DefaultPresetJsonFilePath = defaultPresetJsonFilePath; J2SMaster = new JsonToSimplGenericMaster(); J2SMaster.SaveCallback = this.SaveCallback; J2SMaster.Initialize(jsonMasterKey); } /// /// Gets the user for a passcode /// /// /// /// GetUserForPasscode method /// public void GetUserForPasscode(string passcode) { // Bullshit duplicate code here... These two cases should be the same // except for https/http and the certificate ignores if (!UrlBase.StartsWith("https")) return; var req = new HttpsClientRequest(); req.Url = new UrlParser(UrlBase + "/api/users/dopin"); req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post; req.Header.AddHeader(new HttpsHeader("Content-Type", "application/json")); req.Header.AddHeader(new HttpsHeader("Accept", "application/json")); var jo = new JObject(); jo.Add("pin", passcode); req.ContentString = jo.ToString(); var client = new HttpsClient(); client.HostVerification = false; client.PeerVerification = false; var resp = client.Dispatch(req); var handler = UserReceived; if (resp.Code == 200) { //CrestronConsole.PrintLine("Received: {0}", resp.ContentString); var user = JsonConvert.DeserializeObject(resp.ContentString); CurrentUser = user; if (handler != null) handler(this, new UserReceivedEventArgs(user, true)); } else if (handler != null) handler(this, new UserReceivedEventArgs(null, false)); } /// /// /// /// /// /// /// GetPresetForThisUser method /// public void GetPresetForThisUser(int roomTypeId, int presetNumber) { if (CurrentUser == null) { CrestronConsole.PrintLine("GetPresetForThisUser no user loaded"); return; } var msg = new UserAndRoomMessage { UserId = CurrentUser.Id, RoomTypeId = roomTypeId, PresetNumber = presetNumber }; var handler = PresetReceived; try { if (!UrlBase.StartsWith("https")) return; var req = new HttpsClientRequest(); req.Url = new UrlParser(UrlBase + "/api/presets/userandroom"); req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post; req.Header.AddHeader(new HttpsHeader("Content-Type", "application/json")); req.Header.AddHeader(new HttpsHeader("Accept", "application/json")); req.ContentString = JsonConvert.SerializeObject(msg); var client = new HttpsClient(); client.HostVerification = false; client.PeerVerification = false; // ask for the preset var resp = client.Dispatch(req); if (resp.Code == 200) // got it { //Debug.Console(1, this, "Received: {0}", resp.ContentString); var preset = JsonConvert.DeserializeObject(resp.ContentString); CurrentPreset = preset; //if there's no preset data, load the template if (preset.Data == null || preset.Data.Trim() == string.Empty || JObject.Parse(preset.Data).Count == 0) { //Debug.Console(1, this, "Loaded preset has no data. Loading default template."); LoadDefaultPresetData(); return; } J2SMaster.LoadWithJson(preset.Data); if (handler != null) handler(this, new PresetReceivedEventArgs(preset, true)); } else // no existing preset { CurrentPreset = new Preset(); LoadDefaultPresetData(); if (handler != null) handler(this, new PresetReceivedEventArgs(null, false)); } } catch (HttpException e) { var resp = e.Response; Debug.Console(1, this, "No preset received (code {0}). Loading default template", resp.Code); LoadDefaultPresetData(); if (handler != null) PresetReceived(this, new PresetReceivedEventArgs(null, false)); } } void LoadDefaultPresetData() { CurrentPreset = null; if (!File.Exists(DefaultPresetJsonFilePath)) { Debug.Console(0, this, "Cannot load default preset file. Saving will not work"); return; } using (StreamReader sr = new StreamReader(DefaultPresetJsonFilePath)) { try { var data = sr.ReadToEnd(); J2SMaster.SetJsonWithoutEvaluating(data); CurrentPreset = new Preset() { Data = data, UserId = CurrentUser.Id }; } catch (Exception e) { Debug.Console(0, this, "Error reading default preset JSON: \r{0}", e); } } } /// /// /// /// /// /// /// SavePresetForThisUser method /// public void SavePresetForThisUser(int roomTypeId, int presetNumber) { if (CurrentPreset == null) LoadDefaultPresetData(); //return; //// A new preset needs to have its numbers set //if (CurrentPreset.IsNewPreset) //{ CurrentPreset.UserId = CurrentUser.Id; CurrentPreset.RoomTypeId = roomTypeId; CurrentPreset.PresetNumber = presetNumber; //} J2SMaster.Save(); // Will trigger callback when ready } /// /// After save operation on JSON master happens, send it to server /// /// void SaveCallback(string json) { CurrentPreset.Data = json; if (!UrlBase.StartsWith("https")) return; var req = new HttpsClientRequest(); req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post; req.Url = new UrlParser(string.Format("{0}/api/presets/addorchange", UrlBase)); req.Header.AddHeader(new HttpsHeader("Content-Type", "application/json")); req.Header.AddHeader(new HttpsHeader("Accept", "application/json")); req.ContentString = JsonConvert.SerializeObject(CurrentPreset); var client = new HttpsClient(); client.HostVerification = false; client.PeerVerification = false; try { var resp = client.Dispatch(req); // 201=created // 204=empty content if (resp.Code == 201) CrestronConsole.PrintLine("Preset added"); else if (resp.Code == 204) CrestronConsole.PrintLine("Preset updated"); else if (resp.Code == 209) CrestronConsole.PrintLine("Preset already exists. Cannot save as new."); else CrestronConsole.PrintLine("Preset save failed: {0}\r", resp.Code, resp.ContentString); } catch (HttpException e) { CrestronConsole.PrintLine("Preset save exception {0}", e.Response.Code); } } } } ================================================ FILE: src/PepperDash.Core/XSigUtility/Serialization/IXSigSerialization.cs ================================================ using System.Collections.Generic; using PepperDash.Core.Intersystem.Tokens; namespace PepperDash.Core.Intersystem.Serialization { /// /// Interface to determine XSig serialization for an object. /// public interface IXSigSerialization { /// /// Serialize the sig data /// /// IEnumerable Serialize(); /// /// Deserialize the sig data /// /// /// /// T Deserialize(IEnumerable tokens) where T : class, IXSigSerialization; } } ================================================ FILE: src/PepperDash.Core/XSigUtility/Serialization/XSigSerializationException.cs ================================================ using System; namespace PepperDash.Core.Intersystem.Serialization { /// /// Class to handle this specific exception type /// public class XSigSerializationException : Exception { /// /// default constructor /// public XSigSerializationException() { } /// /// constructor with message /// /// public XSigSerializationException(string message) : base(message) { } /// /// constructor with message and innner exception /// /// /// public XSigSerializationException(string message, Exception inner) : base(message, inner) { } } } ================================================ FILE: src/PepperDash.Core/XSigUtility/Tokens/XSigAnalogToken.cs ================================================ using System; namespace PepperDash.Core.Intersystem.Tokens { /// /// Represents an XSigAnalogToken /// public sealed class XSigAnalogToken : XSigToken, IFormattable { private readonly ushort _value; /// /// Constructor /// /// /// public XSigAnalogToken(int index, ushort value) : base(index) { // 10-bits available for analog encoded data if (index >= 1024 || index < 0) throw new ArgumentOutOfRangeException("index"); _value = value; } /// /// /// public ushort Value { get { return _value; } } /// /// /// public override XSigTokenType TokenType { get { return XSigTokenType.Analog; } } /// /// /// /// public override byte[] GetBytes() { return new[] { (byte)(0xC0 | ((Value & 0xC000) >> 10) | (Index - 1 >> 7)), (byte)((Index - 1) & 0x7F), (byte)((Value & 0x3F80) >> 7), (byte)(Value & 0x7F) }; } /// /// /// /// /// /// /// GetTokenWithOffset method /// public override XSigToken GetTokenWithOffset(int offset) { if (offset == 0) return this; return new XSigAnalogToken(Index + offset, Value); } /// /// /// /// /// /// ToString method /// /// public override string ToString() { return Index + " = 0x" + Value.ToString("X4"); } /// /// /// /// /// /// /// /// ToString method /// public string ToString(string format, IFormatProvider formatProvider) { return Value.ToString(format, formatProvider); } } } ================================================ FILE: src/PepperDash.Core/XSigUtility/Tokens/XSigDigitalToken.cs ================================================ using System; namespace PepperDash.Core.Intersystem.Tokens { /// /// Represents an XSigDigitalToken /// public sealed class XSigDigitalToken : XSigToken { private readonly bool _value; /// /// /// /// /// public XSigDigitalToken(int index, bool value) : base(index) { // 12-bits available for digital encoded data if (index >= 4096 || index < 0) throw new ArgumentOutOfRangeException("index"); _value = value; } /// /// /// public bool Value { get { return _value; } } /// /// /// public override XSigTokenType TokenType { get { return XSigTokenType.Digital; } } /// /// /// /// public override byte[] GetBytes() { return new[] { (byte)(0x80 | (Value ? 0 : 0x20) | ((Index - 1) >> 7)), (byte)((Index - 1) & 0x7F) }; } /// /// /// /// /// /// /// GetTokenWithOffset method /// public override XSigToken GetTokenWithOffset(int offset) { if (offset == 0) return this; return new XSigDigitalToken(Index + offset, Value); } /// /// /// /// /// /// ToString method /// /// public override string ToString() { return Index + " = " + (Value ? "High" : "Low"); } /// /// /// /// /// /// /// ToString method /// public string ToString(IFormatProvider formatProvider) { return Value.ToString(formatProvider); } } } ================================================ FILE: src/PepperDash.Core/XSigUtility/Tokens/XSigSerialToken.cs ================================================ using System; using System.Text; namespace PepperDash.Core.Intersystem.Tokens { /// /// Represents an XSigSerialToken /// public sealed class XSigSerialToken : XSigToken { private readonly string _value; /// /// Constructor /// /// /// public XSigSerialToken(int index, string value) : base(index) { // 10-bits available for serial encoded data if (index >= 1024 || index < 0) throw new ArgumentOutOfRangeException("index"); _value = value; } /// /// /// public string Value { get { return _value; } } /// /// /// public override XSigTokenType TokenType { get { return XSigTokenType.Serial; } } /// /// /// /// public override byte[] GetBytes() { var serialBytes = String.IsNullOrEmpty(Value) ? new byte[0] : Encoding.GetEncoding(28591).GetBytes(Value); var xsig = new byte[serialBytes.Length + 3]; xsig[0] = (byte)(0xC8 | (Index - 1 >> 7)); xsig[1] = (byte)((Index - 1) & 0x7F); xsig[xsig.Length - 1] = 0xFF; Buffer.BlockCopy(serialBytes, 0, xsig, 2, serialBytes.Length); return xsig; } /// /// /// /// /// /// /// GetTokenWithOffset method /// public override XSigToken GetTokenWithOffset(int offset) { if (offset == 0) return this; return new XSigSerialToken(Index + offset, Value); } /// /// /// /// /// /// ToString method /// /// public override string ToString() { return Index + " = \"" + Value + "\""; } } } ================================================ FILE: src/PepperDash.Core/XSigUtility/Tokens/XSigToken.cs ================================================ namespace PepperDash.Core.Intersystem.Tokens { /// /// Represents the base class for all XSig datatypes. /// public abstract class XSigToken { private readonly int _index; /// /// Constructs an XSigToken with the specified index. /// /// Index for the data. protected XSigToken(int index) { _index = index; } /// /// XSig 1-based index. /// public int Index { get { return _index; } } /// /// XSigToken type. /// public abstract XSigTokenType TokenType { get; } /// /// Generates the XSig bytes for the corresponding token. /// /// XSig byte array. public abstract byte[] GetBytes(); /// /// Returns a new token if necessary with an updated index based on the specified offset. /// /// Offset to adjust the index with. /// XSigToken public abstract XSigToken GetTokenWithOffset(int offset); } } ================================================ FILE: src/PepperDash.Core/XSigUtility/Tokens/XSigTokenType.cs ================================================ namespace PepperDash.Core.Intersystem.Tokens { /// /// XSig token types. /// public enum XSigTokenType { /// /// Digital signal datatype. /// Digital, /// /// Analog signal datatype. /// Analog, /// /// Serial signal datatype. /// Serial } } ================================================ FILE: src/PepperDash.Core/XSigUtility/XSigHelpers.cs ================================================ using System; using System.Linq; using Crestron.SimplSharp.CrestronIO; using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Tokens; /* Digital (2 bytes) 10C##### 0####### (mask = 11000000_10000000b -> 0xC080) Analog (4 bytes) 11aa0### 0####### (mask = 11001000_10000000b -> 0xC880) 0aaaaaaa 0aaaaaaa Serial (Variable length) 11001### 0####### (mask = 11111000_10000000b -> 0xF880) dddddddd ........ <- up to 252 bytes of serial data (255 - 3) 11111111 <- denotes end of data */ namespace PepperDash.Core.Intersystem { /// /// Helper methods for creating XSig byte sequences compatible with the Intersystem Communications (ISC) symbol. /// /// /// Indexing is not from the start of each signal type but rather from the beginning of the first defined signal /// the Intersystem Communications (ISC) symbol. /// public static class XSigHelpers { /// /// Forces all outputs to 0. /// /// Bytes in XSig format for clear outputs trigger. public static byte[] ClearOutputs() { return new byte[] { 0xFC }; } /// /// Evaluate all inputs and re-transmit any digital, analog, and permanent serail signals not set to 0. /// /// Bytes in XSig format for send status trigger. public static byte[] SendStatus() { return new byte[] { 0xFD }; } /// /// Get bytes for an IXSigStateResolver object. /// /// XSig state resolver. /// Bytes in XSig format for each token within the state representation. /// /// GetBytes method /// public static byte[] GetBytes(IXSigSerialization xSigSerialization) { return GetBytes(xSigSerialization, 0); } /// /// Get bytes for an IXSigStateResolver object, with a specified offset. /// /// XSig state resolver. /// Offset to which the data will be aligned. /// Bytes in XSig format for each token within the state representation. /// /// GetBytes method /// public static byte[] GetBytes(IXSigSerialization xSigSerialization, int offset) { var tokens = xSigSerialization.Serialize(); if (tokens == null) return new byte[0]; using (var memoryStream = new MemoryStream()) { using (var tokenWriter = new XSigTokenStreamWriter(memoryStream)) tokenWriter.WriteXSigData(xSigSerialization, offset); return memoryStream.ToArray(); } } /// /// Get bytes for a single digital signal. /// /// 1-based digital index /// Digital data to be encoded /// Bytes in XSig format for digtial information. /// /// GetBytes method /// public static byte[] GetBytes(int index, bool value) { return GetBytes(index, 0, value); } /// /// Get bytes for a single digital signal. /// /// 1-based digital index /// Index offset. /// Digital data to be encoded /// Bytes in XSig format for digtial information. /// /// GetBytes method /// public static byte[] GetBytes(int index, int offset, bool value) { return new XSigDigitalToken(index + offset, value).GetBytes(); } /// /// Get byte sequence for multiple digital signals. /// /// Starting index of the sequence. /// Digital signal value array. /// Byte sequence in XSig format for digital signal information. /// /// GetBytes method /// public static byte[] GetBytes(int startIndex, bool[] values) { return GetBytes(startIndex, 0, values); } /// /// Get byte sequence for multiple digital signals. /// /// Starting index of the sequence. /// Index offset. /// Digital signal value array. /// Byte sequence in XSig format for digital signal information. /// /// GetBytes method /// public static byte[] GetBytes(int startIndex, int offset, bool[] values) { // Digital XSig data is 2 bytes per value const int fixedLength = 2; var bytes = new byte[values.Length * fixedLength]; for (var i = 0; i < values.Length; i++) Buffer.BlockCopy(GetBytes(startIndex++, offset, values[i]), 0, bytes, i * fixedLength, fixedLength); return bytes; } /// /// Get bytes for a single analog signal. /// /// 1-based analog index /// Analog data to be encoded /// Bytes in XSig format for analog signal information. /// /// GetBytes method /// public static byte[] GetBytes(int index, ushort value) { return GetBytes(index, 0, value); } /// /// Get bytes for a single analog signal. /// /// 1-based analog index /// Index offset. /// Analog data to be encoded /// Bytes in XSig format for analog signal information. /// /// GetBytes method /// public static byte[] GetBytes(int index, int offset, ushort value) { return new XSigAnalogToken(index + offset, value).GetBytes(); } /// /// Get byte sequence for multiple analog signals. /// /// Starting index of the sequence. /// Analog signal value array. /// Byte sequence in XSig format for analog signal information. /// /// GetBytes method /// public static byte[] GetBytes(int startIndex, ushort[] values) { return GetBytes(startIndex, 0, values); } /// /// Get byte sequence for multiple analog signals. /// /// Starting index of the sequence. /// Index offset. /// Analog signal value array. /// Byte sequence in XSig format for analog signal information. /// /// GetBytes method /// public static byte[] GetBytes(int startIndex, int offset, ushort[] values) { // Analog XSig data is 4 bytes per value const int fixedLength = 4; var bytes = new byte[values.Length * fixedLength]; for (var i = 0; i < values.Length; i++) Buffer.BlockCopy(GetBytes(startIndex++, offset, values[i]), 0, bytes, i * fixedLength, fixedLength); return bytes; } /// /// Get bytes for a single serial signal. /// /// 1-based serial index /// Serial data to be encoded /// Bytes in XSig format for serial signal information. /// /// GetBytes method /// public static byte[] GetBytes(int index, string value) { return GetBytes(index, 0, value); } /// /// Get bytes for a single serial signal. /// /// 1-based serial index /// Index offset. /// Serial data to be encoded /// Bytes in XSig format for serial signal information. /// /// GetBytes method /// public static byte[] GetBytes(int index, int offset, string value) { return new XSigSerialToken(index + offset, value).GetBytes(); } /// /// Get byte sequence for multiple serial signals. /// /// Starting index of the sequence. /// Serial signal value array. /// Byte sequence in XSig format for serial signal information. /// /// GetBytes method /// public static byte[] GetBytes(int startIndex, string[] values) { return GetBytes(startIndex, 0, values); } /// /// Get byte sequence for multiple serial signals. /// /// Starting index of the sequence. /// Index offset. /// Serial signal value array. /// Byte sequence in XSig format for serial signal information. /// /// GetBytes method /// public static byte[] GetBytes(int startIndex, int offset, string[] values) { // Serial XSig data is not fixed-length like the other formats var dstOffset = 0; var bytes = new byte[values.Sum(v => v.Length + 3)]; for (var i = 0; i < values.Length; i++) { var data = GetBytes(startIndex++, offset, values[i]); Buffer.BlockCopy(data, 0, bytes, dstOffset, data.Length); dstOffset += data.Length; } return bytes; } } } ================================================ FILE: src/PepperDash.Core/XSigUtility/XSigTokenStreamReader.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp.CrestronIO; using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Tokens; namespace PepperDash.Core.Intersystem { /// /// XSigToken stream reader. /// public sealed class XSigTokenStreamReader : IDisposable { private readonly Stream _stream; private readonly bool _leaveOpen; /// /// /// XSigToken stream reader constructor. /// /// Input stream to read from. /// Stream is null. /// Stream cannot be read from. public XSigTokenStreamReader(Stream stream) : this(stream, false) { } /// /// XSigToken stream reader constructor. /// /// Input stream to read from. /// Determines whether to leave the stream open or not. /// Stream is null. /// Stream cannot be read from. public XSigTokenStreamReader(Stream stream, bool leaveOpen) { if (stream == null) throw new ArgumentNullException("stream"); if (!stream.CanRead) throw new ArgumentException("The specified stream cannot be read from."); _stream = stream; _leaveOpen = leaveOpen; } /// /// Reads a 16-bit unsigned integer from the specified stream using Big Endian byte order. /// /// Input stream /// Result /// True if successful, otherwise false. /// /// TryReadUInt16BE method /// public static bool TryReadUInt16BE(Stream stream, out ushort value) { value = 0; if (stream.Length < 2) return false; var buffer = new byte[2]; stream.Read(buffer, 0, 2); value = (ushort)((buffer[0] << 8) | buffer[1]); return true; } /// /// Read XSig token from the stream. /// /// XSigToken /// Offset is less than 0. /// /// ReadXSigToken method /// public XSigToken ReadXSigToken() { ushort prefix; if (!TryReadUInt16BE(_stream, out prefix)) return null; if ((prefix & 0xF880) == 0xC800) // Serial data { var index = ((prefix & 0x0700) >> 1) | (prefix & 0x7F); var n = 0; const int maxSerialDataLength = 252; var chars = new char[maxSerialDataLength]; int ch; while ((ch = _stream.ReadByte()) != 0xFF) { if (ch == -1) // Reached end of stream without end of data marker return null; chars[n++] = (char)ch; } return new XSigSerialToken((ushort)(index + 1), new string(chars, 0, n)); } if ((prefix & 0xC880) == 0xC000) // Analog data { ushort data; if (!TryReadUInt16BE(_stream, out data)) return null; var index = ((prefix & 0x0700) >> 1) | (prefix & 0x7F); var value = ((prefix & 0x3000) << 2) | ((data & 0x7F00) >> 1) | (data & 0x7F); return new XSigAnalogToken((ushort)(index + 1), (ushort)value); } if ((prefix & 0xC080) == 0x8000) // Digital data { var index = ((prefix & 0x1F00) >> 1) | (prefix & 0x7F); var value = (prefix & 0x2000) == 0; return new XSigDigitalToken((ushort)(index + 1), value); } return null; } /// /// Reads all available XSig tokens from the stream. /// /// XSigToken collection. /// /// ReadAllXSigTokens method /// public IEnumerable ReadAllXSigTokens() { var tokens = new List(); XSigToken token; while ((token = ReadXSigToken()) != null) tokens.Add(token); return tokens; } /// /// Attempts to deserialize all XSig data within the stream from the current position. /// /// Type to deserialize the information to. /// Deserialized object. public T DeserializeStream() where T : class, IXSigSerialization, new() { return new T().Deserialize(ReadAllXSigTokens()); } /// /// Disposes of the internal stream if specified to not leave open. /// public void Dispose() { if (!_leaveOpen) _stream.Dispose(); } } } ================================================ FILE: src/PepperDash.Core/XSigUtility/XSigTokenStreamWriter.cs ================================================ using System; using System.Linq; using System.Collections.Generic; using Crestron.SimplSharp.CrestronIO; using PepperDash.Core.Intersystem.Serialization; using PepperDash.Core.Intersystem.Tokens; namespace PepperDash.Core.Intersystem { /// /// XSigToken stream writer. /// public sealed class XSigTokenStreamWriter : IDisposable { private readonly Stream _stream; private readonly bool _leaveOpen; /// /// /// XSigToken stream writer constructor. /// /// Input stream to write to. /// Stream is null. /// Stream cannot be written to. public XSigTokenStreamWriter(Stream stream) : this(stream, false) { } /// /// XSigToken stream writer constructor. /// /// Input stream to write to. /// Determines whether to leave the stream open or not. /// Stream is null. /// Stream cannot be written to. public XSigTokenStreamWriter(Stream stream, bool leaveOpen) { if (stream == null) throw new ArgumentNullException("stream"); if (!stream.CanWrite) throw new ArgumentException("The specified stream cannot be written to."); _stream = stream; _leaveOpen = leaveOpen; } /// /// Write XSig data gathered from an IXSigStateResolver to the stream. /// /// IXSigStateResolver object. /// /// WriteXSigData method /// public void WriteXSigData(IXSigSerialization xSigSerialization) { WriteXSigData(xSigSerialization, 0); } /// /// Write XSig data gathered from an IXSigStateResolver to the stream. /// /// IXSigStateResolver object. /// Index offset for each XSigToken. /// /// WriteXSigData method /// public void WriteXSigData(IXSigSerialization xSigSerialization, int offset) { if (xSigSerialization == null) throw new ArgumentNullException("xSigSerialization"); var tokens = xSigSerialization.Serialize(); WriteXSigData(tokens, offset); } /// /// Write XSigToken to the stream. /// /// XSigToken object. /// /// WriteXSigData method /// public void WriteXSigData(XSigToken token) { WriteXSigData(token, 0); } /// /// Write XSigToken to the stream. /// /// XSigToken object. /// Index offset for each XSigToken. /// /// WriteXSigData method /// public void WriteXSigData(XSigToken token, int offset) { WriteXSigData(new[] { token }, offset); } /// /// Writes an array of XSigTokens to the stream. /// /// XSigToken objects. public void WriteXSigData(XSigToken[] tokens) { WriteXSigData(tokens.AsEnumerable()); } /// /// Write an enumerable collection of XSigTokens to the stream. /// /// XSigToken objects. public void WriteXSigData(IEnumerable tokens) { WriteXSigData(tokens, 0); } /// /// Write an enumerable collection of XSigTokens to the stream. /// /// XSigToken objects. /// Index offset for each XSigToken. /// /// WriteXSigData method /// public void WriteXSigData(IEnumerable tokens, int offset) { if (offset < 0) throw new ArgumentOutOfRangeException("offset", "Offset must be greater than or equal to 0."); if (tokens != null) { foreach (var token in tokens) { if (token == null) continue; var bytes = token.GetTokenWithOffset(offset).GetBytes(); _stream.Write(bytes, 0, bytes.Length); } } } /// /// Dispose method /// public void Dispose() { if (!_leaveOpen) _stream.Dispose(); } } } ================================================ FILE: src/PepperDash.Essentials/AssetLoader.cs ================================================ using System; using System.IO; using System.IO.Compression; using System.Linq; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials { /// /// Handles extracting embedded asset bundles and moving configuration files from the /// application directory to the program file-path prefix at startup. /// Implemented using System.IO types so it can run (and be tested) outside /// of a Crestron runtime environment. /// internal static class AssetLoader { /// /// Scans for well-known zip bundles and /// JSON configuration files and deploys them to . /// /// /// The directory to scan (typically the Crestron application root). /// /// /// The program's runtime working directory (e.g. /nvram/program1/). /// internal static void Load(string applicationDirectoryPath, string filePathPrefix) { var applicationDirectory = new DirectoryInfo(applicationDirectoryPath); Debug.LogMessage(LogEventLevel.Information, "Searching: {applicationDirectory:l} for embedded assets - {Destination}", applicationDirectory.FullName, filePathPrefix); ExtractAssetsZip(applicationDirectory, filePathPrefix); ExtractHtmlAssetsZip(applicationDirectory, filePathPrefix); ExtractDevToolsZip(applicationDirectory, filePathPrefix); MoveConfigurationFile(applicationDirectory, filePathPrefix); } // ------------------------------------------------------------------------- // Private helpers // ------------------------------------------------------------------------- private static void ExtractAssetsZip(DirectoryInfo applicationDirectory, string filePathPrefix) { var zipFiles = applicationDirectory.GetFiles("assets*.zip"); if (zipFiles.Length > 1) throw new Exception("Multiple assets zip files found. Cannot continue."); if (zipFiles.Length == 1) { var zipFile = zipFiles[0]; var assetsRoot = Path.GetFullPath(filePathPrefix); if (!assetsRoot.EndsWith(Path.DirectorySeparatorChar.ToString()) && !assetsRoot.EndsWith(Path.AltDirectorySeparatorChar.ToString())) { assetsRoot += Path.DirectorySeparatorChar; } Debug.LogMessage(LogEventLevel.Information, "Found assets zip file: {zipFile:l}... Unzipping...", zipFile.FullName); using (var archive = ZipFile.OpenRead(zipFile.FullName)) { foreach (var entry in archive.Entries) { var destinationPath = Path.Combine(filePathPrefix, entry.FullName); var fullDest = Path.GetFullPath(destinationPath); if (!fullDest.StartsWith(assetsRoot, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException( $"Entry '{entry.FullName}' is trying to extract outside of the target directory."); if (string.IsNullOrEmpty(entry.Name)) { Directory.CreateDirectory(destinationPath); continue; } if (Directory.Exists(destinationPath)) Directory.Delete(destinationPath, recursive: true); Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); entry.ExtractToFile(destinationPath, overwrite: true); Debug.LogMessage(LogEventLevel.Information, "Extracted: {entry:l} to {Destination}", entry.FullName, destinationPath); } } } foreach (var file in zipFiles) File.Delete(file.FullName); } private static void ExtractHtmlAssetsZip(DirectoryInfo applicationDirectory, string filePathPrefix) { var htmlZipFiles = applicationDirectory.GetFiles("htmlassets*.zip"); if (htmlZipFiles.Length > 1) throw new Exception( "Multiple htmlassets zip files found in application directory. " + "Please ensure only one htmlassets*.zip file is present and retry."); if (htmlZipFiles.Length == 1) { var htmlZipFile = htmlZipFiles[0]; var programDir = new DirectoryInfo( filePathPrefix.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); var userOrNvramDir = programDir.Parent; var rootDir = userOrNvramDir?.Parent; if (rootDir == null) throw new Exception( $"Unable to determine root directory for html extraction. Current path: {filePathPrefix}"); var htmlDir = Path.Combine(rootDir.FullName, "html"); var htmlRoot = Path.GetFullPath(htmlDir); if (!htmlRoot.EndsWith(Path.DirectorySeparatorChar.ToString()) && !htmlRoot.EndsWith(Path.AltDirectorySeparatorChar.ToString())) { htmlRoot += Path.DirectorySeparatorChar; } Debug.LogMessage(LogEventLevel.Information, "Found htmlassets zip file: {zipFile:l}... Unzipping...", htmlZipFile.FullName); using (var archive = ZipFile.OpenRead(htmlZipFile.FullName)) { foreach (var entry in archive.Entries) { var destinationPath = Path.Combine(htmlDir, entry.FullName); var fullDest = Path.GetFullPath(destinationPath); if (!fullDest.StartsWith(htmlRoot, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException( $"Entry '{entry.FullName}' is trying to extract outside of the target directory."); if (string.IsNullOrEmpty(entry.Name)) { Directory.CreateDirectory(destinationPath); continue; } if (File.Exists(destinationPath)) File.Delete(destinationPath); var parentDir = Path.GetDirectoryName(destinationPath); if (!string.IsNullOrEmpty(parentDir)) Directory.CreateDirectory(parentDir); entry.ExtractToFile(destinationPath, overwrite: true); Debug.LogMessage(LogEventLevel.Information, "Extracted: {entry:l} to {Destination}", entry.FullName, destinationPath); } } } foreach (var file in htmlZipFiles) File.Delete(file.FullName); } private static void ExtractDevToolsZip(DirectoryInfo applicationDirectory, string filePathPrefix) { var devToolsZipFiles = applicationDirectory.GetFiles("essentials-devtools*.zip"); if (devToolsZipFiles.Length > 1) throw new Exception( "Multiple essentials-devtools zip files found in application directory. " + "Please ensure only one essentials-devtools*.zip file is present and retry."); if (devToolsZipFiles.Length == 1) { var devToolsZipFile = devToolsZipFiles[0]; var programDir = new DirectoryInfo( filePathPrefix.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); var userOrNvramDir = programDir.Parent; var rootDir = userOrNvramDir?.Parent; if (rootDir == null) throw new Exception( $"Unable to determine root directory for debug html extraction. Current path: {filePathPrefix}"); var debugDir = Path.Combine(rootDir.FullName, "html", "debug"); var debugRoot = Path.GetFullPath(debugDir); if (!debugRoot.EndsWith(Path.DirectorySeparatorChar.ToString()) && !debugRoot.EndsWith(Path.AltDirectorySeparatorChar.ToString())) { debugRoot += Path.DirectorySeparatorChar; } Debug.LogMessage(LogEventLevel.Information, "Found essentials-devtools zip file: {zipFile:l}... Unzipping to {Destination}...", devToolsZipFile.FullName, debugDir); using (var archive = ZipFile.OpenRead(devToolsZipFile.FullName)) { foreach (var entry in archive.Entries) { var destinationPath = Path.Combine(debugDir, entry.FullName); var fullDest = Path.GetFullPath(destinationPath); if (!fullDest.StartsWith(debugRoot, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException( $"Entry '{entry.FullName}' is trying to extract outside of the target directory."); if (string.IsNullOrEmpty(entry.Name)) { Directory.CreateDirectory(destinationPath); continue; } if (File.Exists(destinationPath)) File.Delete(destinationPath); var parentDir = Path.GetDirectoryName(destinationPath); if (!string.IsNullOrEmpty(parentDir)) Directory.CreateDirectory(parentDir); entry.ExtractToFile(destinationPath, overwrite: true); Debug.LogMessage(LogEventLevel.Information, "Extracted: {entry:l} to {Destination}", entry.FullName, destinationPath); } } } foreach (var file in devToolsZipFiles) File.Delete(file.FullName); } private static void MoveConfigurationFile(DirectoryInfo applicationDirectory, string filePathPrefix) { var jsonFiles = applicationDirectory.GetFiles("*configurationFile*.json"); if (jsonFiles.Length > 1) { Debug.LogError("Multiple configuration files found in application directory: {@jsonFiles}", jsonFiles.Select(f => f.FullName).ToArray()); throw new Exception("Multiple configuration files found. Cannot continue."); } if (jsonFiles.Length == 1) { var jsonFile = jsonFiles[0]; var finalPath = Path.Combine(filePathPrefix, jsonFile.Name); Debug.LogMessage(LogEventLevel.Information, "Found configuration file: {jsonFile:l}... Moving to: {Destination}", jsonFile.FullName, finalPath); if (File.Exists(finalPath)) { Debug.LogMessage(LogEventLevel.Information, "Removing existing configuration file: {Destination}", finalPath); File.Delete(finalPath); } jsonFile.MoveTo(finalPath); } } } } ================================================ FILE: src/PepperDash.Essentials/ClassDiagram1.cd ================================================  AAAAAQAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAIAgA= Audio\EssentialsVolumeLevelConfig.cs AAAAAAAAEAAAAAAAAAAAAAAAAIAAAAgBAAAAAAAAAAA= Audio\EssentialsVolumeLevelConfig.cs AAAAAAAIAAAAAAAABAAAACAAIAAAAQAAAAAAAAAAEAA= Config\ConfigReader.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAA= Config\DeviceFactory.cs AAAAAAEAAAAAQAIAAAAAAAACAAAAAAAAAAAAAAEAAAA= Config\EssentialsConfig.cs AAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= Config\EssentialsConfig.cs AAAAAAAgEAAAAAAEAAAAAAAAAAAAAAAAAAAAAEAIAIA= Configuration ORIGINAL\ConfigTieLine.cs AEAAAAAAAAAAgQAAAAAAgAAAAAAAAAAAAAAgEDAADAQ= Configuration ORIGINAL\Configuration.cs AAAAAAAAAAAAAAQAAAAAAAQAAACAAAAAAAAAAAAAAAA= Configuration ORIGINAL\Configuration.cs AAAAAAAAAgAAAAAAAEAAAAAAAAAAAAAAAAAgAAAAAAA= Configuration ORIGINAL\Configuration.cs IQAAAAAEAAAAAAADAAACABQAAAAAAAAAAAAAAAAAAAA= Configuration ORIGINAL\Configuration.cs AAAAAAAAAAAAAAAAAEAAAAAAAAAAAIAAAAAgAAAIAAA= Configuration ORIGINAL\ConfigurationHelpers.cs AAAAAAAAAAAQAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAA= Configuration ORIGINAL\Factories\DmFactory.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAEDAAKAA= Configuration ORIGINAL\Factories\FactoryHelper.cs AAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAABAAAA= Configuration ORIGINAL\Factories\FactoryHelper.cs AAoAgAAIAEAACAAEAIEIBICAAAAAAABAAAAAAAAAAAA= ControlSystem.cs AAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA= Devices\Amplifier.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAA= Room\Cotija\CotijaConfig.cs AAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAA= Room\Cotija\CotijaConfig.cs CAAABAABAgACCAKGBIAAEyBAFAAACYSAgIAAAAJkAAA= Room\Cotija\CotijaSystemController.cs AAQIQAAAAAAAAgAAAAAAQAAAAAAAAAAAAAAAABAAAAA= Room\Cotija\RoomBridges\CotijaBridgeBase.cs AAAIAAAAIABAAkgAABgIAAAAAAAAAEAAAAAAgBAAACA= Room\Cotija\RoomBridges\CotijaEssentialsHuddleSpaceRoomBridge.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAA= Room\Cotija\RoomBridges\CotijaEssentialsHuddleSpaceRoomBridge.cs iQFBQAIAAgAAgQAEQACAMABAAABAACAQUAAQAAgCgBA= Room\Types\EssentialsHuddleSpaceRoom.cs iQFBQAIAIgQMgQAEQAigMABAAABAADIwUACQAAgCgTE= Room\Types\EssentialsHuddleVtc1Room.cs iQAEAAIACkAAAQAOQASgMAAJAABgAAAQQAAQAAgCgBA= Room\Types\EssentialsPresentationRoom.cs gQAAEAICECgCAQAEAAAUIwIyAAAAgACiAgAAAQECAgA= Room\Types\EssentialsRoomBase.cs AICCIAAIGIAAAAAgCAAIAEAAAAAAAAAAAAEAIAAAAAA= UI\CrestronTouchpanelPropertiesConfig.cs AAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= UI\CrestronTouchpanelPropertiesConfig.cs AAAIAEAAAAAAAAAAAAAAAAEAAAAACKIBAAgACAAAAAA= UI\EssentialsTouchpanelController.cs AAAAQAAAACAAAAABAAAAAAAAAABAAAAAAAAAAkAAAAA= UI\HttpLogoServer.cs j+jWCNqEIGzi4UTaTgyn37kpncQJK7L42VMLmMgTE5A= UI\JoinConstants\UIBoolJoin.cs BAggBIABCQAAGAAQAAAACAACAAAAAAAAAAIAAAAAAAA= UI\JoinConstants\UISmartObjectJoin.cs BkBgIAgAAggOQAFGAYQIABACgCEBjkSQAUEAASIABCE= UI\JoinConstants\UIStringlJoin.cs AAQAAAACAAAACAEAAIAAAAAAIABAIAAAABAAAEAAAAA= UI\JoinConstants\UIUshortJoin.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA= UI\SubpageReferenceListActivityItem.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA= UI\SubpageReferenceListCallStagingItem.cs AAAABAAAAAAAAAAAAAAAAAAAAgAAAAACAAAAAABgAAA= UI\SubpageReferenceListSourceItem.cs CAAIkAAAAAAQEAAAEAACAAAAAIAEABAAAgAACAAAAAA= UIDrivers\enums and base.cs ABAAAAAAAhgAAAAAEAAAAAAAAIAEAAAAAAAAAAAAAAA= UIDrivers\Essentials\EssentialsPanelMainInterfaceDriver.cs gTEAIIAiCggFNCQ4EA4AWBkAKJCEqAAOS4CKMAQQJQA= UIDrivers\Essentials\EssentialsPresentationPanelAvFunctionsDriver.cs gRQAIICuAghENHQpEA4IWCkBMJDEsEAEC4CAMARQIBA= UIDrivers\EssentialsHuddle\EssentialsHuddlePanelAvFunctionsDriver.cs GRwAIYC+oghAeHStEDAIWCdBMADEsBAcDwCAMARYIBg= UIDrivers\EssentialsHuddleVTC\EssentialsHuddleVtc1PanelAvFunctionsDriver.cs AAAQgAIAAAAAAAAAEAAAAAQAAAAEAAAAAAAAEAAAgAA= UIDrivers\JoinedSigInterlock.cs AAAAAAAAAAAAAAAAEAAAQAAABIAEAAAAAAAAAAAAAAA= UIDrivers\Page Drivers\SingleSubpageModalAndBackDriver.cs AAAAAAAAAAAAAAAAEAAAAAAABAAEAAAAAAAAAAAAAAA= UIDrivers\Page Drivers\SingleSubpageModalDriver.cs AAAQAAIAAAAAAAAIEAAAAAAAAAAEAAAAAAAAEAAAgAA= UIDrivers\SigInterlock.cs AAAAAAAACAAACBAAAAAAAAAAAAAAAAAAAAIAAAAAAQA= UIDrivers\SmartObjectRoomsList.cs AAAAQAAAAAAAAAAAABAAQAAAAAAAAAACAAEAAAAAAAA= UIDrivers\SmartObjectRoomsList.cs AAAAAAABAAAAAEAAAAAAAAAAAAAAAAAAAQAAAAAAAAA= UIDrivers\VolumeAndSourceChangeArgs.cs IAGigRBpCgZwAIMSBBIbIgAAImAPtEBiAAgECpJgKQo= OTHER\Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs AAAAAACgAIQAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAA= OTHER\Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs AAAAAAAAAAAAAAAAAAAAAAAAAQAAACAAAAAAAAAAAAA= OTHER\Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs AACAAAAAAgAAAIAAAAAAAAAgIBAQAAAAAAAAAAAAAQA= OTHER\Fusion\EssentialsHuddleVtc1FusionController.cs AAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionEventHandlers.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAA= OTHER\Fusion\FusionEventHandlers.cs AAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionProcessorQueries.cs AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAEAAAA= OTHER\Fusion\FusionProcessorQueries.cs AAICAAAAAAAAAAAAAAAAAACAAAATQAAAAAAAABAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAAAAQAQAAAAAAAAQAAAAAAQAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAAAAQAQAAAAAAAAQAAAAAAQAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAACACAAAAQAAAAAAAAAAAAAAAAAAAACAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAACAAAgAAQAAAAAAAAAAAAAAAAAAIAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAgAAQAAAAAAAAAAAAAAAAAAIAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAgAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAACAAAAAAQAAAAAAAAAAgAAAAAAAAAAABAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AABCAAAAYEAAEBIBAIAAJAQAQKAYAAAIEAAAEAACCgg= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAgAAAAAAAAAQAAAAAAAAAAAAAAAAEAAA= OTHER\Fusion\FusionRviDataClasses.cs AAABAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAgAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAgAQAAIAAAAAAACAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA= OTHER\Fusion\FusionRviDataClasses.cs AAAAAAAAAAAAAAAAAAAAAIAgAAQAAAAAAAAEAAAAAAA= Room\Config\DDVC01RoomPropertiesConfig.cs AAAAAAAAAAAAAAAAAEAAAAQAAAAAAAAAAAAAAAAAAAA= Room\Config\DDVC01RoomPropertiesConfig.cs AAAAAAAAAAAAgAAAAAAAAAAACAAAAAABAAAAAAAAABA= Room\Config\EssentialsHuddleRoomPropertiesConfig.cs AAAAAAAAAAAAgAAAAAAAAAAACIAAAAABAAAAAAAAABA= Room\Config\EssentialsHuddleVtc1PropertiesConfig.cs AAAAAAACAIAAAAAAAAAAABAACAAAAAABAAAAAAAAABA= Room\Config\EssentialsPresentationPropertiesConfig.cs AAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAEAAAAAA= Room\Config\EssentialsRoomConfig.cs AABAEQAAAAEoAAEEAAQAAAACAAAAAAgggAAAAQAAAgA= Room\Config\EssentialsRoomConfig.cs AAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= Room\Config\EssentialsRoomConfig.cs AAAAAAAAAAEAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA= Room\Config\EssentialsRoomConfig.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAgABAAAAAIAAAAAA= Room\Config\EssentialsRoomConfig.cs AAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAA= Room\Config\EssentialsRoomConfig.cs AAAAAAAAAAAAAAAAAAAAQAAAgAAAAAAAAAAAAAAAAAA= Room\Config\EssentialsRoomConfig.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIACQAAAAAAAAA= Room\Config\EssentialsRoomConfig.cs AACAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAA= Room\Config\EssentialsRoomConfig.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAA= Room\Config\EssentialsRoomConfig.cs AAAAAAAAAAAAABAACAAAAAAAAAAAAAAAAAAAAAAAAAA= Room\Config\EssentialsRoomEmergencyConfig.cs AAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAABQAAAAAAAAA= Room\Config\EssentialsRoomEmergencyConfig.cs AUAAAAgAAAACwAYAAAAAAAEAAAAAAAAAIcAAAEAAAAA= Room\Cotija\CotijaDdvc01DeviceBridge.cs AAACAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= Room\Cotija\DeviceTypeInterfaces\IChannelExtensions.cs AAACAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= Room\Cotija\DeviceTypeInterfaces\IColorExtensions.cs AAACAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= Room\Cotija\DeviceTypeInterfaces\IDPadExtensions.cs AAACAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= Room\Cotija\DeviceTypeInterfaces\IDvrExtensions.cs AAACAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= Room\Cotija\DeviceTypeInterfaces\INumericExtensions.cs AAACAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= Room\Cotija\DeviceTypeInterfaces\IPowerExtensions.cs AAACAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= Room\Cotija\DeviceTypeInterfaces\ISetTopBoxControlsExtensions.cs AAACAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= Room\Cotija\DeviceTypeInterfaces\ITransportExtensions.cs gACIAAAAAAICAFAAAACAAAEIIAAAAAQAQAAAABAAAAA= Room\Cotija\RoomBridges\CotijaDdvc01RoomBridge.cs AAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAA= Room\Emergency\EsentialsRoomEmergencyContactClosure.cs AAAAAAAAAAAAAAAASBAAAAAAAAAAAAAABAAAAAAAEAA= Room\Emergency\EsentialsRoomEmergencyContactClosure.cs AAAQAAAAAiACDAAAGCAACgAIAABECBAgQAAAAQAAAAA= UIDrivers\EssentialsHuddle\EssentialsHuddleTechPageDriver.cs XAASAoAiAagwAcBAGAUURWQEOHQFAKCmAABCNSSEDPA= UIDrivers\VC\EssentialsVideoCodecUiDriver.cs AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= Room\Types\EssentialsRoomBase.cs AAgAAAAAAAAACBAAACAAAAIBAAAEAAAEAgAAAAAAIAA= UIDrivers\EssentialsHuddleVTC\EssentialsHuddleVtc1PanelAvFunctionsDriver.cs AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAA= Room\Cotija\Interfaces.cs AAAAAAAAQAAAAAAACAAAAAAAAAAAAAAAAAAAAAEACAA= Room\Types\EssentialsRoomBase.cs AAAAAAAAACAAAAAAAAAAAAAAAAACAAAAAAAAAAEAAAA= Room\Types\EssentialsRoomBase.cs AAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAIEAAAA= Room\Types\EssentialsRoomBase.cs AIAAAAAAAAAAAAAAAhBAAAAAAAAAAACYAAAAAAAAAAA= UIDrivers\enums and base.cs AAAAAAAAAAAAABAAAAAAAAAAAAAAACAAAEAAAAAAAAA= UIDrivers\enums and base.cs AAAAAAAEAAAAAAAAAIAAAAAAAAQAAAAQAAAAAAAAAAA= UIDrivers\enums and base.cs AAAAABAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAA= UIDrivers\enums and base.cs AAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= UIDrivers\enums and base.cs AAAAgCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= UIDrivers\VolumeAndSourceChangeArgs.cs AAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= Room\Cotija\RoomBridges\CotijaEssentialsHuddleSpaceRoomBridge.cs AAAAAAAAAAAAACAAACAAAAAAAAAAAAAAAAAAACAAAAA= UIDrivers\VolumeAndSourceChangeArgs.cs ================================================ FILE: src/PepperDash.Essentials/ControlSystem.cs ================================================ using System; using System.Linq; using System.Reflection; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.CrestronThread; using Crestron.SimplSharpPro.Diagnostics; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Web; using Serilog.Events; namespace PepperDash.Essentials { /// /// Main control system class that inherits from CrestronControlSystem and manages program lifecycle /// public class ControlSystem : CrestronControlSystem, ILoadConfig { HttpLogoServer LogoServer; private CTimer _startTimer; private CEvent _initializeEvent; private const long StartupTime = 500; // private const string minimumFirmwareVersion = "2.8006.00110"; /// /// Initializes a new instance of the ControlSystem class /// public ControlSystem() : base() { Thread.MaxNumberOfUserThreads = 400; Global.ControlSystem = this; DeviceManager.Initialize(this); SecretsManager.Initialize(); SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true; } /// /// InitializeSystem method /// /// public override void InitializeSystem() { // Get FW version and stop if it's too low to run this version of Essentials. Must be greater than v2.8006.00110 // var fwVersion = InitialParametersClass.FirmwareVersion; // Debug.LogInformation("Control System Hardware Version: {fwVersion}", fwVersion); // // split the version into parts and compare against minimumFirmwareVersion // var versionParts = fwVersion.Split('.').Select(int.Parse).ToArray(); // var minParts = minimumFirmwareVersion.Split('.').Select(int.Parse).ToArray(); // if (versionParts.Length < minParts.Length // || versionParts[0] < minParts[0] // || (versionParts[0] == minParts[0] && versionParts[1] < minParts[1]) // || (versionParts[0] == minParts[0] && versionParts[1] == minParts[1] && versionParts[2] <= minParts[2])) // { // Debug.LogFatal("Firmware version {fwVersion} is too low to run this version of Essentials. Please upgrade to greater than v{minimumFirmwareVersion}.", fwVersion, minimumFirmwareVersion); // return; // } // If the control system is a DMPS type, we need to wait to exit this method until all devices have had time to activate // to allow any HD-BaseT DM endpoints to register first. bool preventInitializationComplete = Global.ControlSystemIsDmpsType; if (preventInitializationComplete) { Debug.LogMessage(LogEventLevel.Debug, "******************* InitializeSystem() Entering **********************"); _startTimer = new CTimer(StartSystem, preventInitializationComplete, StartupTime); _initializeEvent = new CEvent(true, false); DeviceManager.AllDevicesRegistered += (o, a) => { _initializeEvent.Set(); }; _initializeEvent.Wait(30000); Debug.LogMessage(LogEventLevel.Debug, "******************* InitializeSystem() Exiting **********************"); SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true; } else { _startTimer = new CTimer(StartSystem, preventInitializationComplete, StartupTime); } } private void StartSystem(object preventInitialization) { DeterminePlatform(); if (Debug.DoNotLoadConfigOnNextBoot) { CrestronConsole.AddNewConsoleCommand(s => CrestronInvoke.BeginInvoke((o) => GoWithLoad()), "go", "Loads configuration file", ConsoleAccessLevelEnum.AccessOperator); } CrestronConsole.AddNewConsoleCommand(PluginLoader.ReportAssemblyVersions, "reportversions", "Reports the versions of the loaded assemblies", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(Core.DeviceFactory.GetDeviceFactoryTypes, "gettypes", "Gets the device types that can be built. Accepts a filter string.", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(BridgeHelper.PrintJoinMap, "getjoinmap", "map(s) for bridge or device on bridge [brKey [devKey]]", 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.LogMessage(LogEventLevel.Information, "CONSOLE MESSAGE: {0}", s), "appdebugmessage", "Writes message to log", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(ListTieLines, "listtielines", "Prints out all tie lines. Usage: listtielines [signaltype]", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(VisualizeRoutes, "visualizeroutes", "Visualizes routes by signal type", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(VisualizeCurrentRoutes, "visualizecurrentroutes", "Visualizes current active routes from DefaultCollection", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(s => { CrestronConsole.ConsoleCommandResponse ("Current running configuration. This is the merged system and template configuration" + CrestronEnvironment.NewLine); CrestronConsole.ConsoleCommandResponse(Newtonsoft.Json.JsonConvert.SerializeObject (ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented).Replace(Environment.NewLine, "\r\n")); }, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand( PrintPortalInfo, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(DeviceManager.GetRoutingPorts, "getroutingports", "Reports all routing ports, if any. Requires a device key", ConsoleAccessLevelEnum.AccessOperator); DeviceManager.AddDevice(new EssentialsWebApi("essentialsWebApi", "Essentials Web API")); if (!Debug.DoNotLoadConfigOnNextBoot) { GoWithLoad(); return; } if (!(bool)preventInitialization) { SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true; } } private void PrintPortalInfo(string args) { if(ConfigReader.ConfigObject == null) { CrestronConsole.ConsoleCommandResponse("No configuration loaded. Cannot show portal URLs."); return; } if (string.IsNullOrEmpty(ConfigReader.ConfigObject.SystemUrl) && string.IsNullOrEmpty(ConfigReader.ConfigObject.TemplateUrl)) { CrestronConsole.ConsoleCommandResponse("No portal URLs defined in config."); return; } CrestronConsole.ConsoleCommandResponse( "This system can be found at the following URLs:{2}" + "System URL: {0}{2}" + "Template URL: {1}{2}", ConfigReader.ConfigObject?.SystemUrl, ConfigReader.ConfigObject?.TemplateUrl, CrestronEnvironment.NewLine); } /// /// DeterminePlatform method /// public void DeterminePlatform() { try { Debug.LogMessage(LogEventLevel.Information, "Determining Platform..."); string filePathPrefix; var dirSeparator = Global.DirectorySeparator; string directoryPrefix; directoryPrefix = Directory.GetApplicationRootDirectory(); Global.SetAssemblyVersion(PluginLoader.GetAssemblyVersion(Assembly.GetExecutingAssembly())); if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows CE OS { string userFolder; string nvramFolder; bool is4series = false; if (eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4)) // Handle 4-series { is4series = true; // Set path to user/ userFolder = "user"; nvramFolder = "nvram"; } else { userFolder = "User"; nvramFolder = "Nvram"; } Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{version:l} on {processorSeries:l} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series"); //Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{0} on {1} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series"); // Check if User/ProgramX exists if (Directory.Exists(Global.ApplicationDirectoryPathPrefix + dirSeparator + userFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber))) { Debug.LogMessage(LogEventLevel.Information, "{userFolder:l}/program{applicationNumber} directory found", userFolder, InitialParametersClass.ApplicationNumber); filePathPrefix = directoryPrefix + dirSeparator + userFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; } // Check if Nvram/Programx exists else if (Directory.Exists(directoryPrefix + dirSeparator + nvramFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber))) { Debug.LogMessage(LogEventLevel.Information, "{nvramFolder:l}/program{applicationNumber} directory found", nvramFolder, InitialParametersClass.ApplicationNumber); filePathPrefix = directoryPrefix + dirSeparator + nvramFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; } // If neither exists, set path to User/ProgramX else { Debug.LogMessage(LogEventLevel.Information, "{userFolder:l}/program{applicationNumber} directory found", userFolder, InitialParametersClass.ApplicationNumber); filePathPrefix = directoryPrefix + dirSeparator + userFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; } } else // Handles Linux OS (Virtual Control) { //Debug.SetDebugLevel(2); Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{version:l} on Virtual Control Server", Global.AssemblyVersion); // Set path to User/ filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator; } Global.SetFilePathPrefix(filePathPrefix); } catch (Exception e) { Debug.LogMessage(e, "Unable to determine platform due to exception"); } } /// /// GoWithLoad method /// public void GoWithLoad() { try { Debug.SetDoNotLoadConfigOnNextBoot(false); PluginLoader.AddProgramAssemblies(); _ = new Core.DeviceFactory(); LoadAssets(Global.ApplicationDirectoryPathPrefix, Global.FilePathPrefix); Debug.LogMessage(LogEventLevel.Information, "Starting Essentials load from configuration"); var filesReady = SetupFilesystem(); if (filesReady) { Debug.LogMessage(LogEventLevel.Information, "Checking for plugins"); PluginLoader.LoadPlugins(); Debug.LogMessage(LogEventLevel.Information, "Folder structure verified. Loading config..."); if (!ConfigReader.LoadConfig2() || ConfigReader.ConfigObject == null) { Debug.LogMessage(LogEventLevel.Warning, "Unable to load config file."); } Load(); Debug.LogMessage(LogEventLevel.Information, "Essentials load complete"); } else { Debug.LogMessage(LogEventLevel.Information, @"---------------------------------------------- ------------------------------------------------ ------------------------------------------------ Essentials file structure setup completed. Please load config, sgd and ir files and restart program. ------------------------------------------------ ------------------------------------------------ ------------------------------------------------"); } } catch (Exception e) { Debug.LogMessage(e, "FATAL INITIALIZE ERROR. System is in an inconsistent state"); } finally { // Notify the OS that the program intitialization has completed SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true; } } /// /// Verifies filesystem is set up. IR, SGD, and programX folders /// bool SetupFilesystem() { Debug.LogMessage(LogEventLevel.Information, "Verifying and/or creating folder structure"); var configDir = Global.FilePathPrefix; Debug.LogMessage(LogEventLevel.Information, "FilePathPrefix: {filePathPrefix:l}", configDir); var configExists = Directory.Exists(configDir); if (!configExists) Directory.Create(configDir); var irDir = Global.FilePathPrefix + "ir"; if (!Directory.Exists(irDir)) Directory.Create(irDir); var sgdDir = Global.FilePathPrefix + "sgd"; if (!Directory.Exists(sgdDir)) Directory.Create(sgdDir); var pluginDir = Global.FilePathPrefix + "plugins"; if (!Directory.Exists(pluginDir)) Directory.Create(pluginDir); var joinmapDir = Global.FilePathPrefix + "joinmaps"; if (!Directory.Exists(joinmapDir)) Directory.Create(joinmapDir); return configExists; } /// /// TearDown method /// public void TearDown() { Debug.LogMessage(LogEventLevel.Information, "Tearing down existing system"); DeviceManager.DeactivateAll(); TieLineCollection.Default.Clear(); foreach (var key in DeviceManager.GetDevices()) DeviceManager.RemoveDevice(key); Debug.LogMessage(LogEventLevel.Information, "Tear down COMPLETE"); } /// /// /// void Load() { LoadDevices(); LoadRooms(); LoadLogoServer(); DeviceManager.ActivateAll(); LoadTieLines(); /*var mobileControl = GetMobileControlDevice(); if (mobileControl == null) return; mobileControl.LinkSystemMonitorToAppServer();*/ } /// /// LoadDevices method /// public void LoadDevices() { // Build the processor wrapper class DeviceManager.AddDevice(new Core.Devices.CrestronProcessor("processor")); DeviceManager.AddDevice(new RoutingFeedbackManager($"routingFeedbackManager", "Routing Feedback Manager")); // Add global System Monitor device if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) { DeviceManager.AddDevice( new Core.Monitoring.SystemMonitorController("systemMonitor")); } if (ConfigReader.ConfigObject is null) { Debug.LogMessage(LogEventLevel.Warning, "LoadDevices: ConfigObject is null. Cannot load devices."); return; } foreach (var devConf in ConfigReader.ConfigObject.Devices) { IKeyed newDev = null; try { Debug.LogMessage(LogEventLevel.Information, "Creating device '{deviceKey:l}', type '{deviceType:l}'", devConf.Key, devConf.Type); // Skip this to prevent unnecessary warnings if (devConf.Key == "processor") { var prompt = Global.ControlSystem.ControllerPrompt; var typeMatch = string.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) || string.Equals(devConf.Type, prompt.Replace("-", ""), StringComparison.OrdinalIgnoreCase); if (!typeMatch) Debug.LogMessage(LogEventLevel.Information, "WARNING: Config file defines processor type as '{deviceType:l}' but actual processor is '{processorType:l}'! Some ports may not be available", devConf.Type.ToUpper(), Global.ControlSystem.ControllerPrompt.ToUpper()); continue; } if (newDev == null) newDev = Core.DeviceFactory.GetDevice(devConf); if (newDev != null) DeviceManager.AddDevice(newDev); else Debug.LogMessage(LogEventLevel.Information, "ERROR: Cannot load unknown device type '{deviceType:l}', key '{deviceKey:l}'.", devConf.Type, devConf.Key); } catch (Exception e) { Debug.LogMessage(e, "ERROR: Creating device {deviceKey:l}. Skipping device.", args: new[] { devConf.Key }); } } Debug.LogMessage(LogEventLevel.Information, "All Devices Loaded."); } /// /// LoadTieLines method /// public void LoadTieLines() { // In the future, we can't necessarily just clear here because devices // might be making their own internal sources/tie lines var tlc = TieLineCollection.Default; if (ConfigReader.ConfigObject?.TieLines == null) { return; } foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines) { var newTL = tieLineConfig.GetTieLine(); if (newTL != null) tlc.Add(newTL); } Debug.LogMessage(LogEventLevel.Information, "All Tie Lines Loaded."); Extensions.MapDestinationsToSources(); Debug.LogMessage(LogEventLevel.Information, "All Routes Mapped."); } /// /// Visualizes routes in a tree format for better understanding of signal paths /// private void ListTieLines(string args) { try { if (!string.IsNullOrEmpty(args) && args.Contains("?")) { CrestronConsole.ConsoleCommandResponse("Usage: listtielines [signaltype]\r\n"); CrestronConsole.ConsoleCommandResponse("Signal types: Audio, Video, SecondaryAudio, AudioVideo, UsbInput, UsbOutput\r\n"); return; } eRoutingSignalType? signalTypeFilter = null; if (!string.IsNullOrEmpty(args)) { eRoutingSignalType parsedType; if (Enum.TryParse(args.Trim(), true, out parsedType)) { signalTypeFilter = parsedType; } else { CrestronConsole.ConsoleCommandResponse("Invalid signal type: {0}\r\n", args.Trim()); CrestronConsole.ConsoleCommandResponse("Valid types: Audio, Video, SecondaryAudio, AudioVideo, UsbInput, UsbOutput\r\n"); return; } } var tielines = signalTypeFilter.HasValue ? TieLineCollection.Default.Where(tl => tl.Type.HasFlag(signalTypeFilter.Value)) : TieLineCollection.Default; var count = 0; foreach (var tl in tielines) { CrestronConsole.ConsoleCommandResponse(" {0}{1}", tl, CrestronEnvironment.NewLine); count++; } CrestronConsole.ConsoleCommandResponse("\r\nTotal: {0} tieline{1}{2}", count, count == 1 ? "" : "s", CrestronEnvironment.NewLine); } catch (Exception ex) { CrestronConsole.ConsoleCommandResponse("Error listing tielines: {0}\r\n", ex.Message); } } private void VisualizeRoutes(string args) { try { if (!string.IsNullOrEmpty(args) && args.Contains("?")) { CrestronConsole.ConsoleCommandResponse("Usage: visualizeroutes [signaltype] [-s source] [-d destination]\r\n"); CrestronConsole.ConsoleCommandResponse(" signaltype: Audio, Video, AudioVideo, etc.\r\n"); CrestronConsole.ConsoleCommandResponse(" -s: Filter by source key (partial match)\r\n"); CrestronConsole.ConsoleCommandResponse(" -d: Filter by destination key (partial match)\r\n"); return; } ParseRouteFilters(args, out eRoutingSignalType? signalTypeFilter, out string sourceFilter, out string destFilter); CrestronConsole.ConsoleCommandResponse("\r\n+===========================================================================+\r\n"); CrestronConsole.ConsoleCommandResponse("| ROUTE VISUALIZATION |\r\n"); CrestronConsole.ConsoleCommandResponse("+===========================================================================+\r\n\r\n"); foreach (var descriptorCollection in Extensions.RouteDescriptors.Where(kv => kv.Value.Descriptors.Count() > 0)) { // Filter by signal type if specified if (signalTypeFilter.HasValue && descriptorCollection.Key != signalTypeFilter.Value) continue; CrestronConsole.ConsoleCommandResponse("\r\n+--- Signal Type: {0} ({1} routes) ---\r\n", descriptorCollection.Key, descriptorCollection.Value.Descriptors.Count()); foreach (var descriptor in descriptorCollection.Value.Descriptors) { // Filter by source/dest if specified if (sourceFilter != null && !descriptor.Source.Key.ToLower().Contains(sourceFilter)) continue; if (destFilter != null && !descriptor.Destination.Key.ToLower().Contains(destFilter)) continue; VisualizeRouteDescriptor(descriptor); } } CrestronConsole.ConsoleCommandResponse("\r\n"); } catch (Exception ex) { CrestronConsole.ConsoleCommandResponse("Error visualizing routes: {0}\r\n", ex.Message); } } private void VisualizeCurrentRoutes(string args) { try { if (!string.IsNullOrEmpty(args) && args.Contains("?")) { CrestronConsole.ConsoleCommandResponse("Usage: visualizecurrentroutes [signaltype] [-s source] [-d destination]\r\n"); CrestronConsole.ConsoleCommandResponse(" signaltype: Audio, Video, AudioVideo, etc.\r\n"); CrestronConsole.ConsoleCommandResponse(" -s: Filter by source key (partial match)\r\n"); CrestronConsole.ConsoleCommandResponse(" -d: Filter by destination key (partial match)\r\n"); return; } ParseRouteFilters(args, out eRoutingSignalType? signalTypeFilter, out string sourceFilter, out string destFilter); CrestronConsole.ConsoleCommandResponse("\r\n+===========================================================================+\r\n"); CrestronConsole.ConsoleCommandResponse("| CURRENT ROUTES VISUALIZATION |\r\n"); CrestronConsole.ConsoleCommandResponse("+===========================================================================+\r\n\r\n"); var hasRoutes = false; // Get all descriptors from DefaultCollection var allDescriptors = RouteDescriptorCollection.DefaultCollection.Descriptors; // Group by signal type var groupedByType = allDescriptors.GroupBy(d => d.SignalType); foreach (var group in groupedByType) { var signalType = group.Key; // Filter by signal type if specified if (signalTypeFilter.HasValue && signalType != signalTypeFilter.Value) continue; var filteredDescriptors = group.Where(d => { if (sourceFilter != null && !d.Source.Key.ToLower().Contains(sourceFilter)) return false; if (destFilter != null && !d.Destination.Key.ToLower().Contains(destFilter)) return false; return true; }).ToList(); if (filteredDescriptors.Count == 0) continue; hasRoutes = true; CrestronConsole.ConsoleCommandResponse("\r\n+--- Signal Type: {0} ({1} routes) ---\r\n", signalType, filteredDescriptors.Count); foreach (var descriptor in filteredDescriptors) { VisualizeRouteDescriptor(descriptor); } } if (!hasRoutes) { CrestronConsole.ConsoleCommandResponse("\r\nNo active routes found in current state.\r\n"); } CrestronConsole.ConsoleCommandResponse("\r\n"); } catch (Exception ex) { CrestronConsole.ConsoleCommandResponse("Error visualizing current state: {0}\r\n", ex.Message); } } /// /// Parses route filter arguments from command line /// /// Command line arguments /// Parsed signal type filter (if any) /// Parsed source filter (if any) /// Parsed destination filter (if any) private void ParseRouteFilters(string args, out eRoutingSignalType? signalTypeFilter, out string sourceFilter, out string destFilter) { signalTypeFilter = null; sourceFilter = null; destFilter = null; if (string.IsNullOrEmpty(args)) return; var parts = args.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < parts.Length; i++) { var part = parts[i]; // Check for flags if (part == "-s" && i + 1 < parts.Length) { sourceFilter = parts[++i].ToLower(); } else if (part == "-d" && i + 1 < parts.Length) { destFilter = parts[++i].ToLower(); } // Try to parse as signal type if not a flag and no signal type set yet else if (!part.StartsWith("-") && !signalTypeFilter.HasValue) { if (Enum.TryParse(part, true, out eRoutingSignalType parsedType)) { signalTypeFilter = parsedType; } } } } /// /// Visualizes a single route descriptor in a tree format /// private void VisualizeRouteDescriptor(RouteDescriptor descriptor) { CrestronConsole.ConsoleCommandResponse("|\r\n"); CrestronConsole.ConsoleCommandResponse("|-- {0} --> {1}\r\n", descriptor.Source.Key, descriptor.Destination.Key); if (descriptor.Routes == null || descriptor.Routes.Count == 0) { CrestronConsole.ConsoleCommandResponse("| +-- (No switching steps)\r\n"); return; } for (int i = 0; i < descriptor.Routes.Count; i++) { var route = descriptor.Routes[i]; var isLast = i == descriptor.Routes.Count - 1; var prefix = isLast ? "+" : "|"; var continuation = isLast ? " " : "|"; if (route.SwitchingDevice != null) { CrestronConsole.ConsoleCommandResponse("| {0}-- [{1}] {2}\r\n", prefix, route.SwitchingDevice.Key, GetSwitchDescription(route)); // Add visual connection line for non-last items if (!isLast) CrestronConsole.ConsoleCommandResponse("| {0} |\r\n", continuation); } else { CrestronConsole.ConsoleCommandResponse("| {0}-- {1}\r\n", prefix, route.ToString()); } } } /// /// Gets a readable description of the switching operation /// private string GetSwitchDescription(RouteSwitchDescriptor route) { if (route.OutputPort != null && route.InputPort != null) { return string.Format("{0} -> {1}", route.OutputPort.Key, route.InputPort.Key); } else if (route.InputPort != null) { return string.Format("-> {0}", route.InputPort.Key); } else { return "(passthrough)"; } } /// /// LoadRooms method /// public void LoadRooms() { if (ConfigReader.ConfigObject?.Rooms == null) { Debug.LogMessage(LogEventLevel.Information, "Notice: Configuration contains no rooms - Is this intentional? This may be a valid configuration."); return; } foreach (var roomConfig in ConfigReader.ConfigObject.Rooms) { try { var room = Core.DeviceFactory.GetDevice(roomConfig); if (room == null) { Debug.LogWarning("ERROR: Cannot load unknown room type '{roomType:l}', key '{roomKey:l}'.", roomConfig.Type, roomConfig.Key); continue; } DeviceManager.AddDevice(room); } catch (Exception ex) { Debug.LogMessage(ex, "Exception loading room {roomKey}:{roomType}", null, roomConfig.Key, roomConfig.Type); continue; } } Debug.LogMessage(LogEventLevel.Information, "All Rooms Loaded."); } /// /// Fires up a logo server if not already running /// [Obsolete("Logo server is no longer supported and will be removed in a future release.")] void LoadLogoServer() { if (ConfigReader.ConfigObject?.Rooms == null) { Debug.LogMessage(LogEventLevel.Information, "No rooms configured. Bypassing Logo server startup."); return; } if (ConfigReader.ConfigObject?.Rooms == null || !ConfigReader.ConfigObject.Rooms.Any( CheckRoomConfig)) { Debug.LogMessage(LogEventLevel.Information, "No rooms configured to use system Logo server. Bypassing Logo server startup"); return; } try { LogoServer = new HttpLogoServer(8080, Global.DirectorySeparator + "html" + Global.DirectorySeparator + "logo"); } catch (Exception) { Debug.LogMessage(LogEventLevel.Information, "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; try { if (c.Properties["logoDark"] != null) { logoDark = c.Properties["logoDark"].Value("type"); } if (c.Properties["logoLight"] != null) { logoLight = c.Properties["logoLight"].Value("type"); } if (c.Properties["logo"] != null) { logo = c.Properties["logo"].Value("type"); } return ((logoDark != null && logoDark == "system") || (logoLight != null && logoLight == "system") || (logo != null && logo == "system")); } catch { Debug.LogMessage(LogEventLevel.Information, "Unable to find logo information in any room config"); return false; } } internal static void LoadAssets(string applicationDirectoryPath, string filePathPrefix) => AssetLoader.Load(applicationDirectoryPath, filePathPrefix); } } ================================================ FILE: src/PepperDash.Essentials/Example Configuration/EssentialsHuddleSpaceRoom/configurationFile-HuddleSpace-2-Source.json ================================================ { "system": {}, "system_url": "", "template_url": "", "template": { "sourceLists": { "default": { "source-2": { "order": 6, "type": "route", "altIcon": "Blank", "icon": "", "sourceKey": "wePresent-1", "includeInSourceList": true, "volumeControlKey": "$defaultAudio", "routeList": [ { "sourceKey": "wePresent-1", "type": "audioVideo", "destinationKey": "$defaultAll" } ] }, "source-1": { "order": 5, "type": "route", "altIcon": "Blank", "icon": "", "sourceKey": "inRoomPc-1", "includeInSourceList": true, "volumeControlKey": "$defaultAudio", "routeList": [ { "sourceKey": "inRoomPc-1", "type": "audioVideo", "destinationKey": "$defaultAll" } ] }, "roomOff": { "sourceKey": "$off", "type": "off", "routeList": [ { "sourceKey": "$off", "type": "audioVideo", "destinationKey": "$defaultAll" } ] } } }, "devices": [ { "name": "RMC3", "group": "processor", "properties": { "numberOfIrPorts": 2, "numberOfComPorts": 1 }, "supportedSystemTypes": [ "hudType", "presType", "vtType", "custom" ], "type": "rmc3", "supportedConfigModes": [ "compliance", "essentials" ], "supportsCompliance": true, "key": "processor", "uid": 0 }, { "name": "Room PC", "key": "inRoomPc-1", "type": "inRoomPc", "group": "pc", "uid": 8, "properties": { "hasAudio": true, "hasControls": false, "isDefault": true } }, { "name": "Wireless Video", "key": "wePresent-1", "type": "genericSource", "group": "genericSource", "uid": 9, "properties": { "isDefault": false } }, { "name": "Samsung QM Series Display", "key": "display-1", "type": "samsungmdc", "group": "display", "uid": 11, "properties": { "id": "01", "control": { "controlPortDevKey": "processor", "comParams": { "parity": "None", "protocol": "RS232", "baudRate": 9600, "softwareHandshake": "None", "dataBits": 8, "hardwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "method": "com" } } }, { "name": "TSW-760", "key": "tsw760-1", "type": "tsw760", "group": "touchpanel", "uid": 14, "properties": { "control": { "method": "ipid", "ipid": "03", "params": { "deviceReadyResponsePattern": ".*>", "endOfLineString": "\n" } }, "showVolumeGauge": true, "roomListKey": "", "showDate": true, "headerStyle": "Verbose", "sgdFile": "PepperDash Essentials TSW-760.sgd", "showTime": true, "sourcesOverflowCount": 4, "usesSplashPage": false, "defaultRoomKey": "room1" } }, { "name": "iPad", "key": "crestronApp-1", "type": "crestronApp", "group": "touchpanel", "uid": 15, "properties": { "control": { "method": "ipid", "ipid": "04", "params": { "deviceReadyResponsePattern": ".*>", "endOfLineString": "\n" } }, "showVolumeGauge": true, "roomListKey": "", "showDate": false, "headerStyle": "Verbose", "sgdFile": "PepperDash Essentials iPad.sgd", "showTime": false, "sourcesOverflowCount": 5, "projectName": "PepperDash Essentials iPad", "defaultRoomKey": "room1", "usesSplashPage": false } } ], "info": { "processorType": "rmc3", "lastUid": 16, "lastModifiedDate": "2018-02-16T17:54:41.315Z", "systemType": "huddle", "comment": "", "requiredControlSofwareVersion": "" }, "tieLines": [ { "sourceKey": "inRoomPc-1", "sourcePort": "anyVideoOut", "destinationKey": "display-1", "destinationPort": "HdmiIn1", "type": "audioVideo" }, { "sourceKey": "wePresent-1", "sourcePort": "anyOut", "destinationKey": "display-1", "destinationPort": "HdmiIn2", "type": "audioVideo" } ], "rooms": [ { "type": "huddle", "name": "Essentials Huddle 2 Inputs", "key": "room1", "properties": { "defaultDisplayKey": "display-1", "logo": { "type": "system", "url": "" }, "description": "Huddle Space with 2 sources. RMC3 processor. iPad + TSW-560", "defaultSourceItem": "source-1", "hasDsp": false, "helpMessage": "", "sourceListKey": "default", "volumes": { "master": { "level": 40, "deviceKey": "display-1", "label": "Volume" } }, "defaultAudioKey": "display-1", "defaultVideoBehavior": "basic", "tech": { "password": "1234" } } } ] } } ================================================ FILE: src/PepperDash.Essentials/Example Configuration/EssentialsHuddleVtc1Room/configurationFile-mockVideoCodec_din-ap3_-_dm4x1.json ================================================ { "system": { "rooms": [ { "name": "Example Room", "key": "room1", "properties": { "occupancy": { "timeoutMinutes": "60" } } } ], "devices": [ { "key": "hdMd4x14kE-1", "uid": 4, "properties": { "control": { "tcpSshProperties": { "address": "0.0.0.0" } } } }, { "key": "mockCodec-1", "uid": 5, "properties": { "control": { "tcpSshProperties": { "address": "0.0.0.0" } } } } ], "info": { "lastModifiedDate": "2019-02-26T21:08:09.195Z" } }, "system_url": "", "template_url": "", "template": { "rooms": [ { "type": "huddleVtc1", "name": "Essentials DIN-AP3 - DM4x1", "key": "room1", "properties": { "defaultDisplayKey": "display-1", "description": "", "helpMessage": "", "sourceListKey": "default", "defaultVideoBehavior": "basic", "logo": { "type": "system", "url": "" }, "occupancy": { "timeoutMinutes": "60", "deviceKey": "glsOdtCCn-1" }, "defaultSourceItem": "source-1", "videoCodecKey": "mockCodec-1", "hasDsp": false, "volumes": { "master": { "level": 40, "deviceKey": "mockCodec-1", "label": "Volume" } }, "defaultAudioKey": "display-1", "tech": { "password": "1234" } } } ], "devices": [ { "name": "DIN-AP3", "key": "processor", "type": "dinAp3", "group": "processor", "uid": 0, "properties": { } }, { "name": "Room PC", "key": "inRoomPc-1", "type": "inRoomPc", "properties": { "hasAudio": true, "hasControls": false, "isDefault": true }, "group": "pc", "uid": 1 }, { "name": "Laptop", "key": "laptop-1", "type": "laptop", "properties": { "hasAudio": true, "hasControls": false }, "group": "pc", "uid": 2 }, { "name": "Wireless Video", "key": "wePresent-1", "type": "genericSource", "properties": {}, "group": "genericSource", "uid": 3 }, { "name": "HD-MD4x1-4k-E HDMI Switch 1", "key": "hdMd4x14kE-1", "type": "hdMd4x14kE", "properties": { "control": { "params": { "deviceReadyResponsePattern": ".*>", "endOfLineString": "\n" }, "ipid": "10", "method": "ipidTcp", "tcpSshProperties": { "port": 0, "address": "" } }, "parentDeviceKey": "processor", "inputs": { "hdmiIn2": { "disableHdcp": true }, "hdmiIn3": { "disableHdcp": true }, "hdmiIn4": { "disableHdcp": true }, "hdmiIn1": { "disableHdcp": true } } }, "group": "hdMdSwitch", "uid": 4 }, { "name": "Mock Video Codec 1", "key": "mockCodec-1", "type": "mockVc", "properties": { "favorites": [ { "name": "Corporate WebEx", "number": "5555555555" } ] }, "group": "videoCodec", "uid": 5 }, { "name": "Samsung MDC Protocol 1", "key": "display-1", "type": "samsungmdc", "properties": { "id": "01", "control": { "controlPortDevKey": "processor", "controlPortNumber": 1, "method": "com", "comParams": { "protocol": "RS232", "baudRate": 9600, "hardwareHandshake": "None", "softwareHandshake": "None", "dataBits": 8, "parity": "None", "stopBits": 1 } } }, "group": "display", "uid": 6 }, { "name": "Crestron GLS-ODT-C-CN 1", "key": "glsOdtCCn-1", "type": "glsOdtCCn", "properties": { "control": { "method": "cresnet", "cresnetId": "97" } }, "group": "occupancy", "uid": 7 }, { "name": "TSW-760", "key": "tsw760-1", "type": "tsw760", "properties": { "control": { "params": { "deviceReadyResponsePattern": ".*>", "endOfLineString": "\n" }, "ipid": "03", "method": "ipid" }, "showVolumeGauge": true, "sourcesOverflowCount": 4, "showDate": true, "headerStyle": "Verbose", "sgdFile": "PepperDash Essentials TSW-760.sgd", "showTime": true, "roomListKey": "", "usesSplashPage": false, "defaultRoomKey": "room1" }, "group": "touchpanel", "uid": 8 }, { "name": "Crestron XPanel", "key": "crestronApp-1", "type": "crestronApp", "properties": { "control": { "params": { "deviceReadyResponsePattern": ".*>", "endOfLineString": "\n" }, "ipid": "04", "method": "ipid" }, "showVolumeGauge": true, "sourcesOverflowCount": 5, "showDate": true, "headerStyle": "Verbose", "sgdFile": "PepperDash Essentials iPad.sgd", "showTime": true, "roomListKey": "", "projectName": "PepperDash Essentials iPad", "defaultRoomKey": "room1", "usesSplashPage": false }, "group": "touchpanel", "uid": 9 } ], "info": { "comment": "", "lastUid": 10, "lastModifiedDate": "2018-07-02T17:41:06.550Z", "systemType": "huddle", "processorType": "dinAp3", "requiredControlSofwareVersion": "" }, "tieLines": [ { "type": "audioVideo", "sourceKey": "hdMd4x14kE-1", "destinationKey": "mockCodec-1", "destinationPort": "HdmiIn2", "sourcePort": "hdmiOut" }, { "type": "audioVideo", "sourceKey": "mockCodec-1", "destinationKey": "display-1", "destinationPort": "HdmiIn1", "sourcePort": "HdmiOut1" }, { "type": "audioVideo", "sourceKey": "laptop-1", "destinationKey": "hdMd4x14kE-1", "destinationPort": "hdmiIn1", "sourcePort": "anyOut" }, { "type": "audioVideo", "sourceKey": "inRoomPc-1", "destinationKey": "mockCodec-1", "destinationPort": "HdmiIn3", "sourcePort": "anyVideoOut" }, { "type": "audioVideo", "sourceKey": "wePresent-1", "destinationKey": "hdMd4x14kE-1", "destinationPort": "hdmiIn2", "sourcePort": "anyOut" } ], "sourceLists": { "default": { "source-2": { "order": 6, "icon": "", "altIcon": "Blank", "type": "route", "sourceKey": "laptop-1", "includeInSourceList": true, "volumeControlKey": "$defaultAudio", "routeList": [ { "type": "audioVideo", "sourceKey": "laptop-1", "destinationKey": "$defaultAll" } ] }, "source-3": { "order": 7, "icon": "", "altIcon": "Blank", "type": "route", "sourceKey": "wePresent-1", "includeInSourceList": true, "volumeControlKey": "$defaultAudio", "routeList": [ { "type": "audioVideo", "sourceKey": "wePresent-1", "destinationKey": "$defaultAll" } ] }, "source-1": { "order": 5, "icon": "", "altIcon": "Blank", "type": "route", "sourceKey": "inRoomPc-1", "includeInSourceList": true, "volumeControlKey": "$defaultAudio", "routeList": [ { "type": "audioVideo", "sourceKey": "inRoomPc-1", "destinationKey": "$defaultAll" } ] }, "roomOff": { "type": "off", "sourceKey": "$off", "routeList": [ { "type": "audioVideo", "sourceKey": "$off", "destinationKey": "$defaultAll" } ] }, "codecOsd": { "order": 1, "name": "None", "type": "route", "includeInSourceList": true, "sourceKey": "", "routeList": [ { "type": "audioVideo", "sourceKey": "mockCodec-1[osd]", "destinationKey": "$defaultAll" } ] } } } } } ================================================ FILE: src/PepperDash.Essentials/Example Configuration/SIMPLBridging/SIMPLBridgeExample_configurationFile.json ================================================ { "system_url": "", "template": { "info": { "comment": "", "requiredControlSofwareVersion": "", "systemType": "huddle", "lastModifiedDate": "2018-07-09T20:00:47.873Z", "lastUid": 23, "processorType": "rmc3" }, "devices": [ { "key": "processor", "group": "processor", "uid": 0, "supportsCompliance": true, "type": "rmc3", "properties": {}, "name": "RMC3" }, { "key": "comm-1", "uid": 1, "name": "Generic comm 1", "type": "genericComm", "group": "comm", "properties": { "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 9600, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "controlPortDevKey": "processor", "method": "Com" } } }, { "key": "tcp-1", "uid": 2, "name": "Generic TCP 1", "type": "genericComm", "group": "comm", "properties": { "control": { "tcpSshProperties": { "username": "", "autoReconnect": true, "AutoReconnectIntervalMs": 2000, "port": 23, "address": "0.0.0.0", "password": "" }, "method": "Tcpip" } } }, { "key": "ssh-1", "uid": 3, "name": "Generic SSH 1", "type": "genericComm", "group": "comm", "properties": { "control": { "tcpSshProperties": { "username": "crestron", "autoReconnect": true, "AutoReconnectIntervalMs": 2000, "port": 22, "address": "10.11.50.135", "password": "2H3Zu&OvgXp6" }, "method": "Ssh" } } }, { "key": "eisc-1A", "uid": 4, "type": "eiscApi", "group": "api", "properties": { "control": { "tcpSshProperties": { "address": "127.0.0.2", "port": 0 }, "ipId": "1A" }, "devices": [ { "deviceKey": "comm-1", "joinStart": 3001 }, { "deviceKey": "tcp-1", "joinStart": 3011 }, { "deviceKey": "ssh-1", "joinStart": 3021 }, { "deviceKey": "dmMd8x8-1", "joinStart": 1 }, { "deviceKey": "dmTx201C-1", "joinStart": 3051 }, { "deviceKey": "dmRmc4kScalerC-1", "joinStart": 3061 }, { "deviceKey": "dmRmc200C-1", "joinStart": 3071 }, { "deviceKey": "dmRmc100C-1", "joinStart": 3081 }, { "deviceKey": "comm-2", "joinStart": 2501 }, { "deviceKey": "comm-3", "joinStart": 2511 }, { "deviceKey": "comm-4", "joinStart": 2521 }, { "deviceKey": "cec-1", "joinStart": 2531 }, { "deviceKey": "cec-2", "joinStart": 2541 }, { "deviceKey": "cec-3", "joinStart": 2551 }, { "deviceKey": "cec-4", "joinStart": 2561 }, { "deviceKey": "cec-5", "joinStart": 2571 }, { "deviceKey": "cec-6", "joinStart": 2581 }, { "deviceKey": "cec-7", "joinStart": 2591 }, { "deviceKey": "gls-oir-1", "joinStart": 2701 }, { "deviceKey": "gls-odt-1", "joinStart": 2751 }, { "deviceKey": "gls-part-1", "joinStart": 2781 } ] } }, { "key": "dmMd8x8-1", "uid": 5, "name": "DM-MD8x8 Chassis 1", "type": "dmMd8x8", "group": "dmChassis", "properties": { "control": { "method": "ipid", "ipid": "40", "params": { "endOfLineString": "\n", "deviceReadyResponsePattern": ".*>" } }, "volumeControls": {}, "inputSlots": { "1": "dmcHdDsp", "2": "dmcHdDsp", "3": "dmcDvi", "4": "dmcDvi", "5": "dmcC", "6": "dmcCDsp" }, "outputSlots": { "1": "dmcCoHd", "2": "dmcCoHd" }, "inputNames": { "1": "Input 1", "2": "Input 2", "3": "Input 3", "4": "Input 4", "5": "Input 5", "6": "Input 6" }, "parentDeviceKey": "processor", "outputNames": { "1": "Output 1", "2": "Output 2", "3": "Output 3", "4": "Output 4" }, "inputSlotSupportsHdcp2":{ "1": "false", "2": "false", "3": "false", "4": "false", "5": "false", "6": "false" } } }, { "key": "dmTx201C-1", "uid": 6, "name": "DM-TX-201C 1", "type": "dmTx201C", "group": "dmEndpoint", "properties": { "control": { "method": "ipid", "ipid": "45", "params": { "endOfLineString": "\n", "deviceReadyResponsePattern": ".*>" } }, "parentDeviceKey": "dmMd8x8-1", "parentInputNumber": "5" } }, { "key": "dmRmc4kScalerC-1", "uid": 7, "name": "DM-RMC-4K-SCALER-C Out 1", "type": "dmRmc4kScalerC", "group": "dmEndpoint", "properties": { "control": { "method": "ipid", "ipid": "61", "params": { "endOfLineString": "\n", "deviceReadyResponsePattern": ".*>" } }, "parentDeviceKey": "dmMd8x8-1", "parentOutputNumber": "1" } }, { "key": "dmRmc200C-1", "uid": 8, "name": "DM-RMC-200-C Out 2", "type": "dmRmc200C", "group": "dmEndpoint", "properties": { "control": { "method": "ipid", "ipid": "62", "params": { "endOfLineString": "\n", "deviceReadyResponsePattern": ".*>" } }, "parentDeviceKey": "dmMd8x8-1", "parentOutputNumber": "2" } }, { "key": "dmRmc100C-1", "uid": 9, "name": "DM-RMC-100-C Out 3", "type": "dmRmc100C", "group": "dmEndpoint", "properties": { "control": { "method": "ipid", "ipid": "63", "params": { "endOfLineString": "\n", "deviceReadyResponsePattern": ".*>" } }, "parentDeviceKey": "dmMd8x8-1", "parentOutputNumber": "3" } }, { "key": "comm-2", "uid": 10, "name": "Rmc comm 1", "type": "genericComm", "group": "comm", "properties": { "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 9600, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "controlPortDevKey": "dmRmc4kScalerC-1", "method": "Com" } } }, { "key": "comm-3", "uid": 11, "name": "Rmc comm 2", "type": "genericComm", "group": "comm", "properties": { "control": { "comParams": { "hardwareHandshake": "None", "parity": "None", "protocol": "RS232", "baudRate": 9600, "dataBits": 8, "softwareHandshake": "None", "stopBits": 1 }, "controlPortNumber": 1, "controlPortDevKey": "dmRmc200C-1", "method": "Com" } } }, { "key": "cec-1", "uid": 13, "name": "Tx 5 cec 1", "type": "genericComm", "group": "comm", "properties": { "control": { "controlPortName": "HdmiIn", "controlPortDevKey": "dmTx201C-1", "method": "Cec" } } }, { "key": "cec-5", "uid": 17, "name": "Rmc 1 cec 1", "type": "genericComm", "group": "comm", "properties": { "control": { "controlPortName": "HdmiOut", "controlPortDevKey": "dmRmc4kScalerC-1", "method": "Cec" } } }, { "key": "cec-6", "uid": 18, "name": "Dm Chassis In 1 cec 1", "type": "genericComm", "group": "comm", "properties": { "control": { "controlPortName": "inputCard1--hdmiIn", "controlPortDevKey": "dmMd8x8-1", "method": "Cec" } } }, { "key": "cec-7", "uid": 19, "name": "Dm Chassis Out 1 cec 1", "type": "genericComm", "group": "comm", "properties": { "control": { "controlPortName": "outputCard1--hdmiOut1", "controlPortDevKey": "dmMd8x8-1", "method": "Cec" } } }, { "key": "gls-oir-1", "uid": 19, "name": "GLS-OIR-CN 1", "type": "glsoirccn", "group": "occupancy", "properties": { "control": { "cresnetId": "41", "method": "cresnet" } } }, { "key": "gls-odt-1", "uid": 19, "name": "GLS-ODT-CN 1", "type": "glsodtccn", "group": "occupancy", "properties": { "control": { "cresnetId": "42", "method": "cresnet" } } }, { "key": "gls-part-1", "uid": 19, "name": "GLS-PART-CN 1", "type": "glspartcn", "group": "partition", "properties": { "control": { "cresnetId": "90", "method": "cresnet" } } } ], "rooms": [], "sourceLists": {}, "tieLines": [] }, "template_url": "", "system": { } } ================================================ FILE: src/PepperDash.Essentials/Example Configuration/SIMPLBridging/configurationFile-dmps3300c-avRouting.json ================================================ { "system_url": "", "template": { "info": { "comment": "", "requiredControlSofwareVersion": "", "systemType": "huddle", "lastModifiedDate": "2018-07-09T20:00:47.873Z", "lastUid": 23, "processorType": "dmps3300c" }, "devices": [ { "key": "processor", "group": "processor", "uid": 0, "supportsCompliance": true, "type": "dmps3300c", "properties": { }, "name": "DMPS3-300-C" }, { "key": "eisc-A", "uid":4, "type": "eiscApi", "group":"api", "properties": { "control":{ "tcpSshProperties":{ "address":"127.0.0.2", "port":0 }, "ipId":"1A" }, "devices": [ { "deviceKey":"processor-avRouting", "joinStart":1 }, { "deviceKey":"processor-programAudioOutput", "joinStart":3001 }, { "deviceKey":"processor-aux1AudioOutput", "joinStart":3011 }, { "deviceKey":"processor-aux2AudioOutput", "joinStart":3021 } ] } } ], "rooms": [ ], "sourceLists": { }, "tieLines": [ ] }, "template_url": "", "system": { } } ================================================ FILE: src/PepperDash.Essentials/Factory/DeviceFactory.cs ================================================  using System; using System.Linq; using System.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials { /// /// Responsible for loading all of the device types for this library /// public class DeviceFactory { /// /// Initializes a new instance of the DeviceFactory class and loads all device type factories /// public DeviceFactory() { var assy = Assembly.GetExecutingAssembly(); PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy); var types = assy.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract); if (types != null) { foreach (var type in types) { try { var factory = (IDeviceFactory)Activator.CreateInstance(type); LoadDeviceFactories(factory); } catch (Exception e) { Debug.LogMessage(Serilog.Events.LogEventLevel.Error, "Unable to load type: '{exception}' DeviceFactory: {factoryName}", e, type.Name); } } } } /// /// Loads device factories from the specified plugin device factory and registers them for use. /// /// This method retrieves metadata from the provided , including /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type /// names are converted to lowercase for registration. /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered. private static void LoadDeviceFactories(IDeviceFactory deviceFactory) { foreach (var typeName in deviceFactory.TypeNames) { string description = (deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0) ? descriptionAttribute[0].Description : "No description available"; Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice); } } } } ================================================ FILE: src/PepperDash.Essentials/HttpLogoServer.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.Net.Http; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials { /// /// HTTP server for serving logo images and files /// public class HttpLogoServer { /// /// The HTTP server instance /// readonly HttpServer _server; /// /// The directory containing files to serve /// readonly string _fileDirectory; /// /// Dictionary mapping file extensions to content types /// public static Dictionary ExtensionContentTypes; /// /// Initializes a new instance of the HttpLogoServer class /// /// Port number for the HTTP server /// Directory containing files to serve public HttpLogoServer(int port, string directory) { ExtensionContentTypes = new Dictionary { //{ ".css", "text/css" }, //{ ".htm", "text/html" }, //{ ".html", "text/html" }, { ".jpg", "image/jpeg" }, { ".jpeg", "image/jpeg" }, //{ ".js", "application/javascript" }, //{ ".json", "application/json" }, //{ ".map", "application/x-navimap" }, { ".pdf", "application/pdf" }, { ".png", "image/png" }, //{ ".txt", "text/plain" }, }; _server = new HttpServer {Port = port}; _fileDirectory = directory; _server.OnHttpRequest += Server_OnHttpRequest; _server.Open(); CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; } /// /// Handles incoming HTTP requests and serves files from the configured directory /// /// The HTTP server instance /// HTTP request arguments void Server_OnHttpRequest(object sender, OnHttpRequestArgs args) { var path = args.Request.Path; Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "HTTP Request with path: '{requestPath:l}'", args.Request.Path); try { if (File.Exists(_fileDirectory + path)) { var filePath = path.Replace('/', '\\'); var localPath = string.Format(@"{0}{1}", _fileDirectory, filePath); Debug.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server attempting to find file: '{localPath:l}'", 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.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server Cannot find file '{localPath:l}'", localPath); args.Response.ContentString = string.Format("Not found: '{0}'", filePath); args.Response.Code = 404; } } else { Debug.LogMessage(LogEventLevel.Verbose, "HTTP Logo Server: '{file:l}' does not exist", _fileDirectory + path); args.Response.ContentString = string.Format("Not found: '{0}'", _fileDirectory + path); args.Response.Code = 404; } } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Error, "Exception getting file: {exception}", ex.Message, ex.StackTrace); Debug.LogMessage(LogEventLevel.Verbose, "Stack Trace: {stackTrace}", ex.StackTrace); args.Response.Code = 400; args.Response.ContentString = string.Format("invalid request"); } } /// /// Handles program status events and closes the server when the program is stopping /// /// The program status event type void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) _server.Close(); } /// /// Gets the content type for a file based on its extension /// /// The file extension /// The corresponding content type string /// /// GetContentType method /// public static string GetContentType(string extension) { var type = ExtensionContentTypes.ContainsKey(extension) ? ExtensionContentTypes[extension] : "text/plain"; return type; } } } ================================================ FILE: src/PepperDash.Essentials/PepperDash.Essentials.csproj ================================================  Program Debug;Release;Debug 4.7.2 PepperDash.Essentials PepperDashEssentials net472 true bin\$(Configuration)\ PepperDash Essentials PepperDashEssentials $(Version) false full full pdbonly bin\$(Configuration)\PepperDashEssentials.xml Always Always Always Always Always Always Always ================================================ FILE: src/PepperDash.Essentials/Properties/ControlSystem.cfg ================================================  Test RMC3
auto 192.168.1.40;username crestron
Program01 Internal Flash
================================================ FILE: src/PepperDash.Essentials/Properties/UpdateAssemblyVersion.ps1 ================================================ function Update-SourceVersion { Param ([string]$Version) $fullVersion = $Version $baseVersion = [regex]::Match($Version, "(\d+.\d+.\d+).*").captures.groups[1].value $NewAssemblyVersion = ‘AssemblyVersion("‘ + $baseVersion + ‘.*")’ echo "AssemblyVersion = $NewAssemblyVersion" $NewAssemblyInformationalVersion = ‘AssemblyInformationalVersion("‘ + $Version + ‘")’ echo "AssemblyInformationalVersion = $NewAssemblyInformationalVersion" foreach ($o in $input) { Write-output $o.FullName $TmpFile = $o.FullName + “.tmp” get-content $o.FullName | %{ $_ -replace ‘AssemblyVersion\(".*"\)’, $NewAssemblyVersion} | %{ $_ -replace ‘AssemblyInformationalVersion\(".*"\)’, $NewAssemblyInformationalVersion } > $TmpFile move-item $TmpFile $o.FullName -force } } function Update-AllAssemblyInfoFiles ( $version ) { foreach ($file in “AssemblyInfo.cs”, “AssemblyInfo.vb” ) { get-childitem -recurse |? {$_.Name -eq $file} | Update-SourceVersion $version ; } } # validate arguments $r= [System.Text.RegularExpressions.Regex]::Match($args[0], "\d+\.\d+\.\d+.*"); if ($r.Success) { echo "Updating Assembly Version to $args ..."; Update-AllAssemblyInfoFiles $args[0]; } else { echo ” “; echo “Error: Input version does not match x.y.z format!” echo ” “; echo "Unable to apply version to AssemblyInfo.cs files"; } ================================================ FILE: src/PepperDash.Essentials/SGD/PepperDash Essentials TSW-560.sgd ================================================ [ ObjTp=FSgntr Sgntr=SGD RelVrs=3 VTProeVer=6.1.05 Schema=1 CRCGUID=6C002F1C-3D96-4EBF-A0D9-8A124BE8F48A ] ;================================================================================ [ ObjTp=Hd ProjectFile=PepperDash Essentials TSW-560.vtp VtpGuid=D8D5F125-CB35-42E9-8AE3-4142597FD2C5 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[C.AC] Keypad_AC DTMF Keypad_2.ced Hint=AC DTMF Keypad_2 (Smart Object ID=1101) Code=1 SGControlType=Simple Keypad SGControlName=AC DTMF Keypad_2 GUID=F2A259FE-82AD-4085-B5A6-22D7B034458C SmplCName=PepperDash Essentials TSW-560_[C.AC] Keypad_AC DTMF Keypad_2.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=* OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=/# OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=1 CedH=1 SmartObjId=1101d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=1 Tp=1 HD=TRUE DV=1101d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=1 Name=PepperDash Essentials TSW-560_[C.AC] Keypad_AC DTMF Keypad_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[D.VC] Directory_Dynamic Button List Vertical_2.ced Hint=Dynamic Button List Vertical_2 (Smart Object ID=1202) Code=2 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical_2 GUID=79060F3C-D3A4-4A8D-ACF0-CB2376A31702 SmplCName=PepperDash Essentials TSW-560_[D.VC] Directory_Dynamic Button List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=Item 11 Selected InputSigType22=Digital InputCue23=Item 12 Selected InputSigType23=Digital InputCue24=Item 13 Selected InputSigType24=Digital InputCue25=Item 14 Selected InputSigType25=Digital InputCue26=Item 15 Selected InputSigType26=Digital InputCue27=Item 16 Selected InputSigType27=Digital InputCue28=Item 17 Selected InputSigType28=Digital InputCue29=Item 18 Selected InputSigType29=Digital InputCue30=Item 19 Selected InputSigType30=Digital InputCue31=Item 20 Selected InputSigType31=Digital InputCue32=Item 21 Selected InputSigType32=Digital InputCue33=Item 22 Selected InputSigType33=Digital InputCue34=Item 23 Selected InputSigType34=Digital InputCue35=Item 24 Selected InputSigType35=Digital InputCue36=Item 25 Selected InputSigType36=Digital InputCue37=Item 26 Selected InputSigType37=Digital InputCue38=Item 27 Selected InputSigType38=Digital InputCue39=Item 28 Selected InputSigType39=Digital InputCue40=Item 29 Selected InputSigType40=Digital InputCue41=Item 30 Selected InputSigType41=Digital InputCue42=Item 31 Selected InputSigType42=Digital InputCue43=Item 32 Selected InputSigType43=Digital InputCue44=Item 33 Selected InputSigType44=Digital InputCue45=Item 34 Selected InputSigType45=Digital InputCue46=Item 35 Selected InputSigType46=Digital InputCue47=Item 36 Selected InputSigType47=Digital InputCue48=Item 37 Selected InputSigType48=Digital InputCue49=Item 38 Selected InputSigType49=Digital InputCue50=Item 39 Selected InputSigType50=Digital InputCue51=Item 40 Selected InputSigType51=Digital InputCue52=Item 41 Selected InputSigType52=Digital InputCue53=Item 42 Selected InputSigType53=Digital InputCue54=Item 43 Selected InputSigType54=Digital InputCue55=Item 44 Selected InputSigType55=Digital InputCue56=Item 45 Selected InputSigType56=Digital InputCue57=Item 46 Selected InputSigType57=Digital InputCue58=Item 47 Selected InputSigType58=Digital InputCue59=Item 48 Selected InputSigType59=Digital InputCue60=Item 49 Selected InputSigType60=Digital InputCue61=Item 50 Selected InputSigType61=Digital InputCue62=Item 51 Selected InputSigType62=Digital InputCue63=Item 52 Selected InputSigType63=Digital InputCue64=Item 53 Selected InputSigType64=Digital InputCue65=Item 54 Selected InputSigType65=Digital InputCue66=Item 55 Selected InputSigType66=Digital InputCue67=Item 56 Selected InputSigType67=Digital InputCue68=Item 57 Selected InputSigType68=Digital InputCue69=Item 58 Selected InputSigType69=Digital InputCue70=Item 59 Selected InputSigType70=Digital InputCue71=Item 60 Selected InputSigType71=Digital InputCue72=Item 61 Selected InputSigType72=Digital InputCue73=Item 62 Selected InputSigType73=Digital InputCue74=Item 63 Selected InputSigType74=Digital InputCue75=Item 64 Selected InputSigType75=Digital InputCue76=Item 65 Selected InputSigType76=Digital InputCue77=Item 66 Selected InputSigType77=Digital InputCue78=Item 67 Selected InputSigType78=Digital InputCue79=Item 68 Selected InputSigType79=Digital InputCue80=Item 69 Selected InputSigType80=Digital InputCue81=Item 70 Selected InputSigType81=Digital InputCue82=Item 71 Selected InputSigType82=Digital InputCue83=Item 72 Selected InputSigType83=Digital InputCue84=Item 73 Selected InputSigType84=Digital InputCue85=Item 74 Selected InputSigType85=Digital InputCue86=Item 75 Selected InputSigType86=Digital InputCue87=Item 76 Selected InputSigType87=Digital InputCue88=Item 77 Selected InputSigType88=Digital InputCue89=Item 78 Selected InputSigType89=Digital InputCue90=Item 79 Selected InputSigType90=Digital InputCue91=Item 80 Selected InputSigType91=Digital InputCue92=Item 81 Selected InputSigType92=Digital InputCue93=Item 82 Selected InputSigType93=Digital InputCue94=Item 83 Selected InputSigType94=Digital InputCue95=Item 84 Selected InputSigType95=Digital InputCue96=Item 85 Selected InputSigType96=Digital InputCue97=Item 86 Selected InputSigType97=Digital InputCue98=Item 87 Selected InputSigType98=Digital InputCue99=Item 88 Selected InputSigType99=Digital InputCue100=Item 89 Selected InputSigType100=Digital InputCue101=Item 90 Selected InputSigType101=Digital InputCue102=Item 91 Selected InputSigType102=Digital InputCue103=Item 92 Selected InputSigType103=Digital InputCue104=Item 93 Selected InputSigType104=Digital InputCue105=Item 94 Selected InputSigType105=Digital InputCue106=Item 95 Selected InputSigType106=Digital InputCue107=Item 96 Selected InputSigType107=Digital InputCue108=Item 97 Selected InputSigType108=Digital InputCue109=Item 98 Selected InputSigType109=Digital InputCue110=Item 99 Selected InputSigType110=Digital InputCue111=Item 100 Selected InputSigType111=Digital InputCue112=Item 101 Selected InputSigType112=Digital InputCue113=Item 102 Selected InputSigType113=Digital InputCue114=Item 103 Selected InputSigType114=Digital InputCue115=Item 104 Selected InputSigType115=Digital InputCue116=Item 105 Selected InputSigType116=Digital InputCue117=Item 106 Selected InputSigType117=Digital InputCue118=Item 107 Selected InputSigType118=Digital InputCue119=Item 108 Selected InputSigType119=Digital InputCue120=Item 109 Selected InputSigType120=Digital InputCue121=Item 110 Selected InputSigType121=Digital InputCue122=Item 111 Selected InputSigType122=Digital InputCue123=Item 112 Selected InputSigType123=Digital InputCue124=Item 113 Selected InputSigType124=Digital InputCue125=Item 114 Selected InputSigType125=Digital InputCue126=Item 115 Selected InputSigType126=Digital InputCue127=Item 116 Selected InputSigType127=Digital InputCue128=Item 117 Selected InputSigType128=Digital InputCue129=Item 118 Selected InputSigType129=Digital InputCue130=Item 119 Selected InputSigType130=Digital InputCue131=Item 120 Selected InputSigType131=Digital InputCue132=Item 121 Selected InputSigType132=Digital InputCue133=Item 122 Selected InputSigType133=Digital InputCue134=Item 123 Selected InputSigType134=Digital InputCue135=Item 124 Selected InputSigType135=Digital InputCue136=Item 125 Selected InputSigType136=Digital InputCue137=Item 126 Selected InputSigType137=Digital InputCue138=Item 127 Selected InputSigType138=Digital InputCue139=Item 128 Selected InputSigType139=Digital InputCue140=Item 129 Selected InputSigType140=Digital InputCue141=Item 130 Selected InputSigType141=Digital InputCue142=Item 131 Selected InputSigType142=Digital InputCue143=Item 132 Selected InputSigType143=Digital InputCue144=Item 133 Selected InputSigType144=Digital InputCue145=Item 134 Selected InputSigType145=Digital InputCue146=Item 135 Selected InputSigType146=Digital InputCue147=Item 136 Selected InputSigType147=Digital InputCue148=Item 137 Selected InputSigType148=Digital InputCue149=Item 138 Selected InputSigType149=Digital InputCue150=Item 139 Selected InputSigType150=Digital InputCue151=Item 140 Selected InputSigType151=Digital InputCue152=Item 141 Selected InputSigType152=Digital InputCue153=Item 142 Selected InputSigType153=Digital InputCue154=Item 143 Selected InputSigType154=Digital InputCue155=Item 144 Selected InputSigType155=Digital InputCue156=Item 145 Selected InputSigType156=Digital InputCue157=Item 146 Selected InputSigType157=Digital InputCue158=Item 147 Selected InputSigType158=Digital InputCue159=Item 148 Selected InputSigType159=Digital InputCue160=Item 149 Selected InputSigType160=Digital InputCue161=Item 150 Selected InputSigType161=Digital InputCue162=Item 151 Selected InputSigType162=Digital InputCue163=Item 152 Selected InputSigType163=Digital InputCue164=Item 153 Selected InputSigType164=Digital InputCue165=Item 154 Selected InputSigType165=Digital InputCue166=Item 155 Selected InputSigType166=Digital InputCue167=Item 156 Selected InputSigType167=Digital InputCue168=Item 157 Selected InputSigType168=Digital InputCue169=Item 158 Selected InputSigType169=Digital InputCue170=Item 159 Selected InputSigType170=Digital InputCue171=Item 160 Selected InputSigType171=Digital InputCue172=Item 161 Selected InputSigType172=Digital InputCue173=Item 162 Selected InputSigType173=Digital InputCue174=Item 163 Selected InputSigType174=Digital InputCue175=Item 164 Selected InputSigType175=Digital InputCue176=Item 165 Selected InputSigType176=Digital InputCue177=Item 166 Selected InputSigType177=Digital InputCue178=Item 167 Selected InputSigType178=Digital InputCue179=Item 168 Selected InputSigType179=Digital InputCue180=Item 169 Selected InputSigType180=Digital InputCue181=Item 170 Selected InputSigType181=Digital InputCue182=Item 171 Selected InputSigType182=Digital InputCue183=Item 172 Selected InputSigType183=Digital InputCue184=Item 173 Selected InputSigType184=Digital InputCue185=Item 174 Selected InputSigType185=Digital InputCue186=Item 175 Selected InputSigType186=Digital InputCue187=Item 176 Selected InputSigType187=Digital InputCue188=Item 177 Selected InputSigType188=Digital InputCue189=Item 178 Selected InputSigType189=Digital InputCue190=Item 179 Selected InputSigType190=Digital InputCue191=Item 180 Selected InputSigType191=Digital InputCue192=Item 181 Selected InputSigType192=Digital InputCue193=Item 182 Selected InputSigType193=Digital InputCue194=Item 183 Selected InputSigType194=Digital InputCue195=Item 184 Selected InputSigType195=Digital InputCue196=Item 185 Selected InputSigType196=Digital InputCue197=Item 186 Selected InputSigType197=Digital InputCue198=Item 187 Selected InputSigType198=Digital InputCue199=Item 188 Selected InputSigType199=Digital InputCue200=Item 189 Selected InputSigType200=Digital InputCue201=Item 190 Selected InputSigType201=Digital InputCue202=Item 191 Selected InputSigType202=Digital InputCue203=Item 192 Selected InputSigType203=Digital InputCue204=Item 193 Selected InputSigType204=Digital InputCue205=Item 194 Selected InputSigType205=Digital InputCue206=Item 195 Selected InputSigType206=Digital InputCue207=Item 196 Selected InputSigType207=Digital InputCue208=Item 197 Selected InputSigType208=Digital InputCue209=Item 198 Selected InputSigType209=Digital InputCue210=Item 199 Selected InputSigType210=Digital InputCue211=Item 200 Selected InputSigType211=Digital InputCue212=Item 201 Selected InputSigType212=Digital InputCue213=Item 202 Selected InputSigType213=Digital InputCue214=Item 203 Selected InputSigType214=Digital InputCue215=Item 204 Selected InputSigType215=Digital InputCue216=Item 205 Selected InputSigType216=Digital InputCue217=Item 206 Selected InputSigType217=Digital InputCue218=Item 207 Selected InputSigType218=Digital InputCue219=Item 208 Selected InputSigType219=Digital InputCue220=Item 209 Selected InputSigType220=Digital InputCue221=Item 210 Selected InputSigType221=Digital InputCue222=Item 211 Selected InputSigType222=Digital InputCue223=Item 212 Selected InputSigType223=Digital InputCue224=Item 213 Selected InputSigType224=Digital InputCue225=Item 214 Selected InputSigType225=Digital InputCue226=Item 215 Selected InputSigType226=Digital InputCue227=Item 216 Selected InputSigType227=Digital InputCue228=Item 217 Selected InputSigType228=Digital InputCue229=Item 218 Selected InputSigType229=Digital InputCue230=Item 219 Selected InputSigType230=Digital InputCue231=Item 220 Selected InputSigType231=Digital InputCue232=Item 221 Selected InputSigType232=Digital InputCue233=Item 222 Selected InputSigType233=Digital InputCue234=Item 223 Selected InputSigType234=Digital InputCue235=Item 224 Selected InputSigType235=Digital InputCue236=Item 225 Selected InputSigType236=Digital InputCue237=Item 226 Selected InputSigType237=Digital InputCue238=Item 227 Selected InputSigType238=Digital InputCue239=Item 228 Selected InputSigType239=Digital InputCue240=Item 229 Selected InputSigType240=Digital InputCue241=Item 230 Selected InputSigType241=Digital InputCue242=Item 231 Selected InputSigType242=Digital InputCue243=Item 232 Selected InputSigType243=Digital InputCue244=Item 233 Selected InputSigType244=Digital InputCue245=Item 234 Selected InputSigType245=Digital InputCue246=Item 235 Selected InputSigType246=Digital InputCue247=Item 236 Selected InputSigType247=Digital InputCue248=Item 237 Selected InputSigType248=Digital InputCue249=Item 238 Selected InputSigType249=Digital InputCue250=Item 239 Selected InputSigType250=Digital InputCue251=Item 240 Selected InputSigType251=Digital InputCue252=Item 241 Selected InputSigType252=Digital InputCue253=Item 242 Selected InputSigType253=Digital InputCue254=Item 243 Selected InputSigType254=Digital InputCue255=Item 244 Selected InputSigType255=Digital InputCue256=Item 245 Selected InputSigType256=Digital InputCue257=Item 246 Selected InputSigType257=Digital InputCue258=Item 247 Selected InputSigType258=Digital InputCue259=Item 248 Selected InputSigType259=Digital InputCue260=Item 249 Selected InputSigType260=Digital InputCue261=Item 250 Selected InputSigType261=Digital InputCue262=Item 251 Selected InputSigType262=Digital InputCue263=Item 252 Selected InputSigType263=Digital InputCue264=Item 253 Selected InputSigType264=Digital InputCue265=Item 254 Selected InputSigType265=Digital InputCue266=Item 255 Selected InputSigType266=Digital InputCue267=[~UNUSED2~] InputSigType267=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=Item 11 Enabled InputSigType2024=Digital InputCue2025=Item 12 Enabled InputSigType2025=Digital InputCue2026=Item 13 Enabled InputSigType2026=Digital InputCue2027=Item 14 Enabled InputSigType2027=Digital InputCue2028=Item 15 Enabled InputSigType2028=Digital InputCue2029=Item 16 Enabled InputSigType2029=Digital InputCue2030=Item 17 Enabled InputSigType2030=Digital InputCue2031=Item 18 Enabled InputSigType2031=Digital InputCue2032=Item 19 Enabled InputSigType2032=Digital InputCue2033=Item 20 Enabled InputSigType2033=Digital InputCue2034=Item 21 Enabled InputSigType2034=Digital InputCue2035=Item 22 Enabled InputSigType2035=Digital InputCue2036=Item 23 Enabled InputSigType2036=Digital InputCue2037=Item 24 Enabled InputSigType2037=Digital InputCue2038=Item 25 Enabled InputSigType2038=Digital InputCue2039=Item 26 Enabled InputSigType2039=Digital InputCue2040=Item 27 Enabled InputSigType2040=Digital InputCue2041=Item 28 Enabled InputSigType2041=Digital InputCue2042=Item 29 Enabled InputSigType2042=Digital InputCue2043=Item 30 Enabled InputSigType2043=Digital InputCue2044=Item 31 Enabled InputSigType2044=Digital InputCue2045=Item 32 Enabled InputSigType2045=Digital InputCue2046=Item 33 Enabled InputSigType2046=Digital InputCue2047=Item 34 Enabled InputSigType2047=Digital InputCue2048=Item 35 Enabled InputSigType2048=Digital InputCue2049=Item 36 Enabled InputSigType2049=Digital InputCue2050=Item 37 Enabled InputSigType2050=Digital InputCue2051=Item 38 Enabled InputSigType2051=Digital InputCue2052=Item 39 Enabled InputSigType2052=Digital InputCue2053=Item 40 Enabled InputSigType2053=Digital InputCue2054=Item 41 Enabled InputSigType2054=Digital InputCue2055=Item 42 Enabled InputSigType2055=Digital InputCue2056=Item 43 Enabled InputSigType2056=Digital InputCue2057=Item 44 Enabled InputSigType2057=Digital InputCue2058=Item 45 Enabled InputSigType2058=Digital InputCue2059=Item 46 Enabled InputSigType2059=Digital InputCue2060=Item 47 Enabled InputSigType2060=Digital InputCue2061=Item 48 Enabled InputSigType2061=Digital InputCue2062=Item 49 Enabled InputSigType2062=Digital InputCue2063=Item 50 Enabled InputSigType2063=Digital InputCue2064=Item 51 Enabled InputSigType2064=Digital InputCue2065=Item 52 Enabled InputSigType2065=Digital InputCue2066=Item 53 Enabled InputSigType2066=Digital InputCue2067=Item 54 Enabled InputSigType2067=Digital InputCue2068=Item 55 Enabled InputSigType2068=Digital InputCue2069=Item 56 Enabled InputSigType2069=Digital InputCue2070=Item 57 Enabled InputSigType2070=Digital InputCue2071=Item 58 Enabled InputSigType2071=Digital InputCue2072=Item 59 Enabled InputSigType2072=Digital InputCue2073=Item 60 Enabled InputSigType2073=Digital InputCue2074=Item 61 Enabled InputSigType2074=Digital InputCue2075=Item 62 Enabled InputSigType2075=Digital InputCue2076=Item 63 Enabled InputSigType2076=Digital InputCue2077=Item 64 Enabled InputSigType2077=Digital InputCue2078=Item 65 Enabled InputSigType2078=Digital InputCue2079=Item 66 Enabled InputSigType2079=Digital InputCue2080=Item 67 Enabled InputSigType2080=Digital InputCue2081=Item 68 Enabled InputSigType2081=Digital InputCue2082=Item 69 Enabled InputSigType2082=Digital InputCue2083=Item 70 Enabled InputSigType2083=Digital InputCue2084=Item 71 Enabled InputSigType2084=Digital InputCue2085=Item 72 Enabled InputSigType2085=Digital InputCue2086=Item 73 Enabled InputSigType2086=Digital InputCue2087=Item 74 Enabled InputSigType2087=Digital InputCue2088=Item 75 Enabled InputSigType2088=Digital InputCue2089=Item 76 Enabled InputSigType2089=Digital InputCue2090=Item 77 Enabled InputSigType2090=Digital InputCue2091=Item 78 Enabled InputSigType2091=Digital InputCue2092=Item 79 Enabled InputSigType2092=Digital InputCue2093=Item 80 Enabled InputSigType2093=Digital InputCue2094=Item 81 Enabled InputSigType2094=Digital InputCue2095=Item 82 Enabled InputSigType2095=Digital InputCue2096=Item 83 Enabled InputSigType2096=Digital InputCue2097=Item 84 Enabled InputSigType2097=Digital InputCue2098=Item 85 Enabled InputSigType2098=Digital InputCue2099=Item 86 Enabled InputSigType2099=Digital InputCue2100=Item 87 Enabled InputSigType2100=Digital InputCue2101=Item 88 Enabled InputSigType2101=Digital InputCue2102=Item 89 Enabled InputSigType2102=Digital InputCue2103=Item 90 Enabled InputSigType2103=Digital InputCue2104=Item 91 Enabled InputSigType2104=Digital InputCue2105=Item 92 Enabled InputSigType2105=Digital InputCue2106=Item 93 Enabled InputSigType2106=Digital InputCue2107=Item 94 Enabled InputSigType2107=Digital InputCue2108=Item 95 Enabled InputSigType2108=Digital InputCue2109=Item 96 Enabled InputSigType2109=Digital InputCue2110=Item 97 Enabled InputSigType2110=Digital InputCue2111=Item 98 Enabled InputSigType2111=Digital InputCue2112=Item 99 Enabled InputSigType2112=Digital InputCue2113=Item 100 Enabled InputSigType2113=Digital InputCue2114=Item 101 Enabled InputSigType2114=Digital InputCue2115=Item 102 Enabled InputSigType2115=Digital InputCue2116=Item 103 Enabled InputSigType2116=Digital InputCue2117=Item 104 Enabled InputSigType2117=Digital InputCue2118=Item 105 Enabled InputSigType2118=Digital InputCue2119=Item 106 Enabled InputSigType2119=Digital InputCue2120=Item 107 Enabled InputSigType2120=Digital InputCue2121=Item 108 Enabled InputSigType2121=Digital InputCue2122=Item 109 Enabled InputSigType2122=Digital InputCue2123=Item 110 Enabled InputSigType2123=Digital InputCue2124=Item 111 Enabled InputSigType2124=Digital InputCue2125=Item 112 Enabled InputSigType2125=Digital InputCue2126=Item 113 Enabled InputSigType2126=Digital InputCue2127=Item 114 Enabled InputSigType2127=Digital InputCue2128=Item 115 Enabled InputSigType2128=Digital InputCue2129=Item 116 Enabled InputSigType2129=Digital InputCue2130=Item 117 Enabled InputSigType2130=Digital InputCue2131=Item 118 Enabled InputSigType2131=Digital InputCue2132=Item 119 Enabled InputSigType2132=Digital InputCue2133=Item 120 Enabled InputSigType2133=Digital InputCue2134=Item 121 Enabled InputSigType2134=Digital InputCue2135=Item 122 Enabled InputSigType2135=Digital InputCue2136=Item 123 Enabled InputSigType2136=Digital InputCue2137=Item 124 Enabled InputSigType2137=Digital InputCue2138=Item 125 Enabled InputSigType2138=Digital InputCue2139=Item 126 Enabled InputSigType2139=Digital InputCue2140=Item 127 Enabled InputSigType2140=Digital InputCue2141=Item 128 Enabled InputSigType2141=Digital InputCue2142=Item 129 Enabled InputSigType2142=Digital InputCue2143=Item 130 Enabled InputSigType2143=Digital InputCue2144=Item 131 Enabled InputSigType2144=Digital InputCue2145=Item 132 Enabled InputSigType2145=Digital InputCue2146=Item 133 Enabled InputSigType2146=Digital InputCue2147=Item 134 Enabled InputSigType2147=Digital InputCue2148=Item 135 Enabled InputSigType2148=Digital InputCue2149=Item 136 Enabled InputSigType2149=Digital InputCue2150=Item 137 Enabled InputSigType2150=Digital InputCue2151=Item 138 Enabled InputSigType2151=Digital InputCue2152=Item 139 Enabled InputSigType2152=Digital InputCue2153=Item 140 Enabled InputSigType2153=Digital InputCue2154=Item 141 Enabled InputSigType2154=Digital InputCue2155=Item 142 Enabled InputSigType2155=Digital InputCue2156=Item 143 Enabled InputSigType2156=Digital InputCue2157=Item 144 Enabled InputSigType2157=Digital InputCue2158=Item 145 Enabled InputSigType2158=Digital InputCue2159=Item 146 Enabled InputSigType2159=Digital InputCue2160=Item 147 Enabled InputSigType2160=Digital InputCue2161=Item 148 Enabled InputSigType2161=Digital InputCue2162=Item 149 Enabled InputSigType2162=Digital InputCue2163=Item 150 Enabled InputSigType2163=Digital InputCue2164=Item 151 Enabled InputSigType2164=Digital InputCue2165=Item 152 Enabled InputSigType2165=Digital InputCue2166=Item 153 Enabled InputSigType2166=Digital InputCue2167=Item 154 Enabled InputSigType2167=Digital InputCue2168=Item 155 Enabled InputSigType2168=Digital InputCue2169=Item 156 Enabled InputSigType2169=Digital InputCue2170=Item 157 Enabled InputSigType2170=Digital InputCue2171=Item 158 Enabled InputSigType2171=Digital InputCue2172=Item 159 Enabled InputSigType2172=Digital InputCue2173=Item 160 Enabled InputSigType2173=Digital InputCue2174=Item 161 Enabled InputSigType2174=Digital InputCue2175=Item 162 Enabled InputSigType2175=Digital InputCue2176=Item 163 Enabled InputSigType2176=Digital InputCue2177=Item 164 Enabled InputSigType2177=Digital InputCue2178=Item 165 Enabled InputSigType2178=Digital InputCue2179=Item 166 Enabled InputSigType2179=Digital InputCue2180=Item 167 Enabled InputSigType2180=Digital InputCue2181=Item 168 Enabled InputSigType2181=Digital InputCue2182=Item 169 Enabled InputSigType2182=Digital InputCue2183=Item 170 Enabled InputSigType2183=Digital InputCue2184=Item 171 Enabled InputSigType2184=Digital InputCue2185=Item 172 Enabled InputSigType2185=Digital InputCue2186=Item 173 Enabled InputSigType2186=Digital InputCue2187=Item 174 Enabled InputSigType2187=Digital InputCue2188=Item 175 Enabled InputSigType2188=Digital InputCue2189=Item 176 Enabled InputSigType2189=Digital InputCue2190=Item 177 Enabled InputSigType2190=Digital InputCue2191=Item 178 Enabled InputSigType2191=Digital InputCue2192=Item 179 Enabled InputSigType2192=Digital InputCue2193=Item 180 Enabled InputSigType2193=Digital InputCue2194=Item 181 Enabled InputSigType2194=Digital InputCue2195=Item 182 Enabled InputSigType2195=Digital InputCue2196=Item 183 Enabled InputSigType2196=Digital InputCue2197=Item 184 Enabled InputSigType2197=Digital InputCue2198=Item 185 Enabled InputSigType2198=Digital InputCue2199=Item 186 Enabled InputSigType2199=Digital InputCue2200=Item 187 Enabled InputSigType2200=Digital InputCue2201=Item 188 Enabled InputSigType2201=Digital InputCue2202=Item 189 Enabled InputSigType2202=Digital InputCue2203=Item 190 Enabled InputSigType2203=Digital InputCue2204=Item 191 Enabled InputSigType2204=Digital InputCue2205=Item 192 Enabled InputSigType2205=Digital InputCue2206=Item 193 Enabled InputSigType2206=Digital InputCue2207=Item 194 Enabled InputSigType2207=Digital InputCue2208=Item 195 Enabled InputSigType2208=Digital InputCue2209=Item 196 Enabled InputSigType2209=Digital InputCue2210=Item 197 Enabled InputSigType2210=Digital InputCue2211=Item 198 Enabled InputSigType2211=Digital InputCue2212=Item 199 Enabled InputSigType2212=Digital InputCue2213=Item 200 Enabled InputSigType2213=Digital InputCue2214=Item 201 Enabled InputSigType2214=Digital InputCue2215=Item 202 Enabled InputSigType2215=Digital InputCue2216=Item 203 Enabled InputSigType2216=Digital InputCue2217=Item 204 Enabled InputSigType2217=Digital InputCue2218=Item 205 Enabled InputSigType2218=Digital InputCue2219=Item 206 Enabled InputSigType2219=Digital InputCue2220=Item 207 Enabled InputSigType2220=Digital InputCue2221=Item 208 Enabled InputSigType2221=Digital InputCue2222=Item 209 Enabled InputSigType2222=Digital InputCue2223=Item 210 Enabled InputSigType2223=Digital InputCue2224=Item 211 Enabled InputSigType2224=Digital InputCue2225=Item 212 Enabled InputSigType2225=Digital InputCue2226=Item 213 Enabled InputSigType2226=Digital InputCue2227=Item 214 Enabled InputSigType2227=Digital InputCue2228=Item 215 Enabled InputSigType2228=Digital InputCue2229=Item 216 Enabled InputSigType2229=Digital InputCue2230=Item 217 Enabled InputSigType2230=Digital InputCue2231=Item 218 Enabled InputSigType2231=Digital InputCue2232=Item 219 Enabled InputSigType2232=Digital InputCue2233=Item 220 Enabled InputSigType2233=Digital InputCue2234=Item 221 Enabled InputSigType2234=Digital InputCue2235=Item 222 Enabled InputSigType2235=Digital InputCue2236=Item 223 Enabled InputSigType2236=Digital InputCue2237=Item 224 Enabled InputSigType2237=Digital InputCue2238=Item 225 Enabled InputSigType2238=Digital InputCue2239=Item 226 Enabled InputSigType2239=Digital InputCue2240=Item 227 Enabled InputSigType2240=Digital InputCue2241=Item 228 Enabled InputSigType2241=Digital InputCue2242=Item 229 Enabled InputSigType2242=Digital InputCue2243=Item 230 Enabled InputSigType2243=Digital InputCue2244=Item 231 Enabled InputSigType2244=Digital InputCue2245=Item 232 Enabled InputSigType2245=Digital InputCue2246=Item 233 Enabled InputSigType2246=Digital InputCue2247=Item 234 Enabled InputSigType2247=Digital InputCue2248=Item 235 Enabled InputSigType2248=Digital InputCue2249=Item 236 Enabled InputSigType2249=Digital InputCue2250=Item 237 Enabled InputSigType2250=Digital InputCue2251=Item 238 Enabled InputSigType2251=Digital InputCue2252=Item 239 Enabled InputSigType2252=Digital InputCue2253=Item 240 Enabled InputSigType2253=Digital InputCue2254=Item 241 Enabled InputSigType2254=Digital InputCue2255=Item 242 Enabled InputSigType2255=Digital InputCue2256=Item 243 Enabled InputSigType2256=Digital InputCue2257=Item 244 Enabled InputSigType2257=Digital InputCue2258=Item 245 Enabled InputSigType2258=Digital InputCue2259=Item 246 Enabled InputSigType2259=Digital InputCue2260=Item 247 Enabled InputSigType2260=Digital InputCue2261=Item 248 Enabled InputSigType2261=Digital InputCue2262=Item 249 Enabled InputSigType2262=Digital InputCue2263=Item 250 Enabled InputSigType2263=Digital InputCue2264=Item 251 Enabled InputSigType2264=Digital InputCue2265=Item 252 Enabled InputSigType2265=Digital InputCue2266=Item 253 Enabled InputSigType2266=Digital InputCue2267=Item 254 Enabled InputSigType2267=Digital InputCue2268=Item 255 Enabled InputSigType2268=Digital InputCue2269=[~UNUSED2~] InputSigType2269=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=Item 11 Visible InputSigType4026=Digital InputCue4027=Item 12 Visible InputSigType4027=Digital InputCue4028=Item 13 Visible InputSigType4028=Digital InputCue4029=Item 14 Visible InputSigType4029=Digital InputCue4030=Item 15 Visible InputSigType4030=Digital InputCue4031=Item 16 Visible InputSigType4031=Digital InputCue4032=Item 17 Visible InputSigType4032=Digital InputCue4033=Item 18 Visible InputSigType4033=Digital InputCue4034=Item 19 Visible InputSigType4034=Digital InputCue4035=Item 20 Visible InputSigType4035=Digital InputCue4036=Item 21 Visible InputSigType4036=Digital InputCue4037=Item 22 Visible InputSigType4037=Digital InputCue4038=Item 23 Visible InputSigType4038=Digital InputCue4039=Item 24 Visible InputSigType4039=Digital InputCue4040=Item 25 Visible InputSigType4040=Digital InputCue4041=Item 26 Visible InputSigType4041=Digital InputCue4042=Item 27 Visible InputSigType4042=Digital InputCue4043=Item 28 Visible InputSigType4043=Digital InputCue4044=Item 29 Visible InputSigType4044=Digital InputCue4045=Item 30 Visible InputSigType4045=Digital InputCue4046=Item 31 Visible InputSigType4046=Digital InputCue4047=Item 32 Visible InputSigType4047=Digital InputCue4048=Item 33 Visible InputSigType4048=Digital InputCue4049=Item 34 Visible InputSigType4049=Digital InputCue4050=Item 35 Visible InputSigType4050=Digital InputCue4051=Item 36 Visible InputSigType4051=Digital InputCue4052=Item 37 Visible InputSigType4052=Digital InputCue4053=Item 38 Visible InputSigType4053=Digital InputCue4054=Item 39 Visible InputSigType4054=Digital InputCue4055=Item 40 Visible InputSigType4055=Digital InputCue4056=Item 41 Visible InputSigType4056=Digital InputCue4057=Item 42 Visible InputSigType4057=Digital InputCue4058=Item 43 Visible InputSigType4058=Digital InputCue4059=Item 44 Visible InputSigType4059=Digital InputCue4060=Item 45 Visible InputSigType4060=Digital InputCue4061=Item 46 Visible InputSigType4061=Digital InputCue4062=Item 47 Visible InputSigType4062=Digital InputCue4063=Item 48 Visible InputSigType4063=Digital InputCue4064=Item 49 Visible InputSigType4064=Digital InputCue4065=Item 50 Visible InputSigType4065=Digital InputCue4066=Item 51 Visible InputSigType4066=Digital InputCue4067=Item 52 Visible InputSigType4067=Digital InputCue4068=Item 53 Visible InputSigType4068=Digital InputCue4069=Item 54 Visible InputSigType4069=Digital InputCue4070=Item 55 Visible InputSigType4070=Digital InputCue4071=Item 56 Visible InputSigType4071=Digital InputCue4072=Item 57 Visible InputSigType4072=Digital InputCue4073=Item 58 Visible InputSigType4073=Digital InputCue4074=Item 59 Visible InputSigType4074=Digital InputCue4075=Item 60 Visible InputSigType4075=Digital InputCue4076=Item 61 Visible InputSigType4076=Digital InputCue4077=Item 62 Visible InputSigType4077=Digital InputCue4078=Item 63 Visible InputSigType4078=Digital InputCue4079=Item 64 Visible InputSigType4079=Digital InputCue4080=Item 65 Visible InputSigType4080=Digital InputCue4081=Item 66 Visible InputSigType4081=Digital InputCue4082=Item 67 Visible InputSigType4082=Digital InputCue4083=Item 68 Visible InputSigType4083=Digital InputCue4084=Item 69 Visible InputSigType4084=Digital InputCue4085=Item 70 Visible InputSigType4085=Digital InputCue4086=Item 71 Visible InputSigType4086=Digital InputCue4087=Item 72 Visible InputSigType4087=Digital InputCue4088=Item 73 Visible InputSigType4088=Digital InputCue4089=Item 74 Visible InputSigType4089=Digital InputCue4090=Item 75 Visible InputSigType4090=Digital InputCue4091=Item 76 Visible InputSigType4091=Digital InputCue4092=Item 77 Visible InputSigType4092=Digital InputCue4093=Item 78 Visible InputSigType4093=Digital InputCue4094=Item 79 Visible InputSigType4094=Digital InputCue4095=Item 80 Visible InputSigType4095=Digital InputCue4096=Item 81 Visible InputSigType4096=Digital InputCue4097=Item 82 Visible InputSigType4097=Digital InputCue4098=Item 83 Visible InputSigType4098=Digital InputCue4099=Item 84 Visible InputSigType4099=Digital InputCue4100=Item 85 Visible InputSigType4100=Digital InputCue4101=Item 86 Visible InputSigType4101=Digital InputCue4102=Item 87 Visible InputSigType4102=Digital InputCue4103=Item 88 Visible InputSigType4103=Digital InputCue4104=Item 89 Visible InputSigType4104=Digital InputCue4105=Item 90 Visible InputSigType4105=Digital InputCue4106=Item 91 Visible InputSigType4106=Digital InputCue4107=Item 92 Visible InputSigType4107=Digital InputCue4108=Item 93 Visible InputSigType4108=Digital InputCue4109=Item 94 Visible InputSigType4109=Digital InputCue4110=Item 95 Visible InputSigType4110=Digital InputCue4111=Item 96 Visible InputSigType4111=Digital InputCue4112=Item 97 Visible InputSigType4112=Digital InputCue4113=Item 98 Visible InputSigType4113=Digital InputCue4114=Item 99 Visible InputSigType4114=Digital InputCue4115=Item 100 Visible InputSigType4115=Digital InputCue4116=Item 101 Visible InputSigType4116=Digital InputCue4117=Item 102 Visible InputSigType4117=Digital InputCue4118=Item 103 Visible InputSigType4118=Digital InputCue4119=Item 104 Visible InputSigType4119=Digital InputCue4120=Item 105 Visible InputSigType4120=Digital InputCue4121=Item 106 Visible InputSigType4121=Digital InputCue4122=Item 107 Visible InputSigType4122=Digital InputCue4123=Item 108 Visible InputSigType4123=Digital InputCue4124=Item 109 Visible InputSigType4124=Digital InputCue4125=Item 110 Visible InputSigType4125=Digital InputCue4126=Item 111 Visible InputSigType4126=Digital InputCue4127=Item 112 Visible InputSigType4127=Digital InputCue4128=Item 113 Visible InputSigType4128=Digital InputCue4129=Item 114 Visible InputSigType4129=Digital InputCue4130=Item 115 Visible InputSigType4130=Digital InputCue4131=Item 116 Visible InputSigType4131=Digital InputCue4132=Item 117 Visible InputSigType4132=Digital InputCue4133=Item 118 Visible InputSigType4133=Digital InputCue4134=Item 119 Visible InputSigType4134=Digital InputCue4135=Item 120 Visible InputSigType4135=Digital InputCue4136=Item 121 Visible InputSigType4136=Digital InputCue4137=Item 122 Visible InputSigType4137=Digital InputCue4138=Item 123 Visible InputSigType4138=Digital InputCue4139=Item 124 Visible InputSigType4139=Digital InputCue4140=Item 125 Visible InputSigType4140=Digital InputCue4141=Item 126 Visible InputSigType4141=Digital InputCue4142=Item 127 Visible InputSigType4142=Digital InputCue4143=Item 128 Visible InputSigType4143=Digital InputCue4144=Item 129 Visible InputSigType4144=Digital InputCue4145=Item 130 Visible InputSigType4145=Digital InputCue4146=Item 131 Visible InputSigType4146=Digital InputCue4147=Item 132 Visible InputSigType4147=Digital InputCue4148=Item 133 Visible InputSigType4148=Digital InputCue4149=Item 134 Visible InputSigType4149=Digital InputCue4150=Item 135 Visible InputSigType4150=Digital InputCue4151=Item 136 Visible InputSigType4151=Digital InputCue4152=Item 137 Visible InputSigType4152=Digital InputCue4153=Item 138 Visible InputSigType4153=Digital InputCue4154=Item 139 Visible InputSigType4154=Digital InputCue4155=Item 140 Visible InputSigType4155=Digital InputCue4156=Item 141 Visible InputSigType4156=Digital InputCue4157=Item 142 Visible InputSigType4157=Digital InputCue4158=Item 143 Visible InputSigType4158=Digital InputCue4159=Item 144 Visible InputSigType4159=Digital InputCue4160=Item 145 Visible InputSigType4160=Digital InputCue4161=Item 146 Visible InputSigType4161=Digital InputCue4162=Item 147 Visible InputSigType4162=Digital InputCue4163=Item 148 Visible InputSigType4163=Digital InputCue4164=Item 149 Visible InputSigType4164=Digital InputCue4165=Item 150 Visible InputSigType4165=Digital InputCue4166=Item 151 Visible InputSigType4166=Digital InputCue4167=Item 152 Visible InputSigType4167=Digital InputCue4168=Item 153 Visible InputSigType4168=Digital InputCue4169=Item 154 Visible InputSigType4169=Digital InputCue4170=Item 155 Visible InputSigType4170=Digital InputCue4171=Item 156 Visible InputSigType4171=Digital InputCue4172=Item 157 Visible InputSigType4172=Digital InputCue4173=Item 158 Visible InputSigType4173=Digital InputCue4174=Item 159 Visible InputSigType4174=Digital InputCue4175=Item 160 Visible InputSigType4175=Digital InputCue4176=Item 161 Visible InputSigType4176=Digital InputCue4177=Item 162 Visible InputSigType4177=Digital InputCue4178=Item 163 Visible InputSigType4178=Digital InputCue4179=Item 164 Visible InputSigType4179=Digital InputCue4180=Item 165 Visible InputSigType4180=Digital InputCue4181=Item 166 Visible InputSigType4181=Digital InputCue4182=Item 167 Visible InputSigType4182=Digital InputCue4183=Item 168 Visible InputSigType4183=Digital InputCue4184=Item 169 Visible InputSigType4184=Digital InputCue4185=Item 170 Visible InputSigType4185=Digital InputCue4186=Item 171 Visible InputSigType4186=Digital InputCue4187=Item 172 Visible InputSigType4187=Digital InputCue4188=Item 173 Visible InputSigType4188=Digital InputCue4189=Item 174 Visible InputSigType4189=Digital InputCue4190=Item 175 Visible InputSigType4190=Digital InputCue4191=Item 176 Visible InputSigType4191=Digital InputCue4192=Item 177 Visible InputSigType4192=Digital InputCue4193=Item 178 Visible InputSigType4193=Digital InputCue4194=Item 179 Visible InputSigType4194=Digital InputCue4195=Item 180 Visible InputSigType4195=Digital InputCue4196=Item 181 Visible InputSigType4196=Digital InputCue4197=Item 182 Visible InputSigType4197=Digital InputCue4198=Item 183 Visible InputSigType4198=Digital InputCue4199=Item 184 Visible InputSigType4199=Digital InputCue4200=Item 185 Visible InputSigType4200=Digital InputCue4201=Item 186 Visible InputSigType4201=Digital InputCue4202=Item 187 Visible InputSigType4202=Digital InputCue4203=Item 188 Visible InputSigType4203=Digital InputCue4204=Item 189 Visible InputSigType4204=Digital InputCue4205=Item 190 Visible InputSigType4205=Digital InputCue4206=Item 191 Visible InputSigType4206=Digital InputCue4207=Item 192 Visible InputSigType4207=Digital InputCue4208=Item 193 Visible InputSigType4208=Digital InputCue4209=Item 194 Visible InputSigType4209=Digital InputCue4210=Item 195 Visible InputSigType4210=Digital InputCue4211=Item 196 Visible InputSigType4211=Digital InputCue4212=Item 197 Visible InputSigType4212=Digital InputCue4213=Item 198 Visible InputSigType4213=Digital InputCue4214=Item 199 Visible InputSigType4214=Digital InputCue4215=Item 200 Visible InputSigType4215=Digital InputCue4216=Item 201 Visible InputSigType4216=Digital InputCue4217=Item 202 Visible InputSigType4217=Digital InputCue4218=Item 203 Visible InputSigType4218=Digital InputCue4219=Item 204 Visible InputSigType4219=Digital InputCue4220=Item 205 Visible InputSigType4220=Digital InputCue4221=Item 206 Visible InputSigType4221=Digital InputCue4222=Item 207 Visible InputSigType4222=Digital InputCue4223=Item 208 Visible InputSigType4223=Digital InputCue4224=Item 209 Visible InputSigType4224=Digital InputCue4225=Item 210 Visible InputSigType4225=Digital InputCue4226=Item 211 Visible InputSigType4226=Digital InputCue4227=Item 212 Visible InputSigType4227=Digital InputCue4228=Item 213 Visible InputSigType4228=Digital InputCue4229=Item 214 Visible InputSigType4229=Digital InputCue4230=Item 215 Visible InputSigType4230=Digital InputCue4231=Item 216 Visible InputSigType4231=Digital InputCue4232=Item 217 Visible InputSigType4232=Digital InputCue4233=Item 218 Visible InputSigType4233=Digital InputCue4234=Item 219 Visible InputSigType4234=Digital InputCue4235=Item 220 Visible InputSigType4235=Digital InputCue4236=Item 221 Visible InputSigType4236=Digital InputCue4237=Item 222 Visible InputSigType4237=Digital InputCue4238=Item 223 Visible InputSigType4238=Digital InputCue4239=Item 224 Visible InputSigType4239=Digital InputCue4240=Item 225 Visible InputSigType4240=Digital InputCue4241=Item 226 Visible InputSigType4241=Digital InputCue4242=Item 227 Visible InputSigType4242=Digital InputCue4243=Item 228 Visible InputSigType4243=Digital InputCue4244=Item 229 Visible InputSigType4244=Digital InputCue4245=Item 230 Visible InputSigType4245=Digital InputCue4246=Item 231 Visible InputSigType4246=Digital InputCue4247=Item 232 Visible InputSigType4247=Digital InputCue4248=Item 233 Visible InputSigType4248=Digital InputCue4249=Item 234 Visible InputSigType4249=Digital InputCue4250=Item 235 Visible InputSigType4250=Digital InputCue4251=Item 236 Visible InputSigType4251=Digital InputCue4252=Item 237 Visible InputSigType4252=Digital InputCue4253=Item 238 Visible InputSigType4253=Digital InputCue4254=Item 239 Visible InputSigType4254=Digital InputCue4255=Item 240 Visible InputSigType4255=Digital InputCue4256=Item 241 Visible InputSigType4256=Digital InputCue4257=Item 242 Visible InputSigType4257=Digital InputCue4258=Item 243 Visible InputSigType4258=Digital InputCue4259=Item 244 Visible InputSigType4259=Digital InputCue4260=Item 245 Visible InputSigType4260=Digital InputCue4261=Item 246 Visible InputSigType4261=Digital InputCue4262=Item 247 Visible InputSigType4262=Digital InputCue4263=Item 248 Visible InputSigType4263=Digital InputCue4264=Item 249 Visible InputSigType4264=Digital InputCue4265=Item 250 Visible InputSigType4265=Digital InputCue4266=Item 251 Visible InputSigType4266=Digital InputCue4267=Item 252 Visible InputSigType4267=Digital InputCue4268=Item 253 Visible InputSigType4268=Digital InputCue4269=Item 254 Visible InputSigType4269=Digital InputCue4270=Item 255 Visible InputSigType4270=Digital InputCue4271=[~UNUSED2~] InputSigType4271=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=Item 11 Pressed OutputSigType22=Digital OutputCue23=Item 12 Pressed OutputSigType23=Digital OutputCue24=Item 13 Pressed OutputSigType24=Digital OutputCue25=Item 14 Pressed OutputSigType25=Digital OutputCue26=Item 15 Pressed OutputSigType26=Digital OutputCue27=Item 16 Pressed OutputSigType27=Digital OutputCue28=Item 17 Pressed OutputSigType28=Digital OutputCue29=Item 18 Pressed OutputSigType29=Digital OutputCue30=Item 19 Pressed OutputSigType30=Digital OutputCue31=Item 20 Pressed OutputSigType31=Digital OutputCue32=Item 21 Pressed OutputSigType32=Digital OutputCue33=Item 22 Pressed OutputSigType33=Digital OutputCue34=Item 23 Pressed OutputSigType34=Digital OutputCue35=Item 24 Pressed OutputSigType35=Digital OutputCue36=Item 25 Pressed OutputSigType36=Digital OutputCue37=Item 26 Pressed OutputSigType37=Digital OutputCue38=Item 27 Pressed OutputSigType38=Digital OutputCue39=Item 28 Pressed OutputSigType39=Digital OutputCue40=Item 29 Pressed OutputSigType40=Digital OutputCue41=Item 30 Pressed OutputSigType41=Digital OutputCue42=Item 31 Pressed OutputSigType42=Digital OutputCue43=Item 32 Pressed OutputSigType43=Digital OutputCue44=Item 33 Pressed OutputSigType44=Digital OutputCue45=Item 34 Pressed OutputSigType45=Digital OutputCue46=Item 35 Pressed OutputSigType46=Digital OutputCue47=Item 36 Pressed OutputSigType47=Digital OutputCue48=Item 37 Pressed OutputSigType48=Digital OutputCue49=Item 38 Pressed OutputSigType49=Digital OutputCue50=Item 39 Pressed OutputSigType50=Digital OutputCue51=Item 40 Pressed OutputSigType51=Digital OutputCue52=Item 41 Pressed OutputSigType52=Digital OutputCue53=Item 42 Pressed OutputSigType53=Digital OutputCue54=Item 43 Pressed OutputSigType54=Digital OutputCue55=Item 44 Pressed OutputSigType55=Digital OutputCue56=Item 45 Pressed OutputSigType56=Digital OutputCue57=Item 46 Pressed OutputSigType57=Digital OutputCue58=Item 47 Pressed OutputSigType58=Digital OutputCue59=Item 48 Pressed OutputSigType59=Digital OutputCue60=Item 49 Pressed OutputSigType60=Digital OutputCue61=Item 50 Pressed OutputSigType61=Digital OutputCue62=Item 51 Pressed OutputSigType62=Digital OutputCue63=Item 52 Pressed OutputSigType63=Digital OutputCue64=Item 53 Pressed OutputSigType64=Digital OutputCue65=Item 54 Pressed OutputSigType65=Digital OutputCue66=Item 55 Pressed OutputSigType66=Digital OutputCue67=Item 56 Pressed OutputSigType67=Digital OutputCue68=Item 57 Pressed OutputSigType68=Digital OutputCue69=Item 58 Pressed OutputSigType69=Digital OutputCue70=Item 59 Pressed OutputSigType70=Digital OutputCue71=Item 60 Pressed OutputSigType71=Digital OutputCue72=Item 61 Pressed OutputSigType72=Digital OutputCue73=Item 62 Pressed OutputSigType73=Digital OutputCue74=Item 63 Pressed OutputSigType74=Digital OutputCue75=Item 64 Pressed OutputSigType75=Digital OutputCue76=Item 65 Pressed OutputSigType76=Digital OutputCue77=Item 66 Pressed OutputSigType77=Digital OutputCue78=Item 67 Pressed OutputSigType78=Digital OutputCue79=Item 68 Pressed OutputSigType79=Digital OutputCue80=Item 69 Pressed OutputSigType80=Digital OutputCue81=Item 70 Pressed OutputSigType81=Digital OutputCue82=Item 71 Pressed OutputSigType82=Digital OutputCue83=Item 72 Pressed OutputSigType83=Digital OutputCue84=Item 73 Pressed OutputSigType84=Digital OutputCue85=Item 74 Pressed OutputSigType85=Digital OutputCue86=Item 75 Pressed OutputSigType86=Digital OutputCue87=Item 76 Pressed OutputSigType87=Digital OutputCue88=Item 77 Pressed OutputSigType88=Digital OutputCue89=Item 78 Pressed OutputSigType89=Digital OutputCue90=Item 79 Pressed OutputSigType90=Digital OutputCue91=Item 80 Pressed OutputSigType91=Digital OutputCue92=Item 81 Pressed OutputSigType92=Digital OutputCue93=Item 82 Pressed OutputSigType93=Digital OutputCue94=Item 83 Pressed OutputSigType94=Digital OutputCue95=Item 84 Pressed OutputSigType95=Digital OutputCue96=Item 85 Pressed OutputSigType96=Digital OutputCue97=Item 86 Pressed OutputSigType97=Digital OutputCue98=Item 87 Pressed OutputSigType98=Digital OutputCue99=Item 88 Pressed OutputSigType99=Digital OutputCue100=Item 89 Pressed OutputSigType100=Digital OutputCue101=Item 90 Pressed OutputSigType101=Digital OutputCue102=Item 91 Pressed OutputSigType102=Digital OutputCue103=Item 92 Pressed OutputSigType103=Digital OutputCue104=Item 93 Pressed OutputSigType104=Digital OutputCue105=Item 94 Pressed OutputSigType105=Digital OutputCue106=Item 95 Pressed OutputSigType106=Digital OutputCue107=Item 96 Pressed OutputSigType107=Digital OutputCue108=Item 97 Pressed OutputSigType108=Digital OutputCue109=Item 98 Pressed OutputSigType109=Digital OutputCue110=Item 99 Pressed OutputSigType110=Digital OutputCue111=Item 100 Pressed OutputSigType111=Digital OutputCue112=Item 101 Pressed OutputSigType112=Digital OutputCue113=Item 102 Pressed OutputSigType113=Digital OutputCue114=Item 103 Pressed OutputSigType114=Digital OutputCue115=Item 104 Pressed OutputSigType115=Digital OutputCue116=Item 105 Pressed OutputSigType116=Digital OutputCue117=Item 106 Pressed OutputSigType117=Digital OutputCue118=Item 107 Pressed OutputSigType118=Digital OutputCue119=Item 108 Pressed OutputSigType119=Digital OutputCue120=Item 109 Pressed OutputSigType120=Digital OutputCue121=Item 110 Pressed OutputSigType121=Digital OutputCue122=Item 111 Pressed OutputSigType122=Digital OutputCue123=Item 112 Pressed OutputSigType123=Digital OutputCue124=Item 113 Pressed OutputSigType124=Digital OutputCue125=Item 114 Pressed OutputSigType125=Digital OutputCue126=Item 115 Pressed OutputSigType126=Digital OutputCue127=Item 116 Pressed OutputSigType127=Digital OutputCue128=Item 117 Pressed OutputSigType128=Digital OutputCue129=Item 118 Pressed OutputSigType129=Digital OutputCue130=Item 119 Pressed OutputSigType130=Digital OutputCue131=Item 120 Pressed OutputSigType131=Digital OutputCue132=Item 121 Pressed OutputSigType132=Digital OutputCue133=Item 122 Pressed OutputSigType133=Digital OutputCue134=Item 123 Pressed OutputSigType134=Digital OutputCue135=Item 124 Pressed OutputSigType135=Digital OutputCue136=Item 125 Pressed OutputSigType136=Digital OutputCue137=Item 126 Pressed OutputSigType137=Digital OutputCue138=Item 127 Pressed OutputSigType138=Digital OutputCue139=Item 128 Pressed OutputSigType139=Digital OutputCue140=Item 129 Pressed OutputSigType140=Digital OutputCue141=Item 130 Pressed OutputSigType141=Digital OutputCue142=Item 131 Pressed OutputSigType142=Digital OutputCue143=Item 132 Pressed OutputSigType143=Digital OutputCue144=Item 133 Pressed OutputSigType144=Digital OutputCue145=Item 134 Pressed OutputSigType145=Digital OutputCue146=Item 135 Pressed OutputSigType146=Digital OutputCue147=Item 136 Pressed OutputSigType147=Digital OutputCue148=Item 137 Pressed OutputSigType148=Digital OutputCue149=Item 138 Pressed OutputSigType149=Digital OutputCue150=Item 139 Pressed OutputSigType150=Digital OutputCue151=Item 140 Pressed OutputSigType151=Digital OutputCue152=Item 141 Pressed OutputSigType152=Digital OutputCue153=Item 142 Pressed OutputSigType153=Digital OutputCue154=Item 143 Pressed OutputSigType154=Digital OutputCue155=Item 144 Pressed OutputSigType155=Digital OutputCue156=Item 145 Pressed OutputSigType156=Digital OutputCue157=Item 146 Pressed OutputSigType157=Digital OutputCue158=Item 147 Pressed OutputSigType158=Digital OutputCue159=Item 148 Pressed OutputSigType159=Digital OutputCue160=Item 149 Pressed OutputSigType160=Digital OutputCue161=Item 150 Pressed OutputSigType161=Digital OutputCue162=Item 151 Pressed OutputSigType162=Digital OutputCue163=Item 152 Pressed OutputSigType163=Digital OutputCue164=Item 153 Pressed OutputSigType164=Digital OutputCue165=Item 154 Pressed OutputSigType165=Digital OutputCue166=Item 155 Pressed OutputSigType166=Digital OutputCue167=Item 156 Pressed OutputSigType167=Digital OutputCue168=Item 157 Pressed OutputSigType168=Digital OutputCue169=Item 158 Pressed OutputSigType169=Digital OutputCue170=Item 159 Pressed OutputSigType170=Digital OutputCue171=Item 160 Pressed OutputSigType171=Digital OutputCue172=Item 161 Pressed OutputSigType172=Digital OutputCue173=Item 162 Pressed OutputSigType173=Digital OutputCue174=Item 163 Pressed OutputSigType174=Digital OutputCue175=Item 164 Pressed OutputSigType175=Digital OutputCue176=Item 165 Pressed OutputSigType176=Digital OutputCue177=Item 166 Pressed OutputSigType177=Digital OutputCue178=Item 167 Pressed OutputSigType178=Digital OutputCue179=Item 168 Pressed OutputSigType179=Digital OutputCue180=Item 169 Pressed OutputSigType180=Digital OutputCue181=Item 170 Pressed OutputSigType181=Digital OutputCue182=Item 171 Pressed OutputSigType182=Digital OutputCue183=Item 172 Pressed OutputSigType183=Digital OutputCue184=Item 173 Pressed OutputSigType184=Digital OutputCue185=Item 174 Pressed OutputSigType185=Digital OutputCue186=Item 175 Pressed OutputSigType186=Digital OutputCue187=Item 176 Pressed OutputSigType187=Digital OutputCue188=Item 177 Pressed OutputSigType188=Digital OutputCue189=Item 178 Pressed OutputSigType189=Digital OutputCue190=Item 179 Pressed OutputSigType190=Digital OutputCue191=Item 180 Pressed OutputSigType191=Digital OutputCue192=Item 181 Pressed OutputSigType192=Digital OutputCue193=Item 182 Pressed OutputSigType193=Digital OutputCue194=Item 183 Pressed OutputSigType194=Digital OutputCue195=Item 184 Pressed OutputSigType195=Digital OutputCue196=Item 185 Pressed OutputSigType196=Digital OutputCue197=Item 186 Pressed OutputSigType197=Digital OutputCue198=Item 187 Pressed OutputSigType198=Digital OutputCue199=Item 188 Pressed OutputSigType199=Digital OutputCue200=Item 189 Pressed OutputSigType200=Digital OutputCue201=Item 190 Pressed OutputSigType201=Digital OutputCue202=Item 191 Pressed OutputSigType202=Digital OutputCue203=Item 192 Pressed OutputSigType203=Digital OutputCue204=Item 193 Pressed OutputSigType204=Digital OutputCue205=Item 194 Pressed OutputSigType205=Digital OutputCue206=Item 195 Pressed OutputSigType206=Digital OutputCue207=Item 196 Pressed OutputSigType207=Digital OutputCue208=Item 197 Pressed OutputSigType208=Digital OutputCue209=Item 198 Pressed OutputSigType209=Digital OutputCue210=Item 199 Pressed OutputSigType210=Digital OutputCue211=Item 200 Pressed OutputSigType211=Digital OutputCue212=Item 201 Pressed OutputSigType212=Digital OutputCue213=Item 202 Pressed OutputSigType213=Digital OutputCue214=Item 203 Pressed OutputSigType214=Digital OutputCue215=Item 204 Pressed OutputSigType215=Digital OutputCue216=Item 205 Pressed OutputSigType216=Digital OutputCue217=Item 206 Pressed OutputSigType217=Digital OutputCue218=Item 207 Pressed OutputSigType218=Digital OutputCue219=Item 208 Pressed OutputSigType219=Digital OutputCue220=Item 209 Pressed OutputSigType220=Digital OutputCue221=Item 210 Pressed OutputSigType221=Digital OutputCue222=Item 211 Pressed OutputSigType222=Digital OutputCue223=Item 212 Pressed OutputSigType223=Digital OutputCue224=Item 213 Pressed OutputSigType224=Digital OutputCue225=Item 214 Pressed OutputSigType225=Digital OutputCue226=Item 215 Pressed OutputSigType226=Digital OutputCue227=Item 216 Pressed OutputSigType227=Digital OutputCue228=Item 217 Pressed OutputSigType228=Digital OutputCue229=Item 218 Pressed OutputSigType229=Digital OutputCue230=Item 219 Pressed OutputSigType230=Digital OutputCue231=Item 220 Pressed OutputSigType231=Digital OutputCue232=Item 221 Pressed OutputSigType232=Digital OutputCue233=Item 222 Pressed OutputSigType233=Digital OutputCue234=Item 223 Pressed OutputSigType234=Digital OutputCue235=Item 224 Pressed OutputSigType235=Digital OutputCue236=Item 225 Pressed OutputSigType236=Digital OutputCue237=Item 226 Pressed OutputSigType237=Digital OutputCue238=Item 227 Pressed OutputSigType238=Digital OutputCue239=Item 228 Pressed OutputSigType239=Digital OutputCue240=Item 229 Pressed OutputSigType240=Digital OutputCue241=Item 230 Pressed OutputSigType241=Digital OutputCue242=Item 231 Pressed OutputSigType242=Digital OutputCue243=Item 232 Pressed OutputSigType243=Digital OutputCue244=Item 233 Pressed OutputSigType244=Digital OutputCue245=Item 234 Pressed OutputSigType245=Digital OutputCue246=Item 235 Pressed OutputSigType246=Digital OutputCue247=Item 236 Pressed OutputSigType247=Digital OutputCue248=Item 237 Pressed OutputSigType248=Digital OutputCue249=Item 238 Pressed OutputSigType249=Digital OutputCue250=Item 239 Pressed OutputSigType250=Digital OutputCue251=Item 240 Pressed OutputSigType251=Digital OutputCue252=Item 241 Pressed OutputSigType252=Digital OutputCue253=Item 242 Pressed OutputSigType253=Digital OutputCue254=Item 243 Pressed OutputSigType254=Digital OutputCue255=Item 244 Pressed OutputSigType255=Digital OutputCue256=Item 245 Pressed OutputSigType256=Digital OutputCue257=Item 246 Pressed OutputSigType257=Digital OutputCue258=Item 247 Pressed OutputSigType258=Digital OutputCue259=Item 248 Pressed OutputSigType259=Digital OutputCue260=Item 249 Pressed OutputSigType260=Digital OutputCue261=Item 250 Pressed OutputSigType261=Digital OutputCue262=Item 251 Pressed OutputSigType262=Digital OutputCue263=Item 252 Pressed OutputSigType263=Digital OutputCue264=Item 253 Pressed OutputSigType264=Digital OutputCue265=Item 254 Pressed OutputSigType265=Digital OutputCue266=Item 255 Pressed OutputSigType266=Digital OutputCue267=[~UNUSED2~] OutputSigType267=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED3~] OutputSigType2044=Digital OutputCue2045=[~UNUSED3~] OutputSigType2045=Digital OutputCue2046=[~UNUSED3~] OutputSigType2046=Digital OutputCue2047=[~UNUSED3~] OutputSigType2047=Digital OutputCue2048=[~UNUSED3~] OutputSigType2048=Digital OutputCue2049=[~UNUSED3~] OutputSigType2049=Digital OutputCue2050=[~UNUSED3~] OutputSigType2050=Digital OutputCue2051=[~UNUSED3~] OutputSigType2051=Digital OutputCue2052=[~UNUSED3~] OutputSigType2052=Digital OutputCue2053=[~UNUSED3~] OutputSigType2053=Digital OutputCue2054=[~UNUSED3~] OutputSigType2054=Digital OutputCue2055=[~UNUSED3~] OutputSigType2055=Digital OutputCue2056=[~UNUSED3~] OutputSigType2056=Digital OutputCue2057=[~UNUSED3~] OutputSigType2057=Digital OutputCue2058=[~UNUSED3~] OutputSigType2058=Digital OutputCue2059=[~UNUSED3~] OutputSigType2059=Digital OutputCue2060=[~UNUSED3~] OutputSigType2060=Digital OutputCue2061=[~UNUSED3~] OutputSigType2061=Digital OutputCue2062=[~UNUSED3~] OutputSigType2062=Digital OutputCue2063=[~UNUSED3~] OutputSigType2063=Digital OutputCue2064=[~UNUSED3~] OutputSigType2064=Digital OutputCue2065=[~UNUSED3~] OutputSigType2065=Digital OutputCue2066=[~UNUSED3~] OutputSigType2066=Digital OutputCue2067=[~UNUSED3~] OutputSigType2067=Digital OutputCue2068=[~UNUSED3~] OutputSigType2068=Digital OutputCue2069=[~UNUSED3~] OutputSigType2069=Digital OutputCue2070=[~UNUSED3~] OutputSigType2070=Digital OutputCue2071=[~UNUSED3~] OutputSigType2071=Digital OutputCue2072=[~UNUSED3~] OutputSigType2072=Digital OutputCue2073=[~UNUSED3~] OutputSigType2073=Digital OutputCue2074=[~UNUSED3~] OutputSigType2074=Digital OutputCue2075=[~UNUSED3~] OutputSigType2075=Digital OutputCue2076=[~UNUSED3~] OutputSigType2076=Digital OutputCue2077=[~UNUSED3~] OutputSigType2077=Digital OutputCue2078=[~UNUSED3~] OutputSigType2078=Digital OutputCue2079=[~UNUSED3~] OutputSigType2079=Digital OutputCue2080=[~UNUSED3~] OutputSigType2080=Digital OutputCue2081=[~UNUSED3~] OutputSigType2081=Digital OutputCue2082=[~UNUSED3~] OutputSigType2082=Digital OutputCue2083=[~UNUSED3~] OutputSigType2083=Digital OutputCue2084=[~UNUSED3~] OutputSigType2084=Digital OutputCue2085=[~UNUSED3~] OutputSigType2085=Digital OutputCue2086=[~UNUSED3~] OutputSigType2086=Digital OutputCue2087=[~UNUSED3~] OutputSigType2087=Digital OutputCue2088=[~UNUSED3~] OutputSigType2088=Digital OutputCue2089=[~UNUSED3~] OutputSigType2089=Digital OutputCue2090=[~UNUSED3~] OutputSigType2090=Digital OutputCue2091=[~UNUSED3~] OutputSigType2091=Digital OutputCue2092=[~UNUSED3~] OutputSigType2092=Digital OutputCue2093=[~UNUSED3~] OutputSigType2093=Digital OutputCue2094=[~UNUSED3~] OutputSigType2094=Digital OutputCue2095=[~UNUSED3~] OutputSigType2095=Digital OutputCue2096=[~UNUSED3~] OutputSigType2096=Digital OutputCue2097=[~UNUSED3~] OutputSigType2097=Digital OutputCue2098=[~UNUSED3~] OutputSigType2098=Digital OutputCue2099=[~UNUSED3~] OutputSigType2099=Digital OutputCue2100=[~UNUSED3~] OutputSigType2100=Digital OutputCue2101=[~UNUSED3~] OutputSigType2101=Digital OutputCue2102=[~UNUSED3~] OutputSigType2102=Digital OutputCue2103=[~UNUSED3~] OutputSigType2103=Digital OutputCue2104=[~UNUSED3~] OutputSigType2104=Digital OutputCue2105=[~UNUSED3~] OutputSigType2105=Digital OutputCue2106=[~UNUSED3~] OutputSigType2106=Digital OutputCue2107=[~UNUSED3~] OutputSigType2107=Digital OutputCue2108=[~UNUSED3~] OutputSigType2108=Digital OutputCue2109=[~UNUSED3~] OutputSigType2109=Digital OutputCue2110=[~UNUSED3~] OutputSigType2110=Digital OutputCue2111=[~UNUSED3~] OutputSigType2111=Digital OutputCue2112=[~UNUSED3~] OutputSigType2112=Digital OutputCue2113=[~UNUSED3~] OutputSigType2113=Digital OutputCue2114=[~UNUSED3~] OutputSigType2114=Digital OutputCue2115=[~UNUSED3~] OutputSigType2115=Digital OutputCue2116=[~UNUSED3~] OutputSigType2116=Digital OutputCue2117=[~UNUSED3~] OutputSigType2117=Digital OutputCue2118=[~UNUSED3~] OutputSigType2118=Digital OutputCue2119=[~UNUSED3~] OutputSigType2119=Digital OutputCue2120=[~UNUSED3~] OutputSigType2120=Digital OutputCue2121=[~UNUSED3~] OutputSigType2121=Digital OutputCue2122=[~UNUSED3~] OutputSigType2122=Digital OutputCue2123=[~UNUSED3~] OutputSigType2123=Digital OutputCue2124=[~UNUSED3~] OutputSigType2124=Digital OutputCue2125=[~UNUSED3~] OutputSigType2125=Digital OutputCue2126=[~UNUSED3~] OutputSigType2126=Digital OutputCue2127=[~UNUSED3~] OutputSigType2127=Digital OutputCue2128=[~UNUSED3~] OutputSigType2128=Digital OutputCue2129=[~UNUSED3~] OutputSigType2129=Digital OutputCue2130=[~UNUSED3~] OutputSigType2130=Digital OutputCue2131=[~UNUSED3~] OutputSigType2131=Digital OutputCue2132=[~UNUSED3~] OutputSigType2132=Digital OutputCue2133=[~UNUSED3~] OutputSigType2133=Digital OutputCue2134=[~UNUSED3~] OutputSigType2134=Digital OutputCue2135=[~UNUSED3~] OutputSigType2135=Digital OutputCue2136=[~UNUSED3~] OutputSigType2136=Digital OutputCue2137=[~UNUSED3~] OutputSigType2137=Digital OutputCue2138=[~UNUSED3~] OutputSigType2138=Digital OutputCue2139=[~UNUSED3~] OutputSigType2139=Digital OutputCue2140=[~UNUSED3~] OutputSigType2140=Digital OutputCue2141=[~UNUSED3~] OutputSigType2141=Digital OutputCue2142=[~UNUSED3~] OutputSigType2142=Digital OutputCue2143=[~UNUSED3~] OutputSigType2143=Digital OutputCue2144=[~UNUSED3~] OutputSigType2144=Digital OutputCue2145=[~UNUSED3~] OutputSigType2145=Digital OutputCue2146=[~UNUSED3~] OutputSigType2146=Digital OutputCue2147=[~UNUSED3~] OutputSigType2147=Digital OutputCue2148=[~UNUSED3~] OutputSigType2148=Digital OutputCue2149=[~UNUSED3~] OutputSigType2149=Digital OutputCue2150=[~UNUSED3~] OutputSigType2150=Digital OutputCue2151=[~UNUSED3~] OutputSigType2151=Digital OutputCue2152=[~UNUSED3~] OutputSigType2152=Digital OutputCue2153=[~UNUSED3~] OutputSigType2153=Digital OutputCue2154=[~UNUSED3~] OutputSigType2154=Digital OutputCue2155=[~UNUSED3~] OutputSigType2155=Digital OutputCue2156=[~UNUSED3~] OutputSigType2156=Digital OutputCue2157=[~UNUSED3~] OutputSigType2157=Digital OutputCue2158=[~UNUSED3~] OutputSigType2158=Digital OutputCue2159=[~UNUSED3~] OutputSigType2159=Digital OutputCue2160=[~UNUSED3~] OutputSigType2160=Digital OutputCue2161=[~UNUSED3~] OutputSigType2161=Digital OutputCue2162=[~UNUSED3~] OutputSigType2162=Digital OutputCue2163=[~UNUSED3~] OutputSigType2163=Digital OutputCue2164=[~UNUSED3~] OutputSigType2164=Digital OutputCue2165=[~UNUSED3~] OutputSigType2165=Digital OutputCue2166=[~UNUSED3~] OutputSigType2166=Digital OutputCue2167=[~UNUSED3~] OutputSigType2167=Digital OutputCue2168=[~UNUSED3~] OutputSigType2168=Digital OutputCue2169=[~UNUSED3~] OutputSigType2169=Digital OutputCue2170=[~UNUSED3~] OutputSigType2170=Digital OutputCue2171=[~UNUSED3~] OutputSigType2171=Digital OutputCue2172=[~UNUSED3~] OutputSigType2172=Digital OutputCue2173=[~UNUSED3~] OutputSigType2173=Digital OutputCue2174=[~UNUSED3~] OutputSigType2174=Digital OutputCue2175=[~UNUSED3~] OutputSigType2175=Digital OutputCue2176=[~UNUSED3~] OutputSigType2176=Digital OutputCue2177=[~UNUSED3~] OutputSigType2177=Digital OutputCue2178=[~UNUSED3~] OutputSigType2178=Digital OutputCue2179=[~UNUSED3~] OutputSigType2179=Digital OutputCue2180=[~UNUSED3~] OutputSigType2180=Digital OutputCue2181=[~UNUSED3~] OutputSigType2181=Digital OutputCue2182=[~UNUSED3~] OutputSigType2182=Digital OutputCue2183=[~UNUSED3~] OutputSigType2183=Digital OutputCue2184=[~UNUSED3~] OutputSigType2184=Digital OutputCue2185=[~UNUSED3~] OutputSigType2185=Digital OutputCue2186=[~UNUSED3~] OutputSigType2186=Digital OutputCue2187=[~UNUSED3~] OutputSigType2187=Digital OutputCue2188=[~UNUSED3~] OutputSigType2188=Digital OutputCue2189=[~UNUSED3~] OutputSigType2189=Digital OutputCue2190=[~UNUSED3~] OutputSigType2190=Digital OutputCue2191=[~UNUSED3~] OutputSigType2191=Digital OutputCue2192=[~UNUSED3~] OutputSigType2192=Digital OutputCue2193=[~UNUSED3~] OutputSigType2193=Digital OutputCue2194=[~UNUSED3~] OutputSigType2194=Digital OutputCue2195=[~UNUSED3~] OutputSigType2195=Digital OutputCue2196=[~UNUSED3~] OutputSigType2196=Digital OutputCue2197=[~UNUSED3~] OutputSigType2197=Digital OutputCue2198=[~UNUSED3~] OutputSigType2198=Digital OutputCue2199=[~UNUSED3~] OutputSigType2199=Digital OutputCue2200=[~UNUSED3~] OutputSigType2200=Digital OutputCue2201=[~UNUSED3~] OutputSigType2201=Digital OutputCue2202=[~UNUSED3~] OutputSigType2202=Digital OutputCue2203=[~UNUSED3~] OutputSigType2203=Digital OutputCue2204=[~UNUSED3~] OutputSigType2204=Digital OutputCue2205=[~UNUSED3~] OutputSigType2205=Digital OutputCue2206=[~UNUSED3~] OutputSigType2206=Digital OutputCue2207=[~UNUSED3~] OutputSigType2207=Digital OutputCue2208=[~UNUSED3~] OutputSigType2208=Digital OutputCue2209=[~UNUSED3~] OutputSigType2209=Digital OutputCue2210=[~UNUSED3~] OutputSigType2210=Digital OutputCue2211=[~UNUSED3~] OutputSigType2211=Digital OutputCue2212=[~UNUSED3~] OutputSigType2212=Digital OutputCue2213=[~UNUSED3~] OutputSigType2213=Digital OutputCue2214=[~UNUSED3~] OutputSigType2214=Digital OutputCue2215=[~UNUSED3~] OutputSigType2215=Digital OutputCue2216=[~UNUSED3~] OutputSigType2216=Digital OutputCue2217=[~UNUSED3~] OutputSigType2217=Digital OutputCue2218=[~UNUSED3~] OutputSigType2218=Digital OutputCue2219=[~UNUSED3~] OutputSigType2219=Digital OutputCue2220=[~UNUSED3~] OutputSigType2220=Digital OutputCue2221=[~UNUSED3~] OutputSigType2221=Digital OutputCue2222=[~UNUSED3~] OutputSigType2222=Digital OutputCue2223=[~UNUSED3~] OutputSigType2223=Digital OutputCue2224=[~UNUSED3~] OutputSigType2224=Digital OutputCue2225=[~UNUSED3~] OutputSigType2225=Digital OutputCue2226=[~UNUSED3~] OutputSigType2226=Digital OutputCue2227=[~UNUSED3~] OutputSigType2227=Digital OutputCue2228=[~UNUSED3~] OutputSigType2228=Digital OutputCue2229=[~UNUSED3~] OutputSigType2229=Digital OutputCue2230=[~UNUSED3~] OutputSigType2230=Digital OutputCue2231=[~UNUSED3~] OutputSigType2231=Digital OutputCue2232=[~UNUSED3~] OutputSigType2232=Digital OutputCue2233=[~UNUSED3~] OutputSigType2233=Digital OutputCue2234=[~UNUSED3~] OutputSigType2234=Digital OutputCue2235=[~UNUSED3~] OutputSigType2235=Digital OutputCue2236=[~UNUSED3~] OutputSigType2236=Digital OutputCue2237=[~UNUSED3~] OutputSigType2237=Digital OutputCue2238=[~UNUSED3~] OutputSigType2238=Digital OutputCue2239=[~UNUSED3~] OutputSigType2239=Digital OutputCue2240=[~UNUSED3~] OutputSigType2240=Digital OutputCue2241=[~UNUSED3~] OutputSigType2241=Digital OutputCue2242=[~UNUSED3~] OutputSigType2242=Digital OutputCue2243=[~UNUSED3~] OutputSigType2243=Digital OutputCue2244=[~UNUSED3~] OutputSigType2244=Digital OutputCue2245=[~UNUSED3~] OutputSigType2245=Digital OutputCue2246=[~UNUSED3~] OutputSigType2246=Digital OutputCue2247=[~UNUSED3~] OutputSigType2247=Digital OutputCue2248=[~UNUSED3~] OutputSigType2248=Digital OutputCue2249=[~UNUSED3~] OutputSigType2249=Digital OutputCue2250=[~UNUSED3~] OutputSigType2250=Digital OutputCue2251=[~UNUSED3~] OutputSigType2251=Digital OutputCue2252=[~UNUSED3~] OutputSigType2252=Digital OutputCue2253=[~UNUSED3~] OutputSigType2253=Digital OutputCue2254=[~UNUSED3~] OutputSigType2254=Digital OutputCue2255=[~UNUSED3~] OutputSigType2255=Digital OutputCue2256=[~UNUSED3~] OutputSigType2256=Digital OutputCue2257=[~UNUSED3~] OutputSigType2257=Digital OutputCue2258=[~UNUSED3~] OutputSigType2258=Digital OutputCue2259=[~UNUSED3~] OutputSigType2259=Digital OutputCue2260=[~UNUSED3~] OutputSigType2260=Digital OutputCue2261=[~UNUSED3~] OutputSigType2261=Digital OutputCue2262=[~UNUSED3~] OutputSigType2262=Digital OutputCue2263=[~UNUSED3~] OutputSigType2263=Digital OutputCue2264=[~UNUSED3~] OutputSigType2264=Digital OutputCue2265=[~UNUSED3~] OutputSigType2265=Digital OutputCue2266=[~UNUSED3~] OutputSigType2266=Digital OutputCue2267=[~UNUSED3~] OutputSigType2267=Digital OutputCue2268=[~UNUSED3~] OutputSigType2268=Digital OutputCue2269=[~UNUSED2~] OutputSigType2269=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED3~] OutputSigType4026=Digital OutputCue4027=[~UNUSED3~] OutputSigType4027=Digital OutputCue4028=[~UNUSED3~] OutputSigType4028=Digital OutputCue4029=[~UNUSED3~] OutputSigType4029=Digital OutputCue4030=[~UNUSED3~] OutputSigType4030=Digital OutputCue4031=[~UNUSED3~] OutputSigType4031=Digital OutputCue4032=[~UNUSED3~] OutputSigType4032=Digital OutputCue4033=[~UNUSED3~] OutputSigType4033=Digital OutputCue4034=[~UNUSED3~] OutputSigType4034=Digital OutputCue4035=[~UNUSED3~] OutputSigType4035=Digital OutputCue4036=[~UNUSED3~] OutputSigType4036=Digital OutputCue4037=[~UNUSED3~] OutputSigType4037=Digital OutputCue4038=[~UNUSED3~] OutputSigType4038=Digital OutputCue4039=[~UNUSED3~] OutputSigType4039=Digital OutputCue4040=[~UNUSED3~] OutputSigType4040=Digital OutputCue4041=[~UNUSED3~] OutputSigType4041=Digital OutputCue4042=[~UNUSED3~] OutputSigType4042=Digital OutputCue4043=[~UNUSED3~] OutputSigType4043=Digital OutputCue4044=[~UNUSED3~] OutputSigType4044=Digital OutputCue4045=[~UNUSED3~] OutputSigType4045=Digital OutputCue4046=[~UNUSED3~] OutputSigType4046=Digital OutputCue4047=[~UNUSED3~] OutputSigType4047=Digital OutputCue4048=[~UNUSED3~] OutputSigType4048=Digital OutputCue4049=[~UNUSED3~] OutputSigType4049=Digital OutputCue4050=[~UNUSED3~] OutputSigType4050=Digital OutputCue4051=[~UNUSED3~] OutputSigType4051=Digital OutputCue4052=[~UNUSED3~] OutputSigType4052=Digital OutputCue4053=[~UNUSED3~] OutputSigType4053=Digital OutputCue4054=[~UNUSED3~] OutputSigType4054=Digital OutputCue4055=[~UNUSED3~] OutputSigType4055=Digital OutputCue4056=[~UNUSED3~] OutputSigType4056=Digital OutputCue4057=[~UNUSED3~] OutputSigType4057=Digital OutputCue4058=[~UNUSED3~] OutputSigType4058=Digital OutputCue4059=[~UNUSED3~] OutputSigType4059=Digital OutputCue4060=[~UNUSED3~] OutputSigType4060=Digital OutputCue4061=[~UNUSED3~] OutputSigType4061=Digital OutputCue4062=[~UNUSED3~] OutputSigType4062=Digital OutputCue4063=[~UNUSED3~] OutputSigType4063=Digital OutputCue4064=[~UNUSED3~] OutputSigType4064=Digital OutputCue4065=[~UNUSED3~] OutputSigType4065=Digital OutputCue4066=[~UNUSED3~] OutputSigType4066=Digital OutputCue4067=[~UNUSED3~] OutputSigType4067=Digital OutputCue4068=[~UNUSED3~] OutputSigType4068=Digital OutputCue4069=[~UNUSED3~] OutputSigType4069=Digital OutputCue4070=[~UNUSED3~] OutputSigType4070=Digital OutputCue4071=[~UNUSED3~] OutputSigType4071=Digital OutputCue4072=[~UNUSED3~] OutputSigType4072=Digital OutputCue4073=[~UNUSED3~] OutputSigType4073=Digital OutputCue4074=[~UNUSED3~] OutputSigType4074=Digital OutputCue4075=[~UNUSED3~] OutputSigType4075=Digital OutputCue4076=[~UNUSED3~] OutputSigType4076=Digital OutputCue4077=[~UNUSED3~] OutputSigType4077=Digital OutputCue4078=[~UNUSED3~] OutputSigType4078=Digital OutputCue4079=[~UNUSED3~] OutputSigType4079=Digital OutputCue4080=[~UNUSED3~] OutputSigType4080=Digital OutputCue4081=[~UNUSED3~] OutputSigType4081=Digital OutputCue4082=[~UNUSED3~] OutputSigType4082=Digital OutputCue4083=[~UNUSED3~] OutputSigType4083=Digital OutputCue4084=[~UNUSED3~] OutputSigType4084=Digital OutputCue4085=[~UNUSED3~] OutputSigType4085=Digital OutputCue4086=[~UNUSED3~] OutputSigType4086=Digital OutputCue4087=[~UNUSED3~] OutputSigType4087=Digital OutputCue4088=[~UNUSED3~] OutputSigType4088=Digital OutputCue4089=[~UNUSED3~] OutputSigType4089=Digital OutputCue4090=[~UNUSED3~] OutputSigType4090=Digital OutputCue4091=[~UNUSED3~] OutputSigType4091=Digital OutputCue4092=[~UNUSED3~] OutputSigType4092=Digital OutputCue4093=[~UNUSED3~] OutputSigType4093=Digital OutputCue4094=[~UNUSED3~] OutputSigType4094=Digital OutputCue4095=[~UNUSED3~] OutputSigType4095=Digital OutputCue4096=[~UNUSED3~] OutputSigType4096=Digital OutputCue4097=[~UNUSED3~] OutputSigType4097=Digital OutputCue4098=[~UNUSED3~] OutputSigType4098=Digital OutputCue4099=[~UNUSED3~] OutputSigType4099=Digital OutputCue4100=[~UNUSED3~] OutputSigType4100=Digital OutputCue4101=[~UNUSED3~] OutputSigType4101=Digital OutputCue4102=[~UNUSED3~] OutputSigType4102=Digital OutputCue4103=[~UNUSED3~] OutputSigType4103=Digital OutputCue4104=[~UNUSED3~] OutputSigType4104=Digital OutputCue4105=[~UNUSED3~] OutputSigType4105=Digital OutputCue4106=[~UNUSED3~] OutputSigType4106=Digital OutputCue4107=[~UNUSED3~] OutputSigType4107=Digital OutputCue4108=[~UNUSED3~] OutputSigType4108=Digital OutputCue4109=[~UNUSED3~] OutputSigType4109=Digital OutputCue4110=[~UNUSED3~] OutputSigType4110=Digital OutputCue4111=[~UNUSED3~] OutputSigType4111=Digital OutputCue4112=[~UNUSED3~] OutputSigType4112=Digital OutputCue4113=[~UNUSED3~] OutputSigType4113=Digital OutputCue4114=[~UNUSED3~] OutputSigType4114=Digital OutputCue4115=[~UNUSED3~] OutputSigType4115=Digital OutputCue4116=[~UNUSED3~] OutputSigType4116=Digital OutputCue4117=[~UNUSED3~] OutputSigType4117=Digital OutputCue4118=[~UNUSED3~] OutputSigType4118=Digital OutputCue4119=[~UNUSED3~] OutputSigType4119=Digital OutputCue4120=[~UNUSED3~] OutputSigType4120=Digital OutputCue4121=[~UNUSED3~] OutputSigType4121=Digital OutputCue4122=[~UNUSED3~] OutputSigType4122=Digital OutputCue4123=[~UNUSED3~] OutputSigType4123=Digital OutputCue4124=[~UNUSED3~] OutputSigType4124=Digital OutputCue4125=[~UNUSED3~] OutputSigType4125=Digital OutputCue4126=[~UNUSED3~] OutputSigType4126=Digital OutputCue4127=[~UNUSED3~] OutputSigType4127=Digital OutputCue4128=[~UNUSED3~] OutputSigType4128=Digital OutputCue4129=[~UNUSED3~] OutputSigType4129=Digital OutputCue4130=[~UNUSED3~] OutputSigType4130=Digital OutputCue4131=[~UNUSED3~] OutputSigType4131=Digital OutputCue4132=[~UNUSED3~] OutputSigType4132=Digital OutputCue4133=[~UNUSED3~] OutputSigType4133=Digital OutputCue4134=[~UNUSED3~] OutputSigType4134=Digital OutputCue4135=[~UNUSED3~] OutputSigType4135=Digital OutputCue4136=[~UNUSED3~] OutputSigType4136=Digital OutputCue4137=[~UNUSED3~] OutputSigType4137=Digital OutputCue4138=[~UNUSED3~] OutputSigType4138=Digital OutputCue4139=[~UNUSED3~] OutputSigType4139=Digital OutputCue4140=[~UNUSED3~] OutputSigType4140=Digital OutputCue4141=[~UNUSED3~] OutputSigType4141=Digital OutputCue4142=[~UNUSED3~] OutputSigType4142=Digital OutputCue4143=[~UNUSED3~] OutputSigType4143=Digital OutputCue4144=[~UNUSED3~] OutputSigType4144=Digital OutputCue4145=[~UNUSED3~] OutputSigType4145=Digital OutputCue4146=[~UNUSED3~] OutputSigType4146=Digital OutputCue4147=[~UNUSED3~] OutputSigType4147=Digital OutputCue4148=[~UNUSED3~] OutputSigType4148=Digital OutputCue4149=[~UNUSED3~] OutputSigType4149=Digital OutputCue4150=[~UNUSED3~] OutputSigType4150=Digital OutputCue4151=[~UNUSED3~] OutputSigType4151=Digital OutputCue4152=[~UNUSED3~] OutputSigType4152=Digital OutputCue4153=[~UNUSED3~] OutputSigType4153=Digital OutputCue4154=[~UNUSED3~] OutputSigType4154=Digital OutputCue4155=[~UNUSED3~] OutputSigType4155=Digital OutputCue4156=[~UNUSED3~] OutputSigType4156=Digital OutputCue4157=[~UNUSED3~] OutputSigType4157=Digital OutputCue4158=[~UNUSED3~] OutputSigType4158=Digital OutputCue4159=[~UNUSED3~] OutputSigType4159=Digital OutputCue4160=[~UNUSED3~] OutputSigType4160=Digital OutputCue4161=[~UNUSED3~] OutputSigType4161=Digital OutputCue4162=[~UNUSED3~] OutputSigType4162=Digital OutputCue4163=[~UNUSED3~] OutputSigType4163=Digital OutputCue4164=[~UNUSED3~] OutputSigType4164=Digital OutputCue4165=[~UNUSED3~] OutputSigType4165=Digital OutputCue4166=[~UNUSED3~] OutputSigType4166=Digital OutputCue4167=[~UNUSED3~] OutputSigType4167=Digital OutputCue4168=[~UNUSED3~] OutputSigType4168=Digital OutputCue4169=[~UNUSED3~] OutputSigType4169=Digital OutputCue4170=[~UNUSED3~] OutputSigType4170=Digital OutputCue4171=[~UNUSED3~] OutputSigType4171=Digital OutputCue4172=[~UNUSED3~] OutputSigType4172=Digital OutputCue4173=[~UNUSED3~] OutputSigType4173=Digital OutputCue4174=[~UNUSED3~] OutputSigType4174=Digital OutputCue4175=[~UNUSED3~] OutputSigType4175=Digital OutputCue4176=[~UNUSED3~] OutputSigType4176=Digital OutputCue4177=[~UNUSED3~] OutputSigType4177=Digital OutputCue4178=[~UNUSED3~] OutputSigType4178=Digital OutputCue4179=[~UNUSED3~] OutputSigType4179=Digital OutputCue4180=[~UNUSED3~] OutputSigType4180=Digital OutputCue4181=[~UNUSED3~] OutputSigType4181=Digital OutputCue4182=[~UNUSED3~] OutputSigType4182=Digital OutputCue4183=[~UNUSED3~] OutputSigType4183=Digital OutputCue4184=[~UNUSED3~] OutputSigType4184=Digital OutputCue4185=[~UNUSED3~] OutputSigType4185=Digital OutputCue4186=[~UNUSED3~] OutputSigType4186=Digital OutputCue4187=[~UNUSED3~] OutputSigType4187=Digital OutputCue4188=[~UNUSED3~] OutputSigType4188=Digital OutputCue4189=[~UNUSED3~] OutputSigType4189=Digital OutputCue4190=[~UNUSED3~] OutputSigType4190=Digital OutputCue4191=[~UNUSED3~] OutputSigType4191=Digital OutputCue4192=[~UNUSED3~] OutputSigType4192=Digital OutputCue4193=[~UNUSED3~] OutputSigType4193=Digital OutputCue4194=[~UNUSED3~] OutputSigType4194=Digital OutputCue4195=[~UNUSED3~] OutputSigType4195=Digital OutputCue4196=[~UNUSED3~] OutputSigType4196=Digital OutputCue4197=[~UNUSED3~] OutputSigType4197=Digital OutputCue4198=[~UNUSED3~] OutputSigType4198=Digital OutputCue4199=[~UNUSED3~] OutputSigType4199=Digital OutputCue4200=[~UNUSED3~] OutputSigType4200=Digital OutputCue4201=[~UNUSED3~] OutputSigType4201=Digital OutputCue4202=[~UNUSED3~] OutputSigType4202=Digital OutputCue4203=[~UNUSED3~] OutputSigType4203=Digital OutputCue4204=[~UNUSED3~] OutputSigType4204=Digital OutputCue4205=[~UNUSED3~] OutputSigType4205=Digital OutputCue4206=[~UNUSED3~] OutputSigType4206=Digital OutputCue4207=[~UNUSED3~] OutputSigType4207=Digital OutputCue4208=[~UNUSED3~] OutputSigType4208=Digital OutputCue4209=[~UNUSED3~] OutputSigType4209=Digital OutputCue4210=[~UNUSED3~] OutputSigType4210=Digital OutputCue4211=[~UNUSED3~] OutputSigType4211=Digital OutputCue4212=[~UNUSED3~] OutputSigType4212=Digital OutputCue4213=[~UNUSED3~] OutputSigType4213=Digital OutputCue4214=[~UNUSED3~] OutputSigType4214=Digital OutputCue4215=[~UNUSED3~] OutputSigType4215=Digital OutputCue4216=[~UNUSED3~] OutputSigType4216=Digital OutputCue4217=[~UNUSED3~] OutputSigType4217=Digital OutputCue4218=[~UNUSED3~] OutputSigType4218=Digital OutputCue4219=[~UNUSED3~] OutputSigType4219=Digital OutputCue4220=[~UNUSED3~] OutputSigType4220=Digital OutputCue4221=[~UNUSED3~] OutputSigType4221=Digital OutputCue4222=[~UNUSED3~] OutputSigType4222=Digital OutputCue4223=[~UNUSED3~] OutputSigType4223=Digital OutputCue4224=[~UNUSED3~] OutputSigType4224=Digital OutputCue4225=[~UNUSED3~] OutputSigType4225=Digital OutputCue4226=[~UNUSED3~] OutputSigType4226=Digital OutputCue4227=[~UNUSED3~] OutputSigType4227=Digital OutputCue4228=[~UNUSED3~] OutputSigType4228=Digital OutputCue4229=[~UNUSED3~] OutputSigType4229=Digital OutputCue4230=[~UNUSED3~] OutputSigType4230=Digital OutputCue4231=[~UNUSED3~] OutputSigType4231=Digital OutputCue4232=[~UNUSED3~] OutputSigType4232=Digital OutputCue4233=[~UNUSED3~] OutputSigType4233=Digital OutputCue4234=[~UNUSED3~] OutputSigType4234=Digital OutputCue4235=[~UNUSED3~] OutputSigType4235=Digital OutputCue4236=[~UNUSED3~] OutputSigType4236=Digital OutputCue4237=[~UNUSED3~] OutputSigType4237=Digital OutputCue4238=[~UNUSED3~] OutputSigType4238=Digital OutputCue4239=[~UNUSED3~] OutputSigType4239=Digital OutputCue4240=[~UNUSED3~] OutputSigType4240=Digital OutputCue4241=[~UNUSED3~] OutputSigType4241=Digital OutputCue4242=[~UNUSED3~] OutputSigType4242=Digital OutputCue4243=[~UNUSED3~] OutputSigType4243=Digital OutputCue4244=[~UNUSED3~] OutputSigType4244=Digital OutputCue4245=[~UNUSED3~] OutputSigType4245=Digital OutputCue4246=[~UNUSED3~] OutputSigType4246=Digital OutputCue4247=[~UNUSED3~] OutputSigType4247=Digital OutputCue4248=[~UNUSED3~] OutputSigType4248=Digital OutputCue4249=[~UNUSED3~] OutputSigType4249=Digital OutputCue4250=[~UNUSED3~] OutputSigType4250=Digital OutputCue4251=[~UNUSED3~] OutputSigType4251=Digital OutputCue4252=[~UNUSED3~] OutputSigType4252=Digital OutputCue4253=[~UNUSED3~] OutputSigType4253=Digital OutputCue4254=[~UNUSED3~] OutputSigType4254=Digital OutputCue4255=[~UNUSED3~] OutputSigType4255=Digital OutputCue4256=[~UNUSED3~] OutputSigType4256=Digital OutputCue4257=[~UNUSED3~] OutputSigType4257=Digital OutputCue4258=[~UNUSED3~] OutputSigType4258=Digital OutputCue4259=[~UNUSED3~] OutputSigType4259=Digital OutputCue4260=[~UNUSED3~] OutputSigType4260=Digital OutputCue4261=[~UNUSED3~] OutputSigType4261=Digital OutputCue4262=[~UNUSED3~] OutputSigType4262=Digital OutputCue4263=[~UNUSED3~] OutputSigType4263=Digital OutputCue4264=[~UNUSED3~] OutputSigType4264=Digital OutputCue4265=[~UNUSED3~] OutputSigType4265=Digital OutputCue4266=[~UNUSED3~] OutputSigType4266=Digital OutputCue4267=[~UNUSED3~] OutputSigType4267=Digital OutputCue4268=[~UNUSED3~] OutputSigType4268=Digital OutputCue4269=[~UNUSED3~] OutputSigType4269=Digital OutputCue4270=[~UNUSED3~] OutputSigType4270=Digital OutputCue4271=[~UNUSED2~] OutputSigType4271=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=Set Item 11 Icon Analog InputList2SigType22=Analog InputList2Cue23=Set Item 12 Icon Analog InputList2SigType23=Analog InputList2Cue24=Set Item 13 Icon Analog InputList2SigType24=Analog InputList2Cue25=Set Item 14 Icon Analog InputList2SigType25=Analog InputList2Cue26=Set Item 15 Icon Analog InputList2SigType26=Analog InputList2Cue27=Set Item 16 Icon Analog InputList2SigType27=Analog InputList2Cue28=Set Item 17 Icon Analog InputList2SigType28=Analog InputList2Cue29=Set Item 18 Icon Analog InputList2SigType29=Analog InputList2Cue30=Set Item 19 Icon Analog InputList2SigType30=Analog InputList2Cue31=Set Item 20 Icon Analog InputList2SigType31=Analog InputList2Cue32=Set Item 21 Icon Analog InputList2SigType32=Analog InputList2Cue33=Set Item 22 Icon Analog InputList2SigType33=Analog InputList2Cue34=Set Item 23 Icon Analog InputList2SigType34=Analog InputList2Cue35=Set Item 24 Icon Analog InputList2SigType35=Analog InputList2Cue36=Set Item 25 Icon Analog InputList2SigType36=Analog InputList2Cue37=Set Item 26 Icon Analog InputList2SigType37=Analog InputList2Cue38=Set Item 27 Icon Analog InputList2SigType38=Analog InputList2Cue39=Set Item 28 Icon Analog InputList2SigType39=Analog InputList2Cue40=Set Item 29 Icon Analog InputList2SigType40=Analog InputList2Cue41=Set Item 30 Icon Analog InputList2SigType41=Analog InputList2Cue42=Set Item 31 Icon Analog InputList2SigType42=Analog InputList2Cue43=Set Item 32 Icon Analog InputList2SigType43=Analog InputList2Cue44=Set Item 33 Icon Analog InputList2SigType44=Analog InputList2Cue45=Set Item 34 Icon Analog InputList2SigType45=Analog InputList2Cue46=Set Item 35 Icon Analog InputList2SigType46=Analog InputList2Cue47=Set Item 36 Icon Analog InputList2SigType47=Analog InputList2Cue48=Set Item 37 Icon Analog InputList2SigType48=Analog InputList2Cue49=Set Item 38 Icon Analog InputList2SigType49=Analog InputList2Cue50=Set Item 39 Icon Analog InputList2SigType50=Analog InputList2Cue51=Set Item 40 Icon Analog InputList2SigType51=Analog InputList2Cue52=Set Item 41 Icon Analog InputList2SigType52=Analog InputList2Cue53=Set Item 42 Icon Analog InputList2SigType53=Analog InputList2Cue54=Set Item 43 Icon Analog InputList2SigType54=Analog InputList2Cue55=Set Item 44 Icon Analog InputList2SigType55=Analog InputList2Cue56=Set Item 45 Icon Analog InputList2SigType56=Analog InputList2Cue57=Set Item 46 Icon Analog InputList2SigType57=Analog InputList2Cue58=Set Item 47 Icon Analog InputList2SigType58=Analog InputList2Cue59=Set Item 48 Icon Analog InputList2SigType59=Analog InputList2Cue60=Set Item 49 Icon Analog InputList2SigType60=Analog InputList2Cue61=Set Item 50 Icon Analog InputList2SigType61=Analog InputList2Cue62=Set Item 51 Icon Analog InputList2SigType62=Analog InputList2Cue63=Set Item 52 Icon Analog InputList2SigType63=Analog InputList2Cue64=Set Item 53 Icon Analog InputList2SigType64=Analog InputList2Cue65=Set Item 54 Icon Analog InputList2SigType65=Analog InputList2Cue66=Set Item 55 Icon Analog InputList2SigType66=Analog InputList2Cue67=Set Item 56 Icon Analog InputList2SigType67=Analog InputList2Cue68=Set Item 57 Icon Analog InputList2SigType68=Analog InputList2Cue69=Set Item 58 Icon Analog InputList2SigType69=Analog InputList2Cue70=Set Item 59 Icon Analog InputList2SigType70=Analog InputList2Cue71=Set Item 60 Icon Analog InputList2SigType71=Analog InputList2Cue72=Set Item 61 Icon Analog InputList2SigType72=Analog InputList2Cue73=Set Item 62 Icon Analog InputList2SigType73=Analog InputList2Cue74=Set Item 63 Icon Analog InputList2SigType74=Analog InputList2Cue75=Set Item 64 Icon Analog InputList2SigType75=Analog InputList2Cue76=Set Item 65 Icon Analog InputList2SigType76=Analog InputList2Cue77=Set Item 66 Icon Analog InputList2SigType77=Analog InputList2Cue78=Set Item 67 Icon Analog InputList2SigType78=Analog InputList2Cue79=Set Item 68 Icon Analog InputList2SigType79=Analog InputList2Cue80=Set Item 69 Icon Analog InputList2SigType80=Analog InputList2Cue81=Set Item 70 Icon Analog InputList2SigType81=Analog InputList2Cue82=Set Item 71 Icon Analog InputList2SigType82=Analog InputList2Cue83=Set Item 72 Icon Analog InputList2SigType83=Analog InputList2Cue84=Set Item 73 Icon Analog InputList2SigType84=Analog InputList2Cue85=Set Item 74 Icon Analog InputList2SigType85=Analog InputList2Cue86=Set Item 75 Icon Analog InputList2SigType86=Analog InputList2Cue87=Set Item 76 Icon Analog InputList2SigType87=Analog InputList2Cue88=Set Item 77 Icon Analog InputList2SigType88=Analog InputList2Cue89=Set Item 78 Icon Analog InputList2SigType89=Analog InputList2Cue90=Set Item 79 Icon Analog InputList2SigType90=Analog InputList2Cue91=Set Item 80 Icon Analog InputList2SigType91=Analog InputList2Cue92=Set Item 81 Icon Analog InputList2SigType92=Analog InputList2Cue93=Set Item 82 Icon Analog InputList2SigType93=Analog InputList2Cue94=Set Item 83 Icon Analog InputList2SigType94=Analog InputList2Cue95=Set Item 84 Icon Analog InputList2SigType95=Analog InputList2Cue96=Set Item 85 Icon Analog InputList2SigType96=Analog InputList2Cue97=Set Item 86 Icon Analog InputList2SigType97=Analog InputList2Cue98=Set Item 87 Icon Analog InputList2SigType98=Analog InputList2Cue99=Set Item 88 Icon Analog InputList2SigType99=Analog InputList2Cue100=Set Item 89 Icon Analog InputList2SigType100=Analog InputList2Cue101=Set Item 90 Icon Analog InputList2SigType101=Analog InputList2Cue102=Set Item 91 Icon Analog InputList2SigType102=Analog InputList2Cue103=Set Item 92 Icon Analog InputList2SigType103=Analog InputList2Cue104=Set Item 93 Icon Analog InputList2SigType104=Analog InputList2Cue105=Set Item 94 Icon Analog InputList2SigType105=Analog InputList2Cue106=Set Item 95 Icon Analog InputList2SigType106=Analog InputList2Cue107=Set Item 96 Icon Analog InputList2SigType107=Analog InputList2Cue108=Set Item 97 Icon Analog InputList2SigType108=Analog InputList2Cue109=Set Item 98 Icon Analog InputList2SigType109=Analog InputList2Cue110=Set Item 99 Icon Analog InputList2SigType110=Analog InputList2Cue111=Set Item 100 Icon Analog InputList2SigType111=Analog InputList2Cue112=Set Item 101 Icon Analog InputList2SigType112=Analog InputList2Cue113=Set Item 102 Icon Analog InputList2SigType113=Analog InputList2Cue114=Set Item 103 Icon Analog InputList2SigType114=Analog InputList2Cue115=Set Item 104 Icon Analog InputList2SigType115=Analog InputList2Cue116=Set Item 105 Icon Analog InputList2SigType116=Analog InputList2Cue117=Set Item 106 Icon Analog InputList2SigType117=Analog InputList2Cue118=Set Item 107 Icon Analog InputList2SigType118=Analog InputList2Cue119=Set Item 108 Icon Analog InputList2SigType119=Analog InputList2Cue120=Set Item 109 Icon Analog InputList2SigType120=Analog InputList2Cue121=Set Item 110 Icon Analog InputList2SigType121=Analog InputList2Cue122=Set Item 111 Icon Analog InputList2SigType122=Analog InputList2Cue123=Set Item 112 Icon Analog InputList2SigType123=Analog InputList2Cue124=Set Item 113 Icon Analog InputList2SigType124=Analog InputList2Cue125=Set Item 114 Icon Analog InputList2SigType125=Analog InputList2Cue126=Set Item 115 Icon Analog InputList2SigType126=Analog InputList2Cue127=Set Item 116 Icon Analog InputList2SigType127=Analog InputList2Cue128=Set Item 117 Icon Analog InputList2SigType128=Analog InputList2Cue129=Set Item 118 Icon Analog InputList2SigType129=Analog InputList2Cue130=Set Item 119 Icon Analog InputList2SigType130=Analog InputList2Cue131=Set Item 120 Icon Analog InputList2SigType131=Analog InputList2Cue132=Set Item 121 Icon Analog InputList2SigType132=Analog InputList2Cue133=Set Item 122 Icon Analog InputList2SigType133=Analog InputList2Cue134=Set Item 123 Icon Analog InputList2SigType134=Analog InputList2Cue135=Set Item 124 Icon Analog InputList2SigType135=Analog InputList2Cue136=Set Item 125 Icon Analog InputList2SigType136=Analog InputList2Cue137=Set Item 126 Icon Analog InputList2SigType137=Analog InputList2Cue138=Set Item 127 Icon Analog InputList2SigType138=Analog InputList2Cue139=Set Item 128 Icon Analog InputList2SigType139=Analog InputList2Cue140=Set Item 129 Icon Analog InputList2SigType140=Analog InputList2Cue141=Set Item 130 Icon Analog InputList2SigType141=Analog InputList2Cue142=Set Item 131 Icon Analog InputList2SigType142=Analog InputList2Cue143=Set Item 132 Icon Analog InputList2SigType143=Analog InputList2Cue144=Set Item 133 Icon Analog InputList2SigType144=Analog InputList2Cue145=Set Item 134 Icon Analog InputList2SigType145=Analog InputList2Cue146=Set Item 135 Icon Analog InputList2SigType146=Analog InputList2Cue147=Set Item 136 Icon Analog InputList2SigType147=Analog InputList2Cue148=Set Item 137 Icon Analog InputList2SigType148=Analog InputList2Cue149=Set Item 138 Icon Analog InputList2SigType149=Analog InputList2Cue150=Set Item 139 Icon Analog InputList2SigType150=Analog InputList2Cue151=Set Item 140 Icon Analog InputList2SigType151=Analog InputList2Cue152=Set Item 141 Icon Analog InputList2SigType152=Analog InputList2Cue153=Set Item 142 Icon Analog InputList2SigType153=Analog InputList2Cue154=Set Item 143 Icon Analog InputList2SigType154=Analog InputList2Cue155=Set Item 144 Icon Analog InputList2SigType155=Analog InputList2Cue156=Set Item 145 Icon Analog InputList2SigType156=Analog InputList2Cue157=Set Item 146 Icon Analog InputList2SigType157=Analog InputList2Cue158=Set Item 147 Icon Analog InputList2SigType158=Analog InputList2Cue159=Set Item 148 Icon Analog InputList2SigType159=Analog InputList2Cue160=Set Item 149 Icon Analog InputList2SigType160=Analog InputList2Cue161=Set Item 150 Icon Analog InputList2SigType161=Analog InputList2Cue162=Set Item 151 Icon Analog InputList2SigType162=Analog InputList2Cue163=Set Item 152 Icon Analog InputList2SigType163=Analog InputList2Cue164=Set Item 153 Icon Analog InputList2SigType164=Analog InputList2Cue165=Set Item 154 Icon Analog InputList2SigType165=Analog InputList2Cue166=Set Item 155 Icon Analog InputList2SigType166=Analog InputList2Cue167=Set Item 156 Icon Analog InputList2SigType167=Analog InputList2Cue168=Set Item 157 Icon Analog InputList2SigType168=Analog InputList2Cue169=Set Item 158 Icon Analog InputList2SigType169=Analog InputList2Cue170=Set Item 159 Icon Analog InputList2SigType170=Analog InputList2Cue171=Set Item 160 Icon Analog InputList2SigType171=Analog InputList2Cue172=Set Item 161 Icon Analog InputList2SigType172=Analog InputList2Cue173=Set Item 162 Icon Analog InputList2SigType173=Analog InputList2Cue174=Set Item 163 Icon Analog InputList2SigType174=Analog InputList2Cue175=Set Item 164 Icon Analog InputList2SigType175=Analog InputList2Cue176=Set Item 165 Icon Analog InputList2SigType176=Analog InputList2Cue177=Set Item 166 Icon Analog InputList2SigType177=Analog InputList2Cue178=Set Item 167 Icon Analog InputList2SigType178=Analog InputList2Cue179=Set Item 168 Icon Analog InputList2SigType179=Analog InputList2Cue180=Set Item 169 Icon Analog InputList2SigType180=Analog InputList2Cue181=Set Item 170 Icon Analog InputList2SigType181=Analog InputList2Cue182=Set Item 171 Icon Analog InputList2SigType182=Analog InputList2Cue183=Set Item 172 Icon Analog InputList2SigType183=Analog InputList2Cue184=Set Item 173 Icon Analog InputList2SigType184=Analog InputList2Cue185=Set Item 174 Icon Analog InputList2SigType185=Analog InputList2Cue186=Set Item 175 Icon Analog InputList2SigType186=Analog InputList2Cue187=Set Item 176 Icon Analog InputList2SigType187=Analog InputList2Cue188=Set Item 177 Icon Analog InputList2SigType188=Analog InputList2Cue189=Set Item 178 Icon Analog InputList2SigType189=Analog InputList2Cue190=Set Item 179 Icon Analog InputList2SigType190=Analog InputList2Cue191=Set Item 180 Icon Analog InputList2SigType191=Analog InputList2Cue192=Set Item 181 Icon Analog InputList2SigType192=Analog InputList2Cue193=Set Item 182 Icon Analog InputList2SigType193=Analog InputList2Cue194=Set Item 183 Icon Analog InputList2SigType194=Analog InputList2Cue195=Set Item 184 Icon Analog InputList2SigType195=Analog InputList2Cue196=Set Item 185 Icon Analog InputList2SigType196=Analog InputList2Cue197=Set Item 186 Icon Analog InputList2SigType197=Analog InputList2Cue198=Set Item 187 Icon Analog InputList2SigType198=Analog InputList2Cue199=Set Item 188 Icon Analog InputList2SigType199=Analog InputList2Cue200=Set Item 189 Icon Analog InputList2SigType200=Analog InputList2Cue201=Set Item 190 Icon Analog InputList2SigType201=Analog InputList2Cue202=Set Item 191 Icon Analog InputList2SigType202=Analog InputList2Cue203=Set Item 192 Icon Analog InputList2SigType203=Analog InputList2Cue204=Set Item 193 Icon Analog InputList2SigType204=Analog InputList2Cue205=Set Item 194 Icon Analog InputList2SigType205=Analog InputList2Cue206=Set Item 195 Icon Analog InputList2SigType206=Analog InputList2Cue207=Set Item 196 Icon Analog InputList2SigType207=Analog InputList2Cue208=Set Item 197 Icon Analog InputList2SigType208=Analog InputList2Cue209=Set Item 198 Icon Analog InputList2SigType209=Analog InputList2Cue210=Set Item 199 Icon Analog InputList2SigType210=Analog InputList2Cue211=Set Item 200 Icon Analog InputList2SigType211=Analog InputList2Cue212=Set Item 201 Icon Analog InputList2SigType212=Analog InputList2Cue213=Set Item 202 Icon Analog InputList2SigType213=Analog InputList2Cue214=Set Item 203 Icon Analog InputList2SigType214=Analog InputList2Cue215=Set Item 204 Icon Analog InputList2SigType215=Analog InputList2Cue216=Set Item 205 Icon Analog InputList2SigType216=Analog InputList2Cue217=Set Item 206 Icon Analog InputList2SigType217=Analog InputList2Cue218=Set Item 207 Icon Analog InputList2SigType218=Analog InputList2Cue219=Set Item 208 Icon Analog InputList2SigType219=Analog InputList2Cue220=Set Item 209 Icon Analog InputList2SigType220=Analog InputList2Cue221=Set Item 210 Icon Analog InputList2SigType221=Analog InputList2Cue222=Set Item 211 Icon Analog InputList2SigType222=Analog InputList2Cue223=Set Item 212 Icon Analog InputList2SigType223=Analog InputList2Cue224=Set Item 213 Icon Analog InputList2SigType224=Analog InputList2Cue225=Set Item 214 Icon Analog InputList2SigType225=Analog InputList2Cue226=Set Item 215 Icon Analog InputList2SigType226=Analog InputList2Cue227=Set Item 216 Icon Analog InputList2SigType227=Analog InputList2Cue228=Set Item 217 Icon Analog InputList2SigType228=Analog InputList2Cue229=Set Item 218 Icon Analog InputList2SigType229=Analog InputList2Cue230=Set Item 219 Icon Analog InputList2SigType230=Analog InputList2Cue231=Set Item 220 Icon Analog InputList2SigType231=Analog InputList2Cue232=Set Item 221 Icon Analog InputList2SigType232=Analog InputList2Cue233=Set Item 222 Icon Analog InputList2SigType233=Analog InputList2Cue234=Set Item 223 Icon Analog InputList2SigType234=Analog InputList2Cue235=Set Item 224 Icon Analog InputList2SigType235=Analog InputList2Cue236=Set Item 225 Icon Analog InputList2SigType236=Analog InputList2Cue237=Set Item 226 Icon Analog InputList2SigType237=Analog InputList2Cue238=Set Item 227 Icon Analog InputList2SigType238=Analog InputList2Cue239=Set Item 228 Icon Analog InputList2SigType239=Analog InputList2Cue240=Set Item 229 Icon Analog InputList2SigType240=Analog InputList2Cue241=Set Item 230 Icon Analog InputList2SigType241=Analog InputList2Cue242=Set Item 231 Icon Analog InputList2SigType242=Analog InputList2Cue243=Set Item 232 Icon Analog InputList2SigType243=Analog InputList2Cue244=Set Item 233 Icon Analog InputList2SigType244=Analog InputList2Cue245=Set Item 234 Icon Analog InputList2SigType245=Analog InputList2Cue246=Set Item 235 Icon Analog InputList2SigType246=Analog InputList2Cue247=Set Item 236 Icon Analog InputList2SigType247=Analog InputList2Cue248=Set Item 237 Icon Analog InputList2SigType248=Analog InputList2Cue249=Set Item 238 Icon Analog InputList2SigType249=Analog InputList2Cue250=Set Item 239 Icon Analog InputList2SigType250=Analog InputList2Cue251=Set Item 240 Icon Analog InputList2SigType251=Analog InputList2Cue252=Set Item 241 Icon Analog InputList2SigType252=Analog InputList2Cue253=Set Item 242 Icon Analog InputList2SigType253=Analog InputList2Cue254=Set Item 243 Icon Analog InputList2SigType254=Analog InputList2Cue255=Set Item 244 Icon Analog InputList2SigType255=Analog InputList2Cue256=Set Item 245 Icon Analog InputList2SigType256=Analog InputList2Cue257=Set Item 246 Icon Analog InputList2SigType257=Analog InputList2Cue258=Set Item 247 Icon Analog InputList2SigType258=Analog InputList2Cue259=Set Item 248 Icon Analog InputList2SigType259=Analog InputList2Cue260=Set Item 249 Icon Analog InputList2SigType260=Analog InputList2Cue261=Set Item 250 Icon Analog InputList2SigType261=Analog InputList2Cue262=Set Item 251 Icon Analog InputList2SigType262=Analog InputList2Cue263=Set Item 252 Icon Analog InputList2SigType263=Analog InputList2Cue264=Set Item 253 Icon Analog InputList2SigType264=Analog InputList2Cue265=Set Item 254 Icon Analog InputList2SigType265=Analog InputList2Cue266=Set Item 255 Icon Analog InputList2SigType266=Analog InputList2Cue267=[~UNUSED2~] InputList2SigType267=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED3~] OutputList2SigType22=Analog OutputList2Cue23=[~UNUSED3~] OutputList2SigType23=Analog OutputList2Cue24=[~UNUSED3~] OutputList2SigType24=Analog OutputList2Cue25=[~UNUSED3~] OutputList2SigType25=Analog OutputList2Cue26=[~UNUSED3~] OutputList2SigType26=Analog OutputList2Cue27=[~UNUSED3~] OutputList2SigType27=Analog OutputList2Cue28=[~UNUSED3~] OutputList2SigType28=Analog OutputList2Cue29=[~UNUSED3~] OutputList2SigType29=Analog OutputList2Cue30=[~UNUSED3~] OutputList2SigType30=Analog OutputList2Cue31=[~UNUSED3~] OutputList2SigType31=Analog OutputList2Cue32=[~UNUSED3~] OutputList2SigType32=Analog OutputList2Cue33=[~UNUSED3~] OutputList2SigType33=Analog OutputList2Cue34=[~UNUSED3~] OutputList2SigType34=Analog OutputList2Cue35=[~UNUSED3~] OutputList2SigType35=Analog OutputList2Cue36=[~UNUSED3~] OutputList2SigType36=Analog OutputList2Cue37=[~UNUSED3~] OutputList2SigType37=Analog OutputList2Cue38=[~UNUSED3~] OutputList2SigType38=Analog OutputList2Cue39=[~UNUSED3~] OutputList2SigType39=Analog OutputList2Cue40=[~UNUSED3~] OutputList2SigType40=Analog OutputList2Cue41=[~UNUSED3~] OutputList2SigType41=Analog OutputList2Cue42=[~UNUSED3~] OutputList2SigType42=Analog OutputList2Cue43=[~UNUSED3~] OutputList2SigType43=Analog OutputList2Cue44=[~UNUSED3~] OutputList2SigType44=Analog OutputList2Cue45=[~UNUSED3~] OutputList2SigType45=Analog OutputList2Cue46=[~UNUSED3~] OutputList2SigType46=Analog OutputList2Cue47=[~UNUSED3~] OutputList2SigType47=Analog OutputList2Cue48=[~UNUSED3~] OutputList2SigType48=Analog OutputList2Cue49=[~UNUSED3~] OutputList2SigType49=Analog OutputList2Cue50=[~UNUSED3~] OutputList2SigType50=Analog OutputList2Cue51=[~UNUSED3~] OutputList2SigType51=Analog OutputList2Cue52=[~UNUSED3~] OutputList2SigType52=Analog OutputList2Cue53=[~UNUSED3~] OutputList2SigType53=Analog OutputList2Cue54=[~UNUSED3~] OutputList2SigType54=Analog OutputList2Cue55=[~UNUSED3~] OutputList2SigType55=Analog OutputList2Cue56=[~UNUSED3~] OutputList2SigType56=Analog OutputList2Cue57=[~UNUSED3~] OutputList2SigType57=Analog OutputList2Cue58=[~UNUSED3~] OutputList2SigType58=Analog OutputList2Cue59=[~UNUSED3~] OutputList2SigType59=Analog OutputList2Cue60=[~UNUSED3~] OutputList2SigType60=Analog OutputList2Cue61=[~UNUSED3~] OutputList2SigType61=Analog OutputList2Cue62=[~UNUSED3~] OutputList2SigType62=Analog OutputList2Cue63=[~UNUSED3~] OutputList2SigType63=Analog OutputList2Cue64=[~UNUSED3~] OutputList2SigType64=Analog OutputList2Cue65=[~UNUSED3~] OutputList2SigType65=Analog OutputList2Cue66=[~UNUSED3~] OutputList2SigType66=Analog OutputList2Cue67=[~UNUSED3~] OutputList2SigType67=Analog OutputList2Cue68=[~UNUSED3~] OutputList2SigType68=Analog OutputList2Cue69=[~UNUSED3~] OutputList2SigType69=Analog OutputList2Cue70=[~UNUSED3~] OutputList2SigType70=Analog OutputList2Cue71=[~UNUSED3~] OutputList2SigType71=Analog OutputList2Cue72=[~UNUSED3~] OutputList2SigType72=Analog OutputList2Cue73=[~UNUSED3~] OutputList2SigType73=Analog OutputList2Cue74=[~UNUSED3~] OutputList2SigType74=Analog OutputList2Cue75=[~UNUSED3~] OutputList2SigType75=Analog OutputList2Cue76=[~UNUSED3~] OutputList2SigType76=Analog OutputList2Cue77=[~UNUSED3~] OutputList2SigType77=Analog OutputList2Cue78=[~UNUSED3~] OutputList2SigType78=Analog OutputList2Cue79=[~UNUSED3~] OutputList2SigType79=Analog OutputList2Cue80=[~UNUSED3~] OutputList2SigType80=Analog OutputList2Cue81=[~UNUSED3~] OutputList2SigType81=Analog OutputList2Cue82=[~UNUSED3~] OutputList2SigType82=Analog OutputList2Cue83=[~UNUSED3~] OutputList2SigType83=Analog OutputList2Cue84=[~UNUSED3~] OutputList2SigType84=Analog OutputList2Cue85=[~UNUSED3~] OutputList2SigType85=Analog OutputList2Cue86=[~UNUSED3~] OutputList2SigType86=Analog OutputList2Cue87=[~UNUSED3~] OutputList2SigType87=Analog OutputList2Cue88=[~UNUSED3~] OutputList2SigType88=Analog OutputList2Cue89=[~UNUSED3~] OutputList2SigType89=Analog OutputList2Cue90=[~UNUSED3~] OutputList2SigType90=Analog OutputList2Cue91=[~UNUSED3~] OutputList2SigType91=Analog OutputList2Cue92=[~UNUSED3~] OutputList2SigType92=Analog OutputList2Cue93=[~UNUSED3~] OutputList2SigType93=Analog OutputList2Cue94=[~UNUSED3~] OutputList2SigType94=Analog OutputList2Cue95=[~UNUSED3~] OutputList2SigType95=Analog OutputList2Cue96=[~UNUSED3~] OutputList2SigType96=Analog OutputList2Cue97=[~UNUSED3~] OutputList2SigType97=Analog OutputList2Cue98=[~UNUSED3~] OutputList2SigType98=Analog OutputList2Cue99=[~UNUSED3~] OutputList2SigType99=Analog OutputList2Cue100=[~UNUSED3~] OutputList2SigType100=Analog OutputList2Cue101=[~UNUSED3~] OutputList2SigType101=Analog OutputList2Cue102=[~UNUSED3~] OutputList2SigType102=Analog OutputList2Cue103=[~UNUSED3~] OutputList2SigType103=Analog OutputList2Cue104=[~UNUSED3~] OutputList2SigType104=Analog OutputList2Cue105=[~UNUSED3~] OutputList2SigType105=Analog OutputList2Cue106=[~UNUSED3~] OutputList2SigType106=Analog OutputList2Cue107=[~UNUSED3~] OutputList2SigType107=Analog OutputList2Cue108=[~UNUSED3~] OutputList2SigType108=Analog OutputList2Cue109=[~UNUSED3~] OutputList2SigType109=Analog OutputList2Cue110=[~UNUSED3~] OutputList2SigType110=Analog OutputList2Cue111=[~UNUSED3~] OutputList2SigType111=Analog OutputList2Cue112=[~UNUSED3~] OutputList2SigType112=Analog OutputList2Cue113=[~UNUSED3~] OutputList2SigType113=Analog OutputList2Cue114=[~UNUSED3~] OutputList2SigType114=Analog OutputList2Cue115=[~UNUSED3~] OutputList2SigType115=Analog OutputList2Cue116=[~UNUSED3~] OutputList2SigType116=Analog OutputList2Cue117=[~UNUSED3~] OutputList2SigType117=Analog OutputList2Cue118=[~UNUSED3~] OutputList2SigType118=Analog OutputList2Cue119=[~UNUSED3~] OutputList2SigType119=Analog OutputList2Cue120=[~UNUSED3~] OutputList2SigType120=Analog OutputList2Cue121=[~UNUSED3~] OutputList2SigType121=Analog OutputList2Cue122=[~UNUSED3~] OutputList2SigType122=Analog OutputList2Cue123=[~UNUSED3~] OutputList2SigType123=Analog OutputList2Cue124=[~UNUSED3~] OutputList2SigType124=Analog OutputList2Cue125=[~UNUSED3~] OutputList2SigType125=Analog OutputList2Cue126=[~UNUSED3~] OutputList2SigType126=Analog OutputList2Cue127=[~UNUSED3~] OutputList2SigType127=Analog OutputList2Cue128=[~UNUSED3~] OutputList2SigType128=Analog OutputList2Cue129=[~UNUSED3~] OutputList2SigType129=Analog OutputList2Cue130=[~UNUSED3~] OutputList2SigType130=Analog OutputList2Cue131=[~UNUSED3~] OutputList2SigType131=Analog OutputList2Cue132=[~UNUSED3~] OutputList2SigType132=Analog OutputList2Cue133=[~UNUSED3~] OutputList2SigType133=Analog OutputList2Cue134=[~UNUSED3~] OutputList2SigType134=Analog OutputList2Cue135=[~UNUSED3~] OutputList2SigType135=Analog OutputList2Cue136=[~UNUSED3~] OutputList2SigType136=Analog OutputList2Cue137=[~UNUSED3~] OutputList2SigType137=Analog OutputList2Cue138=[~UNUSED3~] OutputList2SigType138=Analog OutputList2Cue139=[~UNUSED3~] OutputList2SigType139=Analog OutputList2Cue140=[~UNUSED3~] OutputList2SigType140=Analog OutputList2Cue141=[~UNUSED3~] OutputList2SigType141=Analog OutputList2Cue142=[~UNUSED3~] OutputList2SigType142=Analog OutputList2Cue143=[~UNUSED3~] OutputList2SigType143=Analog OutputList2Cue144=[~UNUSED3~] OutputList2SigType144=Analog OutputList2Cue145=[~UNUSED3~] OutputList2SigType145=Analog OutputList2Cue146=[~UNUSED3~] OutputList2SigType146=Analog OutputList2Cue147=[~UNUSED3~] OutputList2SigType147=Analog OutputList2Cue148=[~UNUSED3~] OutputList2SigType148=Analog OutputList2Cue149=[~UNUSED3~] OutputList2SigType149=Analog OutputList2Cue150=[~UNUSED3~] OutputList2SigType150=Analog OutputList2Cue151=[~UNUSED3~] OutputList2SigType151=Analog OutputList2Cue152=[~UNUSED3~] OutputList2SigType152=Analog OutputList2Cue153=[~UNUSED3~] OutputList2SigType153=Analog OutputList2Cue154=[~UNUSED3~] OutputList2SigType154=Analog OutputList2Cue155=[~UNUSED3~] OutputList2SigType155=Analog OutputList2Cue156=[~UNUSED3~] OutputList2SigType156=Analog OutputList2Cue157=[~UNUSED3~] OutputList2SigType157=Analog OutputList2Cue158=[~UNUSED3~] OutputList2SigType158=Analog OutputList2Cue159=[~UNUSED3~] OutputList2SigType159=Analog OutputList2Cue160=[~UNUSED3~] OutputList2SigType160=Analog OutputList2Cue161=[~UNUSED3~] OutputList2SigType161=Analog OutputList2Cue162=[~UNUSED3~] OutputList2SigType162=Analog OutputList2Cue163=[~UNUSED3~] OutputList2SigType163=Analog OutputList2Cue164=[~UNUSED3~] OutputList2SigType164=Analog OutputList2Cue165=[~UNUSED3~] OutputList2SigType165=Analog OutputList2Cue166=[~UNUSED3~] OutputList2SigType166=Analog OutputList2Cue167=[~UNUSED3~] OutputList2SigType167=Analog OutputList2Cue168=[~UNUSED3~] OutputList2SigType168=Analog OutputList2Cue169=[~UNUSED3~] OutputList2SigType169=Analog OutputList2Cue170=[~UNUSED3~] OutputList2SigType170=Analog OutputList2Cue171=[~UNUSED3~] OutputList2SigType171=Analog OutputList2Cue172=[~UNUSED3~] OutputList2SigType172=Analog OutputList2Cue173=[~UNUSED3~] OutputList2SigType173=Analog OutputList2Cue174=[~UNUSED3~] OutputList2SigType174=Analog OutputList2Cue175=[~UNUSED3~] OutputList2SigType175=Analog OutputList2Cue176=[~UNUSED3~] OutputList2SigType176=Analog OutputList2Cue177=[~UNUSED3~] OutputList2SigType177=Analog OutputList2Cue178=[~UNUSED3~] OutputList2SigType178=Analog OutputList2Cue179=[~UNUSED3~] OutputList2SigType179=Analog OutputList2Cue180=[~UNUSED3~] OutputList2SigType180=Analog OutputList2Cue181=[~UNUSED3~] OutputList2SigType181=Analog OutputList2Cue182=[~UNUSED3~] OutputList2SigType182=Analog OutputList2Cue183=[~UNUSED3~] OutputList2SigType183=Analog OutputList2Cue184=[~UNUSED3~] OutputList2SigType184=Analog OutputList2Cue185=[~UNUSED3~] OutputList2SigType185=Analog OutputList2Cue186=[~UNUSED3~] OutputList2SigType186=Analog OutputList2Cue187=[~UNUSED3~] OutputList2SigType187=Analog OutputList2Cue188=[~UNUSED3~] OutputList2SigType188=Analog OutputList2Cue189=[~UNUSED3~] OutputList2SigType189=Analog OutputList2Cue190=[~UNUSED3~] OutputList2SigType190=Analog OutputList2Cue191=[~UNUSED3~] OutputList2SigType191=Analog OutputList2Cue192=[~UNUSED3~] OutputList2SigType192=Analog OutputList2Cue193=[~UNUSED3~] OutputList2SigType193=Analog OutputList2Cue194=[~UNUSED3~] OutputList2SigType194=Analog OutputList2Cue195=[~UNUSED3~] OutputList2SigType195=Analog OutputList2Cue196=[~UNUSED3~] OutputList2SigType196=Analog OutputList2Cue197=[~UNUSED3~] OutputList2SigType197=Analog OutputList2Cue198=[~UNUSED3~] OutputList2SigType198=Analog OutputList2Cue199=[~UNUSED3~] OutputList2SigType199=Analog OutputList2Cue200=[~UNUSED3~] OutputList2SigType200=Analog OutputList2Cue201=[~UNUSED3~] OutputList2SigType201=Analog OutputList2Cue202=[~UNUSED3~] OutputList2SigType202=Analog OutputList2Cue203=[~UNUSED3~] OutputList2SigType203=Analog OutputList2Cue204=[~UNUSED3~] OutputList2SigType204=Analog OutputList2Cue205=[~UNUSED3~] OutputList2SigType205=Analog OutputList2Cue206=[~UNUSED3~] OutputList2SigType206=Analog OutputList2Cue207=[~UNUSED3~] OutputList2SigType207=Analog OutputList2Cue208=[~UNUSED3~] OutputList2SigType208=Analog OutputList2Cue209=[~UNUSED3~] OutputList2SigType209=Analog OutputList2Cue210=[~UNUSED3~] OutputList2SigType210=Analog OutputList2Cue211=[~UNUSED3~] OutputList2SigType211=Analog OutputList2Cue212=[~UNUSED3~] OutputList2SigType212=Analog OutputList2Cue213=[~UNUSED3~] OutputList2SigType213=Analog OutputList2Cue214=[~UNUSED3~] OutputList2SigType214=Analog OutputList2Cue215=[~UNUSED3~] OutputList2SigType215=Analog OutputList2Cue216=[~UNUSED3~] OutputList2SigType216=Analog OutputList2Cue217=[~UNUSED3~] OutputList2SigType217=Analog OutputList2Cue218=[~UNUSED3~] OutputList2SigType218=Analog OutputList2Cue219=[~UNUSED3~] OutputList2SigType219=Analog OutputList2Cue220=[~UNUSED3~] OutputList2SigType220=Analog OutputList2Cue221=[~UNUSED3~] OutputList2SigType221=Analog OutputList2Cue222=[~UNUSED3~] OutputList2SigType222=Analog OutputList2Cue223=[~UNUSED3~] OutputList2SigType223=Analog OutputList2Cue224=[~UNUSED3~] OutputList2SigType224=Analog OutputList2Cue225=[~UNUSED3~] OutputList2SigType225=Analog OutputList2Cue226=[~UNUSED3~] OutputList2SigType226=Analog OutputList2Cue227=[~UNUSED3~] OutputList2SigType227=Analog OutputList2Cue228=[~UNUSED3~] OutputList2SigType228=Analog OutputList2Cue229=[~UNUSED3~] OutputList2SigType229=Analog OutputList2Cue230=[~UNUSED3~] OutputList2SigType230=Analog OutputList2Cue231=[~UNUSED3~] OutputList2SigType231=Analog OutputList2Cue232=[~UNUSED3~] OutputList2SigType232=Analog OutputList2Cue233=[~UNUSED3~] OutputList2SigType233=Analog OutputList2Cue234=[~UNUSED3~] OutputList2SigType234=Analog OutputList2Cue235=[~UNUSED3~] OutputList2SigType235=Analog OutputList2Cue236=[~UNUSED3~] OutputList2SigType236=Analog OutputList2Cue237=[~UNUSED3~] OutputList2SigType237=Analog OutputList2Cue238=[~UNUSED3~] OutputList2SigType238=Analog OutputList2Cue239=[~UNUSED3~] OutputList2SigType239=Analog OutputList2Cue240=[~UNUSED3~] OutputList2SigType240=Analog OutputList2Cue241=[~UNUSED3~] OutputList2SigType241=Analog OutputList2Cue242=[~UNUSED3~] OutputList2SigType242=Analog OutputList2Cue243=[~UNUSED3~] OutputList2SigType243=Analog OutputList2Cue244=[~UNUSED3~] OutputList2SigType244=Analog OutputList2Cue245=[~UNUSED3~] OutputList2SigType245=Analog OutputList2Cue246=[~UNUSED3~] OutputList2SigType246=Analog OutputList2Cue247=[~UNUSED3~] OutputList2SigType247=Analog OutputList2Cue248=[~UNUSED3~] OutputList2SigType248=Analog OutputList2Cue249=[~UNUSED3~] OutputList2SigType249=Analog OutputList2Cue250=[~UNUSED3~] OutputList2SigType250=Analog OutputList2Cue251=[~UNUSED3~] OutputList2SigType251=Analog OutputList2Cue252=[~UNUSED3~] OutputList2SigType252=Analog OutputList2Cue253=[~UNUSED3~] OutputList2SigType253=Analog OutputList2Cue254=[~UNUSED3~] OutputList2SigType254=Analog OutputList2Cue255=[~UNUSED3~] OutputList2SigType255=Analog OutputList2Cue256=[~UNUSED3~] OutputList2SigType256=Analog OutputList2Cue257=[~UNUSED3~] OutputList2SigType257=Analog OutputList2Cue258=[~UNUSED3~] OutputList2SigType258=Analog OutputList2Cue259=[~UNUSED3~] OutputList2SigType259=Analog OutputList2Cue260=[~UNUSED3~] OutputList2SigType260=Analog OutputList2Cue261=[~UNUSED3~] OutputList2SigType261=Analog OutputList2Cue262=[~UNUSED3~] OutputList2SigType262=Analog OutputList2Cue263=[~UNUSED3~] OutputList2SigType263=Analog OutputList2Cue264=[~UNUSED3~] OutputList2SigType264=Analog OutputList2Cue265=[~UNUSED3~] OutputList2SigType265=Analog OutputList2Cue266=[~UNUSED3~] OutputList2SigType266=Analog OutputList2Cue267=[~UNUSED2~] OutputList2SigType267=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=Set Item 11 Text InputList3SigType22=Serial InputList3Cue23=Set Item 12 Text InputList3SigType23=Serial InputList3Cue24=Set Item 13 Text InputList3SigType24=Serial InputList3Cue25=Set Item 14 Text InputList3SigType25=Serial InputList3Cue26=Set Item 15 Text InputList3SigType26=Serial InputList3Cue27=Set Item 16 Text InputList3SigType27=Serial InputList3Cue28=Set Item 17 Text InputList3SigType28=Serial InputList3Cue29=Set Item 18 Text InputList3SigType29=Serial InputList3Cue30=Set Item 19 Text InputList3SigType30=Serial InputList3Cue31=Set Item 20 Text InputList3SigType31=Serial InputList3Cue32=Set Item 21 Text InputList3SigType32=Serial InputList3Cue33=Set Item 22 Text InputList3SigType33=Serial InputList3Cue34=Set Item 23 Text InputList3SigType34=Serial InputList3Cue35=Set Item 24 Text InputList3SigType35=Serial InputList3Cue36=Set Item 25 Text InputList3SigType36=Serial InputList3Cue37=Set Item 26 Text InputList3SigType37=Serial InputList3Cue38=Set Item 27 Text InputList3SigType38=Serial InputList3Cue39=Set Item 28 Text InputList3SigType39=Serial InputList3Cue40=Set Item 29 Text InputList3SigType40=Serial InputList3Cue41=Set Item 30 Text InputList3SigType41=Serial InputList3Cue42=Set Item 31 Text InputList3SigType42=Serial InputList3Cue43=Set Item 32 Text InputList3SigType43=Serial InputList3Cue44=Set Item 33 Text InputList3SigType44=Serial InputList3Cue45=Set Item 34 Text InputList3SigType45=Serial InputList3Cue46=Set Item 35 Text InputList3SigType46=Serial InputList3Cue47=Set Item 36 Text InputList3SigType47=Serial InputList3Cue48=Set Item 37 Text InputList3SigType48=Serial InputList3Cue49=Set Item 38 Text InputList3SigType49=Serial InputList3Cue50=Set Item 39 Text InputList3SigType50=Serial InputList3Cue51=Set Item 40 Text InputList3SigType51=Serial InputList3Cue52=Set Item 41 Text InputList3SigType52=Serial InputList3Cue53=Set Item 42 Text InputList3SigType53=Serial InputList3Cue54=Set Item 43 Text InputList3SigType54=Serial InputList3Cue55=Set Item 44 Text InputList3SigType55=Serial InputList3Cue56=Set Item 45 Text InputList3SigType56=Serial InputList3Cue57=Set Item 46 Text InputList3SigType57=Serial InputList3Cue58=Set Item 47 Text InputList3SigType58=Serial InputList3Cue59=Set Item 48 Text InputList3SigType59=Serial InputList3Cue60=Set Item 49 Text InputList3SigType60=Serial InputList3Cue61=Set Item 50 Text InputList3SigType61=Serial InputList3Cue62=Set Item 51 Text InputList3SigType62=Serial InputList3Cue63=Set Item 52 Text InputList3SigType63=Serial InputList3Cue64=Set Item 53 Text InputList3SigType64=Serial InputList3Cue65=Set Item 54 Text InputList3SigType65=Serial InputList3Cue66=Set Item 55 Text InputList3SigType66=Serial InputList3Cue67=Set Item 56 Text InputList3SigType67=Serial InputList3Cue68=Set Item 57 Text InputList3SigType68=Serial InputList3Cue69=Set Item 58 Text InputList3SigType69=Serial InputList3Cue70=Set Item 59 Text InputList3SigType70=Serial InputList3Cue71=Set Item 60 Text InputList3SigType71=Serial InputList3Cue72=Set Item 61 Text InputList3SigType72=Serial InputList3Cue73=Set Item 62 Text InputList3SigType73=Serial InputList3Cue74=Set Item 63 Text InputList3SigType74=Serial InputList3Cue75=Set Item 64 Text InputList3SigType75=Serial InputList3Cue76=Set Item 65 Text InputList3SigType76=Serial InputList3Cue77=Set Item 66 Text InputList3SigType77=Serial InputList3Cue78=Set Item 67 Text InputList3SigType78=Serial InputList3Cue79=Set Item 68 Text InputList3SigType79=Serial InputList3Cue80=Set Item 69 Text InputList3SigType80=Serial InputList3Cue81=Set Item 70 Text InputList3SigType81=Serial InputList3Cue82=Set Item 71 Text InputList3SigType82=Serial InputList3Cue83=Set Item 72 Text InputList3SigType83=Serial InputList3Cue84=Set Item 73 Text InputList3SigType84=Serial InputList3Cue85=Set Item 74 Text InputList3SigType85=Serial InputList3Cue86=Set Item 75 Text InputList3SigType86=Serial InputList3Cue87=Set Item 76 Text InputList3SigType87=Serial InputList3Cue88=Set Item 77 Text InputList3SigType88=Serial InputList3Cue89=Set Item 78 Text InputList3SigType89=Serial InputList3Cue90=Set Item 79 Text InputList3SigType90=Serial InputList3Cue91=Set Item 80 Text InputList3SigType91=Serial InputList3Cue92=Set Item 81 Text InputList3SigType92=Serial InputList3Cue93=Set Item 82 Text InputList3SigType93=Serial InputList3Cue94=Set Item 83 Text InputList3SigType94=Serial InputList3Cue95=Set Item 84 Text InputList3SigType95=Serial InputList3Cue96=Set Item 85 Text InputList3SigType96=Serial InputList3Cue97=Set Item 86 Text InputList3SigType97=Serial InputList3Cue98=Set Item 87 Text InputList3SigType98=Serial InputList3Cue99=Set Item 88 Text InputList3SigType99=Serial InputList3Cue100=Set Item 89 Text InputList3SigType100=Serial InputList3Cue101=Set Item 90 Text InputList3SigType101=Serial InputList3Cue102=Set Item 91 Text InputList3SigType102=Serial InputList3Cue103=Set Item 92 Text InputList3SigType103=Serial InputList3Cue104=Set Item 93 Text InputList3SigType104=Serial InputList3Cue105=Set Item 94 Text InputList3SigType105=Serial InputList3Cue106=Set Item 95 Text InputList3SigType106=Serial InputList3Cue107=Set Item 96 Text InputList3SigType107=Serial InputList3Cue108=Set Item 97 Text InputList3SigType108=Serial InputList3Cue109=Set Item 98 Text InputList3SigType109=Serial InputList3Cue110=Set Item 99 Text InputList3SigType110=Serial InputList3Cue111=Set Item 100 Text InputList3SigType111=Serial InputList3Cue112=Set Item 101 Text InputList3SigType112=Serial InputList3Cue113=Set Item 102 Text InputList3SigType113=Serial InputList3Cue114=Set Item 103 Text InputList3SigType114=Serial InputList3Cue115=Set Item 104 Text InputList3SigType115=Serial InputList3Cue116=Set Item 105 Text InputList3SigType116=Serial InputList3Cue117=Set Item 106 Text InputList3SigType117=Serial InputList3Cue118=Set Item 107 Text InputList3SigType118=Serial InputList3Cue119=Set Item 108 Text InputList3SigType119=Serial InputList3Cue120=Set Item 109 Text InputList3SigType120=Serial InputList3Cue121=Set Item 110 Text InputList3SigType121=Serial InputList3Cue122=Set Item 111 Text InputList3SigType122=Serial InputList3Cue123=Set Item 112 Text InputList3SigType123=Serial InputList3Cue124=Set Item 113 Text InputList3SigType124=Serial InputList3Cue125=Set Item 114 Text InputList3SigType125=Serial InputList3Cue126=Set Item 115 Text InputList3SigType126=Serial InputList3Cue127=Set Item 116 Text InputList3SigType127=Serial InputList3Cue128=Set Item 117 Text InputList3SigType128=Serial InputList3Cue129=Set Item 118 Text InputList3SigType129=Serial InputList3Cue130=Set Item 119 Text InputList3SigType130=Serial InputList3Cue131=Set Item 120 Text InputList3SigType131=Serial InputList3Cue132=Set Item 121 Text InputList3SigType132=Serial InputList3Cue133=Set Item 122 Text InputList3SigType133=Serial InputList3Cue134=Set Item 123 Text InputList3SigType134=Serial InputList3Cue135=Set Item 124 Text InputList3SigType135=Serial InputList3Cue136=Set Item 125 Text InputList3SigType136=Serial InputList3Cue137=Set Item 126 Text InputList3SigType137=Serial InputList3Cue138=Set Item 127 Text InputList3SigType138=Serial InputList3Cue139=Set Item 128 Text InputList3SigType139=Serial InputList3Cue140=Set Item 129 Text InputList3SigType140=Serial InputList3Cue141=Set Item 130 Text InputList3SigType141=Serial InputList3Cue142=Set Item 131 Text InputList3SigType142=Serial InputList3Cue143=Set Item 132 Text InputList3SigType143=Serial InputList3Cue144=Set Item 133 Text InputList3SigType144=Serial InputList3Cue145=Set Item 134 Text InputList3SigType145=Serial InputList3Cue146=Set Item 135 Text InputList3SigType146=Serial InputList3Cue147=Set Item 136 Text InputList3SigType147=Serial InputList3Cue148=Set Item 137 Text InputList3SigType148=Serial InputList3Cue149=Set Item 138 Text InputList3SigType149=Serial InputList3Cue150=Set Item 139 Text InputList3SigType150=Serial InputList3Cue151=Set Item 140 Text InputList3SigType151=Serial InputList3Cue152=Set Item 141 Text InputList3SigType152=Serial InputList3Cue153=Set Item 142 Text InputList3SigType153=Serial InputList3Cue154=Set Item 143 Text InputList3SigType154=Serial InputList3Cue155=Set Item 144 Text InputList3SigType155=Serial InputList3Cue156=Set Item 145 Text InputList3SigType156=Serial InputList3Cue157=Set Item 146 Text InputList3SigType157=Serial InputList3Cue158=Set Item 147 Text InputList3SigType158=Serial InputList3Cue159=Set Item 148 Text InputList3SigType159=Serial InputList3Cue160=Set Item 149 Text InputList3SigType160=Serial InputList3Cue161=Set Item 150 Text InputList3SigType161=Serial InputList3Cue162=Set Item 151 Text InputList3SigType162=Serial InputList3Cue163=Set Item 152 Text InputList3SigType163=Serial InputList3Cue164=Set Item 153 Text InputList3SigType164=Serial InputList3Cue165=Set Item 154 Text InputList3SigType165=Serial InputList3Cue166=Set Item 155 Text InputList3SigType166=Serial InputList3Cue167=Set Item 156 Text InputList3SigType167=Serial InputList3Cue168=Set Item 157 Text InputList3SigType168=Serial InputList3Cue169=Set Item 158 Text InputList3SigType169=Serial InputList3Cue170=Set Item 159 Text InputList3SigType170=Serial InputList3Cue171=Set Item 160 Text InputList3SigType171=Serial InputList3Cue172=Set Item 161 Text InputList3SigType172=Serial InputList3Cue173=Set Item 162 Text InputList3SigType173=Serial InputList3Cue174=Set Item 163 Text InputList3SigType174=Serial InputList3Cue175=Set Item 164 Text InputList3SigType175=Serial InputList3Cue176=Set Item 165 Text InputList3SigType176=Serial InputList3Cue177=Set Item 166 Text InputList3SigType177=Serial InputList3Cue178=Set Item 167 Text InputList3SigType178=Serial InputList3Cue179=Set Item 168 Text InputList3SigType179=Serial InputList3Cue180=Set Item 169 Text InputList3SigType180=Serial InputList3Cue181=Set Item 170 Text InputList3SigType181=Serial InputList3Cue182=Set Item 171 Text InputList3SigType182=Serial InputList3Cue183=Set Item 172 Text InputList3SigType183=Serial InputList3Cue184=Set Item 173 Text InputList3SigType184=Serial InputList3Cue185=Set Item 174 Text InputList3SigType185=Serial InputList3Cue186=Set Item 175 Text InputList3SigType186=Serial InputList3Cue187=Set Item 176 Text InputList3SigType187=Serial InputList3Cue188=Set Item 177 Text InputList3SigType188=Serial InputList3Cue189=Set Item 178 Text InputList3SigType189=Serial InputList3Cue190=Set Item 179 Text InputList3SigType190=Serial InputList3Cue191=Set Item 180 Text InputList3SigType191=Serial InputList3Cue192=Set Item 181 Text InputList3SigType192=Serial InputList3Cue193=Set Item 182 Text InputList3SigType193=Serial InputList3Cue194=Set Item 183 Text InputList3SigType194=Serial InputList3Cue195=Set Item 184 Text InputList3SigType195=Serial InputList3Cue196=Set Item 185 Text InputList3SigType196=Serial InputList3Cue197=Set Item 186 Text InputList3SigType197=Serial InputList3Cue198=Set Item 187 Text InputList3SigType198=Serial InputList3Cue199=Set Item 188 Text InputList3SigType199=Serial InputList3Cue200=Set Item 189 Text InputList3SigType200=Serial InputList3Cue201=Set Item 190 Text InputList3SigType201=Serial InputList3Cue202=Set Item 191 Text InputList3SigType202=Serial InputList3Cue203=Set Item 192 Text InputList3SigType203=Serial InputList3Cue204=Set Item 193 Text InputList3SigType204=Serial InputList3Cue205=Set Item 194 Text InputList3SigType205=Serial InputList3Cue206=Set Item 195 Text InputList3SigType206=Serial InputList3Cue207=Set Item 196 Text InputList3SigType207=Serial InputList3Cue208=Set Item 197 Text InputList3SigType208=Serial InputList3Cue209=Set Item 198 Text InputList3SigType209=Serial InputList3Cue210=Set Item 199 Text InputList3SigType210=Serial InputList3Cue211=Set Item 200 Text InputList3SigType211=Serial InputList3Cue212=Set Item 201 Text InputList3SigType212=Serial InputList3Cue213=Set Item 202 Text InputList3SigType213=Serial InputList3Cue214=Set Item 203 Text InputList3SigType214=Serial InputList3Cue215=Set Item 204 Text InputList3SigType215=Serial InputList3Cue216=Set Item 205 Text InputList3SigType216=Serial InputList3Cue217=Set Item 206 Text InputList3SigType217=Serial InputList3Cue218=Set Item 207 Text InputList3SigType218=Serial InputList3Cue219=Set Item 208 Text InputList3SigType219=Serial InputList3Cue220=Set Item 209 Text InputList3SigType220=Serial InputList3Cue221=Set Item 210 Text InputList3SigType221=Serial InputList3Cue222=Set Item 211 Text InputList3SigType222=Serial InputList3Cue223=Set Item 212 Text InputList3SigType223=Serial InputList3Cue224=Set Item 213 Text InputList3SigType224=Serial InputList3Cue225=Set Item 214 Text InputList3SigType225=Serial InputList3Cue226=Set Item 215 Text InputList3SigType226=Serial InputList3Cue227=Set Item 216 Text InputList3SigType227=Serial InputList3Cue228=Set Item 217 Text InputList3SigType228=Serial InputList3Cue229=Set Item 218 Text InputList3SigType229=Serial InputList3Cue230=Set Item 219 Text InputList3SigType230=Serial InputList3Cue231=Set Item 220 Text InputList3SigType231=Serial InputList3Cue232=Set Item 221 Text InputList3SigType232=Serial InputList3Cue233=Set Item 222 Text InputList3SigType233=Serial InputList3Cue234=Set Item 223 Text InputList3SigType234=Serial InputList3Cue235=Set Item 224 Text InputList3SigType235=Serial InputList3Cue236=Set Item 225 Text InputList3SigType236=Serial InputList3Cue237=Set Item 226 Text InputList3SigType237=Serial InputList3Cue238=Set Item 227 Text InputList3SigType238=Serial InputList3Cue239=Set Item 228 Text InputList3SigType239=Serial InputList3Cue240=Set Item 229 Text InputList3SigType240=Serial InputList3Cue241=Set Item 230 Text InputList3SigType241=Serial InputList3Cue242=Set Item 231 Text InputList3SigType242=Serial InputList3Cue243=Set Item 232 Text InputList3SigType243=Serial InputList3Cue244=Set Item 233 Text InputList3SigType244=Serial InputList3Cue245=Set Item 234 Text InputList3SigType245=Serial InputList3Cue246=Set Item 235 Text InputList3SigType246=Serial InputList3Cue247=Set Item 236 Text InputList3SigType247=Serial InputList3Cue248=Set Item 237 Text InputList3SigType248=Serial InputList3Cue249=Set Item 238 Text InputList3SigType249=Serial InputList3Cue250=Set Item 239 Text InputList3SigType250=Serial InputList3Cue251=Set Item 240 Text InputList3SigType251=Serial InputList3Cue252=Set Item 241 Text InputList3SigType252=Serial InputList3Cue253=Set Item 242 Text InputList3SigType253=Serial InputList3Cue254=Set Item 243 Text InputList3SigType254=Serial InputList3Cue255=Set Item 244 Text InputList3SigType255=Serial InputList3Cue256=Set Item 245 Text InputList3SigType256=Serial InputList3Cue257=Set Item 246 Text InputList3SigType257=Serial InputList3Cue258=Set Item 247 Text InputList3SigType258=Serial InputList3Cue259=Set Item 248 Text InputList3SigType259=Serial InputList3Cue260=Set Item 249 Text InputList3SigType260=Serial InputList3Cue261=Set Item 250 Text InputList3SigType261=Serial InputList3Cue262=Set Item 251 Text InputList3SigType262=Serial InputList3Cue263=Set Item 252 Text InputList3SigType263=Serial InputList3Cue264=Set Item 253 Text InputList3SigType264=Serial InputList3Cue265=Set Item 254 Text InputList3SigType265=Serial InputList3Cue266=Set Item 255 Text InputList3SigType266=Serial InputList3Cue267=[~UNUSED2~] InputList3SigType267=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=Set Item 11 Icon Serial InputList3SigType2024=Serial InputList3Cue2025=Set Item 12 Icon Serial InputList3SigType2025=Serial InputList3Cue2026=Set Item 13 Icon Serial InputList3SigType2026=Serial InputList3Cue2027=Set Item 14 Icon Serial InputList3SigType2027=Serial InputList3Cue2028=Set Item 15 Icon Serial InputList3SigType2028=Serial InputList3Cue2029=Set Item 16 Icon Serial InputList3SigType2029=Serial InputList3Cue2030=Set Item 17 Icon Serial InputList3SigType2030=Serial InputList3Cue2031=Set Item 18 Icon Serial InputList3SigType2031=Serial InputList3Cue2032=Set Item 19 Icon Serial InputList3SigType2032=Serial InputList3Cue2033=Set Item 20 Icon Serial InputList3SigType2033=Serial InputList3Cue2034=Set Item 21 Icon Serial InputList3SigType2034=Serial InputList3Cue2035=Set Item 22 Icon Serial InputList3SigType2035=Serial InputList3Cue2036=Set Item 23 Icon Serial InputList3SigType2036=Serial InputList3Cue2037=Set Item 24 Icon Serial InputList3SigType2037=Serial InputList3Cue2038=Set Item 25 Icon Serial InputList3SigType2038=Serial InputList3Cue2039=Set Item 26 Icon Serial InputList3SigType2039=Serial InputList3Cue2040=Set Item 27 Icon Serial InputList3SigType2040=Serial InputList3Cue2041=Set Item 28 Icon Serial InputList3SigType2041=Serial InputList3Cue2042=Set Item 29 Icon Serial InputList3SigType2042=Serial InputList3Cue2043=Set Item 30 Icon Serial InputList3SigType2043=Serial InputList3Cue2044=Set Item 31 Icon Serial InputList3SigType2044=Serial InputList3Cue2045=Set Item 32 Icon Serial InputList3SigType2045=Serial InputList3Cue2046=Set Item 33 Icon Serial InputList3SigType2046=Serial InputList3Cue2047=Set Item 34 Icon Serial InputList3SigType2047=Serial InputList3Cue2048=Set Item 35 Icon Serial InputList3SigType2048=Serial InputList3Cue2049=Set Item 36 Icon Serial InputList3SigType2049=Serial InputList3Cue2050=Set Item 37 Icon Serial InputList3SigType2050=Serial InputList3Cue2051=Set Item 38 Icon Serial InputList3SigType2051=Serial InputList3Cue2052=Set Item 39 Icon Serial InputList3SigType2052=Serial InputList3Cue2053=Set Item 40 Icon Serial InputList3SigType2053=Serial InputList3Cue2054=Set Item 41 Icon Serial InputList3SigType2054=Serial InputList3Cue2055=Set Item 42 Icon Serial InputList3SigType2055=Serial InputList3Cue2056=Set Item 43 Icon Serial InputList3SigType2056=Serial InputList3Cue2057=Set Item 44 Icon Serial InputList3SigType2057=Serial InputList3Cue2058=Set Item 45 Icon Serial InputList3SigType2058=Serial InputList3Cue2059=Set Item 46 Icon Serial InputList3SigType2059=Serial InputList3Cue2060=Set Item 47 Icon Serial InputList3SigType2060=Serial InputList3Cue2061=Set Item 48 Icon Serial InputList3SigType2061=Serial InputList3Cue2062=Set Item 49 Icon Serial InputList3SigType2062=Serial InputList3Cue2063=Set Item 50 Icon Serial InputList3SigType2063=Serial InputList3Cue2064=Set Item 51 Icon Serial InputList3SigType2064=Serial InputList3Cue2065=Set Item 52 Icon Serial InputList3SigType2065=Serial InputList3Cue2066=Set Item 53 Icon Serial InputList3SigType2066=Serial InputList3Cue2067=Set Item 54 Icon Serial InputList3SigType2067=Serial InputList3Cue2068=Set Item 55 Icon Serial InputList3SigType2068=Serial InputList3Cue2069=Set Item 56 Icon Serial InputList3SigType2069=Serial InputList3Cue2070=Set Item 57 Icon Serial InputList3SigType2070=Serial InputList3Cue2071=Set Item 58 Icon Serial InputList3SigType2071=Serial InputList3Cue2072=Set Item 59 Icon Serial InputList3SigType2072=Serial InputList3Cue2073=Set Item 60 Icon Serial InputList3SigType2073=Serial InputList3Cue2074=Set Item 61 Icon Serial InputList3SigType2074=Serial InputList3Cue2075=Set Item 62 Icon Serial InputList3SigType2075=Serial InputList3Cue2076=Set Item 63 Icon Serial InputList3SigType2076=Serial InputList3Cue2077=Set Item 64 Icon Serial InputList3SigType2077=Serial InputList3Cue2078=Set Item 65 Icon Serial InputList3SigType2078=Serial InputList3Cue2079=Set Item 66 Icon Serial InputList3SigType2079=Serial InputList3Cue2080=Set Item 67 Icon Serial InputList3SigType2080=Serial InputList3Cue2081=Set Item 68 Icon Serial InputList3SigType2081=Serial InputList3Cue2082=Set Item 69 Icon Serial InputList3SigType2082=Serial InputList3Cue2083=Set Item 70 Icon Serial InputList3SigType2083=Serial InputList3Cue2084=Set Item 71 Icon Serial InputList3SigType2084=Serial InputList3Cue2085=Set Item 72 Icon Serial InputList3SigType2085=Serial InputList3Cue2086=Set Item 73 Icon Serial InputList3SigType2086=Serial InputList3Cue2087=Set Item 74 Icon Serial InputList3SigType2087=Serial InputList3Cue2088=Set Item 75 Icon Serial InputList3SigType2088=Serial InputList3Cue2089=Set Item 76 Icon Serial InputList3SigType2089=Serial InputList3Cue2090=Set Item 77 Icon Serial InputList3SigType2090=Serial InputList3Cue2091=Set Item 78 Icon Serial InputList3SigType2091=Serial InputList3Cue2092=Set Item 79 Icon Serial InputList3SigType2092=Serial InputList3Cue2093=Set Item 80 Icon Serial InputList3SigType2093=Serial InputList3Cue2094=Set Item 81 Icon Serial InputList3SigType2094=Serial InputList3Cue2095=Set Item 82 Icon Serial InputList3SigType2095=Serial InputList3Cue2096=Set Item 83 Icon Serial InputList3SigType2096=Serial InputList3Cue2097=Set Item 84 Icon Serial InputList3SigType2097=Serial InputList3Cue2098=Set Item 85 Icon Serial InputList3SigType2098=Serial InputList3Cue2099=Set Item 86 Icon Serial InputList3SigType2099=Serial InputList3Cue2100=Set Item 87 Icon Serial InputList3SigType2100=Serial InputList3Cue2101=Set Item 88 Icon Serial InputList3SigType2101=Serial InputList3Cue2102=Set Item 89 Icon Serial InputList3SigType2102=Serial InputList3Cue2103=Set Item 90 Icon Serial InputList3SigType2103=Serial InputList3Cue2104=Set Item 91 Icon Serial InputList3SigType2104=Serial InputList3Cue2105=Set Item 92 Icon Serial InputList3SigType2105=Serial InputList3Cue2106=Set Item 93 Icon Serial InputList3SigType2106=Serial InputList3Cue2107=Set Item 94 Icon Serial InputList3SigType2107=Serial InputList3Cue2108=Set Item 95 Icon Serial InputList3SigType2108=Serial InputList3Cue2109=Set Item 96 Icon Serial InputList3SigType2109=Serial InputList3Cue2110=Set Item 97 Icon Serial InputList3SigType2110=Serial InputList3Cue2111=Set Item 98 Icon Serial InputList3SigType2111=Serial InputList3Cue2112=Set Item 99 Icon Serial InputList3SigType2112=Serial InputList3Cue2113=Set Item 100 Icon Serial InputList3SigType2113=Serial InputList3Cue2114=Set Item 101 Icon Serial InputList3SigType2114=Serial InputList3Cue2115=Set Item 102 Icon Serial InputList3SigType2115=Serial InputList3Cue2116=Set Item 103 Icon Serial InputList3SigType2116=Serial InputList3Cue2117=Set Item 104 Icon Serial InputList3SigType2117=Serial InputList3Cue2118=Set Item 105 Icon Serial InputList3SigType2118=Serial InputList3Cue2119=Set Item 106 Icon Serial InputList3SigType2119=Serial InputList3Cue2120=Set Item 107 Icon Serial InputList3SigType2120=Serial InputList3Cue2121=Set Item 108 Icon Serial InputList3SigType2121=Serial InputList3Cue2122=Set Item 109 Icon Serial InputList3SigType2122=Serial InputList3Cue2123=Set Item 110 Icon Serial InputList3SigType2123=Serial InputList3Cue2124=Set Item 111 Icon Serial InputList3SigType2124=Serial InputList3Cue2125=Set Item 112 Icon Serial InputList3SigType2125=Serial InputList3Cue2126=Set Item 113 Icon Serial InputList3SigType2126=Serial InputList3Cue2127=Set Item 114 Icon Serial InputList3SigType2127=Serial InputList3Cue2128=Set Item 115 Icon Serial InputList3SigType2128=Serial InputList3Cue2129=Set Item 116 Icon Serial InputList3SigType2129=Serial InputList3Cue2130=Set Item 117 Icon Serial InputList3SigType2130=Serial InputList3Cue2131=Set Item 118 Icon Serial InputList3SigType2131=Serial InputList3Cue2132=Set Item 119 Icon Serial InputList3SigType2132=Serial InputList3Cue2133=Set Item 120 Icon Serial InputList3SigType2133=Serial InputList3Cue2134=Set Item 121 Icon Serial InputList3SigType2134=Serial InputList3Cue2135=Set Item 122 Icon Serial InputList3SigType2135=Serial InputList3Cue2136=Set Item 123 Icon Serial InputList3SigType2136=Serial InputList3Cue2137=Set Item 124 Icon Serial InputList3SigType2137=Serial InputList3Cue2138=Set Item 125 Icon Serial InputList3SigType2138=Serial InputList3Cue2139=Set Item 126 Icon Serial InputList3SigType2139=Serial InputList3Cue2140=Set Item 127 Icon Serial InputList3SigType2140=Serial InputList3Cue2141=Set Item 128 Icon Serial InputList3SigType2141=Serial InputList3Cue2142=Set Item 129 Icon Serial InputList3SigType2142=Serial InputList3Cue2143=Set Item 130 Icon Serial InputList3SigType2143=Serial InputList3Cue2144=Set Item 131 Icon Serial InputList3SigType2144=Serial InputList3Cue2145=Set Item 132 Icon Serial InputList3SigType2145=Serial InputList3Cue2146=Set Item 133 Icon Serial InputList3SigType2146=Serial InputList3Cue2147=Set Item 134 Icon Serial InputList3SigType2147=Serial InputList3Cue2148=Set Item 135 Icon Serial InputList3SigType2148=Serial InputList3Cue2149=Set Item 136 Icon Serial InputList3SigType2149=Serial InputList3Cue2150=Set Item 137 Icon Serial InputList3SigType2150=Serial InputList3Cue2151=Set Item 138 Icon Serial InputList3SigType2151=Serial InputList3Cue2152=Set Item 139 Icon Serial InputList3SigType2152=Serial InputList3Cue2153=Set Item 140 Icon Serial InputList3SigType2153=Serial InputList3Cue2154=Set Item 141 Icon Serial InputList3SigType2154=Serial InputList3Cue2155=Set Item 142 Icon Serial InputList3SigType2155=Serial InputList3Cue2156=Set Item 143 Icon Serial InputList3SigType2156=Serial InputList3Cue2157=Set Item 144 Icon Serial InputList3SigType2157=Serial InputList3Cue2158=Set Item 145 Icon Serial InputList3SigType2158=Serial InputList3Cue2159=Set Item 146 Icon Serial InputList3SigType2159=Serial InputList3Cue2160=Set Item 147 Icon Serial InputList3SigType2160=Serial InputList3Cue2161=Set Item 148 Icon Serial InputList3SigType2161=Serial InputList3Cue2162=Set Item 149 Icon Serial InputList3SigType2162=Serial InputList3Cue2163=Set Item 150 Icon Serial InputList3SigType2163=Serial InputList3Cue2164=Set Item 151 Icon Serial InputList3SigType2164=Serial InputList3Cue2165=Set Item 152 Icon Serial InputList3SigType2165=Serial InputList3Cue2166=Set Item 153 Icon Serial InputList3SigType2166=Serial InputList3Cue2167=Set Item 154 Icon Serial InputList3SigType2167=Serial InputList3Cue2168=Set Item 155 Icon Serial InputList3SigType2168=Serial InputList3Cue2169=Set Item 156 Icon Serial InputList3SigType2169=Serial InputList3Cue2170=Set Item 157 Icon Serial InputList3SigType2170=Serial InputList3Cue2171=Set Item 158 Icon Serial InputList3SigType2171=Serial InputList3Cue2172=Set Item 159 Icon Serial InputList3SigType2172=Serial InputList3Cue2173=Set Item 160 Icon Serial InputList3SigType2173=Serial InputList3Cue2174=Set Item 161 Icon Serial InputList3SigType2174=Serial InputList3Cue2175=Set Item 162 Icon Serial InputList3SigType2175=Serial InputList3Cue2176=Set Item 163 Icon Serial InputList3SigType2176=Serial InputList3Cue2177=Set Item 164 Icon Serial InputList3SigType2177=Serial InputList3Cue2178=Set Item 165 Icon Serial InputList3SigType2178=Serial InputList3Cue2179=Set Item 166 Icon Serial InputList3SigType2179=Serial InputList3Cue2180=Set Item 167 Icon Serial InputList3SigType2180=Serial InputList3Cue2181=Set Item 168 Icon Serial InputList3SigType2181=Serial InputList3Cue2182=Set Item 169 Icon Serial InputList3SigType2182=Serial InputList3Cue2183=Set Item 170 Icon Serial InputList3SigType2183=Serial InputList3Cue2184=Set Item 171 Icon Serial InputList3SigType2184=Serial InputList3Cue2185=Set Item 172 Icon Serial InputList3SigType2185=Serial InputList3Cue2186=Set Item 173 Icon Serial InputList3SigType2186=Serial InputList3Cue2187=Set Item 174 Icon Serial InputList3SigType2187=Serial InputList3Cue2188=Set Item 175 Icon Serial InputList3SigType2188=Serial InputList3Cue2189=Set Item 176 Icon Serial InputList3SigType2189=Serial InputList3Cue2190=Set Item 177 Icon Serial InputList3SigType2190=Serial InputList3Cue2191=Set Item 178 Icon Serial InputList3SigType2191=Serial InputList3Cue2192=Set Item 179 Icon Serial InputList3SigType2192=Serial InputList3Cue2193=Set Item 180 Icon Serial InputList3SigType2193=Serial InputList3Cue2194=Set Item 181 Icon Serial InputList3SigType2194=Serial InputList3Cue2195=Set Item 182 Icon Serial InputList3SigType2195=Serial InputList3Cue2196=Set Item 183 Icon Serial InputList3SigType2196=Serial InputList3Cue2197=Set Item 184 Icon Serial InputList3SigType2197=Serial InputList3Cue2198=Set Item 185 Icon Serial InputList3SigType2198=Serial InputList3Cue2199=Set Item 186 Icon Serial InputList3SigType2199=Serial InputList3Cue2200=Set Item 187 Icon Serial InputList3SigType2200=Serial InputList3Cue2201=Set Item 188 Icon Serial InputList3SigType2201=Serial InputList3Cue2202=Set Item 189 Icon Serial InputList3SigType2202=Serial InputList3Cue2203=Set Item 190 Icon Serial InputList3SigType2203=Serial InputList3Cue2204=Set Item 191 Icon Serial InputList3SigType2204=Serial InputList3Cue2205=Set Item 192 Icon Serial InputList3SigType2205=Serial InputList3Cue2206=Set Item 193 Icon Serial InputList3SigType2206=Serial InputList3Cue2207=Set Item 194 Icon Serial InputList3SigType2207=Serial InputList3Cue2208=Set Item 195 Icon Serial InputList3SigType2208=Serial InputList3Cue2209=Set Item 196 Icon Serial InputList3SigType2209=Serial InputList3Cue2210=Set Item 197 Icon Serial InputList3SigType2210=Serial InputList3Cue2211=Set Item 198 Icon Serial InputList3SigType2211=Serial InputList3Cue2212=Set Item 199 Icon Serial InputList3SigType2212=Serial InputList3Cue2213=Set Item 200 Icon Serial InputList3SigType2213=Serial InputList3Cue2214=Set Item 201 Icon Serial InputList3SigType2214=Serial InputList3Cue2215=Set Item 202 Icon Serial InputList3SigType2215=Serial InputList3Cue2216=Set Item 203 Icon Serial InputList3SigType2216=Serial InputList3Cue2217=Set Item 204 Icon Serial InputList3SigType2217=Serial InputList3Cue2218=Set Item 205 Icon Serial InputList3SigType2218=Serial InputList3Cue2219=Set Item 206 Icon Serial InputList3SigType2219=Serial InputList3Cue2220=Set Item 207 Icon Serial InputList3SigType2220=Serial InputList3Cue2221=Set Item 208 Icon Serial InputList3SigType2221=Serial InputList3Cue2222=Set Item 209 Icon Serial InputList3SigType2222=Serial InputList3Cue2223=Set Item 210 Icon Serial InputList3SigType2223=Serial InputList3Cue2224=Set Item 211 Icon Serial InputList3SigType2224=Serial InputList3Cue2225=Set Item 212 Icon Serial InputList3SigType2225=Serial InputList3Cue2226=Set Item 213 Icon Serial InputList3SigType2226=Serial InputList3Cue2227=Set Item 214 Icon Serial InputList3SigType2227=Serial InputList3Cue2228=Set Item 215 Icon Serial InputList3SigType2228=Serial InputList3Cue2229=Set Item 216 Icon Serial InputList3SigType2229=Serial InputList3Cue2230=Set Item 217 Icon Serial InputList3SigType2230=Serial InputList3Cue2231=Set Item 218 Icon Serial InputList3SigType2231=Serial InputList3Cue2232=Set Item 219 Icon Serial InputList3SigType2232=Serial InputList3Cue2233=Set Item 220 Icon Serial InputList3SigType2233=Serial InputList3Cue2234=Set Item 221 Icon Serial InputList3SigType2234=Serial InputList3Cue2235=Set Item 222 Icon Serial InputList3SigType2235=Serial InputList3Cue2236=Set Item 223 Icon Serial InputList3SigType2236=Serial InputList3Cue2237=Set Item 224 Icon Serial InputList3SigType2237=Serial InputList3Cue2238=Set Item 225 Icon Serial InputList3SigType2238=Serial InputList3Cue2239=Set Item 226 Icon Serial InputList3SigType2239=Serial InputList3Cue2240=Set Item 227 Icon Serial InputList3SigType2240=Serial InputList3Cue2241=Set Item 228 Icon Serial InputList3SigType2241=Serial InputList3Cue2242=Set Item 229 Icon Serial InputList3SigType2242=Serial InputList3Cue2243=Set Item 230 Icon Serial InputList3SigType2243=Serial InputList3Cue2244=Set Item 231 Icon Serial InputList3SigType2244=Serial InputList3Cue2245=Set Item 232 Icon Serial InputList3SigType2245=Serial InputList3Cue2246=Set Item 233 Icon Serial InputList3SigType2246=Serial InputList3Cue2247=Set Item 234 Icon Serial InputList3SigType2247=Serial InputList3Cue2248=Set Item 235 Icon Serial InputList3SigType2248=Serial InputList3Cue2249=Set Item 236 Icon Serial InputList3SigType2249=Serial InputList3Cue2250=Set Item 237 Icon Serial InputList3SigType2250=Serial InputList3Cue2251=Set Item 238 Icon Serial InputList3SigType2251=Serial InputList3Cue2252=Set Item 239 Icon Serial InputList3SigType2252=Serial InputList3Cue2253=Set Item 240 Icon Serial InputList3SigType2253=Serial InputList3Cue2254=Set Item 241 Icon Serial InputList3SigType2254=Serial InputList3Cue2255=Set Item 242 Icon Serial InputList3SigType2255=Serial InputList3Cue2256=Set Item 243 Icon Serial InputList3SigType2256=Serial InputList3Cue2257=Set Item 244 Icon Serial InputList3SigType2257=Serial InputList3Cue2258=Set Item 245 Icon Serial InputList3SigType2258=Serial InputList3Cue2259=Set Item 246 Icon Serial InputList3SigType2259=Serial InputList3Cue2260=Set Item 247 Icon Serial InputList3SigType2260=Serial InputList3Cue2261=Set Item 248 Icon Serial InputList3SigType2261=Serial InputList3Cue2262=Set Item 249 Icon Serial InputList3SigType2262=Serial InputList3Cue2263=Set Item 250 Icon Serial InputList3SigType2263=Serial InputList3Cue2264=Set Item 251 Icon Serial InputList3SigType2264=Serial InputList3Cue2265=Set Item 252 Icon Serial InputList3SigType2265=Serial InputList3Cue2266=Set Item 253 Icon Serial InputList3SigType2266=Serial InputList3Cue2267=Set Item 254 Icon Serial InputList3SigType2267=Serial InputList3Cue2268=Set Item 255 Icon Serial InputList3SigType2268=Serial InputList3Cue2269=[~UNUSED2~] InputList3SigType2269=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED3~] OutputList3SigType22=Serial OutputList3Cue23=[~UNUSED3~] OutputList3SigType23=Serial OutputList3Cue24=[~UNUSED3~] OutputList3SigType24=Serial OutputList3Cue25=[~UNUSED3~] OutputList3SigType25=Serial OutputList3Cue26=[~UNUSED3~] OutputList3SigType26=Serial OutputList3Cue27=[~UNUSED3~] OutputList3SigType27=Serial OutputList3Cue28=[~UNUSED3~] OutputList3SigType28=Serial OutputList3Cue29=[~UNUSED3~] OutputList3SigType29=Serial OutputList3Cue30=[~UNUSED3~] OutputList3SigType30=Serial OutputList3Cue31=[~UNUSED3~] OutputList3SigType31=Serial OutputList3Cue32=[~UNUSED3~] OutputList3SigType32=Serial OutputList3Cue33=[~UNUSED3~] OutputList3SigType33=Serial OutputList3Cue34=[~UNUSED3~] OutputList3SigType34=Serial OutputList3Cue35=[~UNUSED3~] OutputList3SigType35=Serial OutputList3Cue36=[~UNUSED3~] OutputList3SigType36=Serial OutputList3Cue37=[~UNUSED3~] OutputList3SigType37=Serial OutputList3Cue38=[~UNUSED3~] OutputList3SigType38=Serial OutputList3Cue39=[~UNUSED3~] OutputList3SigType39=Serial OutputList3Cue40=[~UNUSED3~] OutputList3SigType40=Serial OutputList3Cue41=[~UNUSED3~] OutputList3SigType41=Serial OutputList3Cue42=[~UNUSED3~] OutputList3SigType42=Serial OutputList3Cue43=[~UNUSED3~] OutputList3SigType43=Serial OutputList3Cue44=[~UNUSED3~] OutputList3SigType44=Serial OutputList3Cue45=[~UNUSED3~] OutputList3SigType45=Serial OutputList3Cue46=[~UNUSED3~] OutputList3SigType46=Serial OutputList3Cue47=[~UNUSED3~] OutputList3SigType47=Serial OutputList3Cue48=[~UNUSED3~] OutputList3SigType48=Serial OutputList3Cue49=[~UNUSED3~] OutputList3SigType49=Serial OutputList3Cue50=[~UNUSED3~] OutputList3SigType50=Serial OutputList3Cue51=[~UNUSED3~] OutputList3SigType51=Serial OutputList3Cue52=[~UNUSED3~] OutputList3SigType52=Serial OutputList3Cue53=[~UNUSED3~] OutputList3SigType53=Serial OutputList3Cue54=[~UNUSED3~] OutputList3SigType54=Serial OutputList3Cue55=[~UNUSED3~] OutputList3SigType55=Serial OutputList3Cue56=[~UNUSED3~] OutputList3SigType56=Serial OutputList3Cue57=[~UNUSED3~] OutputList3SigType57=Serial OutputList3Cue58=[~UNUSED3~] OutputList3SigType58=Serial OutputList3Cue59=[~UNUSED3~] OutputList3SigType59=Serial OutputList3Cue60=[~UNUSED3~] OutputList3SigType60=Serial OutputList3Cue61=[~UNUSED3~] OutputList3SigType61=Serial OutputList3Cue62=[~UNUSED3~] OutputList3SigType62=Serial OutputList3Cue63=[~UNUSED3~] OutputList3SigType63=Serial OutputList3Cue64=[~UNUSED3~] OutputList3SigType64=Serial OutputList3Cue65=[~UNUSED3~] OutputList3SigType65=Serial OutputList3Cue66=[~UNUSED3~] OutputList3SigType66=Serial OutputList3Cue67=[~UNUSED3~] OutputList3SigType67=Serial OutputList3Cue68=[~UNUSED3~] OutputList3SigType68=Serial OutputList3Cue69=[~UNUSED3~] OutputList3SigType69=Serial OutputList3Cue70=[~UNUSED3~] OutputList3SigType70=Serial OutputList3Cue71=[~UNUSED3~] OutputList3SigType71=Serial OutputList3Cue72=[~UNUSED3~] OutputList3SigType72=Serial OutputList3Cue73=[~UNUSED3~] OutputList3SigType73=Serial OutputList3Cue74=[~UNUSED3~] OutputList3SigType74=Serial OutputList3Cue75=[~UNUSED3~] OutputList3SigType75=Serial OutputList3Cue76=[~UNUSED3~] OutputList3SigType76=Serial OutputList3Cue77=[~UNUSED3~] OutputList3SigType77=Serial OutputList3Cue78=[~UNUSED3~] OutputList3SigType78=Serial OutputList3Cue79=[~UNUSED3~] OutputList3SigType79=Serial OutputList3Cue80=[~UNUSED3~] OutputList3SigType80=Serial OutputList3Cue81=[~UNUSED3~] OutputList3SigType81=Serial OutputList3Cue82=[~UNUSED3~] OutputList3SigType82=Serial OutputList3Cue83=[~UNUSED3~] OutputList3SigType83=Serial OutputList3Cue84=[~UNUSED3~] OutputList3SigType84=Serial OutputList3Cue85=[~UNUSED3~] OutputList3SigType85=Serial OutputList3Cue86=[~UNUSED3~] OutputList3SigType86=Serial OutputList3Cue87=[~UNUSED3~] OutputList3SigType87=Serial OutputList3Cue88=[~UNUSED3~] OutputList3SigType88=Serial OutputList3Cue89=[~UNUSED3~] OutputList3SigType89=Serial OutputList3Cue90=[~UNUSED3~] OutputList3SigType90=Serial OutputList3Cue91=[~UNUSED3~] OutputList3SigType91=Serial OutputList3Cue92=[~UNUSED3~] OutputList3SigType92=Serial OutputList3Cue93=[~UNUSED3~] OutputList3SigType93=Serial OutputList3Cue94=[~UNUSED3~] OutputList3SigType94=Serial OutputList3Cue95=[~UNUSED3~] OutputList3SigType95=Serial OutputList3Cue96=[~UNUSED3~] OutputList3SigType96=Serial OutputList3Cue97=[~UNUSED3~] OutputList3SigType97=Serial OutputList3Cue98=[~UNUSED3~] OutputList3SigType98=Serial OutputList3Cue99=[~UNUSED3~] OutputList3SigType99=Serial OutputList3Cue100=[~UNUSED3~] OutputList3SigType100=Serial OutputList3Cue101=[~UNUSED3~] OutputList3SigType101=Serial OutputList3Cue102=[~UNUSED3~] OutputList3SigType102=Serial OutputList3Cue103=[~UNUSED3~] OutputList3SigType103=Serial OutputList3Cue104=[~UNUSED3~] OutputList3SigType104=Serial OutputList3Cue105=[~UNUSED3~] OutputList3SigType105=Serial OutputList3Cue106=[~UNUSED3~] OutputList3SigType106=Serial OutputList3Cue107=[~UNUSED3~] OutputList3SigType107=Serial OutputList3Cue108=[~UNUSED3~] OutputList3SigType108=Serial OutputList3Cue109=[~UNUSED3~] OutputList3SigType109=Serial OutputList3Cue110=[~UNUSED3~] OutputList3SigType110=Serial OutputList3Cue111=[~UNUSED3~] OutputList3SigType111=Serial OutputList3Cue112=[~UNUSED3~] OutputList3SigType112=Serial OutputList3Cue113=[~UNUSED3~] OutputList3SigType113=Serial OutputList3Cue114=[~UNUSED3~] OutputList3SigType114=Serial OutputList3Cue115=[~UNUSED3~] OutputList3SigType115=Serial OutputList3Cue116=[~UNUSED3~] OutputList3SigType116=Serial OutputList3Cue117=[~UNUSED3~] OutputList3SigType117=Serial OutputList3Cue118=[~UNUSED3~] OutputList3SigType118=Serial OutputList3Cue119=[~UNUSED3~] OutputList3SigType119=Serial OutputList3Cue120=[~UNUSED3~] OutputList3SigType120=Serial OutputList3Cue121=[~UNUSED3~] OutputList3SigType121=Serial OutputList3Cue122=[~UNUSED3~] OutputList3SigType122=Serial OutputList3Cue123=[~UNUSED3~] OutputList3SigType123=Serial OutputList3Cue124=[~UNUSED3~] OutputList3SigType124=Serial OutputList3Cue125=[~UNUSED3~] OutputList3SigType125=Serial OutputList3Cue126=[~UNUSED3~] OutputList3SigType126=Serial OutputList3Cue127=[~UNUSED3~] OutputList3SigType127=Serial OutputList3Cue128=[~UNUSED3~] OutputList3SigType128=Serial OutputList3Cue129=[~UNUSED3~] OutputList3SigType129=Serial OutputList3Cue130=[~UNUSED3~] OutputList3SigType130=Serial OutputList3Cue131=[~UNUSED3~] OutputList3SigType131=Serial OutputList3Cue132=[~UNUSED3~] OutputList3SigType132=Serial OutputList3Cue133=[~UNUSED3~] OutputList3SigType133=Serial OutputList3Cue134=[~UNUSED3~] OutputList3SigType134=Serial OutputList3Cue135=[~UNUSED3~] OutputList3SigType135=Serial OutputList3Cue136=[~UNUSED3~] OutputList3SigType136=Serial OutputList3Cue137=[~UNUSED3~] OutputList3SigType137=Serial OutputList3Cue138=[~UNUSED3~] OutputList3SigType138=Serial OutputList3Cue139=[~UNUSED3~] OutputList3SigType139=Serial OutputList3Cue140=[~UNUSED3~] OutputList3SigType140=Serial OutputList3Cue141=[~UNUSED3~] OutputList3SigType141=Serial OutputList3Cue142=[~UNUSED3~] OutputList3SigType142=Serial OutputList3Cue143=[~UNUSED3~] OutputList3SigType143=Serial OutputList3Cue144=[~UNUSED3~] OutputList3SigType144=Serial OutputList3Cue145=[~UNUSED3~] OutputList3SigType145=Serial OutputList3Cue146=[~UNUSED3~] OutputList3SigType146=Serial OutputList3Cue147=[~UNUSED3~] OutputList3SigType147=Serial OutputList3Cue148=[~UNUSED3~] OutputList3SigType148=Serial OutputList3Cue149=[~UNUSED3~] OutputList3SigType149=Serial OutputList3Cue150=[~UNUSED3~] OutputList3SigType150=Serial OutputList3Cue151=[~UNUSED3~] OutputList3SigType151=Serial OutputList3Cue152=[~UNUSED3~] OutputList3SigType152=Serial OutputList3Cue153=[~UNUSED3~] OutputList3SigType153=Serial OutputList3Cue154=[~UNUSED3~] OutputList3SigType154=Serial OutputList3Cue155=[~UNUSED3~] OutputList3SigType155=Serial OutputList3Cue156=[~UNUSED3~] OutputList3SigType156=Serial OutputList3Cue157=[~UNUSED3~] OutputList3SigType157=Serial OutputList3Cue158=[~UNUSED3~] OutputList3SigType158=Serial OutputList3Cue159=[~UNUSED3~] OutputList3SigType159=Serial OutputList3Cue160=[~UNUSED3~] OutputList3SigType160=Serial OutputList3Cue161=[~UNUSED3~] OutputList3SigType161=Serial OutputList3Cue162=[~UNUSED3~] OutputList3SigType162=Serial OutputList3Cue163=[~UNUSED3~] OutputList3SigType163=Serial OutputList3Cue164=[~UNUSED3~] OutputList3SigType164=Serial OutputList3Cue165=[~UNUSED3~] OutputList3SigType165=Serial OutputList3Cue166=[~UNUSED3~] OutputList3SigType166=Serial OutputList3Cue167=[~UNUSED3~] OutputList3SigType167=Serial OutputList3Cue168=[~UNUSED3~] OutputList3SigType168=Serial OutputList3Cue169=[~UNUSED3~] OutputList3SigType169=Serial OutputList3Cue170=[~UNUSED3~] OutputList3SigType170=Serial OutputList3Cue171=[~UNUSED3~] OutputList3SigType171=Serial OutputList3Cue172=[~UNUSED3~] OutputList3SigType172=Serial OutputList3Cue173=[~UNUSED3~] OutputList3SigType173=Serial OutputList3Cue174=[~UNUSED3~] OutputList3SigType174=Serial OutputList3Cue175=[~UNUSED3~] OutputList3SigType175=Serial OutputList3Cue176=[~UNUSED3~] OutputList3SigType176=Serial OutputList3Cue177=[~UNUSED3~] OutputList3SigType177=Serial OutputList3Cue178=[~UNUSED3~] OutputList3SigType178=Serial OutputList3Cue179=[~UNUSED3~] OutputList3SigType179=Serial OutputList3Cue180=[~UNUSED3~] OutputList3SigType180=Serial OutputList3Cue181=[~UNUSED3~] OutputList3SigType181=Serial OutputList3Cue182=[~UNUSED3~] OutputList3SigType182=Serial OutputList3Cue183=[~UNUSED3~] OutputList3SigType183=Serial OutputList3Cue184=[~UNUSED3~] OutputList3SigType184=Serial OutputList3Cue185=[~UNUSED3~] OutputList3SigType185=Serial OutputList3Cue186=[~UNUSED3~] OutputList3SigType186=Serial OutputList3Cue187=[~UNUSED3~] OutputList3SigType187=Serial OutputList3Cue188=[~UNUSED3~] OutputList3SigType188=Serial OutputList3Cue189=[~UNUSED3~] OutputList3SigType189=Serial OutputList3Cue190=[~UNUSED3~] OutputList3SigType190=Serial OutputList3Cue191=[~UNUSED3~] OutputList3SigType191=Serial OutputList3Cue192=[~UNUSED3~] OutputList3SigType192=Serial OutputList3Cue193=[~UNUSED3~] OutputList3SigType193=Serial OutputList3Cue194=[~UNUSED3~] OutputList3SigType194=Serial OutputList3Cue195=[~UNUSED3~] OutputList3SigType195=Serial OutputList3Cue196=[~UNUSED3~] OutputList3SigType196=Serial OutputList3Cue197=[~UNUSED3~] OutputList3SigType197=Serial OutputList3Cue198=[~UNUSED3~] OutputList3SigType198=Serial OutputList3Cue199=[~UNUSED3~] OutputList3SigType199=Serial OutputList3Cue200=[~UNUSED3~] OutputList3SigType200=Serial OutputList3Cue201=[~UNUSED3~] OutputList3SigType201=Serial OutputList3Cue202=[~UNUSED3~] OutputList3SigType202=Serial OutputList3Cue203=[~UNUSED3~] OutputList3SigType203=Serial OutputList3Cue204=[~UNUSED3~] OutputList3SigType204=Serial OutputList3Cue205=[~UNUSED3~] OutputList3SigType205=Serial OutputList3Cue206=[~UNUSED3~] OutputList3SigType206=Serial OutputList3Cue207=[~UNUSED3~] OutputList3SigType207=Serial OutputList3Cue208=[~UNUSED3~] OutputList3SigType208=Serial OutputList3Cue209=[~UNUSED3~] OutputList3SigType209=Serial OutputList3Cue210=[~UNUSED3~] OutputList3SigType210=Serial OutputList3Cue211=[~UNUSED3~] OutputList3SigType211=Serial OutputList3Cue212=[~UNUSED3~] OutputList3SigType212=Serial OutputList3Cue213=[~UNUSED3~] OutputList3SigType213=Serial OutputList3Cue214=[~UNUSED3~] OutputList3SigType214=Serial OutputList3Cue215=[~UNUSED3~] OutputList3SigType215=Serial OutputList3Cue216=[~UNUSED3~] OutputList3SigType216=Serial OutputList3Cue217=[~UNUSED3~] OutputList3SigType217=Serial OutputList3Cue218=[~UNUSED3~] OutputList3SigType218=Serial OutputList3Cue219=[~UNUSED3~] OutputList3SigType219=Serial OutputList3Cue220=[~UNUSED3~] OutputList3SigType220=Serial OutputList3Cue221=[~UNUSED3~] OutputList3SigType221=Serial OutputList3Cue222=[~UNUSED3~] OutputList3SigType222=Serial OutputList3Cue223=[~UNUSED3~] OutputList3SigType223=Serial OutputList3Cue224=[~UNUSED3~] OutputList3SigType224=Serial OutputList3Cue225=[~UNUSED3~] OutputList3SigType225=Serial OutputList3Cue226=[~UNUSED3~] OutputList3SigType226=Serial OutputList3Cue227=[~UNUSED3~] OutputList3SigType227=Serial OutputList3Cue228=[~UNUSED3~] OutputList3SigType228=Serial OutputList3Cue229=[~UNUSED3~] OutputList3SigType229=Serial OutputList3Cue230=[~UNUSED3~] OutputList3SigType230=Serial OutputList3Cue231=[~UNUSED3~] OutputList3SigType231=Serial OutputList3Cue232=[~UNUSED3~] OutputList3SigType232=Serial OutputList3Cue233=[~UNUSED3~] OutputList3SigType233=Serial OutputList3Cue234=[~UNUSED3~] OutputList3SigType234=Serial OutputList3Cue235=[~UNUSED3~] OutputList3SigType235=Serial OutputList3Cue236=[~UNUSED3~] OutputList3SigType236=Serial OutputList3Cue237=[~UNUSED3~] OutputList3SigType237=Serial OutputList3Cue238=[~UNUSED3~] OutputList3SigType238=Serial OutputList3Cue239=[~UNUSED3~] OutputList3SigType239=Serial OutputList3Cue240=[~UNUSED3~] OutputList3SigType240=Serial OutputList3Cue241=[~UNUSED3~] OutputList3SigType241=Serial OutputList3Cue242=[~UNUSED3~] OutputList3SigType242=Serial OutputList3Cue243=[~UNUSED3~] OutputList3SigType243=Serial OutputList3Cue244=[~UNUSED3~] OutputList3SigType244=Serial OutputList3Cue245=[~UNUSED3~] OutputList3SigType245=Serial OutputList3Cue246=[~UNUSED3~] OutputList3SigType246=Serial OutputList3Cue247=[~UNUSED3~] OutputList3SigType247=Serial OutputList3Cue248=[~UNUSED3~] OutputList3SigType248=Serial OutputList3Cue249=[~UNUSED3~] OutputList3SigType249=Serial OutputList3Cue250=[~UNUSED3~] OutputList3SigType250=Serial OutputList3Cue251=[~UNUSED3~] OutputList3SigType251=Serial OutputList3Cue252=[~UNUSED3~] OutputList3SigType252=Serial OutputList3Cue253=[~UNUSED3~] OutputList3SigType253=Serial OutputList3Cue254=[~UNUSED3~] OutputList3SigType254=Serial OutputList3Cue255=[~UNUSED3~] OutputList3SigType255=Serial OutputList3Cue256=[~UNUSED3~] OutputList3SigType256=Serial OutputList3Cue257=[~UNUSED3~] OutputList3SigType257=Serial OutputList3Cue258=[~UNUSED3~] OutputList3SigType258=Serial OutputList3Cue259=[~UNUSED3~] OutputList3SigType259=Serial OutputList3Cue260=[~UNUSED3~] OutputList3SigType260=Serial OutputList3Cue261=[~UNUSED3~] OutputList3SigType261=Serial OutputList3Cue262=[~UNUSED3~] OutputList3SigType262=Serial OutputList3Cue263=[~UNUSED3~] OutputList3SigType263=Serial OutputList3Cue264=[~UNUSED3~] OutputList3SigType264=Serial OutputList3Cue265=[~UNUSED3~] OutputList3SigType265=Serial OutputList3Cue266=[~UNUSED3~] OutputList3SigType266=Serial OutputList3Cue267=[~UNUSED2~] OutputList3SigType267=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED3~] OutputList3SigType2024=Serial OutputList3Cue2025=[~UNUSED3~] OutputList3SigType2025=Serial OutputList3Cue2026=[~UNUSED3~] OutputList3SigType2026=Serial OutputList3Cue2027=[~UNUSED3~] OutputList3SigType2027=Serial OutputList3Cue2028=[~UNUSED3~] OutputList3SigType2028=Serial OutputList3Cue2029=[~UNUSED3~] OutputList3SigType2029=Serial OutputList3Cue2030=[~UNUSED3~] OutputList3SigType2030=Serial OutputList3Cue2031=[~UNUSED3~] OutputList3SigType2031=Serial OutputList3Cue2032=[~UNUSED3~] OutputList3SigType2032=Serial OutputList3Cue2033=[~UNUSED3~] OutputList3SigType2033=Serial OutputList3Cue2034=[~UNUSED3~] OutputList3SigType2034=Serial OutputList3Cue2035=[~UNUSED3~] OutputList3SigType2035=Serial OutputList3Cue2036=[~UNUSED3~] OutputList3SigType2036=Serial OutputList3Cue2037=[~UNUSED3~] OutputList3SigType2037=Serial OutputList3Cue2038=[~UNUSED3~] OutputList3SigType2038=Serial OutputList3Cue2039=[~UNUSED3~] OutputList3SigType2039=Serial OutputList3Cue2040=[~UNUSED3~] OutputList3SigType2040=Serial OutputList3Cue2041=[~UNUSED3~] OutputList3SigType2041=Serial OutputList3Cue2042=[~UNUSED3~] OutputList3SigType2042=Serial OutputList3Cue2043=[~UNUSED3~] OutputList3SigType2043=Serial OutputList3Cue2044=[~UNUSED3~] OutputList3SigType2044=Serial OutputList3Cue2045=[~UNUSED3~] OutputList3SigType2045=Serial OutputList3Cue2046=[~UNUSED3~] OutputList3SigType2046=Serial OutputList3Cue2047=[~UNUSED3~] OutputList3SigType2047=Serial OutputList3Cue2048=[~UNUSED3~] OutputList3SigType2048=Serial OutputList3Cue2049=[~UNUSED3~] OutputList3SigType2049=Serial OutputList3Cue2050=[~UNUSED3~] OutputList3SigType2050=Serial OutputList3Cue2051=[~UNUSED3~] OutputList3SigType2051=Serial OutputList3Cue2052=[~UNUSED3~] OutputList3SigType2052=Serial OutputList3Cue2053=[~UNUSED3~] OutputList3SigType2053=Serial OutputList3Cue2054=[~UNUSED3~] OutputList3SigType2054=Serial OutputList3Cue2055=[~UNUSED3~] OutputList3SigType2055=Serial OutputList3Cue2056=[~UNUSED3~] OutputList3SigType2056=Serial OutputList3Cue2057=[~UNUSED3~] OutputList3SigType2057=Serial OutputList3Cue2058=[~UNUSED3~] OutputList3SigType2058=Serial OutputList3Cue2059=[~UNUSED3~] OutputList3SigType2059=Serial OutputList3Cue2060=[~UNUSED3~] OutputList3SigType2060=Serial OutputList3Cue2061=[~UNUSED3~] OutputList3SigType2061=Serial OutputList3Cue2062=[~UNUSED3~] OutputList3SigType2062=Serial OutputList3Cue2063=[~UNUSED3~] OutputList3SigType2063=Serial OutputList3Cue2064=[~UNUSED3~] OutputList3SigType2064=Serial OutputList3Cue2065=[~UNUSED3~] OutputList3SigType2065=Serial OutputList3Cue2066=[~UNUSED3~] OutputList3SigType2066=Serial OutputList3Cue2067=[~UNUSED3~] OutputList3SigType2067=Serial OutputList3Cue2068=[~UNUSED3~] OutputList3SigType2068=Serial OutputList3Cue2069=[~UNUSED3~] OutputList3SigType2069=Serial OutputList3Cue2070=[~UNUSED3~] OutputList3SigType2070=Serial OutputList3Cue2071=[~UNUSED3~] OutputList3SigType2071=Serial OutputList3Cue2072=[~UNUSED3~] OutputList3SigType2072=Serial OutputList3Cue2073=[~UNUSED3~] OutputList3SigType2073=Serial OutputList3Cue2074=[~UNUSED3~] OutputList3SigType2074=Serial OutputList3Cue2075=[~UNUSED3~] OutputList3SigType2075=Serial OutputList3Cue2076=[~UNUSED3~] OutputList3SigType2076=Serial OutputList3Cue2077=[~UNUSED3~] OutputList3SigType2077=Serial OutputList3Cue2078=[~UNUSED3~] OutputList3SigType2078=Serial OutputList3Cue2079=[~UNUSED3~] OutputList3SigType2079=Serial OutputList3Cue2080=[~UNUSED3~] OutputList3SigType2080=Serial OutputList3Cue2081=[~UNUSED3~] OutputList3SigType2081=Serial OutputList3Cue2082=[~UNUSED3~] OutputList3SigType2082=Serial OutputList3Cue2083=[~UNUSED3~] OutputList3SigType2083=Serial OutputList3Cue2084=[~UNUSED3~] OutputList3SigType2084=Serial OutputList3Cue2085=[~UNUSED3~] OutputList3SigType2085=Serial OutputList3Cue2086=[~UNUSED3~] OutputList3SigType2086=Serial OutputList3Cue2087=[~UNUSED3~] OutputList3SigType2087=Serial OutputList3Cue2088=[~UNUSED3~] OutputList3SigType2088=Serial OutputList3Cue2089=[~UNUSED3~] OutputList3SigType2089=Serial OutputList3Cue2090=[~UNUSED3~] OutputList3SigType2090=Serial OutputList3Cue2091=[~UNUSED3~] OutputList3SigType2091=Serial OutputList3Cue2092=[~UNUSED3~] OutputList3SigType2092=Serial OutputList3Cue2093=[~UNUSED3~] OutputList3SigType2093=Serial OutputList3Cue2094=[~UNUSED3~] OutputList3SigType2094=Serial OutputList3Cue2095=[~UNUSED3~] OutputList3SigType2095=Serial OutputList3Cue2096=[~UNUSED3~] OutputList3SigType2096=Serial OutputList3Cue2097=[~UNUSED3~] OutputList3SigType2097=Serial OutputList3Cue2098=[~UNUSED3~] OutputList3SigType2098=Serial OutputList3Cue2099=[~UNUSED3~] OutputList3SigType2099=Serial OutputList3Cue2100=[~UNUSED3~] OutputList3SigType2100=Serial OutputList3Cue2101=[~UNUSED3~] OutputList3SigType2101=Serial OutputList3Cue2102=[~UNUSED3~] OutputList3SigType2102=Serial OutputList3Cue2103=[~UNUSED3~] OutputList3SigType2103=Serial OutputList3Cue2104=[~UNUSED3~] OutputList3SigType2104=Serial OutputList3Cue2105=[~UNUSED3~] OutputList3SigType2105=Serial OutputList3Cue2106=[~UNUSED3~] OutputList3SigType2106=Serial OutputList3Cue2107=[~UNUSED3~] OutputList3SigType2107=Serial OutputList3Cue2108=[~UNUSED3~] OutputList3SigType2108=Serial OutputList3Cue2109=[~UNUSED3~] OutputList3SigType2109=Serial OutputList3Cue2110=[~UNUSED3~] OutputList3SigType2110=Serial OutputList3Cue2111=[~UNUSED3~] OutputList3SigType2111=Serial OutputList3Cue2112=[~UNUSED3~] OutputList3SigType2112=Serial OutputList3Cue2113=[~UNUSED3~] OutputList3SigType2113=Serial OutputList3Cue2114=[~UNUSED3~] OutputList3SigType2114=Serial OutputList3Cue2115=[~UNUSED3~] OutputList3SigType2115=Serial OutputList3Cue2116=[~UNUSED3~] OutputList3SigType2116=Serial OutputList3Cue2117=[~UNUSED3~] OutputList3SigType2117=Serial OutputList3Cue2118=[~UNUSED3~] OutputList3SigType2118=Serial OutputList3Cue2119=[~UNUSED3~] OutputList3SigType2119=Serial OutputList3Cue2120=[~UNUSED3~] OutputList3SigType2120=Serial OutputList3Cue2121=[~UNUSED3~] OutputList3SigType2121=Serial OutputList3Cue2122=[~UNUSED3~] OutputList3SigType2122=Serial OutputList3Cue2123=[~UNUSED3~] OutputList3SigType2123=Serial OutputList3Cue2124=[~UNUSED3~] OutputList3SigType2124=Serial OutputList3Cue2125=[~UNUSED3~] OutputList3SigType2125=Serial OutputList3Cue2126=[~UNUSED3~] OutputList3SigType2126=Serial OutputList3Cue2127=[~UNUSED3~] OutputList3SigType2127=Serial OutputList3Cue2128=[~UNUSED3~] OutputList3SigType2128=Serial OutputList3Cue2129=[~UNUSED3~] OutputList3SigType2129=Serial OutputList3Cue2130=[~UNUSED3~] OutputList3SigType2130=Serial OutputList3Cue2131=[~UNUSED3~] OutputList3SigType2131=Serial OutputList3Cue2132=[~UNUSED3~] OutputList3SigType2132=Serial OutputList3Cue2133=[~UNUSED3~] OutputList3SigType2133=Serial OutputList3Cue2134=[~UNUSED3~] OutputList3SigType2134=Serial OutputList3Cue2135=[~UNUSED3~] OutputList3SigType2135=Serial OutputList3Cue2136=[~UNUSED3~] OutputList3SigType2136=Serial OutputList3Cue2137=[~UNUSED3~] OutputList3SigType2137=Serial OutputList3Cue2138=[~UNUSED3~] OutputList3SigType2138=Serial OutputList3Cue2139=[~UNUSED3~] OutputList3SigType2139=Serial OutputList3Cue2140=[~UNUSED3~] OutputList3SigType2140=Serial OutputList3Cue2141=[~UNUSED3~] OutputList3SigType2141=Serial OutputList3Cue2142=[~UNUSED3~] OutputList3SigType2142=Serial OutputList3Cue2143=[~UNUSED3~] OutputList3SigType2143=Serial OutputList3Cue2144=[~UNUSED3~] OutputList3SigType2144=Serial OutputList3Cue2145=[~UNUSED3~] OutputList3SigType2145=Serial OutputList3Cue2146=[~UNUSED3~] OutputList3SigType2146=Serial OutputList3Cue2147=[~UNUSED3~] OutputList3SigType2147=Serial OutputList3Cue2148=[~UNUSED3~] OutputList3SigType2148=Serial OutputList3Cue2149=[~UNUSED3~] OutputList3SigType2149=Serial OutputList3Cue2150=[~UNUSED3~] OutputList3SigType2150=Serial OutputList3Cue2151=[~UNUSED3~] OutputList3SigType2151=Serial OutputList3Cue2152=[~UNUSED3~] OutputList3SigType2152=Serial OutputList3Cue2153=[~UNUSED3~] OutputList3SigType2153=Serial OutputList3Cue2154=[~UNUSED3~] OutputList3SigType2154=Serial OutputList3Cue2155=[~UNUSED3~] OutputList3SigType2155=Serial OutputList3Cue2156=[~UNUSED3~] OutputList3SigType2156=Serial OutputList3Cue2157=[~UNUSED3~] OutputList3SigType2157=Serial OutputList3Cue2158=[~UNUSED3~] OutputList3SigType2158=Serial OutputList3Cue2159=[~UNUSED3~] OutputList3SigType2159=Serial OutputList3Cue2160=[~UNUSED3~] OutputList3SigType2160=Serial OutputList3Cue2161=[~UNUSED3~] OutputList3SigType2161=Serial OutputList3Cue2162=[~UNUSED3~] OutputList3SigType2162=Serial OutputList3Cue2163=[~UNUSED3~] OutputList3SigType2163=Serial OutputList3Cue2164=[~UNUSED3~] OutputList3SigType2164=Serial OutputList3Cue2165=[~UNUSED3~] OutputList3SigType2165=Serial OutputList3Cue2166=[~UNUSED3~] OutputList3SigType2166=Serial OutputList3Cue2167=[~UNUSED3~] OutputList3SigType2167=Serial OutputList3Cue2168=[~UNUSED3~] OutputList3SigType2168=Serial OutputList3Cue2169=[~UNUSED3~] OutputList3SigType2169=Serial OutputList3Cue2170=[~UNUSED3~] OutputList3SigType2170=Serial OutputList3Cue2171=[~UNUSED3~] OutputList3SigType2171=Serial OutputList3Cue2172=[~UNUSED3~] OutputList3SigType2172=Serial OutputList3Cue2173=[~UNUSED3~] OutputList3SigType2173=Serial OutputList3Cue2174=[~UNUSED3~] OutputList3SigType2174=Serial OutputList3Cue2175=[~UNUSED3~] OutputList3SigType2175=Serial OutputList3Cue2176=[~UNUSED3~] OutputList3SigType2176=Serial OutputList3Cue2177=[~UNUSED3~] OutputList3SigType2177=Serial OutputList3Cue2178=[~UNUSED3~] OutputList3SigType2178=Serial OutputList3Cue2179=[~UNUSED3~] OutputList3SigType2179=Serial OutputList3Cue2180=[~UNUSED3~] OutputList3SigType2180=Serial OutputList3Cue2181=[~UNUSED3~] OutputList3SigType2181=Serial OutputList3Cue2182=[~UNUSED3~] OutputList3SigType2182=Serial OutputList3Cue2183=[~UNUSED3~] OutputList3SigType2183=Serial OutputList3Cue2184=[~UNUSED3~] OutputList3SigType2184=Serial OutputList3Cue2185=[~UNUSED3~] OutputList3SigType2185=Serial OutputList3Cue2186=[~UNUSED3~] OutputList3SigType2186=Serial OutputList3Cue2187=[~UNUSED3~] OutputList3SigType2187=Serial OutputList3Cue2188=[~UNUSED3~] OutputList3SigType2188=Serial OutputList3Cue2189=[~UNUSED3~] OutputList3SigType2189=Serial OutputList3Cue2190=[~UNUSED3~] OutputList3SigType2190=Serial OutputList3Cue2191=[~UNUSED3~] OutputList3SigType2191=Serial OutputList3Cue2192=[~UNUSED3~] OutputList3SigType2192=Serial OutputList3Cue2193=[~UNUSED3~] OutputList3SigType2193=Serial OutputList3Cue2194=[~UNUSED3~] OutputList3SigType2194=Serial OutputList3Cue2195=[~UNUSED3~] OutputList3SigType2195=Serial OutputList3Cue2196=[~UNUSED3~] OutputList3SigType2196=Serial OutputList3Cue2197=[~UNUSED3~] OutputList3SigType2197=Serial OutputList3Cue2198=[~UNUSED3~] OutputList3SigType2198=Serial OutputList3Cue2199=[~UNUSED3~] OutputList3SigType2199=Serial OutputList3Cue2200=[~UNUSED3~] OutputList3SigType2200=Serial OutputList3Cue2201=[~UNUSED3~] OutputList3SigType2201=Serial OutputList3Cue2202=[~UNUSED3~] OutputList3SigType2202=Serial OutputList3Cue2203=[~UNUSED3~] OutputList3SigType2203=Serial OutputList3Cue2204=[~UNUSED3~] OutputList3SigType2204=Serial OutputList3Cue2205=[~UNUSED3~] OutputList3SigType2205=Serial OutputList3Cue2206=[~UNUSED3~] OutputList3SigType2206=Serial OutputList3Cue2207=[~UNUSED3~] OutputList3SigType2207=Serial OutputList3Cue2208=[~UNUSED3~] OutputList3SigType2208=Serial OutputList3Cue2209=[~UNUSED3~] OutputList3SigType2209=Serial OutputList3Cue2210=[~UNUSED3~] OutputList3SigType2210=Serial OutputList3Cue2211=[~UNUSED3~] OutputList3SigType2211=Serial OutputList3Cue2212=[~UNUSED3~] OutputList3SigType2212=Serial OutputList3Cue2213=[~UNUSED3~] OutputList3SigType2213=Serial OutputList3Cue2214=[~UNUSED3~] OutputList3SigType2214=Serial OutputList3Cue2215=[~UNUSED3~] OutputList3SigType2215=Serial OutputList3Cue2216=[~UNUSED3~] OutputList3SigType2216=Serial OutputList3Cue2217=[~UNUSED3~] OutputList3SigType2217=Serial OutputList3Cue2218=[~UNUSED3~] OutputList3SigType2218=Serial OutputList3Cue2219=[~UNUSED3~] OutputList3SigType2219=Serial OutputList3Cue2220=[~UNUSED3~] OutputList3SigType2220=Serial OutputList3Cue2221=[~UNUSED3~] OutputList3SigType2221=Serial OutputList3Cue2222=[~UNUSED3~] OutputList3SigType2222=Serial OutputList3Cue2223=[~UNUSED3~] OutputList3SigType2223=Serial OutputList3Cue2224=[~UNUSED3~] OutputList3SigType2224=Serial OutputList3Cue2225=[~UNUSED3~] OutputList3SigType2225=Serial OutputList3Cue2226=[~UNUSED3~] OutputList3SigType2226=Serial OutputList3Cue2227=[~UNUSED3~] OutputList3SigType2227=Serial OutputList3Cue2228=[~UNUSED3~] OutputList3SigType2228=Serial OutputList3Cue2229=[~UNUSED3~] OutputList3SigType2229=Serial OutputList3Cue2230=[~UNUSED3~] OutputList3SigType2230=Serial OutputList3Cue2231=[~UNUSED3~] OutputList3SigType2231=Serial OutputList3Cue2232=[~UNUSED3~] OutputList3SigType2232=Serial OutputList3Cue2233=[~UNUSED3~] OutputList3SigType2233=Serial OutputList3Cue2234=[~UNUSED3~] OutputList3SigType2234=Serial OutputList3Cue2235=[~UNUSED3~] OutputList3SigType2235=Serial OutputList3Cue2236=[~UNUSED3~] OutputList3SigType2236=Serial OutputList3Cue2237=[~UNUSED3~] OutputList3SigType2237=Serial OutputList3Cue2238=[~UNUSED3~] OutputList3SigType2238=Serial OutputList3Cue2239=[~UNUSED3~] OutputList3SigType2239=Serial OutputList3Cue2240=[~UNUSED3~] OutputList3SigType2240=Serial OutputList3Cue2241=[~UNUSED3~] OutputList3SigType2241=Serial OutputList3Cue2242=[~UNUSED3~] OutputList3SigType2242=Serial OutputList3Cue2243=[~UNUSED3~] OutputList3SigType2243=Serial OutputList3Cue2244=[~UNUSED3~] OutputList3SigType2244=Serial OutputList3Cue2245=[~UNUSED3~] OutputList3SigType2245=Serial OutputList3Cue2246=[~UNUSED3~] OutputList3SigType2246=Serial OutputList3Cue2247=[~UNUSED3~] OutputList3SigType2247=Serial OutputList3Cue2248=[~UNUSED3~] OutputList3SigType2248=Serial OutputList3Cue2249=[~UNUSED3~] OutputList3SigType2249=Serial OutputList3Cue2250=[~UNUSED3~] OutputList3SigType2250=Serial OutputList3Cue2251=[~UNUSED3~] OutputList3SigType2251=Serial OutputList3Cue2252=[~UNUSED3~] OutputList3SigType2252=Serial OutputList3Cue2253=[~UNUSED3~] OutputList3SigType2253=Serial OutputList3Cue2254=[~UNUSED3~] OutputList3SigType2254=Serial OutputList3Cue2255=[~UNUSED3~] OutputList3SigType2255=Serial OutputList3Cue2256=[~UNUSED3~] OutputList3SigType2256=Serial OutputList3Cue2257=[~UNUSED3~] OutputList3SigType2257=Serial OutputList3Cue2258=[~UNUSED3~] OutputList3SigType2258=Serial OutputList3Cue2259=[~UNUSED3~] OutputList3SigType2259=Serial OutputList3Cue2260=[~UNUSED3~] OutputList3SigType2260=Serial OutputList3Cue2261=[~UNUSED3~] OutputList3SigType2261=Serial OutputList3Cue2262=[~UNUSED3~] OutputList3SigType2262=Serial OutputList3Cue2263=[~UNUSED3~] OutputList3SigType2263=Serial OutputList3Cue2264=[~UNUSED3~] OutputList3SigType2264=Serial OutputList3Cue2265=[~UNUSED3~] OutputList3SigType2265=Serial OutputList3Cue2266=[~UNUSED3~] OutputList3SigType2266=Serial OutputList3Cue2267=[~UNUSED3~] OutputList3SigType2267=Serial OutputList3Cue2268=[~UNUSED3~] OutputList3SigType2268=Serial OutputList3Cue2269=[~UNUSED2~] OutputList3SigType2269=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=2 CedH=2 SmartObjId=1202d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=2 Tp=1 HD=TRUE DV=1202d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=2 Name=PepperDash Essentials TSW-560_[D.VC] Directory_Dynamic Button List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[D.VC] Keypad with favorites_VC DTMF Keypad.ced Hint=VC DTMF Keypad (Smart Object ID=1201) Code=3 SGControlType=Simple Keypad SGControlName=VC DTMF Keypad GUID=B4D53525-26EF-4326-8234-1D53F6E9BF04 SmplCName=PepperDash Essentials TSW-560_[D.VC] Keypad with favorites_VC DTMF Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=* OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=/# OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=3 CedH=3 SmartObjId=1201d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=3 Tp=1 HD=TRUE DV=1201d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=3 Name=PepperDash Essentials TSW-560_[D.VC] Keypad with favorites_VC DTMF Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[Z.Dialogs] PIN_PIN Keypad.ced Hint=PIN Keypad (Smart Object ID=3903) Code=4 SGControlType=Simple Keypad SGControlName=PIN Keypad GUID=D85E5DFB-DE45-45FE-93C5-2FA177B68BFB SmplCName=PepperDash Essentials TSW-560_[Z.Dialogs] PIN_PIN Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=Misc_1 OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=Misc_2 OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=4 CedH=4 SmartObjId=3903d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=4 Tp=1 HD=TRUE DV=3903d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=4 Name=PepperDash Essentials TSW-560_[Z.Dialogs] PIN_PIN Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced Hint=Subpage Reference List Vertical_3 (Smart Object ID=3902) Code=5 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_3 GUID=3490D547-0B98-444B-A284-D6C1BAB2FDCE SmplCName=PepperDash Essentials TSW-560_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4076 MaxVariableInputs=4076 MinVariableOutputs=4076 MaxVariableOutputs=4076 NumFixedParams=1 MinVariableInputsList2=72 MaxVariableInputsList2=72 MinVariableOutputsList2=72 MaxVariableOutputsList2=72 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=[~UNUSED2~] InputSigType32=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=[~UNUSED2~] InputSigType2034=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=[~EndGroup~]fb InputSigType4076=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED2~] OutputSigType32=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED2~] OutputSigType2034=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=[~EndGroup~]Press OutputSigType4076=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=an_fb37 InputList2SigType48=Analog InputList2Cue49=an_fb38 InputList2SigType49=Analog InputList2Cue50=an_fb39 InputList2SigType50=Analog InputList2Cue51=an_fb40 InputList2SigType51=Analog InputList2Cue52=an_fb41 InputList2SigType52=Analog InputList2Cue53=an_fb42 InputList2SigType53=Analog InputList2Cue54=an_fb43 InputList2SigType54=Analog InputList2Cue55=an_fb44 InputList2SigType55=Analog InputList2Cue56=an_fb45 InputList2SigType56=Analog InputList2Cue57=an_fb46 InputList2SigType57=Analog InputList2Cue58=an_fb47 InputList2SigType58=Analog InputList2Cue59=an_fb48 InputList2SigType59=Analog InputList2Cue60=an_fb49 InputList2SigType60=Analog InputList2Cue61=an_fb50 InputList2SigType61=Analog InputList2Cue62=an_fb51 InputList2SigType62=Analog InputList2Cue63=an_fb52 InputList2SigType63=Analog InputList2Cue64=an_fb53 InputList2SigType64=Analog InputList2Cue65=an_fb54 InputList2SigType65=Analog InputList2Cue66=an_fb55 InputList2SigType66=Analog InputList2Cue67=an_fb56 InputList2SigType67=Analog InputList2Cue68=an_fb57 InputList2SigType68=Analog InputList2Cue69=an_fb58 InputList2SigType69=Analog InputList2Cue70=an_fb59 InputList2SigType70=Analog InputList2Cue71=an_fb60 InputList2SigType71=Analog InputList2Cue72=[~EndGroup~]an_fb InputList2SigType72=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=an_act37 OutputList2SigType48=Analog OutputList2Cue49=an_act38 OutputList2SigType49=Analog OutputList2Cue50=an_act39 OutputList2SigType50=Analog OutputList2Cue51=an_act40 OutputList2SigType51=Analog OutputList2Cue52=an_act41 OutputList2SigType52=Analog OutputList2Cue53=an_act42 OutputList2SigType53=Analog OutputList2Cue54=an_act43 OutputList2SigType54=Analog OutputList2Cue55=an_act44 OutputList2SigType55=Analog OutputList2Cue56=an_act45 OutputList2SigType56=Analog OutputList2Cue57=an_act46 OutputList2SigType57=Analog OutputList2Cue58=an_act47 OutputList2SigType58=Analog OutputList2Cue59=an_act48 OutputList2SigType59=Analog OutputList2Cue60=an_act49 OutputList2SigType60=Analog OutputList2Cue61=an_act50 OutputList2SigType61=Analog OutputList2Cue62=an_act51 OutputList2SigType62=Analog OutputList2Cue63=an_act52 OutputList2SigType63=Analog OutputList2Cue64=an_act53 OutputList2SigType64=Analog OutputList2Cue65=an_act54 OutputList2SigType65=Analog OutputList2Cue66=an_act55 OutputList2SigType66=Analog OutputList2Cue67=an_act56 OutputList2SigType67=Analog OutputList2Cue68=an_act57 OutputList2SigType68=Analog OutputList2Cue69=an_act58 OutputList2SigType69=Analog OutputList2Cue70=an_act59 OutputList2SigType70=Analog OutputList2Cue71=an_act60 OutputList2SigType71=Analog OutputList2Cue72=[~EndGroup~]an_act OutputList2SigType72=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=5 CedH=5 SmartObjId=3902d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=5 Tp=1 HD=TRUE DV=3902d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=5 Name=PepperDash Essentials TSW-560_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced Hint=Subpage Reference List Vertical_4 (Smart Object ID=3904) Code=6 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_4 GUID=AC10DF35-3FD4-4F62-9708-0A06AE7A5A14 SmplCName=PepperDash Essentials TSW-560_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4116 MaxVariableInputs=4116 MinVariableOutputs=4116 MaxVariableOutputs=4116 NumFixedParams=1 MinVariableInputsList2=42 MaxVariableInputsList2=42 MinVariableOutputsList2=42 MaxVariableOutputsList2=42 MinVariableInputsList3=42 MaxVariableInputsList3=42 MinVariableOutputsList3=42 MaxVariableOutputsList3=42 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=[~UNUSED2~] InputSigType22=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=[~UNUSED2~] InputSigType2024=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=fb91 InputSigType4106=Digital InputCue4107=fb92 InputSigType4107=Digital InputCue4108=fb93 InputSigType4108=Digital InputCue4109=fb94 InputSigType4109=Digital InputCue4110=fb95 InputSigType4110=Digital InputCue4111=fb96 InputSigType4111=Digital InputCue4112=fb97 InputSigType4112=Digital InputCue4113=fb98 InputSigType4113=Digital InputCue4114=fb99 InputSigType4114=Digital InputCue4115=fb100 InputSigType4115=Digital InputCue4116=[~EndGroup~]fb InputSigType4116=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED2~] OutputSigType22=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED2~] OutputSigType2024=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=press91 OutputSigType4106=Digital OutputCue4107=press92 OutputSigType4107=Digital OutputCue4108=press93 OutputSigType4108=Digital OutputCue4109=press94 OutputSigType4109=Digital OutputCue4110=press95 OutputSigType4110=Digital OutputCue4111=press96 OutputSigType4111=Digital OutputCue4112=press97 OutputSigType4112=Digital OutputCue4113=press98 OutputSigType4113=Digital OutputCue4114=press99 OutputSigType4114=Digital OutputCue4115=press100 OutputSigType4115=Digital OutputCue4116=[~EndGroup~]Press OutputSigType4116=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=[~EndGroup~]an_fb InputList2SigType42=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=[~EndGroup~]an_act OutputList2SigType42=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=[~EndGroup~]text-o InputList3SigType42=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=[~EndGroup~]text-i OutputList3SigType42=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=6 CedH=6 SmartObjId=3904d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=6 Tp=1 HD=TRUE DV=3904d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=6 Name=PepperDash Essentials TSW-560_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[B.AV] Staging_Subpage Reference List Horizontal_3.ced Hint=Subpage Reference List Horizontal_3 (Smart Object ID=3200) Code=7 SGControlType=Subpage Reference List Horizontal SGControlName=Subpage Reference List Horizontal_3 GUID=D638D437-6722-43E1-B435-EF13DCE5ECF0 SmplCName=PepperDash Essentials TSW-560_[B.AV] Staging_Subpage Reference List Horizontal_3.ced SMWRev=4.02.20 Expand=expand_random HelpID=10124 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4076 MaxVariableInputs=4076 MinVariableOutputs=4076 MaxVariableOutputs=4076 NumFixedParams=1 MinVariableInputsList2=72 MaxVariableInputsList2=72 MinVariableOutputsList2=72 MaxVariableOutputsList2=72 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=[~UNUSED2~] InputSigType32=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=[~UNUSED2~] InputSigType2034=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=[~EndGroup~]fb InputSigType4076=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED2~] OutputSigType32=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED2~] OutputSigType2034=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=[~EndGroup~]Press OutputSigType4076=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=an_fb37 InputList2SigType48=Analog InputList2Cue49=an_fb38 InputList2SigType49=Analog InputList2Cue50=an_fb39 InputList2SigType50=Analog InputList2Cue51=an_fb40 InputList2SigType51=Analog InputList2Cue52=an_fb41 InputList2SigType52=Analog InputList2Cue53=an_fb42 InputList2SigType53=Analog InputList2Cue54=an_fb43 InputList2SigType54=Analog InputList2Cue55=an_fb44 InputList2SigType55=Analog InputList2Cue56=an_fb45 InputList2SigType56=Analog InputList2Cue57=an_fb46 InputList2SigType57=Analog InputList2Cue58=an_fb47 InputList2SigType58=Analog InputList2Cue59=an_fb48 InputList2SigType59=Analog InputList2Cue60=an_fb49 InputList2SigType60=Analog InputList2Cue61=an_fb50 InputList2SigType61=Analog InputList2Cue62=an_fb51 InputList2SigType62=Analog InputList2Cue63=an_fb52 InputList2SigType63=Analog InputList2Cue64=an_fb53 InputList2SigType64=Analog InputList2Cue65=an_fb54 InputList2SigType65=Analog InputList2Cue66=an_fb55 InputList2SigType66=Analog InputList2Cue67=an_fb56 InputList2SigType67=Analog InputList2Cue68=an_fb57 InputList2SigType68=Analog InputList2Cue69=an_fb58 InputList2SigType69=Analog InputList2Cue70=an_fb59 InputList2SigType70=Analog InputList2Cue71=an_fb60 InputList2SigType71=Analog InputList2Cue72=[~EndGroup~]an_fb InputList2SigType72=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=an_act37 OutputList2SigType48=Analog OutputList2Cue49=an_act38 OutputList2SigType49=Analog OutputList2Cue50=an_act39 OutputList2SigType50=Analog OutputList2Cue51=an_act40 OutputList2SigType51=Analog OutputList2Cue52=an_act41 OutputList2SigType52=Analog OutputList2Cue53=an_act42 OutputList2SigType53=Analog OutputList2Cue54=an_act43 OutputList2SigType54=Analog OutputList2Cue55=an_act44 OutputList2SigType55=Analog OutputList2Cue56=an_act45 OutputList2SigType56=Analog OutputList2Cue57=an_act46 OutputList2SigType57=Analog OutputList2Cue58=an_act47 OutputList2SigType58=Analog OutputList2Cue59=an_act48 OutputList2SigType59=Analog OutputList2Cue60=an_act49 OutputList2SigType60=Analog OutputList2Cue61=an_act50 OutputList2SigType61=Analog OutputList2Cue62=an_act51 OutputList2SigType62=Analog OutputList2Cue63=an_act52 OutputList2SigType63=Analog OutputList2Cue64=an_act53 OutputList2SigType64=Analog OutputList2Cue65=an_act54 OutputList2SigType65=Analog OutputList2Cue66=an_act55 OutputList2SigType66=Analog OutputList2Cue67=an_act56 OutputList2SigType67=Analog OutputList2Cue68=an_act57 OutputList2SigType68=Analog OutputList2Cue69=an_act58 OutputList2SigType69=Analog OutputList2Cue70=an_act59 OutputList2SigType70=Analog OutputList2Cue71=an_act60 OutputList2SigType71=Analog OutputList2Cue72=[~EndGroup~]an_act OutputList2SigType72=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=7 CedH=7 SmartObjId=3200d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=7 Tp=1 HD=TRUE DV=3200d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=7 Name=PepperDash Essentials TSW-560_[B.AV] Staging_Subpage Reference List Horizontal_3.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced Hint=Channel Preset List Basic (Smart Object ID=1806) Code=8 SGControlType=Subpage Reference List Vertical SGControlName=Channel Preset List Basic GUID=46C43CE4-6BB9-4B76-A13E-B4279202F998 SmplCName=PepperDash Essentials TSW-560_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4106 MaxVariableInputs=4106 MinVariableOutputs=4106 MaxVariableOutputs=4106 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=132 MaxVariableInputsList3=132 MinVariableOutputsList3=132 MaxVariableOutputsList3=132 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=[~EndGroup~]fb InputSigType4106=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=[~EndGroup~]Press OutputSigType4106=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=[~EndGroup~]text-o InputList3SigType132=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=[~EndGroup~]text-i OutputList3SigType132=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=8 CedH=8 SmartObjId=1806d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=8 Tp=1 HD=TRUE DV=1806d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=8 Name=PepperDash Essentials TSW-560_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced Hint=Modes Bottom Bar SRL (Smart Object ID=15022) Code=9 SGControlType=Subpage Reference List Horizontal SGControlName=Modes Bottom Bar SRL GUID=812FF0C4-486D-4ABC-90FA-405F19104323 SmplCName=PepperDash Essentials TSW-560_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced SMWRev=4.02.20 Expand=expand_random HelpID=10124 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4028 MaxVariableInputs=4028 MinVariableOutputs=4028 MaxVariableOutputs=4028 NumFixedParams=1 MinVariableInputsList2=24 MaxVariableInputsList2=24 MinVariableOutputsList2=24 MaxVariableOutputsList2=24 MinVariableInputsList3=24 MaxVariableInputsList3=24 MinVariableOutputsList3=24 MaxVariableOutputsList3=24 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=[~UNUSED2~] InputSigType16=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=[~UNUSED2~] InputSigType2018=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=[~EndGroup~]fb InputSigType4028=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED2~] OutputSigType16=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED2~] OutputSigType2018=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=[~EndGroup~]Press OutputSigType4028=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=[~EndGroup~]an_fb InputList2SigType24=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=[~EndGroup~]an_act OutputList2SigType24=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=[~EndGroup~]text-o InputList3SigType24=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=[~EndGroup~]text-i OutputList3SigType24=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=9 CedH=9 SmartObjId=15022d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=9 Tp=1 HD=TRUE DV=15022d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=9 Name=PepperDash Essentials TSW-560_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[B.AV] Object - Presets_CATV Icon List Vertical.ced Hint=CATV Icon List Vertical (Smart Object ID=10012) Code=10 SGControlType=Subpage Reference List Vertical SGControlName=CATV Icon List Vertical GUID=B34C4DC0-DD10-4C49-AEBA-F968934EFDC6 SmplCName=PepperDash Essentials TSW-560_[B.AV] Object - Presets_CATV Icon List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4316 MaxVariableInputs=4316 MinVariableOutputs=4316 MaxVariableOutputs=4316 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=412 MaxVariableInputsList3=412 MinVariableOutputsList3=412 MaxVariableOutputsList3=412 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=Item 31 Enable InputSigType42=Digital InputCue43=Item 32 Enable InputSigType43=Digital InputCue44=Item 33 Enable InputSigType44=Digital InputCue45=Item 34 Enable InputSigType45=Digital InputCue46=Item 35 Enable InputSigType46=Digital InputCue47=Item 36 Enable InputSigType47=Digital InputCue48=Item 37 Enable InputSigType48=Digital InputCue49=Item 38 Enable InputSigType49=Digital InputCue50=Item 39 Enable InputSigType50=Digital InputCue51=Item 40 Enable InputSigType51=Digital InputCue52=Item 41 Enable InputSigType52=Digital InputCue53=Item 42 Enable InputSigType53=Digital InputCue54=Item 43 Enable InputSigType54=Digital InputCue55=Item 44 Enable InputSigType55=Digital InputCue56=Item 45 Enable InputSigType56=Digital InputCue57=Item 46 Enable InputSigType57=Digital InputCue58=Item 47 Enable InputSigType58=Digital InputCue59=Item 48 Enable InputSigType59=Digital InputCue60=Item 49 Enable InputSigType60=Digital InputCue61=Item 50 Enable InputSigType61=Digital InputCue62=Item 51 Enable InputSigType62=Digital InputCue63=Item 52 Enable InputSigType63=Digital InputCue64=Item 53 Enable InputSigType64=Digital InputCue65=Item 54 Enable InputSigType65=Digital InputCue66=Item 55 Enable InputSigType66=Digital InputCue67=Item 56 Enable InputSigType67=Digital InputCue68=Item 57 Enable InputSigType68=Digital InputCue69=Item 58 Enable InputSigType69=Digital InputCue70=Item 59 Enable InputSigType70=Digital InputCue71=Item 60 Enable InputSigType71=Digital InputCue72=Item 61 Enable InputSigType72=Digital InputCue73=Item 62 Enable InputSigType73=Digital InputCue74=Item 63 Enable InputSigType74=Digital InputCue75=Item 64 Enable InputSigType75=Digital InputCue76=Item 65 Enable InputSigType76=Digital InputCue77=Item 66 Enable InputSigType77=Digital InputCue78=Item 67 Enable InputSigType78=Digital InputCue79=Item 68 Enable InputSigType79=Digital InputCue80=Item 69 Enable InputSigType80=Digital InputCue81=Item 70 Enable InputSigType81=Digital InputCue82=Item 71 Enable InputSigType82=Digital InputCue83=Item 72 Enable InputSigType83=Digital InputCue84=Item 73 Enable InputSigType84=Digital InputCue85=Item 74 Enable InputSigType85=Digital InputCue86=Item 75 Enable InputSigType86=Digital InputCue87=Item 76 Enable InputSigType87=Digital InputCue88=Item 77 Enable InputSigType88=Digital InputCue89=Item 78 Enable InputSigType89=Digital InputCue90=Item 79 Enable InputSigType90=Digital InputCue91=Item 80 Enable InputSigType91=Digital InputCue92=Item 81 Enable InputSigType92=Digital InputCue93=Item 82 Enable InputSigType93=Digital InputCue94=Item 83 Enable InputSigType94=Digital InputCue95=Item 84 Enable InputSigType95=Digital InputCue96=Item 85 Enable InputSigType96=Digital InputCue97=Item 86 Enable InputSigType97=Digital InputCue98=Item 87 Enable InputSigType98=Digital InputCue99=Item 88 Enable InputSigType99=Digital InputCue100=Item 89 Enable InputSigType100=Digital InputCue101=Item 90 Enable InputSigType101=Digital InputCue102=Item 91 Enable InputSigType102=Digital InputCue103=Item 92 Enable InputSigType103=Digital InputCue104=Item 93 Enable InputSigType104=Digital InputCue105=Item 94 Enable InputSigType105=Digital InputCue106=Item 95 Enable InputSigType106=Digital InputCue107=Item 96 Enable InputSigType107=Digital InputCue108=Item 97 Enable InputSigType108=Digital InputCue109=Item 98 Enable InputSigType109=Digital InputCue110=Item 99 Enable InputSigType110=Digital InputCue111=Item 100 Enable InputSigType111=Digital InputCue112=[~UNUSED2~] InputSigType112=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=Item 31 Visible InputSigType2044=Digital InputCue2045=Item 32 Visible InputSigType2045=Digital InputCue2046=Item 33 Visible InputSigType2046=Digital InputCue2047=Item 34 Visible InputSigType2047=Digital InputCue2048=Item 35 Visible InputSigType2048=Digital InputCue2049=Item 36 Visible InputSigType2049=Digital InputCue2050=Item 37 Visible InputSigType2050=Digital InputCue2051=Item 38 Visible InputSigType2051=Digital InputCue2052=Item 39 Visible InputSigType2052=Digital InputCue2053=Item 40 Visible InputSigType2053=Digital InputCue2054=Item 41 Visible InputSigType2054=Digital InputCue2055=Item 42 Visible InputSigType2055=Digital InputCue2056=Item 43 Visible InputSigType2056=Digital InputCue2057=Item 44 Visible InputSigType2057=Digital InputCue2058=Item 45 Visible InputSigType2058=Digital InputCue2059=Item 46 Visible InputSigType2059=Digital InputCue2060=Item 47 Visible InputSigType2060=Digital InputCue2061=Item 48 Visible InputSigType2061=Digital InputCue2062=Item 49 Visible InputSigType2062=Digital InputCue2063=Item 50 Visible InputSigType2063=Digital InputCue2064=Item 51 Visible InputSigType2064=Digital InputCue2065=Item 52 Visible InputSigType2065=Digital InputCue2066=Item 53 Visible InputSigType2066=Digital InputCue2067=Item 54 Visible InputSigType2067=Digital InputCue2068=Item 55 Visible InputSigType2068=Digital InputCue2069=Item 56 Visible InputSigType2069=Digital InputCue2070=Item 57 Visible InputSigType2070=Digital InputCue2071=Item 58 Visible InputSigType2071=Digital InputCue2072=Item 59 Visible InputSigType2072=Digital InputCue2073=Item 60 Visible InputSigType2073=Digital InputCue2074=Item 61 Visible InputSigType2074=Digital InputCue2075=Item 62 Visible InputSigType2075=Digital InputCue2076=Item 63 Visible InputSigType2076=Digital InputCue2077=Item 64 Visible InputSigType2077=Digital InputCue2078=Item 65 Visible InputSigType2078=Digital InputCue2079=Item 66 Visible InputSigType2079=Digital InputCue2080=Item 67 Visible InputSigType2080=Digital InputCue2081=Item 68 Visible InputSigType2081=Digital InputCue2082=Item 69 Visible InputSigType2082=Digital InputCue2083=Item 70 Visible InputSigType2083=Digital InputCue2084=Item 71 Visible InputSigType2084=Digital InputCue2085=Item 72 Visible InputSigType2085=Digital InputCue2086=Item 73 Visible InputSigType2086=Digital InputCue2087=Item 74 Visible InputSigType2087=Digital InputCue2088=Item 75 Visible InputSigType2088=Digital InputCue2089=Item 76 Visible InputSigType2089=Digital InputCue2090=Item 77 Visible InputSigType2090=Digital InputCue2091=Item 78 Visible InputSigType2091=Digital InputCue2092=Item 79 Visible InputSigType2092=Digital InputCue2093=Item 80 Visible InputSigType2093=Digital InputCue2094=Item 81 Visible InputSigType2094=Digital InputCue2095=Item 82 Visible InputSigType2095=Digital InputCue2096=Item 83 Visible InputSigType2096=Digital InputCue2097=Item 84 Visible InputSigType2097=Digital InputCue2098=Item 85 Visible InputSigType2098=Digital InputCue2099=Item 86 Visible InputSigType2099=Digital InputCue2100=Item 87 Visible InputSigType2100=Digital InputCue2101=Item 88 Visible InputSigType2101=Digital InputCue2102=Item 89 Visible InputSigType2102=Digital InputCue2103=Item 90 Visible InputSigType2103=Digital InputCue2104=Item 91 Visible InputSigType2104=Digital InputCue2105=Item 92 Visible InputSigType2105=Digital InputCue2106=Item 93 Visible InputSigType2106=Digital InputCue2107=Item 94 Visible InputSigType2107=Digital InputCue2108=Item 95 Visible InputSigType2108=Digital InputCue2109=Item 96 Visible InputSigType2109=Digital InputCue2110=Item 97 Visible InputSigType2110=Digital InputCue2111=Item 98 Visible InputSigType2111=Digital InputCue2112=Item 99 Visible InputSigType2112=Digital InputCue2113=Item 100 Visible InputSigType2113=Digital InputCue2114=[~UNUSED2~] InputSigType2114=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=fb91 InputSigType4106=Digital InputCue4107=fb92 InputSigType4107=Digital InputCue4108=fb93 InputSigType4108=Digital InputCue4109=fb94 InputSigType4109=Digital InputCue4110=fb95 InputSigType4110=Digital InputCue4111=fb96 InputSigType4111=Digital InputCue4112=fb97 InputSigType4112=Digital InputCue4113=fb98 InputSigType4113=Digital InputCue4114=fb99 InputSigType4114=Digital InputCue4115=fb100 InputSigType4115=Digital InputCue4116=fb101 InputSigType4116=Digital InputCue4117=fb102 InputSigType4117=Digital InputCue4118=fb103 InputSigType4118=Digital InputCue4119=fb104 InputSigType4119=Digital InputCue4120=fb105 InputSigType4120=Digital InputCue4121=fb106 InputSigType4121=Digital InputCue4122=fb107 InputSigType4122=Digital InputCue4123=fb108 InputSigType4123=Digital InputCue4124=fb109 InputSigType4124=Digital InputCue4125=fb110 InputSigType4125=Digital InputCue4126=fb111 InputSigType4126=Digital InputCue4127=fb112 InputSigType4127=Digital InputCue4128=fb113 InputSigType4128=Digital InputCue4129=fb114 InputSigType4129=Digital InputCue4130=fb115 InputSigType4130=Digital InputCue4131=fb116 InputSigType4131=Digital InputCue4132=fb117 InputSigType4132=Digital InputCue4133=fb118 InputSigType4133=Digital InputCue4134=fb119 InputSigType4134=Digital InputCue4135=fb120 InputSigType4135=Digital InputCue4136=fb121 InputSigType4136=Digital InputCue4137=fb122 InputSigType4137=Digital InputCue4138=fb123 InputSigType4138=Digital InputCue4139=fb124 InputSigType4139=Digital InputCue4140=fb125 InputSigType4140=Digital InputCue4141=fb126 InputSigType4141=Digital InputCue4142=fb127 InputSigType4142=Digital InputCue4143=fb128 InputSigType4143=Digital InputCue4144=fb129 InputSigType4144=Digital InputCue4145=fb130 InputSigType4145=Digital InputCue4146=fb131 InputSigType4146=Digital InputCue4147=fb132 InputSigType4147=Digital InputCue4148=fb133 InputSigType4148=Digital InputCue4149=fb134 InputSigType4149=Digital InputCue4150=fb135 InputSigType4150=Digital InputCue4151=fb136 InputSigType4151=Digital InputCue4152=fb137 InputSigType4152=Digital InputCue4153=fb138 InputSigType4153=Digital InputCue4154=fb139 InputSigType4154=Digital InputCue4155=fb140 InputSigType4155=Digital InputCue4156=fb141 InputSigType4156=Digital InputCue4157=fb142 InputSigType4157=Digital InputCue4158=fb143 InputSigType4158=Digital InputCue4159=fb144 InputSigType4159=Digital InputCue4160=fb145 InputSigType4160=Digital InputCue4161=fb146 InputSigType4161=Digital InputCue4162=fb147 InputSigType4162=Digital InputCue4163=fb148 InputSigType4163=Digital InputCue4164=fb149 InputSigType4164=Digital InputCue4165=fb150 InputSigType4165=Digital InputCue4166=fb151 InputSigType4166=Digital InputCue4167=fb152 InputSigType4167=Digital InputCue4168=fb153 InputSigType4168=Digital InputCue4169=fb154 InputSigType4169=Digital InputCue4170=fb155 InputSigType4170=Digital InputCue4171=fb156 InputSigType4171=Digital InputCue4172=fb157 InputSigType4172=Digital InputCue4173=fb158 InputSigType4173=Digital InputCue4174=fb159 InputSigType4174=Digital InputCue4175=fb160 InputSigType4175=Digital InputCue4176=fb161 InputSigType4176=Digital InputCue4177=fb162 InputSigType4177=Digital InputCue4178=fb163 InputSigType4178=Digital InputCue4179=fb164 InputSigType4179=Digital InputCue4180=fb165 InputSigType4180=Digital InputCue4181=fb166 InputSigType4181=Digital InputCue4182=fb167 InputSigType4182=Digital InputCue4183=fb168 InputSigType4183=Digital InputCue4184=fb169 InputSigType4184=Digital InputCue4185=fb170 InputSigType4185=Digital InputCue4186=fb171 InputSigType4186=Digital InputCue4187=fb172 InputSigType4187=Digital InputCue4188=fb173 InputSigType4188=Digital InputCue4189=fb174 InputSigType4189=Digital InputCue4190=fb175 InputSigType4190=Digital InputCue4191=fb176 InputSigType4191=Digital InputCue4192=fb177 InputSigType4192=Digital InputCue4193=fb178 InputSigType4193=Digital InputCue4194=fb179 InputSigType4194=Digital InputCue4195=fb180 InputSigType4195=Digital InputCue4196=fb181 InputSigType4196=Digital InputCue4197=fb182 InputSigType4197=Digital InputCue4198=fb183 InputSigType4198=Digital InputCue4199=fb184 InputSigType4199=Digital InputCue4200=fb185 InputSigType4200=Digital InputCue4201=fb186 InputSigType4201=Digital InputCue4202=fb187 InputSigType4202=Digital InputCue4203=fb188 InputSigType4203=Digital InputCue4204=fb189 InputSigType4204=Digital InputCue4205=fb190 InputSigType4205=Digital InputCue4206=fb191 InputSigType4206=Digital InputCue4207=fb192 InputSigType4207=Digital InputCue4208=fb193 InputSigType4208=Digital InputCue4209=fb194 InputSigType4209=Digital InputCue4210=fb195 InputSigType4210=Digital InputCue4211=fb196 InputSigType4211=Digital InputCue4212=fb197 InputSigType4212=Digital InputCue4213=fb198 InputSigType4213=Digital InputCue4214=fb199 InputSigType4214=Digital InputCue4215=fb200 InputSigType4215=Digital InputCue4216=fb201 InputSigType4216=Digital InputCue4217=fb202 InputSigType4217=Digital InputCue4218=fb203 InputSigType4218=Digital InputCue4219=fb204 InputSigType4219=Digital InputCue4220=fb205 InputSigType4220=Digital InputCue4221=fb206 InputSigType4221=Digital InputCue4222=fb207 InputSigType4222=Digital InputCue4223=fb208 InputSigType4223=Digital InputCue4224=fb209 InputSigType4224=Digital InputCue4225=fb210 InputSigType4225=Digital InputCue4226=fb211 InputSigType4226=Digital InputCue4227=fb212 InputSigType4227=Digital InputCue4228=fb213 InputSigType4228=Digital InputCue4229=fb214 InputSigType4229=Digital InputCue4230=fb215 InputSigType4230=Digital InputCue4231=fb216 InputSigType4231=Digital InputCue4232=fb217 InputSigType4232=Digital InputCue4233=fb218 InputSigType4233=Digital InputCue4234=fb219 InputSigType4234=Digital InputCue4235=fb220 InputSigType4235=Digital InputCue4236=fb221 InputSigType4236=Digital InputCue4237=fb222 InputSigType4237=Digital InputCue4238=fb223 InputSigType4238=Digital InputCue4239=fb224 InputSigType4239=Digital InputCue4240=fb225 InputSigType4240=Digital InputCue4241=fb226 InputSigType4241=Digital InputCue4242=fb227 InputSigType4242=Digital InputCue4243=fb228 InputSigType4243=Digital InputCue4244=fb229 InputSigType4244=Digital InputCue4245=fb230 InputSigType4245=Digital InputCue4246=fb231 InputSigType4246=Digital InputCue4247=fb232 InputSigType4247=Digital InputCue4248=fb233 InputSigType4248=Digital InputCue4249=fb234 InputSigType4249=Digital InputCue4250=fb235 InputSigType4250=Digital InputCue4251=fb236 InputSigType4251=Digital InputCue4252=fb237 InputSigType4252=Digital InputCue4253=fb238 InputSigType4253=Digital InputCue4254=fb239 InputSigType4254=Digital InputCue4255=fb240 InputSigType4255=Digital InputCue4256=fb241 InputSigType4256=Digital InputCue4257=fb242 InputSigType4257=Digital InputCue4258=fb243 InputSigType4258=Digital InputCue4259=fb244 InputSigType4259=Digital InputCue4260=fb245 InputSigType4260=Digital InputCue4261=fb246 InputSigType4261=Digital InputCue4262=fb247 InputSigType4262=Digital InputCue4263=fb248 InputSigType4263=Digital InputCue4264=fb249 InputSigType4264=Digital InputCue4265=fb250 InputSigType4265=Digital InputCue4266=fb251 InputSigType4266=Digital InputCue4267=fb252 InputSigType4267=Digital InputCue4268=fb253 InputSigType4268=Digital InputCue4269=fb254 InputSigType4269=Digital InputCue4270=fb255 InputSigType4270=Digital InputCue4271=fb256 InputSigType4271=Digital InputCue4272=fb257 InputSigType4272=Digital InputCue4273=fb258 InputSigType4273=Digital InputCue4274=fb259 InputSigType4274=Digital InputCue4275=fb260 InputSigType4275=Digital InputCue4276=fb261 InputSigType4276=Digital InputCue4277=fb262 InputSigType4277=Digital InputCue4278=fb263 InputSigType4278=Digital InputCue4279=fb264 InputSigType4279=Digital InputCue4280=fb265 InputSigType4280=Digital InputCue4281=fb266 InputSigType4281=Digital InputCue4282=fb267 InputSigType4282=Digital InputCue4283=fb268 InputSigType4283=Digital InputCue4284=fb269 InputSigType4284=Digital InputCue4285=fb270 InputSigType4285=Digital InputCue4286=fb271 InputSigType4286=Digital InputCue4287=fb272 InputSigType4287=Digital InputCue4288=fb273 InputSigType4288=Digital InputCue4289=fb274 InputSigType4289=Digital InputCue4290=fb275 InputSigType4290=Digital InputCue4291=fb276 InputSigType4291=Digital InputCue4292=fb277 InputSigType4292=Digital InputCue4293=fb278 InputSigType4293=Digital InputCue4294=fb279 InputSigType4294=Digital InputCue4295=fb280 InputSigType4295=Digital InputCue4296=fb281 InputSigType4296=Digital InputCue4297=fb282 InputSigType4297=Digital InputCue4298=fb283 InputSigType4298=Digital InputCue4299=fb284 InputSigType4299=Digital InputCue4300=fb285 InputSigType4300=Digital InputCue4301=fb286 InputSigType4301=Digital InputCue4302=fb287 InputSigType4302=Digital InputCue4303=fb288 InputSigType4303=Digital InputCue4304=fb289 InputSigType4304=Digital InputCue4305=fb290 InputSigType4305=Digital InputCue4306=fb291 InputSigType4306=Digital InputCue4307=fb292 InputSigType4307=Digital InputCue4308=fb293 InputSigType4308=Digital InputCue4309=fb294 InputSigType4309=Digital InputCue4310=fb295 InputSigType4310=Digital InputCue4311=fb296 InputSigType4311=Digital InputCue4312=fb297 InputSigType4312=Digital InputCue4313=fb298 InputSigType4313=Digital InputCue4314=fb299 InputSigType4314=Digital InputCue4315=fb300 InputSigType4315=Digital InputCue4316=[~EndGroup~]fb InputSigType4316=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED3~] OutputSigType42=Digital OutputCue43=[~UNUSED3~] OutputSigType43=Digital OutputCue44=[~UNUSED3~] OutputSigType44=Digital OutputCue45=[~UNUSED3~] OutputSigType45=Digital OutputCue46=[~UNUSED3~] OutputSigType46=Digital OutputCue47=[~UNUSED3~] OutputSigType47=Digital OutputCue48=[~UNUSED3~] OutputSigType48=Digital OutputCue49=[~UNUSED3~] OutputSigType49=Digital OutputCue50=[~UNUSED3~] OutputSigType50=Digital OutputCue51=[~UNUSED3~] OutputSigType51=Digital OutputCue52=[~UNUSED3~] OutputSigType52=Digital OutputCue53=[~UNUSED3~] OutputSigType53=Digital OutputCue54=[~UNUSED3~] OutputSigType54=Digital OutputCue55=[~UNUSED3~] OutputSigType55=Digital OutputCue56=[~UNUSED3~] OutputSigType56=Digital OutputCue57=[~UNUSED3~] OutputSigType57=Digital OutputCue58=[~UNUSED3~] OutputSigType58=Digital OutputCue59=[~UNUSED3~] OutputSigType59=Digital OutputCue60=[~UNUSED3~] OutputSigType60=Digital OutputCue61=[~UNUSED3~] OutputSigType61=Digital OutputCue62=[~UNUSED3~] OutputSigType62=Digital OutputCue63=[~UNUSED3~] OutputSigType63=Digital OutputCue64=[~UNUSED3~] OutputSigType64=Digital OutputCue65=[~UNUSED3~] OutputSigType65=Digital OutputCue66=[~UNUSED3~] OutputSigType66=Digital OutputCue67=[~UNUSED3~] OutputSigType67=Digital OutputCue68=[~UNUSED3~] OutputSigType68=Digital OutputCue69=[~UNUSED3~] OutputSigType69=Digital OutputCue70=[~UNUSED3~] OutputSigType70=Digital OutputCue71=[~UNUSED3~] OutputSigType71=Digital OutputCue72=[~UNUSED3~] OutputSigType72=Digital OutputCue73=[~UNUSED3~] OutputSigType73=Digital OutputCue74=[~UNUSED3~] OutputSigType74=Digital OutputCue75=[~UNUSED3~] OutputSigType75=Digital OutputCue76=[~UNUSED3~] OutputSigType76=Digital OutputCue77=[~UNUSED3~] OutputSigType77=Digital OutputCue78=[~UNUSED3~] OutputSigType78=Digital OutputCue79=[~UNUSED3~] OutputSigType79=Digital OutputCue80=[~UNUSED3~] OutputSigType80=Digital OutputCue81=[~UNUSED3~] OutputSigType81=Digital OutputCue82=[~UNUSED3~] OutputSigType82=Digital OutputCue83=[~UNUSED3~] OutputSigType83=Digital OutputCue84=[~UNUSED3~] OutputSigType84=Digital OutputCue85=[~UNUSED3~] OutputSigType85=Digital OutputCue86=[~UNUSED3~] OutputSigType86=Digital OutputCue87=[~UNUSED3~] OutputSigType87=Digital OutputCue88=[~UNUSED3~] OutputSigType88=Digital OutputCue89=[~UNUSED3~] OutputSigType89=Digital OutputCue90=[~UNUSED3~] OutputSigType90=Digital OutputCue91=[~UNUSED3~] OutputSigType91=Digital OutputCue92=[~UNUSED3~] OutputSigType92=Digital OutputCue93=[~UNUSED3~] OutputSigType93=Digital OutputCue94=[~UNUSED3~] OutputSigType94=Digital OutputCue95=[~UNUSED3~] OutputSigType95=Digital OutputCue96=[~UNUSED3~] OutputSigType96=Digital OutputCue97=[~UNUSED3~] OutputSigType97=Digital OutputCue98=[~UNUSED3~] OutputSigType98=Digital OutputCue99=[~UNUSED3~] OutputSigType99=Digital OutputCue100=[~UNUSED3~] OutputSigType100=Digital OutputCue101=[~UNUSED3~] OutputSigType101=Digital OutputCue102=[~UNUSED3~] OutputSigType102=Digital OutputCue103=[~UNUSED3~] OutputSigType103=Digital OutputCue104=[~UNUSED3~] OutputSigType104=Digital OutputCue105=[~UNUSED3~] OutputSigType105=Digital OutputCue106=[~UNUSED3~] OutputSigType106=Digital OutputCue107=[~UNUSED3~] OutputSigType107=Digital OutputCue108=[~UNUSED3~] OutputSigType108=Digital OutputCue109=[~UNUSED3~] OutputSigType109=Digital OutputCue110=[~UNUSED3~] OutputSigType110=Digital OutputCue111=[~UNUSED3~] OutputSigType111=Digital OutputCue112=[~UNUSED2~] OutputSigType112=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED3~] OutputSigType2044=Digital OutputCue2045=[~UNUSED3~] OutputSigType2045=Digital OutputCue2046=[~UNUSED3~] OutputSigType2046=Digital OutputCue2047=[~UNUSED3~] OutputSigType2047=Digital OutputCue2048=[~UNUSED3~] OutputSigType2048=Digital OutputCue2049=[~UNUSED3~] OutputSigType2049=Digital OutputCue2050=[~UNUSED3~] OutputSigType2050=Digital OutputCue2051=[~UNUSED3~] OutputSigType2051=Digital OutputCue2052=[~UNUSED3~] OutputSigType2052=Digital OutputCue2053=[~UNUSED3~] OutputSigType2053=Digital OutputCue2054=[~UNUSED3~] OutputSigType2054=Digital OutputCue2055=[~UNUSED3~] OutputSigType2055=Digital OutputCue2056=[~UNUSED3~] OutputSigType2056=Digital OutputCue2057=[~UNUSED3~] OutputSigType2057=Digital OutputCue2058=[~UNUSED3~] OutputSigType2058=Digital OutputCue2059=[~UNUSED3~] OutputSigType2059=Digital OutputCue2060=[~UNUSED3~] OutputSigType2060=Digital OutputCue2061=[~UNUSED3~] OutputSigType2061=Digital OutputCue2062=[~UNUSED3~] OutputSigType2062=Digital OutputCue2063=[~UNUSED3~] OutputSigType2063=Digital OutputCue2064=[~UNUSED3~] OutputSigType2064=Digital OutputCue2065=[~UNUSED3~] OutputSigType2065=Digital OutputCue2066=[~UNUSED3~] OutputSigType2066=Digital OutputCue2067=[~UNUSED3~] OutputSigType2067=Digital OutputCue2068=[~UNUSED3~] OutputSigType2068=Digital OutputCue2069=[~UNUSED3~] OutputSigType2069=Digital OutputCue2070=[~UNUSED3~] OutputSigType2070=Digital OutputCue2071=[~UNUSED3~] OutputSigType2071=Digital OutputCue2072=[~UNUSED3~] OutputSigType2072=Digital OutputCue2073=[~UNUSED3~] OutputSigType2073=Digital OutputCue2074=[~UNUSED3~] OutputSigType2074=Digital OutputCue2075=[~UNUSED3~] OutputSigType2075=Digital OutputCue2076=[~UNUSED3~] OutputSigType2076=Digital OutputCue2077=[~UNUSED3~] OutputSigType2077=Digital OutputCue2078=[~UNUSED3~] OutputSigType2078=Digital OutputCue2079=[~UNUSED3~] OutputSigType2079=Digital OutputCue2080=[~UNUSED3~] OutputSigType2080=Digital OutputCue2081=[~UNUSED3~] OutputSigType2081=Digital OutputCue2082=[~UNUSED3~] OutputSigType2082=Digital OutputCue2083=[~UNUSED3~] OutputSigType2083=Digital OutputCue2084=[~UNUSED3~] OutputSigType2084=Digital OutputCue2085=[~UNUSED3~] OutputSigType2085=Digital OutputCue2086=[~UNUSED3~] OutputSigType2086=Digital OutputCue2087=[~UNUSED3~] OutputSigType2087=Digital OutputCue2088=[~UNUSED3~] OutputSigType2088=Digital OutputCue2089=[~UNUSED3~] OutputSigType2089=Digital OutputCue2090=[~UNUSED3~] OutputSigType2090=Digital OutputCue2091=[~UNUSED3~] OutputSigType2091=Digital OutputCue2092=[~UNUSED3~] OutputSigType2092=Digital OutputCue2093=[~UNUSED3~] OutputSigType2093=Digital OutputCue2094=[~UNUSED3~] OutputSigType2094=Digital OutputCue2095=[~UNUSED3~] OutputSigType2095=Digital OutputCue2096=[~UNUSED3~] OutputSigType2096=Digital OutputCue2097=[~UNUSED3~] OutputSigType2097=Digital OutputCue2098=[~UNUSED3~] OutputSigType2098=Digital OutputCue2099=[~UNUSED3~] OutputSigType2099=Digital OutputCue2100=[~UNUSED3~] OutputSigType2100=Digital OutputCue2101=[~UNUSED3~] OutputSigType2101=Digital OutputCue2102=[~UNUSED3~] OutputSigType2102=Digital OutputCue2103=[~UNUSED3~] OutputSigType2103=Digital OutputCue2104=[~UNUSED3~] OutputSigType2104=Digital OutputCue2105=[~UNUSED3~] OutputSigType2105=Digital OutputCue2106=[~UNUSED3~] OutputSigType2106=Digital OutputCue2107=[~UNUSED3~] OutputSigType2107=Digital OutputCue2108=[~UNUSED3~] OutputSigType2108=Digital OutputCue2109=[~UNUSED3~] OutputSigType2109=Digital OutputCue2110=[~UNUSED3~] OutputSigType2110=Digital OutputCue2111=[~UNUSED3~] OutputSigType2111=Digital OutputCue2112=[~UNUSED3~] OutputSigType2112=Digital OutputCue2113=[~UNUSED3~] OutputSigType2113=Digital OutputCue2114=[~UNUSED2~] OutputSigType2114=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=press91 OutputSigType4106=Digital OutputCue4107=press92 OutputSigType4107=Digital OutputCue4108=press93 OutputSigType4108=Digital OutputCue4109=press94 OutputSigType4109=Digital OutputCue4110=press95 OutputSigType4110=Digital OutputCue4111=press96 OutputSigType4111=Digital OutputCue4112=press97 OutputSigType4112=Digital OutputCue4113=press98 OutputSigType4113=Digital OutputCue4114=press99 OutputSigType4114=Digital OutputCue4115=press100 OutputSigType4115=Digital OutputCue4116=press101 OutputSigType4116=Digital OutputCue4117=press102 OutputSigType4117=Digital OutputCue4118=press103 OutputSigType4118=Digital OutputCue4119=press104 OutputSigType4119=Digital OutputCue4120=press105 OutputSigType4120=Digital OutputCue4121=press106 OutputSigType4121=Digital OutputCue4122=press107 OutputSigType4122=Digital OutputCue4123=press108 OutputSigType4123=Digital OutputCue4124=press109 OutputSigType4124=Digital OutputCue4125=press110 OutputSigType4125=Digital OutputCue4126=press111 OutputSigType4126=Digital OutputCue4127=press112 OutputSigType4127=Digital OutputCue4128=press113 OutputSigType4128=Digital OutputCue4129=press114 OutputSigType4129=Digital OutputCue4130=press115 OutputSigType4130=Digital OutputCue4131=press116 OutputSigType4131=Digital OutputCue4132=press117 OutputSigType4132=Digital OutputCue4133=press118 OutputSigType4133=Digital OutputCue4134=press119 OutputSigType4134=Digital OutputCue4135=press120 OutputSigType4135=Digital OutputCue4136=press121 OutputSigType4136=Digital OutputCue4137=press122 OutputSigType4137=Digital OutputCue4138=press123 OutputSigType4138=Digital OutputCue4139=press124 OutputSigType4139=Digital OutputCue4140=press125 OutputSigType4140=Digital OutputCue4141=press126 OutputSigType4141=Digital OutputCue4142=press127 OutputSigType4142=Digital OutputCue4143=press128 OutputSigType4143=Digital OutputCue4144=press129 OutputSigType4144=Digital OutputCue4145=press130 OutputSigType4145=Digital OutputCue4146=press131 OutputSigType4146=Digital OutputCue4147=press132 OutputSigType4147=Digital OutputCue4148=press133 OutputSigType4148=Digital OutputCue4149=press134 OutputSigType4149=Digital OutputCue4150=press135 OutputSigType4150=Digital OutputCue4151=press136 OutputSigType4151=Digital OutputCue4152=press137 OutputSigType4152=Digital OutputCue4153=press138 OutputSigType4153=Digital OutputCue4154=press139 OutputSigType4154=Digital OutputCue4155=press140 OutputSigType4155=Digital OutputCue4156=press141 OutputSigType4156=Digital OutputCue4157=press142 OutputSigType4157=Digital OutputCue4158=press143 OutputSigType4158=Digital OutputCue4159=press144 OutputSigType4159=Digital OutputCue4160=press145 OutputSigType4160=Digital OutputCue4161=press146 OutputSigType4161=Digital OutputCue4162=press147 OutputSigType4162=Digital OutputCue4163=press148 OutputSigType4163=Digital OutputCue4164=press149 OutputSigType4164=Digital OutputCue4165=press150 OutputSigType4165=Digital OutputCue4166=press151 OutputSigType4166=Digital OutputCue4167=press152 OutputSigType4167=Digital OutputCue4168=press153 OutputSigType4168=Digital OutputCue4169=press154 OutputSigType4169=Digital OutputCue4170=press155 OutputSigType4170=Digital OutputCue4171=press156 OutputSigType4171=Digital OutputCue4172=press157 OutputSigType4172=Digital OutputCue4173=press158 OutputSigType4173=Digital OutputCue4174=press159 OutputSigType4174=Digital OutputCue4175=press160 OutputSigType4175=Digital OutputCue4176=press161 OutputSigType4176=Digital OutputCue4177=press162 OutputSigType4177=Digital OutputCue4178=press163 OutputSigType4178=Digital OutputCue4179=press164 OutputSigType4179=Digital OutputCue4180=press165 OutputSigType4180=Digital OutputCue4181=press166 OutputSigType4181=Digital OutputCue4182=press167 OutputSigType4182=Digital OutputCue4183=press168 OutputSigType4183=Digital OutputCue4184=press169 OutputSigType4184=Digital OutputCue4185=press170 OutputSigType4185=Digital OutputCue4186=press171 OutputSigType4186=Digital OutputCue4187=press172 OutputSigType4187=Digital OutputCue4188=press173 OutputSigType4188=Digital OutputCue4189=press174 OutputSigType4189=Digital OutputCue4190=press175 OutputSigType4190=Digital OutputCue4191=press176 OutputSigType4191=Digital OutputCue4192=press177 OutputSigType4192=Digital OutputCue4193=press178 OutputSigType4193=Digital OutputCue4194=press179 OutputSigType4194=Digital OutputCue4195=press180 OutputSigType4195=Digital OutputCue4196=press181 OutputSigType4196=Digital OutputCue4197=press182 OutputSigType4197=Digital OutputCue4198=press183 OutputSigType4198=Digital OutputCue4199=press184 OutputSigType4199=Digital OutputCue4200=press185 OutputSigType4200=Digital OutputCue4201=press186 OutputSigType4201=Digital OutputCue4202=press187 OutputSigType4202=Digital OutputCue4203=press188 OutputSigType4203=Digital OutputCue4204=press189 OutputSigType4204=Digital OutputCue4205=press190 OutputSigType4205=Digital OutputCue4206=press191 OutputSigType4206=Digital OutputCue4207=press192 OutputSigType4207=Digital OutputCue4208=press193 OutputSigType4208=Digital OutputCue4209=press194 OutputSigType4209=Digital OutputCue4210=press195 OutputSigType4210=Digital OutputCue4211=press196 OutputSigType4211=Digital OutputCue4212=press197 OutputSigType4212=Digital OutputCue4213=press198 OutputSigType4213=Digital OutputCue4214=press199 OutputSigType4214=Digital OutputCue4215=press200 OutputSigType4215=Digital OutputCue4216=press201 OutputSigType4216=Digital OutputCue4217=press202 OutputSigType4217=Digital OutputCue4218=press203 OutputSigType4218=Digital OutputCue4219=press204 OutputSigType4219=Digital OutputCue4220=press205 OutputSigType4220=Digital OutputCue4221=press206 OutputSigType4221=Digital OutputCue4222=press207 OutputSigType4222=Digital OutputCue4223=press208 OutputSigType4223=Digital OutputCue4224=press209 OutputSigType4224=Digital OutputCue4225=press210 OutputSigType4225=Digital OutputCue4226=press211 OutputSigType4226=Digital OutputCue4227=press212 OutputSigType4227=Digital OutputCue4228=press213 OutputSigType4228=Digital OutputCue4229=press214 OutputSigType4229=Digital OutputCue4230=press215 OutputSigType4230=Digital OutputCue4231=press216 OutputSigType4231=Digital OutputCue4232=press217 OutputSigType4232=Digital OutputCue4233=press218 OutputSigType4233=Digital OutputCue4234=press219 OutputSigType4234=Digital OutputCue4235=press220 OutputSigType4235=Digital OutputCue4236=press221 OutputSigType4236=Digital OutputCue4237=press222 OutputSigType4237=Digital OutputCue4238=press223 OutputSigType4238=Digital OutputCue4239=press224 OutputSigType4239=Digital OutputCue4240=press225 OutputSigType4240=Digital OutputCue4241=press226 OutputSigType4241=Digital OutputCue4242=press227 OutputSigType4242=Digital OutputCue4243=press228 OutputSigType4243=Digital OutputCue4244=press229 OutputSigType4244=Digital OutputCue4245=press230 OutputSigType4245=Digital OutputCue4246=press231 OutputSigType4246=Digital OutputCue4247=press232 OutputSigType4247=Digital OutputCue4248=press233 OutputSigType4248=Digital OutputCue4249=press234 OutputSigType4249=Digital OutputCue4250=press235 OutputSigType4250=Digital OutputCue4251=press236 OutputSigType4251=Digital OutputCue4252=press237 OutputSigType4252=Digital OutputCue4253=press238 OutputSigType4253=Digital OutputCue4254=press239 OutputSigType4254=Digital OutputCue4255=press240 OutputSigType4255=Digital OutputCue4256=press241 OutputSigType4256=Digital OutputCue4257=press242 OutputSigType4257=Digital OutputCue4258=press243 OutputSigType4258=Digital OutputCue4259=press244 OutputSigType4259=Digital OutputCue4260=press245 OutputSigType4260=Digital OutputCue4261=press246 OutputSigType4261=Digital OutputCue4262=press247 OutputSigType4262=Digital OutputCue4263=press248 OutputSigType4263=Digital OutputCue4264=press249 OutputSigType4264=Digital OutputCue4265=press250 OutputSigType4265=Digital OutputCue4266=press251 OutputSigType4266=Digital OutputCue4267=press252 OutputSigType4267=Digital OutputCue4268=press253 OutputSigType4268=Digital OutputCue4269=press254 OutputSigType4269=Digital OutputCue4270=press255 OutputSigType4270=Digital OutputCue4271=press256 OutputSigType4271=Digital OutputCue4272=press257 OutputSigType4272=Digital OutputCue4273=press258 OutputSigType4273=Digital OutputCue4274=press259 OutputSigType4274=Digital OutputCue4275=press260 OutputSigType4275=Digital OutputCue4276=press261 OutputSigType4276=Digital OutputCue4277=press262 OutputSigType4277=Digital OutputCue4278=press263 OutputSigType4278=Digital OutputCue4279=press264 OutputSigType4279=Digital OutputCue4280=press265 OutputSigType4280=Digital OutputCue4281=press266 OutputSigType4281=Digital OutputCue4282=press267 OutputSigType4282=Digital OutputCue4283=press268 OutputSigType4283=Digital OutputCue4284=press269 OutputSigType4284=Digital OutputCue4285=press270 OutputSigType4285=Digital OutputCue4286=press271 OutputSigType4286=Digital OutputCue4287=press272 OutputSigType4287=Digital OutputCue4288=press273 OutputSigType4288=Digital OutputCue4289=press274 OutputSigType4289=Digital OutputCue4290=press275 OutputSigType4290=Digital OutputCue4291=press276 OutputSigType4291=Digital OutputCue4292=press277 OutputSigType4292=Digital OutputCue4293=press278 OutputSigType4293=Digital OutputCue4294=press279 OutputSigType4294=Digital OutputCue4295=press280 OutputSigType4295=Digital OutputCue4296=press281 OutputSigType4296=Digital OutputCue4297=press282 OutputSigType4297=Digital OutputCue4298=press283 OutputSigType4298=Digital OutputCue4299=press284 OutputSigType4299=Digital OutputCue4300=press285 OutputSigType4300=Digital OutputCue4301=press286 OutputSigType4301=Digital OutputCue4302=press287 OutputSigType4302=Digital OutputCue4303=press288 OutputSigType4303=Digital OutputCue4304=press289 OutputSigType4304=Digital OutputCue4305=press290 OutputSigType4305=Digital OutputCue4306=press291 OutputSigType4306=Digital OutputCue4307=press292 OutputSigType4307=Digital OutputCue4308=press293 OutputSigType4308=Digital OutputCue4309=press294 OutputSigType4309=Digital OutputCue4310=press295 OutputSigType4310=Digital OutputCue4311=press296 OutputSigType4311=Digital OutputCue4312=press297 OutputSigType4312=Digital OutputCue4313=press298 OutputSigType4313=Digital OutputCue4314=press299 OutputSigType4314=Digital OutputCue4315=press300 OutputSigType4315=Digital OutputCue4316=[~EndGroup~]Press OutputSigType4316=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=text-o121 InputList3SigType132=Serial InputList3Cue133=text-o122 InputList3SigType133=Serial InputList3Cue134=text-o123 InputList3SigType134=Serial InputList3Cue135=text-o124 InputList3SigType135=Serial InputList3Cue136=text-o125 InputList3SigType136=Serial InputList3Cue137=text-o126 InputList3SigType137=Serial InputList3Cue138=text-o127 InputList3SigType138=Serial InputList3Cue139=text-o128 InputList3SigType139=Serial InputList3Cue140=text-o129 InputList3SigType140=Serial InputList3Cue141=text-o130 InputList3SigType141=Serial InputList3Cue142=text-o131 InputList3SigType142=Serial InputList3Cue143=text-o132 InputList3SigType143=Serial InputList3Cue144=text-o133 InputList3SigType144=Serial InputList3Cue145=text-o134 InputList3SigType145=Serial InputList3Cue146=text-o135 InputList3SigType146=Serial InputList3Cue147=text-o136 InputList3SigType147=Serial InputList3Cue148=text-o137 InputList3SigType148=Serial InputList3Cue149=text-o138 InputList3SigType149=Serial InputList3Cue150=text-o139 InputList3SigType150=Serial InputList3Cue151=text-o140 InputList3SigType151=Serial InputList3Cue152=text-o141 InputList3SigType152=Serial InputList3Cue153=text-o142 InputList3SigType153=Serial InputList3Cue154=text-o143 InputList3SigType154=Serial InputList3Cue155=text-o144 InputList3SigType155=Serial InputList3Cue156=text-o145 InputList3SigType156=Serial InputList3Cue157=text-o146 InputList3SigType157=Serial InputList3Cue158=text-o147 InputList3SigType158=Serial InputList3Cue159=text-o148 InputList3SigType159=Serial InputList3Cue160=text-o149 InputList3SigType160=Serial InputList3Cue161=text-o150 InputList3SigType161=Serial InputList3Cue162=text-o151 InputList3SigType162=Serial InputList3Cue163=text-o152 InputList3SigType163=Serial InputList3Cue164=text-o153 InputList3SigType164=Serial InputList3Cue165=text-o154 InputList3SigType165=Serial InputList3Cue166=text-o155 InputList3SigType166=Serial InputList3Cue167=text-o156 InputList3SigType167=Serial InputList3Cue168=text-o157 InputList3SigType168=Serial InputList3Cue169=text-o158 InputList3SigType169=Serial InputList3Cue170=text-o159 InputList3SigType170=Serial InputList3Cue171=text-o160 InputList3SigType171=Serial InputList3Cue172=text-o161 InputList3SigType172=Serial InputList3Cue173=text-o162 InputList3SigType173=Serial InputList3Cue174=text-o163 InputList3SigType174=Serial InputList3Cue175=text-o164 InputList3SigType175=Serial InputList3Cue176=text-o165 InputList3SigType176=Serial InputList3Cue177=text-o166 InputList3SigType177=Serial InputList3Cue178=text-o167 InputList3SigType178=Serial InputList3Cue179=text-o168 InputList3SigType179=Serial InputList3Cue180=text-o169 InputList3SigType180=Serial InputList3Cue181=text-o170 InputList3SigType181=Serial InputList3Cue182=text-o171 InputList3SigType182=Serial InputList3Cue183=text-o172 InputList3SigType183=Serial InputList3Cue184=text-o173 InputList3SigType184=Serial InputList3Cue185=text-o174 InputList3SigType185=Serial InputList3Cue186=text-o175 InputList3SigType186=Serial InputList3Cue187=text-o176 InputList3SigType187=Serial InputList3Cue188=text-o177 InputList3SigType188=Serial InputList3Cue189=text-o178 InputList3SigType189=Serial InputList3Cue190=text-o179 InputList3SigType190=Serial InputList3Cue191=text-o180 InputList3SigType191=Serial InputList3Cue192=text-o181 InputList3SigType192=Serial InputList3Cue193=text-o182 InputList3SigType193=Serial InputList3Cue194=text-o183 InputList3SigType194=Serial InputList3Cue195=text-o184 InputList3SigType195=Serial InputList3Cue196=text-o185 InputList3SigType196=Serial InputList3Cue197=text-o186 InputList3SigType197=Serial InputList3Cue198=text-o187 InputList3SigType198=Serial InputList3Cue199=text-o188 InputList3SigType199=Serial InputList3Cue200=text-o189 InputList3SigType200=Serial InputList3Cue201=text-o190 InputList3SigType201=Serial InputList3Cue202=text-o191 InputList3SigType202=Serial InputList3Cue203=text-o192 InputList3SigType203=Serial InputList3Cue204=text-o193 InputList3SigType204=Serial InputList3Cue205=text-o194 InputList3SigType205=Serial InputList3Cue206=text-o195 InputList3SigType206=Serial InputList3Cue207=text-o196 InputList3SigType207=Serial InputList3Cue208=text-o197 InputList3SigType208=Serial InputList3Cue209=text-o198 InputList3SigType209=Serial InputList3Cue210=text-o199 InputList3SigType210=Serial InputList3Cue211=text-o200 InputList3SigType211=Serial InputList3Cue212=text-o201 InputList3SigType212=Serial InputList3Cue213=text-o202 InputList3SigType213=Serial InputList3Cue214=text-o203 InputList3SigType214=Serial InputList3Cue215=text-o204 InputList3SigType215=Serial InputList3Cue216=text-o205 InputList3SigType216=Serial InputList3Cue217=text-o206 InputList3SigType217=Serial InputList3Cue218=text-o207 InputList3SigType218=Serial InputList3Cue219=text-o208 InputList3SigType219=Serial InputList3Cue220=text-o209 InputList3SigType220=Serial InputList3Cue221=text-o210 InputList3SigType221=Serial InputList3Cue222=text-o211 InputList3SigType222=Serial InputList3Cue223=text-o212 InputList3SigType223=Serial InputList3Cue224=text-o213 InputList3SigType224=Serial InputList3Cue225=text-o214 InputList3SigType225=Serial InputList3Cue226=text-o215 InputList3SigType226=Serial InputList3Cue227=text-o216 InputList3SigType227=Serial InputList3Cue228=text-o217 InputList3SigType228=Serial InputList3Cue229=text-o218 InputList3SigType229=Serial InputList3Cue230=text-o219 InputList3SigType230=Serial InputList3Cue231=text-o220 InputList3SigType231=Serial InputList3Cue232=text-o221 InputList3SigType232=Serial InputList3Cue233=text-o222 InputList3SigType233=Serial InputList3Cue234=text-o223 InputList3SigType234=Serial InputList3Cue235=text-o224 InputList3SigType235=Serial InputList3Cue236=text-o225 InputList3SigType236=Serial InputList3Cue237=text-o226 InputList3SigType237=Serial InputList3Cue238=text-o227 InputList3SigType238=Serial InputList3Cue239=text-o228 InputList3SigType239=Serial InputList3Cue240=text-o229 InputList3SigType240=Serial InputList3Cue241=text-o230 InputList3SigType241=Serial InputList3Cue242=text-o231 InputList3SigType242=Serial InputList3Cue243=text-o232 InputList3SigType243=Serial InputList3Cue244=text-o233 InputList3SigType244=Serial InputList3Cue245=text-o234 InputList3SigType245=Serial InputList3Cue246=text-o235 InputList3SigType246=Serial InputList3Cue247=text-o236 InputList3SigType247=Serial InputList3Cue248=text-o237 InputList3SigType248=Serial InputList3Cue249=text-o238 InputList3SigType249=Serial InputList3Cue250=text-o239 InputList3SigType250=Serial InputList3Cue251=text-o240 InputList3SigType251=Serial InputList3Cue252=text-o241 InputList3SigType252=Serial InputList3Cue253=text-o242 InputList3SigType253=Serial InputList3Cue254=text-o243 InputList3SigType254=Serial InputList3Cue255=text-o244 InputList3SigType255=Serial InputList3Cue256=text-o245 InputList3SigType256=Serial InputList3Cue257=text-o246 InputList3SigType257=Serial InputList3Cue258=text-o247 InputList3SigType258=Serial InputList3Cue259=text-o248 InputList3SigType259=Serial InputList3Cue260=text-o249 InputList3SigType260=Serial InputList3Cue261=text-o250 InputList3SigType261=Serial InputList3Cue262=text-o251 InputList3SigType262=Serial InputList3Cue263=text-o252 InputList3SigType263=Serial InputList3Cue264=text-o253 InputList3SigType264=Serial InputList3Cue265=text-o254 InputList3SigType265=Serial InputList3Cue266=text-o255 InputList3SigType266=Serial InputList3Cue267=text-o256 InputList3SigType267=Serial InputList3Cue268=text-o257 InputList3SigType268=Serial InputList3Cue269=text-o258 InputList3SigType269=Serial InputList3Cue270=text-o259 InputList3SigType270=Serial InputList3Cue271=text-o260 InputList3SigType271=Serial InputList3Cue272=text-o261 InputList3SigType272=Serial InputList3Cue273=text-o262 InputList3SigType273=Serial InputList3Cue274=text-o263 InputList3SigType274=Serial InputList3Cue275=text-o264 InputList3SigType275=Serial InputList3Cue276=text-o265 InputList3SigType276=Serial InputList3Cue277=text-o266 InputList3SigType277=Serial InputList3Cue278=text-o267 InputList3SigType278=Serial InputList3Cue279=text-o268 InputList3SigType279=Serial InputList3Cue280=text-o269 InputList3SigType280=Serial InputList3Cue281=text-o270 InputList3SigType281=Serial InputList3Cue282=text-o271 InputList3SigType282=Serial InputList3Cue283=text-o272 InputList3SigType283=Serial InputList3Cue284=text-o273 InputList3SigType284=Serial InputList3Cue285=text-o274 InputList3SigType285=Serial InputList3Cue286=text-o275 InputList3SigType286=Serial InputList3Cue287=text-o276 InputList3SigType287=Serial InputList3Cue288=text-o277 InputList3SigType288=Serial InputList3Cue289=text-o278 InputList3SigType289=Serial InputList3Cue290=text-o279 InputList3SigType290=Serial InputList3Cue291=text-o280 InputList3SigType291=Serial InputList3Cue292=text-o281 InputList3SigType292=Serial InputList3Cue293=text-o282 InputList3SigType293=Serial InputList3Cue294=text-o283 InputList3SigType294=Serial InputList3Cue295=text-o284 InputList3SigType295=Serial InputList3Cue296=text-o285 InputList3SigType296=Serial InputList3Cue297=text-o286 InputList3SigType297=Serial InputList3Cue298=text-o287 InputList3SigType298=Serial InputList3Cue299=text-o288 InputList3SigType299=Serial InputList3Cue300=text-o289 InputList3SigType300=Serial InputList3Cue301=text-o290 InputList3SigType301=Serial InputList3Cue302=text-o291 InputList3SigType302=Serial InputList3Cue303=text-o292 InputList3SigType303=Serial InputList3Cue304=text-o293 InputList3SigType304=Serial InputList3Cue305=text-o294 InputList3SigType305=Serial InputList3Cue306=text-o295 InputList3SigType306=Serial InputList3Cue307=text-o296 InputList3SigType307=Serial InputList3Cue308=text-o297 InputList3SigType308=Serial InputList3Cue309=text-o298 InputList3SigType309=Serial InputList3Cue310=text-o299 InputList3SigType310=Serial InputList3Cue311=text-o300 InputList3SigType311=Serial InputList3Cue312=text-o301 InputList3SigType312=Serial InputList3Cue313=text-o302 InputList3SigType313=Serial InputList3Cue314=text-o303 InputList3SigType314=Serial InputList3Cue315=text-o304 InputList3SigType315=Serial InputList3Cue316=text-o305 InputList3SigType316=Serial InputList3Cue317=text-o306 InputList3SigType317=Serial InputList3Cue318=text-o307 InputList3SigType318=Serial InputList3Cue319=text-o308 InputList3SigType319=Serial InputList3Cue320=text-o309 InputList3SigType320=Serial InputList3Cue321=text-o310 InputList3SigType321=Serial InputList3Cue322=text-o311 InputList3SigType322=Serial InputList3Cue323=text-o312 InputList3SigType323=Serial InputList3Cue324=text-o313 InputList3SigType324=Serial InputList3Cue325=text-o314 InputList3SigType325=Serial InputList3Cue326=text-o315 InputList3SigType326=Serial InputList3Cue327=text-o316 InputList3SigType327=Serial InputList3Cue328=text-o317 InputList3SigType328=Serial InputList3Cue329=text-o318 InputList3SigType329=Serial InputList3Cue330=text-o319 InputList3SigType330=Serial InputList3Cue331=text-o320 InputList3SigType331=Serial InputList3Cue332=text-o321 InputList3SigType332=Serial InputList3Cue333=text-o322 InputList3SigType333=Serial InputList3Cue334=text-o323 InputList3SigType334=Serial InputList3Cue335=text-o324 InputList3SigType335=Serial InputList3Cue336=text-o325 InputList3SigType336=Serial InputList3Cue337=text-o326 InputList3SigType337=Serial InputList3Cue338=text-o327 InputList3SigType338=Serial InputList3Cue339=text-o328 InputList3SigType339=Serial InputList3Cue340=text-o329 InputList3SigType340=Serial InputList3Cue341=text-o330 InputList3SigType341=Serial InputList3Cue342=text-o331 InputList3SigType342=Serial InputList3Cue343=text-o332 InputList3SigType343=Serial InputList3Cue344=text-o333 InputList3SigType344=Serial InputList3Cue345=text-o334 InputList3SigType345=Serial InputList3Cue346=text-o335 InputList3SigType346=Serial InputList3Cue347=text-o336 InputList3SigType347=Serial InputList3Cue348=text-o337 InputList3SigType348=Serial InputList3Cue349=text-o338 InputList3SigType349=Serial InputList3Cue350=text-o339 InputList3SigType350=Serial InputList3Cue351=text-o340 InputList3SigType351=Serial InputList3Cue352=text-o341 InputList3SigType352=Serial InputList3Cue353=text-o342 InputList3SigType353=Serial InputList3Cue354=text-o343 InputList3SigType354=Serial InputList3Cue355=text-o344 InputList3SigType355=Serial InputList3Cue356=text-o345 InputList3SigType356=Serial InputList3Cue357=text-o346 InputList3SigType357=Serial InputList3Cue358=text-o347 InputList3SigType358=Serial InputList3Cue359=text-o348 InputList3SigType359=Serial InputList3Cue360=text-o349 InputList3SigType360=Serial InputList3Cue361=text-o350 InputList3SigType361=Serial InputList3Cue362=text-o351 InputList3SigType362=Serial InputList3Cue363=text-o352 InputList3SigType363=Serial InputList3Cue364=text-o353 InputList3SigType364=Serial InputList3Cue365=text-o354 InputList3SigType365=Serial InputList3Cue366=text-o355 InputList3SigType366=Serial InputList3Cue367=text-o356 InputList3SigType367=Serial InputList3Cue368=text-o357 InputList3SigType368=Serial InputList3Cue369=text-o358 InputList3SigType369=Serial InputList3Cue370=text-o359 InputList3SigType370=Serial InputList3Cue371=text-o360 InputList3SigType371=Serial InputList3Cue372=text-o361 InputList3SigType372=Serial InputList3Cue373=text-o362 InputList3SigType373=Serial InputList3Cue374=text-o363 InputList3SigType374=Serial InputList3Cue375=text-o364 InputList3SigType375=Serial InputList3Cue376=text-o365 InputList3SigType376=Serial InputList3Cue377=text-o366 InputList3SigType377=Serial InputList3Cue378=text-o367 InputList3SigType378=Serial InputList3Cue379=text-o368 InputList3SigType379=Serial InputList3Cue380=text-o369 InputList3SigType380=Serial InputList3Cue381=text-o370 InputList3SigType381=Serial InputList3Cue382=text-o371 InputList3SigType382=Serial InputList3Cue383=text-o372 InputList3SigType383=Serial InputList3Cue384=text-o373 InputList3SigType384=Serial InputList3Cue385=text-o374 InputList3SigType385=Serial InputList3Cue386=text-o375 InputList3SigType386=Serial InputList3Cue387=text-o376 InputList3SigType387=Serial InputList3Cue388=text-o377 InputList3SigType388=Serial InputList3Cue389=text-o378 InputList3SigType389=Serial InputList3Cue390=text-o379 InputList3SigType390=Serial InputList3Cue391=text-o380 InputList3SigType391=Serial InputList3Cue392=text-o381 InputList3SigType392=Serial InputList3Cue393=text-o382 InputList3SigType393=Serial InputList3Cue394=text-o383 InputList3SigType394=Serial InputList3Cue395=text-o384 InputList3SigType395=Serial InputList3Cue396=text-o385 InputList3SigType396=Serial InputList3Cue397=text-o386 InputList3SigType397=Serial InputList3Cue398=text-o387 InputList3SigType398=Serial InputList3Cue399=text-o388 InputList3SigType399=Serial InputList3Cue400=text-o389 InputList3SigType400=Serial InputList3Cue401=text-o390 InputList3SigType401=Serial InputList3Cue402=text-o391 InputList3SigType402=Serial InputList3Cue403=text-o392 InputList3SigType403=Serial InputList3Cue404=text-o393 InputList3SigType404=Serial InputList3Cue405=text-o394 InputList3SigType405=Serial InputList3Cue406=text-o395 InputList3SigType406=Serial InputList3Cue407=text-o396 InputList3SigType407=Serial InputList3Cue408=text-o397 InputList3SigType408=Serial InputList3Cue409=text-o398 InputList3SigType409=Serial InputList3Cue410=text-o399 InputList3SigType410=Serial InputList3Cue411=text-o400 InputList3SigType411=Serial InputList3Cue412=[~EndGroup~]text-o InputList3SigType412=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=text-i121 OutputList3SigType132=Serial OutputList3Cue133=text-i122 OutputList3SigType133=Serial OutputList3Cue134=text-i123 OutputList3SigType134=Serial OutputList3Cue135=text-i124 OutputList3SigType135=Serial OutputList3Cue136=text-i125 OutputList3SigType136=Serial OutputList3Cue137=text-i126 OutputList3SigType137=Serial OutputList3Cue138=text-i127 OutputList3SigType138=Serial OutputList3Cue139=text-i128 OutputList3SigType139=Serial OutputList3Cue140=text-i129 OutputList3SigType140=Serial OutputList3Cue141=text-i130 OutputList3SigType141=Serial OutputList3Cue142=text-i131 OutputList3SigType142=Serial OutputList3Cue143=text-i132 OutputList3SigType143=Serial OutputList3Cue144=text-i133 OutputList3SigType144=Serial OutputList3Cue145=text-i134 OutputList3SigType145=Serial OutputList3Cue146=text-i135 OutputList3SigType146=Serial OutputList3Cue147=text-i136 OutputList3SigType147=Serial OutputList3Cue148=text-i137 OutputList3SigType148=Serial OutputList3Cue149=text-i138 OutputList3SigType149=Serial OutputList3Cue150=text-i139 OutputList3SigType150=Serial OutputList3Cue151=text-i140 OutputList3SigType151=Serial OutputList3Cue152=text-i141 OutputList3SigType152=Serial OutputList3Cue153=text-i142 OutputList3SigType153=Serial OutputList3Cue154=text-i143 OutputList3SigType154=Serial OutputList3Cue155=text-i144 OutputList3SigType155=Serial OutputList3Cue156=text-i145 OutputList3SigType156=Serial OutputList3Cue157=text-i146 OutputList3SigType157=Serial OutputList3Cue158=text-i147 OutputList3SigType158=Serial OutputList3Cue159=text-i148 OutputList3SigType159=Serial OutputList3Cue160=text-i149 OutputList3SigType160=Serial OutputList3Cue161=text-i150 OutputList3SigType161=Serial OutputList3Cue162=text-i151 OutputList3SigType162=Serial OutputList3Cue163=text-i152 OutputList3SigType163=Serial OutputList3Cue164=text-i153 OutputList3SigType164=Serial OutputList3Cue165=text-i154 OutputList3SigType165=Serial OutputList3Cue166=text-i155 OutputList3SigType166=Serial OutputList3Cue167=text-i156 OutputList3SigType167=Serial OutputList3Cue168=text-i157 OutputList3SigType168=Serial OutputList3Cue169=text-i158 OutputList3SigType169=Serial OutputList3Cue170=text-i159 OutputList3SigType170=Serial OutputList3Cue171=text-i160 OutputList3SigType171=Serial OutputList3Cue172=text-i161 OutputList3SigType172=Serial OutputList3Cue173=text-i162 OutputList3SigType173=Serial OutputList3Cue174=text-i163 OutputList3SigType174=Serial OutputList3Cue175=text-i164 OutputList3SigType175=Serial OutputList3Cue176=text-i165 OutputList3SigType176=Serial OutputList3Cue177=text-i166 OutputList3SigType177=Serial OutputList3Cue178=text-i167 OutputList3SigType178=Serial OutputList3Cue179=text-i168 OutputList3SigType179=Serial OutputList3Cue180=text-i169 OutputList3SigType180=Serial OutputList3Cue181=text-i170 OutputList3SigType181=Serial OutputList3Cue182=text-i171 OutputList3SigType182=Serial OutputList3Cue183=text-i172 OutputList3SigType183=Serial OutputList3Cue184=text-i173 OutputList3SigType184=Serial OutputList3Cue185=text-i174 OutputList3SigType185=Serial OutputList3Cue186=text-i175 OutputList3SigType186=Serial OutputList3Cue187=text-i176 OutputList3SigType187=Serial OutputList3Cue188=text-i177 OutputList3SigType188=Serial OutputList3Cue189=text-i178 OutputList3SigType189=Serial OutputList3Cue190=text-i179 OutputList3SigType190=Serial OutputList3Cue191=text-i180 OutputList3SigType191=Serial OutputList3Cue192=text-i181 OutputList3SigType192=Serial OutputList3Cue193=text-i182 OutputList3SigType193=Serial OutputList3Cue194=text-i183 OutputList3SigType194=Serial OutputList3Cue195=text-i184 OutputList3SigType195=Serial OutputList3Cue196=text-i185 OutputList3SigType196=Serial OutputList3Cue197=text-i186 OutputList3SigType197=Serial OutputList3Cue198=text-i187 OutputList3SigType198=Serial OutputList3Cue199=text-i188 OutputList3SigType199=Serial OutputList3Cue200=text-i189 OutputList3SigType200=Serial OutputList3Cue201=text-i190 OutputList3SigType201=Serial OutputList3Cue202=text-i191 OutputList3SigType202=Serial OutputList3Cue203=text-i192 OutputList3SigType203=Serial OutputList3Cue204=text-i193 OutputList3SigType204=Serial OutputList3Cue205=text-i194 OutputList3SigType205=Serial OutputList3Cue206=text-i195 OutputList3SigType206=Serial OutputList3Cue207=text-i196 OutputList3SigType207=Serial OutputList3Cue208=text-i197 OutputList3SigType208=Serial OutputList3Cue209=text-i198 OutputList3SigType209=Serial OutputList3Cue210=text-i199 OutputList3SigType210=Serial OutputList3Cue211=text-i200 OutputList3SigType211=Serial OutputList3Cue212=text-i201 OutputList3SigType212=Serial OutputList3Cue213=text-i202 OutputList3SigType213=Serial OutputList3Cue214=text-i203 OutputList3SigType214=Serial OutputList3Cue215=text-i204 OutputList3SigType215=Serial OutputList3Cue216=text-i205 OutputList3SigType216=Serial OutputList3Cue217=text-i206 OutputList3SigType217=Serial OutputList3Cue218=text-i207 OutputList3SigType218=Serial OutputList3Cue219=text-i208 OutputList3SigType219=Serial OutputList3Cue220=text-i209 OutputList3SigType220=Serial OutputList3Cue221=text-i210 OutputList3SigType221=Serial OutputList3Cue222=text-i211 OutputList3SigType222=Serial OutputList3Cue223=text-i212 OutputList3SigType223=Serial OutputList3Cue224=text-i213 OutputList3SigType224=Serial OutputList3Cue225=text-i214 OutputList3SigType225=Serial OutputList3Cue226=text-i215 OutputList3SigType226=Serial OutputList3Cue227=text-i216 OutputList3SigType227=Serial OutputList3Cue228=text-i217 OutputList3SigType228=Serial OutputList3Cue229=text-i218 OutputList3SigType229=Serial OutputList3Cue230=text-i219 OutputList3SigType230=Serial OutputList3Cue231=text-i220 OutputList3SigType231=Serial OutputList3Cue232=text-i221 OutputList3SigType232=Serial OutputList3Cue233=text-i222 OutputList3SigType233=Serial OutputList3Cue234=text-i223 OutputList3SigType234=Serial OutputList3Cue235=text-i224 OutputList3SigType235=Serial OutputList3Cue236=text-i225 OutputList3SigType236=Serial OutputList3Cue237=text-i226 OutputList3SigType237=Serial OutputList3Cue238=text-i227 OutputList3SigType238=Serial OutputList3Cue239=text-i228 OutputList3SigType239=Serial OutputList3Cue240=text-i229 OutputList3SigType240=Serial OutputList3Cue241=text-i230 OutputList3SigType241=Serial OutputList3Cue242=text-i231 OutputList3SigType242=Serial OutputList3Cue243=text-i232 OutputList3SigType243=Serial OutputList3Cue244=text-i233 OutputList3SigType244=Serial OutputList3Cue245=text-i234 OutputList3SigType245=Serial OutputList3Cue246=text-i235 OutputList3SigType246=Serial OutputList3Cue247=text-i236 OutputList3SigType247=Serial OutputList3Cue248=text-i237 OutputList3SigType248=Serial OutputList3Cue249=text-i238 OutputList3SigType249=Serial OutputList3Cue250=text-i239 OutputList3SigType250=Serial OutputList3Cue251=text-i240 OutputList3SigType251=Serial OutputList3Cue252=text-i241 OutputList3SigType252=Serial OutputList3Cue253=text-i242 OutputList3SigType253=Serial OutputList3Cue254=text-i243 OutputList3SigType254=Serial OutputList3Cue255=text-i244 OutputList3SigType255=Serial OutputList3Cue256=text-i245 OutputList3SigType256=Serial OutputList3Cue257=text-i246 OutputList3SigType257=Serial OutputList3Cue258=text-i247 OutputList3SigType258=Serial OutputList3Cue259=text-i248 OutputList3SigType259=Serial OutputList3Cue260=text-i249 OutputList3SigType260=Serial OutputList3Cue261=text-i250 OutputList3SigType261=Serial OutputList3Cue262=text-i251 OutputList3SigType262=Serial OutputList3Cue263=text-i252 OutputList3SigType263=Serial OutputList3Cue264=text-i253 OutputList3SigType264=Serial OutputList3Cue265=text-i254 OutputList3SigType265=Serial OutputList3Cue266=text-i255 OutputList3SigType266=Serial OutputList3Cue267=text-i256 OutputList3SigType267=Serial OutputList3Cue268=text-i257 OutputList3SigType268=Serial OutputList3Cue269=text-i258 OutputList3SigType269=Serial OutputList3Cue270=text-i259 OutputList3SigType270=Serial OutputList3Cue271=text-i260 OutputList3SigType271=Serial OutputList3Cue272=text-i261 OutputList3SigType272=Serial OutputList3Cue273=text-i262 OutputList3SigType273=Serial OutputList3Cue274=text-i263 OutputList3SigType274=Serial OutputList3Cue275=text-i264 OutputList3SigType275=Serial OutputList3Cue276=text-i265 OutputList3SigType276=Serial OutputList3Cue277=text-i266 OutputList3SigType277=Serial OutputList3Cue278=text-i267 OutputList3SigType278=Serial OutputList3Cue279=text-i268 OutputList3SigType279=Serial OutputList3Cue280=text-i269 OutputList3SigType280=Serial OutputList3Cue281=text-i270 OutputList3SigType281=Serial OutputList3Cue282=text-i271 OutputList3SigType282=Serial OutputList3Cue283=text-i272 OutputList3SigType283=Serial OutputList3Cue284=text-i273 OutputList3SigType284=Serial OutputList3Cue285=text-i274 OutputList3SigType285=Serial OutputList3Cue286=text-i275 OutputList3SigType286=Serial OutputList3Cue287=text-i276 OutputList3SigType287=Serial OutputList3Cue288=text-i277 OutputList3SigType288=Serial OutputList3Cue289=text-i278 OutputList3SigType289=Serial OutputList3Cue290=text-i279 OutputList3SigType290=Serial OutputList3Cue291=text-i280 OutputList3SigType291=Serial OutputList3Cue292=text-i281 OutputList3SigType292=Serial OutputList3Cue293=text-i282 OutputList3SigType293=Serial OutputList3Cue294=text-i283 OutputList3SigType294=Serial OutputList3Cue295=text-i284 OutputList3SigType295=Serial OutputList3Cue296=text-i285 OutputList3SigType296=Serial OutputList3Cue297=text-i286 OutputList3SigType297=Serial OutputList3Cue298=text-i287 OutputList3SigType298=Serial OutputList3Cue299=text-i288 OutputList3SigType299=Serial OutputList3Cue300=text-i289 OutputList3SigType300=Serial OutputList3Cue301=text-i290 OutputList3SigType301=Serial OutputList3Cue302=text-i291 OutputList3SigType302=Serial OutputList3Cue303=text-i292 OutputList3SigType303=Serial OutputList3Cue304=text-i293 OutputList3SigType304=Serial OutputList3Cue305=text-i294 OutputList3SigType305=Serial OutputList3Cue306=text-i295 OutputList3SigType306=Serial OutputList3Cue307=text-i296 OutputList3SigType307=Serial OutputList3Cue308=text-i297 OutputList3SigType308=Serial OutputList3Cue309=text-i298 OutputList3SigType309=Serial OutputList3Cue310=text-i299 OutputList3SigType310=Serial OutputList3Cue311=text-i300 OutputList3SigType311=Serial OutputList3Cue312=text-i301 OutputList3SigType312=Serial OutputList3Cue313=text-i302 OutputList3SigType313=Serial OutputList3Cue314=text-i303 OutputList3SigType314=Serial OutputList3Cue315=text-i304 OutputList3SigType315=Serial OutputList3Cue316=text-i305 OutputList3SigType316=Serial OutputList3Cue317=text-i306 OutputList3SigType317=Serial OutputList3Cue318=text-i307 OutputList3SigType318=Serial OutputList3Cue319=text-i308 OutputList3SigType319=Serial OutputList3Cue320=text-i309 OutputList3SigType320=Serial OutputList3Cue321=text-i310 OutputList3SigType321=Serial OutputList3Cue322=text-i311 OutputList3SigType322=Serial OutputList3Cue323=text-i312 OutputList3SigType323=Serial OutputList3Cue324=text-i313 OutputList3SigType324=Serial OutputList3Cue325=text-i314 OutputList3SigType325=Serial OutputList3Cue326=text-i315 OutputList3SigType326=Serial OutputList3Cue327=text-i316 OutputList3SigType327=Serial OutputList3Cue328=text-i317 OutputList3SigType328=Serial OutputList3Cue329=text-i318 OutputList3SigType329=Serial OutputList3Cue330=text-i319 OutputList3SigType330=Serial OutputList3Cue331=text-i320 OutputList3SigType331=Serial OutputList3Cue332=text-i321 OutputList3SigType332=Serial OutputList3Cue333=text-i322 OutputList3SigType333=Serial OutputList3Cue334=text-i323 OutputList3SigType334=Serial OutputList3Cue335=text-i324 OutputList3SigType335=Serial OutputList3Cue336=text-i325 OutputList3SigType336=Serial OutputList3Cue337=text-i326 OutputList3SigType337=Serial OutputList3Cue338=text-i327 OutputList3SigType338=Serial OutputList3Cue339=text-i328 OutputList3SigType339=Serial OutputList3Cue340=text-i329 OutputList3SigType340=Serial OutputList3Cue341=text-i330 OutputList3SigType341=Serial OutputList3Cue342=text-i331 OutputList3SigType342=Serial OutputList3Cue343=text-i332 OutputList3SigType343=Serial OutputList3Cue344=text-i333 OutputList3SigType344=Serial OutputList3Cue345=text-i334 OutputList3SigType345=Serial OutputList3Cue346=text-i335 OutputList3SigType346=Serial OutputList3Cue347=text-i336 OutputList3SigType347=Serial OutputList3Cue348=text-i337 OutputList3SigType348=Serial OutputList3Cue349=text-i338 OutputList3SigType349=Serial OutputList3Cue350=text-i339 OutputList3SigType350=Serial OutputList3Cue351=text-i340 OutputList3SigType351=Serial OutputList3Cue352=text-i341 OutputList3SigType352=Serial OutputList3Cue353=text-i342 OutputList3SigType353=Serial OutputList3Cue354=text-i343 OutputList3SigType354=Serial OutputList3Cue355=text-i344 OutputList3SigType355=Serial OutputList3Cue356=text-i345 OutputList3SigType356=Serial OutputList3Cue357=text-i346 OutputList3SigType357=Serial OutputList3Cue358=text-i347 OutputList3SigType358=Serial OutputList3Cue359=text-i348 OutputList3SigType359=Serial OutputList3Cue360=text-i349 OutputList3SigType360=Serial OutputList3Cue361=text-i350 OutputList3SigType361=Serial OutputList3Cue362=text-i351 OutputList3SigType362=Serial OutputList3Cue363=text-i352 OutputList3SigType363=Serial OutputList3Cue364=text-i353 OutputList3SigType364=Serial OutputList3Cue365=text-i354 OutputList3SigType365=Serial OutputList3Cue366=text-i355 OutputList3SigType366=Serial OutputList3Cue367=text-i356 OutputList3SigType367=Serial OutputList3Cue368=text-i357 OutputList3SigType368=Serial OutputList3Cue369=text-i358 OutputList3SigType369=Serial OutputList3Cue370=text-i359 OutputList3SigType370=Serial OutputList3Cue371=text-i360 OutputList3SigType371=Serial OutputList3Cue372=text-i361 OutputList3SigType372=Serial OutputList3Cue373=text-i362 OutputList3SigType373=Serial OutputList3Cue374=text-i363 OutputList3SigType374=Serial OutputList3Cue375=text-i364 OutputList3SigType375=Serial OutputList3Cue376=text-i365 OutputList3SigType376=Serial OutputList3Cue377=text-i366 OutputList3SigType377=Serial OutputList3Cue378=text-i367 OutputList3SigType378=Serial OutputList3Cue379=text-i368 OutputList3SigType379=Serial OutputList3Cue380=text-i369 OutputList3SigType380=Serial OutputList3Cue381=text-i370 OutputList3SigType381=Serial OutputList3Cue382=text-i371 OutputList3SigType382=Serial OutputList3Cue383=text-i372 OutputList3SigType383=Serial OutputList3Cue384=text-i373 OutputList3SigType384=Serial OutputList3Cue385=text-i374 OutputList3SigType385=Serial OutputList3Cue386=text-i375 OutputList3SigType386=Serial OutputList3Cue387=text-i376 OutputList3SigType387=Serial OutputList3Cue388=text-i377 OutputList3SigType388=Serial OutputList3Cue389=text-i378 OutputList3SigType389=Serial OutputList3Cue390=text-i379 OutputList3SigType390=Serial OutputList3Cue391=text-i380 OutputList3SigType391=Serial OutputList3Cue392=text-i381 OutputList3SigType392=Serial OutputList3Cue393=text-i382 OutputList3SigType393=Serial OutputList3Cue394=text-i383 OutputList3SigType394=Serial OutputList3Cue395=text-i384 OutputList3SigType395=Serial OutputList3Cue396=text-i385 OutputList3SigType396=Serial OutputList3Cue397=text-i386 OutputList3SigType397=Serial OutputList3Cue398=text-i387 OutputList3SigType398=Serial OutputList3Cue399=text-i388 OutputList3SigType399=Serial OutputList3Cue400=text-i389 OutputList3SigType400=Serial OutputList3Cue401=text-i390 OutputList3SigType401=Serial OutputList3Cue402=text-i391 OutputList3SigType402=Serial OutputList3Cue403=text-i392 OutputList3SigType403=Serial OutputList3Cue404=text-i393 OutputList3SigType404=Serial OutputList3Cue405=text-i394 OutputList3SigType405=Serial OutputList3Cue406=text-i395 OutputList3SigType406=Serial OutputList3Cue407=text-i396 OutputList3SigType407=Serial OutputList3Cue408=text-i397 OutputList3SigType408=Serial OutputList3Cue409=text-i398 OutputList3SigType409=Serial OutputList3Cue410=text-i399 OutputList3SigType410=Serial OutputList3Cue411=text-i400 OutputList3SigType411=Serial OutputList3Cue412=[~EndGroup~]text-i OutputList3SigType412=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=10 CedH=10 SmartObjId=10012d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=10 Tp=1 HD=TRUE DV=10012d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=10 Name=PepperDash Essentials TSW-560_[B.AV] Object - Presets_CATV Icon List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[B.AV] Object - DPad STB_STB DPad.ced Hint=STB DPad (Smart Object ID=10011) Code=11 SGControlType=DPad SGControlName=STB DPad GUID=F2340FAD-85E9-4E49-B46E-15E9B096F58B SmplCName=PepperDash Essentials TSW-560_[B.AV] Object - DPad STB_STB DPad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10015 ;Define the number of inputs, outputs and parameters MinVariableInputs=5 MaxVariableInputs=5 MinVariableOutputs=5 MaxVariableOutputs=5 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Up OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=Down OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Left OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=Right OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=OK OutputSigType5=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=11 CedH=11 SmartObjId=10011d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=11 Tp=1 HD=TRUE DV=10011d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=11 Name=PepperDash Essentials TSW-560_[B.AV] Object - DPad STB_STB DPad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced Hint=Tab Button Horizontal (Smart Object ID=10081) Code=12 SGControlType=Horizontal Tab Button SGControlName=Tab Button Horizontal GUID=198C97B0-9D0C-46C2-9557-27EA33C0BE9F SmplCName=PepperDash Essentials TSW-560_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced SMWRev=4.02.19 Expand=expand_random HelpID=10031 ;Define the number of inputs, outputs and parameters MinVariableInputs=4 MaxVariableInputs=4 MinVariableOutputs=4 MaxVariableOutputs=4 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Tab Button 1 Press OutputSigType1=Digital InputCue2=Tab Button 1 Select InputSigType2=Digital OutputCue2=[~UNUSED3~] OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Tab Button 2 Press OutputSigType3=Digital InputCue4=Tab Button 2 Select InputSigType4=Digital OutputCue4=[~UNUSED3~] OutputSigType4=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=12 CedH=12 SmartObjId=10081d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=12 Tp=1 HD=TRUE DV=10081d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=12 Name=PepperDash Essentials TSW-560_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[B.AV] Object - Dpad DVD_DVD DPad.ced Hint=DVD DPad (Smart Object ID=10411) Code=13 SGControlType=DPad SGControlName=DVD DPad GUID=D49BCF22-C770-4146-93E6-00867D885E1E SmplCName=PepperDash Essentials TSW-560_[B.AV] Object - Dpad DVD_DVD DPad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10015 ;Define the number of inputs, outputs and parameters MinVariableInputs=5 MaxVariableInputs=5 MinVariableOutputs=5 MaxVariableOutputs=5 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Up OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=Down OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Left OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=Right OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=OK OutputSigType5=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=13 CedH=13 SmartObjId=10411d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=13 Tp=1 HD=TRUE DV=10411d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=13 Name=PepperDash Essentials TSW-560_[B.AV] Object - Dpad DVD_DVD DPad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced Hint=CATV Keypad (Smart Object ID=10014) Code=14 SGControlType=Simple Keypad SGControlName=CATV Keypad GUID=5E33D4F4-5C5F-430C-879A-AE82529B3943 SmplCName=PepperDash Essentials TSW-560_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=Misc_1 OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=Misc_2 OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=14 CedH=14 SmartObjId=10014d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=14 Tp=1 HD=TRUE DV=10014d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=14 Name=PepperDash Essentials TSW-560_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced Hint=CATV Icon List Vertical (Smart Object ID=3333) Code=15 SGControlType=Subpage Reference List Vertical SGControlName=CATV Icon List Vertical GUID=D6A79678-BAD2-4F6D-8104-A941FBA9432F SmplCName=PepperDash Essentials TSW-560_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4106 MaxVariableInputs=4106 MinVariableOutputs=4106 MaxVariableOutputs=4106 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=132 MaxVariableInputsList3=132 MinVariableOutputsList3=132 MaxVariableOutputsList3=132 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=[~EndGroup~]fb InputSigType4106=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=[~EndGroup~]Press OutputSigType4106=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=[~EndGroup~]text-o InputList3SigType132=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=[~EndGroup~]text-i OutputList3SigType132=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=15 CedH=15 SmartObjId=3333d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=15 Tp=1 HD=TRUE DV=3333d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=15 Name=PepperDash Essentials TSW-560_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced Hint=Subpage Reference List Vertical_2 (Smart Object ID=1001) Code=16 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_2 GUID=5F63F5C2-A987-4957-9243-C28805CE297E SmplCName=PepperDash Essentials TSW-560_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4036 MaxVariableInputs=4036 MinVariableOutputs=4036 MaxVariableOutputs=4036 NumFixedParams=1 MinVariableInputsList2=32 MaxVariableInputsList2=32 MinVariableOutputsList2=32 MaxVariableOutputsList2=32 MinVariableInputsList3=32 MaxVariableInputsList3=32 MinVariableOutputsList3=32 MaxVariableOutputsList3=32 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=[~UNUSED2~] InputSigType16=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=[~UNUSED2~] InputSigType2018=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=[~EndGroup~]fb InputSigType4036=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED2~] OutputSigType16=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED2~] OutputSigType2018=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=[~EndGroup~]Press OutputSigType4036=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=[~EndGroup~]an_fb InputList2SigType32=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=[~EndGroup~]an_act OutputList2SigType32=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=[~EndGroup~]text-o InputList3SigType32=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=[~EndGroup~]text-i OutputList3SigType32=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=16 CedH=16 SmartObjId=1001d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=16 Tp=1 HD=TRUE DV=1001d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=16 Name=PepperDash Essentials TSW-560_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced Hint=Dynamic Button List Vertical (Smart Object ID=3901) Code=17 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical GUID=15B95903-FB30-472E-9D10-82A9C3A9D7C7 SmplCName=PepperDash Essentials TSW-560_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=[~UNUSED2~] InputSigType22=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=[~UNUSED2~] InputSigType2024=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=[~UNUSED2~] InputSigType4026=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=[~UNUSED2~] OutputSigType22=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED2~] OutputSigType2024=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED2~] OutputSigType4026=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=[~UNUSED2~] InputList2SigType22=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED2~] OutputList2SigType22=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=[~UNUSED2~] InputList3SigType22=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=[~UNUSED2~] InputList3SigType2024=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED2~] OutputList3SigType22=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED2~] OutputList3SigType2024=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=17 CedH=17 SmartObjId=3901d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=17 Tp=1 HD=TRUE DV=3901d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=17 Name=PepperDash Essentials TSW-560_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced Hint=Subpage Reference List Vertical (Smart Object ID=15023) Code=18 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical GUID=EC6E6B35-F033-4F14-9465-FEEBE20455CC SmplCName=PepperDash Essentials TSW-560_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4052 MaxVariableInputs=4052 MinVariableOutputs=4052 MaxVariableOutputs=4052 NumFixedParams=1 MinVariableInputsList2=48 MaxVariableInputsList2=48 MinVariableOutputsList2=48 MaxVariableOutputsList2=48 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=[~UNUSED2~] InputSigType24=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=[~UNUSED2~] InputSigType2026=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=[~EndGroup~]fb InputSigType4052=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED2~] OutputSigType24=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED2~] OutputSigType2026=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=[~EndGroup~]Press OutputSigType4052=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=[~EndGroup~]an_fb InputList2SigType48=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=[~EndGroup~]an_act OutputList2SigType48=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=18 CedH=18 SmartObjId=15023d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=18 Tp=1 HD=TRUE DV=15023d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=18 Name=PepperDash Essentials TSW-560_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-560_[D.VC] Recents_Dynamic Button List Vertical_2.ced Hint=Dynamic Button List Vertical_2 (Smart Object ID=1203) Code=19 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical_2 GUID=2C4B55E4-42AC-486D-BC6E-C7DD7D24C974 SmplCName=PepperDash Essentials TSW-560_[D.VC] Recents_Dynamic Button List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=Item 11 Selected InputSigType22=Digital InputCue23=Item 12 Selected InputSigType23=Digital InputCue24=Item 13 Selected InputSigType24=Digital InputCue25=Item 14 Selected InputSigType25=Digital InputCue26=Item 15 Selected InputSigType26=Digital InputCue27=Item 16 Selected InputSigType27=Digital InputCue28=Item 17 Selected InputSigType28=Digital InputCue29=Item 18 Selected InputSigType29=Digital InputCue30=Item 19 Selected InputSigType30=Digital InputCue31=Item 20 Selected InputSigType31=Digital InputCue32=Item 21 Selected InputSigType32=Digital InputCue33=Item 22 Selected InputSigType33=Digital InputCue34=Item 23 Selected InputSigType34=Digital InputCue35=Item 24 Selected InputSigType35=Digital InputCue36=Item 25 Selected InputSigType36=Digital InputCue37=Item 26 Selected InputSigType37=Digital InputCue38=Item 27 Selected InputSigType38=Digital InputCue39=Item 28 Selected InputSigType39=Digital InputCue40=Item 29 Selected InputSigType40=Digital InputCue41=Item 30 Selected InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=Item 11 Enabled InputSigType2024=Digital InputCue2025=Item 12 Enabled InputSigType2025=Digital InputCue2026=Item 13 Enabled InputSigType2026=Digital InputCue2027=Item 14 Enabled InputSigType2027=Digital InputCue2028=Item 15 Enabled InputSigType2028=Digital InputCue2029=Item 16 Enabled InputSigType2029=Digital InputCue2030=Item 17 Enabled InputSigType2030=Digital InputCue2031=Item 18 Enabled InputSigType2031=Digital InputCue2032=Item 19 Enabled InputSigType2032=Digital InputCue2033=Item 20 Enabled InputSigType2033=Digital InputCue2034=Item 21 Enabled InputSigType2034=Digital InputCue2035=Item 22 Enabled InputSigType2035=Digital InputCue2036=Item 23 Enabled InputSigType2036=Digital InputCue2037=Item 24 Enabled InputSigType2037=Digital InputCue2038=Item 25 Enabled InputSigType2038=Digital InputCue2039=Item 26 Enabled InputSigType2039=Digital InputCue2040=Item 27 Enabled InputSigType2040=Digital InputCue2041=Item 28 Enabled InputSigType2041=Digital InputCue2042=Item 29 Enabled InputSigType2042=Digital InputCue2043=Item 30 Enabled InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=Item 11 Visible InputSigType4026=Digital InputCue4027=Item 12 Visible InputSigType4027=Digital InputCue4028=Item 13 Visible InputSigType4028=Digital InputCue4029=Item 14 Visible InputSigType4029=Digital InputCue4030=Item 15 Visible InputSigType4030=Digital InputCue4031=Item 16 Visible InputSigType4031=Digital InputCue4032=Item 17 Visible InputSigType4032=Digital InputCue4033=Item 18 Visible InputSigType4033=Digital InputCue4034=Item 19 Visible InputSigType4034=Digital InputCue4035=Item 20 Visible InputSigType4035=Digital InputCue4036=Item 21 Visible InputSigType4036=Digital InputCue4037=Item 22 Visible InputSigType4037=Digital InputCue4038=Item 23 Visible InputSigType4038=Digital InputCue4039=Item 24 Visible InputSigType4039=Digital InputCue4040=Item 25 Visible InputSigType4040=Digital InputCue4041=Item 26 Visible InputSigType4041=Digital InputCue4042=Item 27 Visible InputSigType4042=Digital InputCue4043=Item 28 Visible InputSigType4043=Digital InputCue4044=Item 29 Visible InputSigType4044=Digital InputCue4045=Item 30 Visible InputSigType4045=Digital InputCue4046=[~UNUSED2~] InputSigType4046=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=Item 11 Pressed OutputSigType22=Digital OutputCue23=Item 12 Pressed OutputSigType23=Digital OutputCue24=Item 13 Pressed OutputSigType24=Digital OutputCue25=Item 14 Pressed OutputSigType25=Digital OutputCue26=Item 15 Pressed OutputSigType26=Digital OutputCue27=Item 16 Pressed OutputSigType27=Digital OutputCue28=Item 17 Pressed OutputSigType28=Digital OutputCue29=Item 18 Pressed OutputSigType29=Digital OutputCue30=Item 19 Pressed OutputSigType30=Digital OutputCue31=Item 20 Pressed OutputSigType31=Digital OutputCue32=Item 21 Pressed OutputSigType32=Digital OutputCue33=Item 22 Pressed OutputSigType33=Digital OutputCue34=Item 23 Pressed OutputSigType34=Digital OutputCue35=Item 24 Pressed OutputSigType35=Digital OutputCue36=Item 25 Pressed OutputSigType36=Digital OutputCue37=Item 26 Pressed OutputSigType37=Digital OutputCue38=Item 27 Pressed OutputSigType38=Digital OutputCue39=Item 28 Pressed OutputSigType39=Digital OutputCue40=Item 29 Pressed OutputSigType40=Digital OutputCue41=Item 30 Pressed OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED3~] OutputSigType4026=Digital OutputCue4027=[~UNUSED3~] OutputSigType4027=Digital OutputCue4028=[~UNUSED3~] OutputSigType4028=Digital OutputCue4029=[~UNUSED3~] OutputSigType4029=Digital OutputCue4030=[~UNUSED3~] OutputSigType4030=Digital OutputCue4031=[~UNUSED3~] OutputSigType4031=Digital OutputCue4032=[~UNUSED3~] OutputSigType4032=Digital OutputCue4033=[~UNUSED3~] OutputSigType4033=Digital OutputCue4034=[~UNUSED3~] OutputSigType4034=Digital OutputCue4035=[~UNUSED3~] OutputSigType4035=Digital OutputCue4036=[~UNUSED3~] OutputSigType4036=Digital OutputCue4037=[~UNUSED3~] OutputSigType4037=Digital OutputCue4038=[~UNUSED3~] OutputSigType4038=Digital OutputCue4039=[~UNUSED3~] OutputSigType4039=Digital OutputCue4040=[~UNUSED3~] OutputSigType4040=Digital OutputCue4041=[~UNUSED3~] OutputSigType4041=Digital OutputCue4042=[~UNUSED3~] OutputSigType4042=Digital OutputCue4043=[~UNUSED3~] OutputSigType4043=Digital OutputCue4044=[~UNUSED3~] OutputSigType4044=Digital OutputCue4045=[~UNUSED3~] OutputSigType4045=Digital OutputCue4046=[~UNUSED2~] OutputSigType4046=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=Set Item 11 Icon Analog InputList2SigType22=Analog InputList2Cue23=Set Item 12 Icon Analog InputList2SigType23=Analog InputList2Cue24=Set Item 13 Icon Analog InputList2SigType24=Analog InputList2Cue25=Set Item 14 Icon Analog InputList2SigType25=Analog InputList2Cue26=Set Item 15 Icon Analog InputList2SigType26=Analog InputList2Cue27=Set Item 16 Icon Analog InputList2SigType27=Analog InputList2Cue28=Set Item 17 Icon Analog InputList2SigType28=Analog InputList2Cue29=Set Item 18 Icon Analog InputList2SigType29=Analog InputList2Cue30=Set Item 19 Icon Analog InputList2SigType30=Analog InputList2Cue31=Set Item 20 Icon Analog InputList2SigType31=Analog InputList2Cue32=Set Item 21 Icon Analog InputList2SigType32=Analog InputList2Cue33=Set Item 22 Icon Analog InputList2SigType33=Analog InputList2Cue34=Set Item 23 Icon Analog InputList2SigType34=Analog InputList2Cue35=Set Item 24 Icon Analog InputList2SigType35=Analog InputList2Cue36=Set Item 25 Icon Analog InputList2SigType36=Analog InputList2Cue37=Set Item 26 Icon Analog InputList2SigType37=Analog InputList2Cue38=Set Item 27 Icon Analog InputList2SigType38=Analog InputList2Cue39=Set Item 28 Icon Analog InputList2SigType39=Analog InputList2Cue40=Set Item 29 Icon Analog InputList2SigType40=Analog InputList2Cue41=Set Item 30 Icon Analog InputList2SigType41=Analog InputList2Cue42=[~UNUSED2~] InputList2SigType42=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED3~] OutputList2SigType22=Analog OutputList2Cue23=[~UNUSED3~] OutputList2SigType23=Analog OutputList2Cue24=[~UNUSED3~] OutputList2SigType24=Analog OutputList2Cue25=[~UNUSED3~] OutputList2SigType25=Analog OutputList2Cue26=[~UNUSED3~] OutputList2SigType26=Analog OutputList2Cue27=[~UNUSED3~] OutputList2SigType27=Analog OutputList2Cue28=[~UNUSED3~] OutputList2SigType28=Analog OutputList2Cue29=[~UNUSED3~] OutputList2SigType29=Analog OutputList2Cue30=[~UNUSED3~] OutputList2SigType30=Analog OutputList2Cue31=[~UNUSED3~] OutputList2SigType31=Analog OutputList2Cue32=[~UNUSED3~] OutputList2SigType32=Analog OutputList2Cue33=[~UNUSED3~] OutputList2SigType33=Analog OutputList2Cue34=[~UNUSED3~] OutputList2SigType34=Analog OutputList2Cue35=[~UNUSED3~] OutputList2SigType35=Analog OutputList2Cue36=[~UNUSED3~] OutputList2SigType36=Analog OutputList2Cue37=[~UNUSED3~] OutputList2SigType37=Analog OutputList2Cue38=[~UNUSED3~] OutputList2SigType38=Analog OutputList2Cue39=[~UNUSED3~] OutputList2SigType39=Analog OutputList2Cue40=[~UNUSED3~] OutputList2SigType40=Analog OutputList2Cue41=[~UNUSED3~] OutputList2SigType41=Analog OutputList2Cue42=[~UNUSED2~] OutputList2SigType42=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=Set Item 11 Text InputList3SigType22=Serial InputList3Cue23=Set Item 12 Text InputList3SigType23=Serial InputList3Cue24=Set Item 13 Text InputList3SigType24=Serial InputList3Cue25=Set Item 14 Text InputList3SigType25=Serial InputList3Cue26=Set Item 15 Text InputList3SigType26=Serial InputList3Cue27=Set Item 16 Text InputList3SigType27=Serial InputList3Cue28=Set Item 17 Text InputList3SigType28=Serial InputList3Cue29=Set Item 18 Text InputList3SigType29=Serial InputList3Cue30=Set Item 19 Text InputList3SigType30=Serial InputList3Cue31=Set Item 20 Text InputList3SigType31=Serial InputList3Cue32=Set Item 21 Text InputList3SigType32=Serial InputList3Cue33=Set Item 22 Text InputList3SigType33=Serial InputList3Cue34=Set Item 23 Text InputList3SigType34=Serial InputList3Cue35=Set Item 24 Text InputList3SigType35=Serial InputList3Cue36=Set Item 25 Text InputList3SigType36=Serial InputList3Cue37=Set Item 26 Text InputList3SigType37=Serial InputList3Cue38=Set Item 27 Text InputList3SigType38=Serial InputList3Cue39=Set Item 28 Text InputList3SigType39=Serial InputList3Cue40=Set Item 29 Text InputList3SigType40=Serial InputList3Cue41=Set Item 30 Text InputList3SigType41=Serial InputList3Cue42=[~UNUSED2~] InputList3SigType42=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=Set Item 11 Icon Serial InputList3SigType2024=Serial InputList3Cue2025=Set Item 12 Icon Serial InputList3SigType2025=Serial InputList3Cue2026=Set Item 13 Icon Serial InputList3SigType2026=Serial InputList3Cue2027=Set Item 14 Icon Serial InputList3SigType2027=Serial InputList3Cue2028=Set Item 15 Icon Serial InputList3SigType2028=Serial InputList3Cue2029=Set Item 16 Icon Serial InputList3SigType2029=Serial InputList3Cue2030=Set Item 17 Icon Serial InputList3SigType2030=Serial InputList3Cue2031=Set Item 18 Icon Serial InputList3SigType2031=Serial InputList3Cue2032=Set Item 19 Icon Serial InputList3SigType2032=Serial InputList3Cue2033=Set Item 20 Icon Serial InputList3SigType2033=Serial InputList3Cue2034=Set Item 21 Icon Serial InputList3SigType2034=Serial InputList3Cue2035=Set Item 22 Icon Serial InputList3SigType2035=Serial InputList3Cue2036=Set Item 23 Icon Serial InputList3SigType2036=Serial InputList3Cue2037=Set Item 24 Icon Serial InputList3SigType2037=Serial InputList3Cue2038=Set Item 25 Icon Serial InputList3SigType2038=Serial InputList3Cue2039=Set Item 26 Icon Serial InputList3SigType2039=Serial InputList3Cue2040=Set Item 27 Icon Serial InputList3SigType2040=Serial InputList3Cue2041=Set Item 28 Icon Serial InputList3SigType2041=Serial InputList3Cue2042=Set Item 29 Icon Serial InputList3SigType2042=Serial InputList3Cue2043=Set Item 30 Icon Serial InputList3SigType2043=Serial InputList3Cue2044=[~UNUSED2~] InputList3SigType2044=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED3~] OutputList3SigType22=Serial OutputList3Cue23=[~UNUSED3~] OutputList3SigType23=Serial OutputList3Cue24=[~UNUSED3~] OutputList3SigType24=Serial OutputList3Cue25=[~UNUSED3~] OutputList3SigType25=Serial OutputList3Cue26=[~UNUSED3~] OutputList3SigType26=Serial OutputList3Cue27=[~UNUSED3~] OutputList3SigType27=Serial OutputList3Cue28=[~UNUSED3~] OutputList3SigType28=Serial OutputList3Cue29=[~UNUSED3~] OutputList3SigType29=Serial OutputList3Cue30=[~UNUSED3~] OutputList3SigType30=Serial OutputList3Cue31=[~UNUSED3~] OutputList3SigType31=Serial OutputList3Cue32=[~UNUSED3~] OutputList3SigType32=Serial OutputList3Cue33=[~UNUSED3~] OutputList3SigType33=Serial OutputList3Cue34=[~UNUSED3~] OutputList3SigType34=Serial OutputList3Cue35=[~UNUSED3~] OutputList3SigType35=Serial OutputList3Cue36=[~UNUSED3~] OutputList3SigType36=Serial OutputList3Cue37=[~UNUSED3~] OutputList3SigType37=Serial OutputList3Cue38=[~UNUSED3~] OutputList3SigType38=Serial OutputList3Cue39=[~UNUSED3~] OutputList3SigType39=Serial OutputList3Cue40=[~UNUSED3~] OutputList3SigType40=Serial OutputList3Cue41=[~UNUSED3~] OutputList3SigType41=Serial OutputList3Cue42=[~UNUSED2~] OutputList3SigType42=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED3~] OutputList3SigType2024=Serial OutputList3Cue2025=[~UNUSED3~] OutputList3SigType2025=Serial OutputList3Cue2026=[~UNUSED3~] OutputList3SigType2026=Serial OutputList3Cue2027=[~UNUSED3~] OutputList3SigType2027=Serial OutputList3Cue2028=[~UNUSED3~] OutputList3SigType2028=Serial OutputList3Cue2029=[~UNUSED3~] OutputList3SigType2029=Serial OutputList3Cue2030=[~UNUSED3~] OutputList3SigType2030=Serial OutputList3Cue2031=[~UNUSED3~] OutputList3SigType2031=Serial OutputList3Cue2032=[~UNUSED3~] OutputList3SigType2032=Serial OutputList3Cue2033=[~UNUSED3~] OutputList3SigType2033=Serial OutputList3Cue2034=[~UNUSED3~] OutputList3SigType2034=Serial OutputList3Cue2035=[~UNUSED3~] OutputList3SigType2035=Serial OutputList3Cue2036=[~UNUSED3~] OutputList3SigType2036=Serial OutputList3Cue2037=[~UNUSED3~] OutputList3SigType2037=Serial OutputList3Cue2038=[~UNUSED3~] OutputList3SigType2038=Serial OutputList3Cue2039=[~UNUSED3~] OutputList3SigType2039=Serial OutputList3Cue2040=[~UNUSED3~] OutputList3SigType2040=Serial OutputList3Cue2041=[~UNUSED3~] OutputList3SigType2041=Serial OutputList3Cue2042=[~UNUSED3~] OutputList3SigType2042=Serial OutputList3Cue2043=[~UNUSED3~] OutputList3SigType2043=Serial OutputList3Cue2044=[~UNUSED2~] OutputList3SigType2044=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=19 CedH=19 SmartObjId=1203d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=19 Tp=1 HD=TRUE DV=1203d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=19 Name=PepperDash Essentials TSW-560_[D.VC] Recents_Dynamic Button List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ================================================ FILE: src/PepperDash.Essentials/SGD/PepperDash Essentials TSW-760.sgd ================================================ [ ObjTp=FSgntr Sgntr=SGD RelVrs=3 VTProeVer=6.1.05 Schema=1 CRCGUID=6C002F1C-3D96-4EBF-A0D9-8A124BE8F48A ] ;================================================================================ [ ObjTp=Hd ProjectFile=PepperDash Essentials TSW-760.vtp VtpGuid=D8D5F125-CB35-42E9-8AE3-4142597FD2C5 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[C.AC] Keypad_AC DTMF Keypad_2.ced Hint=AC DTMF Keypad_2 (Smart Object ID=1101) Code=1 SGControlType=Simple Keypad SGControlName=AC DTMF Keypad_2 GUID=F2A259FE-82AD-4085-B5A6-22D7B034458C SmplCName=PepperDash Essentials TSW-760_[C.AC] Keypad_AC DTMF Keypad_2.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=* OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=/# OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=1 CedH=1 SmartObjId=1101d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=1 Tp=1 HD=TRUE DV=1101d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=1 Name=PepperDash Essentials TSW-760_[C.AC] Keypad_AC DTMF Keypad_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[D.VC] Directory_Dynamic Button List Vertical_2.ced Hint=Dynamic Button List Vertical_2 (Smart Object ID=1202) Code=2 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical_2 GUID=79060F3C-D3A4-4A8D-ACF0-CB2376A31702 SmplCName=PepperDash Essentials TSW-760_[D.VC] Directory_Dynamic Button List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=Item 11 Selected InputSigType22=Digital InputCue23=Item 12 Selected InputSigType23=Digital InputCue24=Item 13 Selected InputSigType24=Digital InputCue25=Item 14 Selected InputSigType25=Digital InputCue26=Item 15 Selected InputSigType26=Digital InputCue27=Item 16 Selected InputSigType27=Digital InputCue28=Item 17 Selected InputSigType28=Digital InputCue29=Item 18 Selected InputSigType29=Digital InputCue30=Item 19 Selected InputSigType30=Digital InputCue31=Item 20 Selected InputSigType31=Digital InputCue32=Item 21 Selected InputSigType32=Digital InputCue33=Item 22 Selected InputSigType33=Digital InputCue34=Item 23 Selected InputSigType34=Digital InputCue35=Item 24 Selected InputSigType35=Digital InputCue36=Item 25 Selected InputSigType36=Digital InputCue37=Item 26 Selected InputSigType37=Digital InputCue38=Item 27 Selected InputSigType38=Digital InputCue39=Item 28 Selected InputSigType39=Digital InputCue40=Item 29 Selected InputSigType40=Digital InputCue41=Item 30 Selected InputSigType41=Digital InputCue42=Item 31 Selected InputSigType42=Digital InputCue43=Item 32 Selected InputSigType43=Digital InputCue44=Item 33 Selected InputSigType44=Digital InputCue45=Item 34 Selected InputSigType45=Digital InputCue46=Item 35 Selected InputSigType46=Digital InputCue47=Item 36 Selected InputSigType47=Digital InputCue48=Item 37 Selected InputSigType48=Digital InputCue49=Item 38 Selected InputSigType49=Digital InputCue50=Item 39 Selected InputSigType50=Digital InputCue51=Item 40 Selected InputSigType51=Digital InputCue52=Item 41 Selected InputSigType52=Digital InputCue53=Item 42 Selected InputSigType53=Digital InputCue54=Item 43 Selected InputSigType54=Digital InputCue55=Item 44 Selected InputSigType55=Digital InputCue56=Item 45 Selected InputSigType56=Digital InputCue57=Item 46 Selected InputSigType57=Digital InputCue58=Item 47 Selected InputSigType58=Digital InputCue59=Item 48 Selected InputSigType59=Digital InputCue60=Item 49 Selected InputSigType60=Digital InputCue61=Item 50 Selected InputSigType61=Digital InputCue62=Item 51 Selected InputSigType62=Digital InputCue63=Item 52 Selected InputSigType63=Digital InputCue64=Item 53 Selected InputSigType64=Digital InputCue65=Item 54 Selected InputSigType65=Digital InputCue66=Item 55 Selected InputSigType66=Digital InputCue67=Item 56 Selected InputSigType67=Digital InputCue68=Item 57 Selected InputSigType68=Digital InputCue69=Item 58 Selected InputSigType69=Digital InputCue70=Item 59 Selected InputSigType70=Digital InputCue71=Item 60 Selected InputSigType71=Digital InputCue72=Item 61 Selected InputSigType72=Digital InputCue73=Item 62 Selected InputSigType73=Digital InputCue74=Item 63 Selected InputSigType74=Digital InputCue75=Item 64 Selected InputSigType75=Digital InputCue76=Item 65 Selected InputSigType76=Digital InputCue77=Item 66 Selected InputSigType77=Digital InputCue78=Item 67 Selected InputSigType78=Digital InputCue79=Item 68 Selected InputSigType79=Digital InputCue80=Item 69 Selected InputSigType80=Digital InputCue81=Item 70 Selected InputSigType81=Digital InputCue82=Item 71 Selected InputSigType82=Digital InputCue83=Item 72 Selected InputSigType83=Digital InputCue84=Item 73 Selected InputSigType84=Digital InputCue85=Item 74 Selected InputSigType85=Digital InputCue86=Item 75 Selected InputSigType86=Digital InputCue87=Item 76 Selected InputSigType87=Digital InputCue88=Item 77 Selected InputSigType88=Digital InputCue89=Item 78 Selected InputSigType89=Digital InputCue90=Item 79 Selected InputSigType90=Digital InputCue91=Item 80 Selected InputSigType91=Digital InputCue92=Item 81 Selected InputSigType92=Digital InputCue93=Item 82 Selected InputSigType93=Digital InputCue94=Item 83 Selected InputSigType94=Digital InputCue95=Item 84 Selected InputSigType95=Digital InputCue96=Item 85 Selected InputSigType96=Digital InputCue97=Item 86 Selected InputSigType97=Digital InputCue98=Item 87 Selected InputSigType98=Digital InputCue99=Item 88 Selected InputSigType99=Digital InputCue100=Item 89 Selected InputSigType100=Digital InputCue101=Item 90 Selected InputSigType101=Digital InputCue102=Item 91 Selected InputSigType102=Digital InputCue103=Item 92 Selected InputSigType103=Digital InputCue104=Item 93 Selected InputSigType104=Digital InputCue105=Item 94 Selected InputSigType105=Digital InputCue106=Item 95 Selected InputSigType106=Digital InputCue107=Item 96 Selected InputSigType107=Digital InputCue108=Item 97 Selected InputSigType108=Digital InputCue109=Item 98 Selected InputSigType109=Digital InputCue110=Item 99 Selected InputSigType110=Digital InputCue111=Item 100 Selected InputSigType111=Digital InputCue112=[~UNUSED2~] InputSigType112=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=Item 11 Enabled InputSigType2024=Digital InputCue2025=Item 12 Enabled InputSigType2025=Digital InputCue2026=Item 13 Enabled InputSigType2026=Digital InputCue2027=Item 14 Enabled InputSigType2027=Digital InputCue2028=Item 15 Enabled InputSigType2028=Digital InputCue2029=Item 16 Enabled InputSigType2029=Digital InputCue2030=Item 17 Enabled InputSigType2030=Digital InputCue2031=Item 18 Enabled InputSigType2031=Digital InputCue2032=Item 19 Enabled InputSigType2032=Digital InputCue2033=Item 20 Enabled InputSigType2033=Digital InputCue2034=Item 21 Enabled InputSigType2034=Digital InputCue2035=Item 22 Enabled InputSigType2035=Digital InputCue2036=Item 23 Enabled InputSigType2036=Digital InputCue2037=Item 24 Enabled InputSigType2037=Digital InputCue2038=Item 25 Enabled InputSigType2038=Digital InputCue2039=Item 26 Enabled InputSigType2039=Digital InputCue2040=Item 27 Enabled InputSigType2040=Digital InputCue2041=Item 28 Enabled InputSigType2041=Digital InputCue2042=Item 29 Enabled InputSigType2042=Digital InputCue2043=Item 30 Enabled InputSigType2043=Digital InputCue2044=Item 31 Enabled InputSigType2044=Digital InputCue2045=Item 32 Enabled InputSigType2045=Digital InputCue2046=Item 33 Enabled InputSigType2046=Digital InputCue2047=Item 34 Enabled InputSigType2047=Digital InputCue2048=Item 35 Enabled InputSigType2048=Digital InputCue2049=Item 36 Enabled InputSigType2049=Digital InputCue2050=Item 37 Enabled InputSigType2050=Digital InputCue2051=Item 38 Enabled InputSigType2051=Digital InputCue2052=Item 39 Enabled InputSigType2052=Digital InputCue2053=Item 40 Enabled InputSigType2053=Digital InputCue2054=Item 41 Enabled InputSigType2054=Digital InputCue2055=Item 42 Enabled InputSigType2055=Digital InputCue2056=Item 43 Enabled InputSigType2056=Digital InputCue2057=Item 44 Enabled InputSigType2057=Digital InputCue2058=Item 45 Enabled InputSigType2058=Digital InputCue2059=Item 46 Enabled InputSigType2059=Digital InputCue2060=Item 47 Enabled InputSigType2060=Digital InputCue2061=Item 48 Enabled InputSigType2061=Digital InputCue2062=Item 49 Enabled InputSigType2062=Digital InputCue2063=Item 50 Enabled InputSigType2063=Digital InputCue2064=Item 51 Enabled InputSigType2064=Digital InputCue2065=Item 52 Enabled InputSigType2065=Digital InputCue2066=Item 53 Enabled InputSigType2066=Digital InputCue2067=Item 54 Enabled InputSigType2067=Digital InputCue2068=Item 55 Enabled InputSigType2068=Digital InputCue2069=Item 56 Enabled InputSigType2069=Digital InputCue2070=Item 57 Enabled InputSigType2070=Digital InputCue2071=Item 58 Enabled InputSigType2071=Digital InputCue2072=Item 59 Enabled InputSigType2072=Digital InputCue2073=Item 60 Enabled InputSigType2073=Digital InputCue2074=Item 61 Enabled InputSigType2074=Digital InputCue2075=Item 62 Enabled InputSigType2075=Digital InputCue2076=Item 63 Enabled InputSigType2076=Digital InputCue2077=Item 64 Enabled InputSigType2077=Digital InputCue2078=Item 65 Enabled InputSigType2078=Digital InputCue2079=Item 66 Enabled InputSigType2079=Digital InputCue2080=Item 67 Enabled InputSigType2080=Digital InputCue2081=Item 68 Enabled InputSigType2081=Digital InputCue2082=Item 69 Enabled InputSigType2082=Digital InputCue2083=Item 70 Enabled InputSigType2083=Digital InputCue2084=Item 71 Enabled InputSigType2084=Digital InputCue2085=Item 72 Enabled InputSigType2085=Digital InputCue2086=Item 73 Enabled InputSigType2086=Digital InputCue2087=Item 74 Enabled InputSigType2087=Digital InputCue2088=Item 75 Enabled InputSigType2088=Digital InputCue2089=Item 76 Enabled InputSigType2089=Digital InputCue2090=Item 77 Enabled InputSigType2090=Digital InputCue2091=Item 78 Enabled InputSigType2091=Digital InputCue2092=Item 79 Enabled InputSigType2092=Digital InputCue2093=Item 80 Enabled InputSigType2093=Digital InputCue2094=Item 81 Enabled InputSigType2094=Digital InputCue2095=Item 82 Enabled InputSigType2095=Digital InputCue2096=Item 83 Enabled InputSigType2096=Digital InputCue2097=Item 84 Enabled InputSigType2097=Digital InputCue2098=Item 85 Enabled InputSigType2098=Digital InputCue2099=Item 86 Enabled InputSigType2099=Digital InputCue2100=Item 87 Enabled InputSigType2100=Digital InputCue2101=Item 88 Enabled InputSigType2101=Digital InputCue2102=Item 89 Enabled InputSigType2102=Digital InputCue2103=Item 90 Enabled InputSigType2103=Digital InputCue2104=Item 91 Enabled InputSigType2104=Digital InputCue2105=Item 92 Enabled InputSigType2105=Digital InputCue2106=Item 93 Enabled InputSigType2106=Digital InputCue2107=Item 94 Enabled InputSigType2107=Digital InputCue2108=Item 95 Enabled InputSigType2108=Digital InputCue2109=Item 96 Enabled InputSigType2109=Digital InputCue2110=Item 97 Enabled InputSigType2110=Digital InputCue2111=Item 98 Enabled InputSigType2111=Digital InputCue2112=Item 99 Enabled InputSigType2112=Digital InputCue2113=Item 100 Enabled InputSigType2113=Digital InputCue2114=[~UNUSED2~] InputSigType2114=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=Item 11 Visible InputSigType4026=Digital InputCue4027=Item 12 Visible InputSigType4027=Digital InputCue4028=Item 13 Visible InputSigType4028=Digital InputCue4029=Item 14 Visible InputSigType4029=Digital InputCue4030=Item 15 Visible InputSigType4030=Digital InputCue4031=Item 16 Visible InputSigType4031=Digital InputCue4032=Item 17 Visible InputSigType4032=Digital InputCue4033=Item 18 Visible InputSigType4033=Digital InputCue4034=Item 19 Visible InputSigType4034=Digital InputCue4035=Item 20 Visible InputSigType4035=Digital InputCue4036=Item 21 Visible InputSigType4036=Digital InputCue4037=Item 22 Visible InputSigType4037=Digital InputCue4038=Item 23 Visible InputSigType4038=Digital InputCue4039=Item 24 Visible InputSigType4039=Digital InputCue4040=Item 25 Visible InputSigType4040=Digital InputCue4041=Item 26 Visible InputSigType4041=Digital InputCue4042=Item 27 Visible InputSigType4042=Digital InputCue4043=Item 28 Visible InputSigType4043=Digital InputCue4044=Item 29 Visible InputSigType4044=Digital InputCue4045=Item 30 Visible InputSigType4045=Digital InputCue4046=Item 31 Visible InputSigType4046=Digital InputCue4047=Item 32 Visible InputSigType4047=Digital InputCue4048=Item 33 Visible InputSigType4048=Digital InputCue4049=Item 34 Visible InputSigType4049=Digital InputCue4050=Item 35 Visible InputSigType4050=Digital InputCue4051=Item 36 Visible InputSigType4051=Digital InputCue4052=Item 37 Visible InputSigType4052=Digital InputCue4053=Item 38 Visible InputSigType4053=Digital InputCue4054=Item 39 Visible InputSigType4054=Digital InputCue4055=Item 40 Visible InputSigType4055=Digital InputCue4056=Item 41 Visible InputSigType4056=Digital InputCue4057=Item 42 Visible InputSigType4057=Digital InputCue4058=Item 43 Visible InputSigType4058=Digital InputCue4059=Item 44 Visible InputSigType4059=Digital InputCue4060=Item 45 Visible InputSigType4060=Digital InputCue4061=Item 46 Visible InputSigType4061=Digital InputCue4062=Item 47 Visible InputSigType4062=Digital InputCue4063=Item 48 Visible InputSigType4063=Digital InputCue4064=Item 49 Visible InputSigType4064=Digital InputCue4065=Item 50 Visible InputSigType4065=Digital InputCue4066=Item 51 Visible InputSigType4066=Digital InputCue4067=Item 52 Visible InputSigType4067=Digital InputCue4068=Item 53 Visible InputSigType4068=Digital InputCue4069=Item 54 Visible InputSigType4069=Digital InputCue4070=Item 55 Visible InputSigType4070=Digital InputCue4071=Item 56 Visible InputSigType4071=Digital InputCue4072=Item 57 Visible InputSigType4072=Digital InputCue4073=Item 58 Visible InputSigType4073=Digital InputCue4074=Item 59 Visible InputSigType4074=Digital InputCue4075=Item 60 Visible InputSigType4075=Digital InputCue4076=Item 61 Visible InputSigType4076=Digital InputCue4077=Item 62 Visible InputSigType4077=Digital InputCue4078=Item 63 Visible InputSigType4078=Digital InputCue4079=Item 64 Visible InputSigType4079=Digital InputCue4080=Item 65 Visible InputSigType4080=Digital InputCue4081=Item 66 Visible InputSigType4081=Digital InputCue4082=Item 67 Visible InputSigType4082=Digital InputCue4083=Item 68 Visible InputSigType4083=Digital InputCue4084=Item 69 Visible InputSigType4084=Digital InputCue4085=Item 70 Visible InputSigType4085=Digital InputCue4086=Item 71 Visible InputSigType4086=Digital InputCue4087=Item 72 Visible InputSigType4087=Digital InputCue4088=Item 73 Visible InputSigType4088=Digital InputCue4089=Item 74 Visible InputSigType4089=Digital InputCue4090=Item 75 Visible InputSigType4090=Digital InputCue4091=Item 76 Visible InputSigType4091=Digital InputCue4092=Item 77 Visible InputSigType4092=Digital InputCue4093=Item 78 Visible InputSigType4093=Digital InputCue4094=Item 79 Visible InputSigType4094=Digital InputCue4095=Item 80 Visible InputSigType4095=Digital InputCue4096=Item 81 Visible InputSigType4096=Digital InputCue4097=Item 82 Visible InputSigType4097=Digital InputCue4098=Item 83 Visible InputSigType4098=Digital InputCue4099=Item 84 Visible InputSigType4099=Digital InputCue4100=Item 85 Visible InputSigType4100=Digital InputCue4101=Item 86 Visible InputSigType4101=Digital InputCue4102=Item 87 Visible InputSigType4102=Digital InputCue4103=Item 88 Visible InputSigType4103=Digital InputCue4104=Item 89 Visible InputSigType4104=Digital InputCue4105=Item 90 Visible InputSigType4105=Digital InputCue4106=Item 91 Visible InputSigType4106=Digital InputCue4107=Item 92 Visible InputSigType4107=Digital InputCue4108=Item 93 Visible InputSigType4108=Digital InputCue4109=Item 94 Visible InputSigType4109=Digital InputCue4110=Item 95 Visible InputSigType4110=Digital InputCue4111=Item 96 Visible InputSigType4111=Digital InputCue4112=Item 97 Visible InputSigType4112=Digital InputCue4113=Item 98 Visible InputSigType4113=Digital InputCue4114=Item 99 Visible InputSigType4114=Digital InputCue4115=Item 100 Visible InputSigType4115=Digital InputCue4116=[~UNUSED2~] InputSigType4116=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=Item 11 Pressed OutputSigType22=Digital OutputCue23=Item 12 Pressed OutputSigType23=Digital OutputCue24=Item 13 Pressed OutputSigType24=Digital OutputCue25=Item 14 Pressed OutputSigType25=Digital OutputCue26=Item 15 Pressed OutputSigType26=Digital OutputCue27=Item 16 Pressed OutputSigType27=Digital OutputCue28=Item 17 Pressed OutputSigType28=Digital OutputCue29=Item 18 Pressed OutputSigType29=Digital OutputCue30=Item 19 Pressed OutputSigType30=Digital OutputCue31=Item 20 Pressed OutputSigType31=Digital OutputCue32=Item 21 Pressed OutputSigType32=Digital OutputCue33=Item 22 Pressed OutputSigType33=Digital OutputCue34=Item 23 Pressed OutputSigType34=Digital OutputCue35=Item 24 Pressed OutputSigType35=Digital OutputCue36=Item 25 Pressed OutputSigType36=Digital OutputCue37=Item 26 Pressed OutputSigType37=Digital OutputCue38=Item 27 Pressed OutputSigType38=Digital OutputCue39=Item 28 Pressed OutputSigType39=Digital OutputCue40=Item 29 Pressed OutputSigType40=Digital OutputCue41=Item 30 Pressed OutputSigType41=Digital OutputCue42=Item 31 Pressed OutputSigType42=Digital OutputCue43=Item 32 Pressed OutputSigType43=Digital OutputCue44=Item 33 Pressed OutputSigType44=Digital OutputCue45=Item 34 Pressed OutputSigType45=Digital OutputCue46=Item 35 Pressed OutputSigType46=Digital OutputCue47=Item 36 Pressed OutputSigType47=Digital OutputCue48=Item 37 Pressed OutputSigType48=Digital OutputCue49=Item 38 Pressed OutputSigType49=Digital OutputCue50=Item 39 Pressed OutputSigType50=Digital OutputCue51=Item 40 Pressed OutputSigType51=Digital OutputCue52=Item 41 Pressed OutputSigType52=Digital OutputCue53=Item 42 Pressed OutputSigType53=Digital OutputCue54=Item 43 Pressed OutputSigType54=Digital OutputCue55=Item 44 Pressed OutputSigType55=Digital OutputCue56=Item 45 Pressed OutputSigType56=Digital OutputCue57=Item 46 Pressed OutputSigType57=Digital OutputCue58=Item 47 Pressed OutputSigType58=Digital OutputCue59=Item 48 Pressed OutputSigType59=Digital OutputCue60=Item 49 Pressed OutputSigType60=Digital OutputCue61=Item 50 Pressed OutputSigType61=Digital OutputCue62=Item 51 Pressed OutputSigType62=Digital OutputCue63=Item 52 Pressed OutputSigType63=Digital OutputCue64=Item 53 Pressed OutputSigType64=Digital OutputCue65=Item 54 Pressed OutputSigType65=Digital OutputCue66=Item 55 Pressed OutputSigType66=Digital OutputCue67=Item 56 Pressed OutputSigType67=Digital OutputCue68=Item 57 Pressed OutputSigType68=Digital OutputCue69=Item 58 Pressed OutputSigType69=Digital OutputCue70=Item 59 Pressed OutputSigType70=Digital OutputCue71=Item 60 Pressed OutputSigType71=Digital OutputCue72=Item 61 Pressed OutputSigType72=Digital OutputCue73=Item 62 Pressed OutputSigType73=Digital OutputCue74=Item 63 Pressed OutputSigType74=Digital OutputCue75=Item 64 Pressed OutputSigType75=Digital OutputCue76=Item 65 Pressed OutputSigType76=Digital OutputCue77=Item 66 Pressed OutputSigType77=Digital OutputCue78=Item 67 Pressed OutputSigType78=Digital OutputCue79=Item 68 Pressed OutputSigType79=Digital OutputCue80=Item 69 Pressed OutputSigType80=Digital OutputCue81=Item 70 Pressed OutputSigType81=Digital OutputCue82=Item 71 Pressed OutputSigType82=Digital OutputCue83=Item 72 Pressed OutputSigType83=Digital OutputCue84=Item 73 Pressed OutputSigType84=Digital OutputCue85=Item 74 Pressed OutputSigType85=Digital OutputCue86=Item 75 Pressed OutputSigType86=Digital OutputCue87=Item 76 Pressed OutputSigType87=Digital OutputCue88=Item 77 Pressed OutputSigType88=Digital OutputCue89=Item 78 Pressed OutputSigType89=Digital OutputCue90=Item 79 Pressed OutputSigType90=Digital OutputCue91=Item 80 Pressed OutputSigType91=Digital OutputCue92=Item 81 Pressed OutputSigType92=Digital OutputCue93=Item 82 Pressed OutputSigType93=Digital OutputCue94=Item 83 Pressed OutputSigType94=Digital OutputCue95=Item 84 Pressed OutputSigType95=Digital OutputCue96=Item 85 Pressed OutputSigType96=Digital OutputCue97=Item 86 Pressed OutputSigType97=Digital OutputCue98=Item 87 Pressed OutputSigType98=Digital OutputCue99=Item 88 Pressed OutputSigType99=Digital OutputCue100=Item 89 Pressed OutputSigType100=Digital OutputCue101=Item 90 Pressed OutputSigType101=Digital OutputCue102=Item 91 Pressed OutputSigType102=Digital OutputCue103=Item 92 Pressed OutputSigType103=Digital OutputCue104=Item 93 Pressed OutputSigType104=Digital OutputCue105=Item 94 Pressed OutputSigType105=Digital OutputCue106=Item 95 Pressed OutputSigType106=Digital OutputCue107=Item 96 Pressed OutputSigType107=Digital OutputCue108=Item 97 Pressed OutputSigType108=Digital OutputCue109=Item 98 Pressed OutputSigType109=Digital OutputCue110=Item 99 Pressed OutputSigType110=Digital OutputCue111=Item 100 Pressed OutputSigType111=Digital OutputCue112=[~UNUSED2~] OutputSigType112=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED3~] OutputSigType2044=Digital OutputCue2045=[~UNUSED3~] OutputSigType2045=Digital OutputCue2046=[~UNUSED3~] OutputSigType2046=Digital OutputCue2047=[~UNUSED3~] OutputSigType2047=Digital OutputCue2048=[~UNUSED3~] OutputSigType2048=Digital OutputCue2049=[~UNUSED3~] OutputSigType2049=Digital OutputCue2050=[~UNUSED3~] OutputSigType2050=Digital OutputCue2051=[~UNUSED3~] OutputSigType2051=Digital OutputCue2052=[~UNUSED3~] OutputSigType2052=Digital OutputCue2053=[~UNUSED3~] OutputSigType2053=Digital OutputCue2054=[~UNUSED3~] OutputSigType2054=Digital OutputCue2055=[~UNUSED3~] OutputSigType2055=Digital OutputCue2056=[~UNUSED3~] OutputSigType2056=Digital OutputCue2057=[~UNUSED3~] OutputSigType2057=Digital OutputCue2058=[~UNUSED3~] OutputSigType2058=Digital OutputCue2059=[~UNUSED3~] OutputSigType2059=Digital OutputCue2060=[~UNUSED3~] OutputSigType2060=Digital OutputCue2061=[~UNUSED3~] OutputSigType2061=Digital OutputCue2062=[~UNUSED3~] OutputSigType2062=Digital OutputCue2063=[~UNUSED3~] OutputSigType2063=Digital OutputCue2064=[~UNUSED3~] OutputSigType2064=Digital OutputCue2065=[~UNUSED3~] OutputSigType2065=Digital OutputCue2066=[~UNUSED3~] OutputSigType2066=Digital OutputCue2067=[~UNUSED3~] OutputSigType2067=Digital OutputCue2068=[~UNUSED3~] OutputSigType2068=Digital OutputCue2069=[~UNUSED3~] OutputSigType2069=Digital OutputCue2070=[~UNUSED3~] OutputSigType2070=Digital OutputCue2071=[~UNUSED3~] OutputSigType2071=Digital OutputCue2072=[~UNUSED3~] OutputSigType2072=Digital OutputCue2073=[~UNUSED3~] OutputSigType2073=Digital OutputCue2074=[~UNUSED3~] OutputSigType2074=Digital OutputCue2075=[~UNUSED3~] OutputSigType2075=Digital OutputCue2076=[~UNUSED3~] OutputSigType2076=Digital OutputCue2077=[~UNUSED3~] OutputSigType2077=Digital OutputCue2078=[~UNUSED3~] OutputSigType2078=Digital OutputCue2079=[~UNUSED3~] OutputSigType2079=Digital OutputCue2080=[~UNUSED3~] OutputSigType2080=Digital OutputCue2081=[~UNUSED3~] OutputSigType2081=Digital OutputCue2082=[~UNUSED3~] OutputSigType2082=Digital OutputCue2083=[~UNUSED3~] OutputSigType2083=Digital OutputCue2084=[~UNUSED3~] OutputSigType2084=Digital OutputCue2085=[~UNUSED3~] OutputSigType2085=Digital OutputCue2086=[~UNUSED3~] OutputSigType2086=Digital OutputCue2087=[~UNUSED3~] OutputSigType2087=Digital OutputCue2088=[~UNUSED3~] OutputSigType2088=Digital OutputCue2089=[~UNUSED3~] OutputSigType2089=Digital OutputCue2090=[~UNUSED3~] OutputSigType2090=Digital OutputCue2091=[~UNUSED3~] OutputSigType2091=Digital OutputCue2092=[~UNUSED3~] OutputSigType2092=Digital OutputCue2093=[~UNUSED3~] OutputSigType2093=Digital OutputCue2094=[~UNUSED3~] OutputSigType2094=Digital OutputCue2095=[~UNUSED3~] OutputSigType2095=Digital OutputCue2096=[~UNUSED3~] OutputSigType2096=Digital OutputCue2097=[~UNUSED3~] OutputSigType2097=Digital OutputCue2098=[~UNUSED3~] OutputSigType2098=Digital OutputCue2099=[~UNUSED3~] OutputSigType2099=Digital OutputCue2100=[~UNUSED3~] OutputSigType2100=Digital OutputCue2101=[~UNUSED3~] OutputSigType2101=Digital OutputCue2102=[~UNUSED3~] OutputSigType2102=Digital OutputCue2103=[~UNUSED3~] OutputSigType2103=Digital OutputCue2104=[~UNUSED3~] OutputSigType2104=Digital OutputCue2105=[~UNUSED3~] OutputSigType2105=Digital OutputCue2106=[~UNUSED3~] OutputSigType2106=Digital OutputCue2107=[~UNUSED3~] OutputSigType2107=Digital OutputCue2108=[~UNUSED3~] OutputSigType2108=Digital OutputCue2109=[~UNUSED3~] OutputSigType2109=Digital OutputCue2110=[~UNUSED3~] OutputSigType2110=Digital OutputCue2111=[~UNUSED3~] OutputSigType2111=Digital OutputCue2112=[~UNUSED3~] OutputSigType2112=Digital OutputCue2113=[~UNUSED3~] OutputSigType2113=Digital OutputCue2114=[~UNUSED2~] OutputSigType2114=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED3~] OutputSigType4026=Digital OutputCue4027=[~UNUSED3~] OutputSigType4027=Digital OutputCue4028=[~UNUSED3~] OutputSigType4028=Digital OutputCue4029=[~UNUSED3~] OutputSigType4029=Digital OutputCue4030=[~UNUSED3~] OutputSigType4030=Digital OutputCue4031=[~UNUSED3~] OutputSigType4031=Digital OutputCue4032=[~UNUSED3~] OutputSigType4032=Digital OutputCue4033=[~UNUSED3~] OutputSigType4033=Digital OutputCue4034=[~UNUSED3~] OutputSigType4034=Digital OutputCue4035=[~UNUSED3~] OutputSigType4035=Digital OutputCue4036=[~UNUSED3~] OutputSigType4036=Digital OutputCue4037=[~UNUSED3~] OutputSigType4037=Digital OutputCue4038=[~UNUSED3~] OutputSigType4038=Digital OutputCue4039=[~UNUSED3~] OutputSigType4039=Digital OutputCue4040=[~UNUSED3~] OutputSigType4040=Digital OutputCue4041=[~UNUSED3~] OutputSigType4041=Digital OutputCue4042=[~UNUSED3~] OutputSigType4042=Digital OutputCue4043=[~UNUSED3~] OutputSigType4043=Digital OutputCue4044=[~UNUSED3~] OutputSigType4044=Digital OutputCue4045=[~UNUSED3~] OutputSigType4045=Digital OutputCue4046=[~UNUSED3~] OutputSigType4046=Digital OutputCue4047=[~UNUSED3~] OutputSigType4047=Digital OutputCue4048=[~UNUSED3~] OutputSigType4048=Digital OutputCue4049=[~UNUSED3~] OutputSigType4049=Digital OutputCue4050=[~UNUSED3~] OutputSigType4050=Digital OutputCue4051=[~UNUSED3~] OutputSigType4051=Digital OutputCue4052=[~UNUSED3~] OutputSigType4052=Digital OutputCue4053=[~UNUSED3~] OutputSigType4053=Digital OutputCue4054=[~UNUSED3~] OutputSigType4054=Digital OutputCue4055=[~UNUSED3~] OutputSigType4055=Digital OutputCue4056=[~UNUSED3~] OutputSigType4056=Digital OutputCue4057=[~UNUSED3~] OutputSigType4057=Digital OutputCue4058=[~UNUSED3~] OutputSigType4058=Digital OutputCue4059=[~UNUSED3~] OutputSigType4059=Digital OutputCue4060=[~UNUSED3~] OutputSigType4060=Digital OutputCue4061=[~UNUSED3~] OutputSigType4061=Digital OutputCue4062=[~UNUSED3~] OutputSigType4062=Digital OutputCue4063=[~UNUSED3~] OutputSigType4063=Digital OutputCue4064=[~UNUSED3~] OutputSigType4064=Digital OutputCue4065=[~UNUSED3~] OutputSigType4065=Digital OutputCue4066=[~UNUSED3~] OutputSigType4066=Digital OutputCue4067=[~UNUSED3~] OutputSigType4067=Digital OutputCue4068=[~UNUSED3~] OutputSigType4068=Digital OutputCue4069=[~UNUSED3~] OutputSigType4069=Digital OutputCue4070=[~UNUSED3~] OutputSigType4070=Digital OutputCue4071=[~UNUSED3~] OutputSigType4071=Digital OutputCue4072=[~UNUSED3~] OutputSigType4072=Digital OutputCue4073=[~UNUSED3~] OutputSigType4073=Digital OutputCue4074=[~UNUSED3~] OutputSigType4074=Digital OutputCue4075=[~UNUSED3~] OutputSigType4075=Digital OutputCue4076=[~UNUSED3~] OutputSigType4076=Digital OutputCue4077=[~UNUSED3~] OutputSigType4077=Digital OutputCue4078=[~UNUSED3~] OutputSigType4078=Digital OutputCue4079=[~UNUSED3~] OutputSigType4079=Digital OutputCue4080=[~UNUSED3~] OutputSigType4080=Digital OutputCue4081=[~UNUSED3~] OutputSigType4081=Digital OutputCue4082=[~UNUSED3~] OutputSigType4082=Digital OutputCue4083=[~UNUSED3~] OutputSigType4083=Digital OutputCue4084=[~UNUSED3~] OutputSigType4084=Digital OutputCue4085=[~UNUSED3~] OutputSigType4085=Digital OutputCue4086=[~UNUSED3~] OutputSigType4086=Digital OutputCue4087=[~UNUSED3~] OutputSigType4087=Digital OutputCue4088=[~UNUSED3~] OutputSigType4088=Digital OutputCue4089=[~UNUSED3~] OutputSigType4089=Digital OutputCue4090=[~UNUSED3~] OutputSigType4090=Digital OutputCue4091=[~UNUSED3~] OutputSigType4091=Digital OutputCue4092=[~UNUSED3~] OutputSigType4092=Digital OutputCue4093=[~UNUSED3~] OutputSigType4093=Digital OutputCue4094=[~UNUSED3~] OutputSigType4094=Digital OutputCue4095=[~UNUSED3~] OutputSigType4095=Digital OutputCue4096=[~UNUSED3~] OutputSigType4096=Digital OutputCue4097=[~UNUSED3~] OutputSigType4097=Digital OutputCue4098=[~UNUSED3~] OutputSigType4098=Digital OutputCue4099=[~UNUSED3~] OutputSigType4099=Digital OutputCue4100=[~UNUSED3~] OutputSigType4100=Digital OutputCue4101=[~UNUSED3~] OutputSigType4101=Digital OutputCue4102=[~UNUSED3~] OutputSigType4102=Digital OutputCue4103=[~UNUSED3~] OutputSigType4103=Digital OutputCue4104=[~UNUSED3~] OutputSigType4104=Digital OutputCue4105=[~UNUSED3~] OutputSigType4105=Digital OutputCue4106=[~UNUSED3~] OutputSigType4106=Digital OutputCue4107=[~UNUSED3~] OutputSigType4107=Digital OutputCue4108=[~UNUSED3~] OutputSigType4108=Digital OutputCue4109=[~UNUSED3~] OutputSigType4109=Digital OutputCue4110=[~UNUSED3~] OutputSigType4110=Digital OutputCue4111=[~UNUSED3~] OutputSigType4111=Digital OutputCue4112=[~UNUSED3~] OutputSigType4112=Digital OutputCue4113=[~UNUSED3~] OutputSigType4113=Digital OutputCue4114=[~UNUSED3~] OutputSigType4114=Digital OutputCue4115=[~UNUSED3~] OutputSigType4115=Digital OutputCue4116=[~UNUSED2~] OutputSigType4116=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=Set Item 11 Icon Analog InputList2SigType22=Analog InputList2Cue23=Set Item 12 Icon Analog InputList2SigType23=Analog InputList2Cue24=Set Item 13 Icon Analog InputList2SigType24=Analog InputList2Cue25=Set Item 14 Icon Analog InputList2SigType25=Analog InputList2Cue26=Set Item 15 Icon Analog InputList2SigType26=Analog InputList2Cue27=Set Item 16 Icon Analog InputList2SigType27=Analog InputList2Cue28=Set Item 17 Icon Analog InputList2SigType28=Analog InputList2Cue29=Set Item 18 Icon Analog InputList2SigType29=Analog InputList2Cue30=Set Item 19 Icon Analog InputList2SigType30=Analog InputList2Cue31=Set Item 20 Icon Analog InputList2SigType31=Analog InputList2Cue32=Set Item 21 Icon Analog InputList2SigType32=Analog InputList2Cue33=Set Item 22 Icon Analog InputList2SigType33=Analog InputList2Cue34=Set Item 23 Icon Analog InputList2SigType34=Analog InputList2Cue35=Set Item 24 Icon Analog InputList2SigType35=Analog InputList2Cue36=Set Item 25 Icon Analog InputList2SigType36=Analog InputList2Cue37=Set Item 26 Icon Analog InputList2SigType37=Analog InputList2Cue38=Set Item 27 Icon Analog InputList2SigType38=Analog InputList2Cue39=Set Item 28 Icon Analog InputList2SigType39=Analog InputList2Cue40=Set Item 29 Icon Analog InputList2SigType40=Analog InputList2Cue41=Set Item 30 Icon Analog InputList2SigType41=Analog InputList2Cue42=Set Item 31 Icon Analog InputList2SigType42=Analog InputList2Cue43=Set Item 32 Icon Analog InputList2SigType43=Analog InputList2Cue44=Set Item 33 Icon Analog InputList2SigType44=Analog InputList2Cue45=Set Item 34 Icon Analog InputList2SigType45=Analog InputList2Cue46=Set Item 35 Icon Analog InputList2SigType46=Analog InputList2Cue47=Set Item 36 Icon Analog InputList2SigType47=Analog InputList2Cue48=Set Item 37 Icon Analog InputList2SigType48=Analog InputList2Cue49=Set Item 38 Icon Analog InputList2SigType49=Analog InputList2Cue50=Set Item 39 Icon Analog InputList2SigType50=Analog InputList2Cue51=Set Item 40 Icon Analog InputList2SigType51=Analog InputList2Cue52=Set Item 41 Icon Analog InputList2SigType52=Analog InputList2Cue53=Set Item 42 Icon Analog InputList2SigType53=Analog InputList2Cue54=Set Item 43 Icon Analog InputList2SigType54=Analog InputList2Cue55=Set Item 44 Icon Analog InputList2SigType55=Analog InputList2Cue56=Set Item 45 Icon Analog InputList2SigType56=Analog InputList2Cue57=Set Item 46 Icon Analog InputList2SigType57=Analog InputList2Cue58=Set Item 47 Icon Analog InputList2SigType58=Analog InputList2Cue59=Set Item 48 Icon Analog InputList2SigType59=Analog InputList2Cue60=Set Item 49 Icon Analog InputList2SigType60=Analog InputList2Cue61=Set Item 50 Icon Analog InputList2SigType61=Analog InputList2Cue62=Set Item 51 Icon Analog InputList2SigType62=Analog InputList2Cue63=Set Item 52 Icon Analog InputList2SigType63=Analog InputList2Cue64=Set Item 53 Icon Analog InputList2SigType64=Analog InputList2Cue65=Set Item 54 Icon Analog InputList2SigType65=Analog InputList2Cue66=Set Item 55 Icon Analog InputList2SigType66=Analog InputList2Cue67=Set Item 56 Icon Analog InputList2SigType67=Analog InputList2Cue68=Set Item 57 Icon Analog InputList2SigType68=Analog InputList2Cue69=Set Item 58 Icon Analog InputList2SigType69=Analog InputList2Cue70=Set Item 59 Icon Analog InputList2SigType70=Analog InputList2Cue71=Set Item 60 Icon Analog InputList2SigType71=Analog InputList2Cue72=Set Item 61 Icon Analog InputList2SigType72=Analog InputList2Cue73=Set Item 62 Icon Analog InputList2SigType73=Analog InputList2Cue74=Set Item 63 Icon Analog InputList2SigType74=Analog InputList2Cue75=Set Item 64 Icon Analog InputList2SigType75=Analog InputList2Cue76=Set Item 65 Icon Analog InputList2SigType76=Analog InputList2Cue77=Set Item 66 Icon Analog InputList2SigType77=Analog InputList2Cue78=Set Item 67 Icon Analog InputList2SigType78=Analog InputList2Cue79=Set Item 68 Icon Analog InputList2SigType79=Analog InputList2Cue80=Set Item 69 Icon Analog InputList2SigType80=Analog InputList2Cue81=Set Item 70 Icon Analog InputList2SigType81=Analog InputList2Cue82=Set Item 71 Icon Analog InputList2SigType82=Analog InputList2Cue83=Set Item 72 Icon Analog InputList2SigType83=Analog InputList2Cue84=Set Item 73 Icon Analog InputList2SigType84=Analog InputList2Cue85=Set Item 74 Icon Analog InputList2SigType85=Analog InputList2Cue86=Set Item 75 Icon Analog InputList2SigType86=Analog InputList2Cue87=Set Item 76 Icon Analog InputList2SigType87=Analog InputList2Cue88=Set Item 77 Icon Analog InputList2SigType88=Analog InputList2Cue89=Set Item 78 Icon Analog InputList2SigType89=Analog InputList2Cue90=Set Item 79 Icon Analog InputList2SigType90=Analog InputList2Cue91=Set Item 80 Icon Analog InputList2SigType91=Analog InputList2Cue92=Set Item 81 Icon Analog InputList2SigType92=Analog InputList2Cue93=Set Item 82 Icon Analog InputList2SigType93=Analog InputList2Cue94=Set Item 83 Icon Analog InputList2SigType94=Analog InputList2Cue95=Set Item 84 Icon Analog InputList2SigType95=Analog InputList2Cue96=Set Item 85 Icon Analog InputList2SigType96=Analog InputList2Cue97=Set Item 86 Icon Analog InputList2SigType97=Analog InputList2Cue98=Set Item 87 Icon Analog InputList2SigType98=Analog InputList2Cue99=Set Item 88 Icon Analog InputList2SigType99=Analog InputList2Cue100=Set Item 89 Icon Analog InputList2SigType100=Analog InputList2Cue101=Set Item 90 Icon Analog InputList2SigType101=Analog InputList2Cue102=Set Item 91 Icon Analog InputList2SigType102=Analog InputList2Cue103=Set Item 92 Icon Analog InputList2SigType103=Analog InputList2Cue104=Set Item 93 Icon Analog InputList2SigType104=Analog InputList2Cue105=Set Item 94 Icon Analog InputList2SigType105=Analog InputList2Cue106=Set Item 95 Icon Analog InputList2SigType106=Analog InputList2Cue107=Set Item 96 Icon Analog InputList2SigType107=Analog InputList2Cue108=Set Item 97 Icon Analog InputList2SigType108=Analog InputList2Cue109=Set Item 98 Icon Analog InputList2SigType109=Analog InputList2Cue110=Set Item 99 Icon Analog InputList2SigType110=Analog InputList2Cue111=Set Item 100 Icon Analog InputList2SigType111=Analog InputList2Cue112=[~UNUSED2~] InputList2SigType112=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED3~] OutputList2SigType22=Analog OutputList2Cue23=[~UNUSED3~] OutputList2SigType23=Analog OutputList2Cue24=[~UNUSED3~] OutputList2SigType24=Analog OutputList2Cue25=[~UNUSED3~] OutputList2SigType25=Analog OutputList2Cue26=[~UNUSED3~] OutputList2SigType26=Analog OutputList2Cue27=[~UNUSED3~] OutputList2SigType27=Analog OutputList2Cue28=[~UNUSED3~] OutputList2SigType28=Analog OutputList2Cue29=[~UNUSED3~] OutputList2SigType29=Analog OutputList2Cue30=[~UNUSED3~] OutputList2SigType30=Analog OutputList2Cue31=[~UNUSED3~] OutputList2SigType31=Analog OutputList2Cue32=[~UNUSED3~] OutputList2SigType32=Analog OutputList2Cue33=[~UNUSED3~] OutputList2SigType33=Analog OutputList2Cue34=[~UNUSED3~] OutputList2SigType34=Analog OutputList2Cue35=[~UNUSED3~] OutputList2SigType35=Analog OutputList2Cue36=[~UNUSED3~] OutputList2SigType36=Analog OutputList2Cue37=[~UNUSED3~] OutputList2SigType37=Analog OutputList2Cue38=[~UNUSED3~] OutputList2SigType38=Analog OutputList2Cue39=[~UNUSED3~] OutputList2SigType39=Analog OutputList2Cue40=[~UNUSED3~] OutputList2SigType40=Analog OutputList2Cue41=[~UNUSED3~] OutputList2SigType41=Analog OutputList2Cue42=[~UNUSED3~] OutputList2SigType42=Analog OutputList2Cue43=[~UNUSED3~] OutputList2SigType43=Analog OutputList2Cue44=[~UNUSED3~] OutputList2SigType44=Analog OutputList2Cue45=[~UNUSED3~] OutputList2SigType45=Analog OutputList2Cue46=[~UNUSED3~] OutputList2SigType46=Analog OutputList2Cue47=[~UNUSED3~] OutputList2SigType47=Analog OutputList2Cue48=[~UNUSED3~] OutputList2SigType48=Analog OutputList2Cue49=[~UNUSED3~] OutputList2SigType49=Analog OutputList2Cue50=[~UNUSED3~] OutputList2SigType50=Analog OutputList2Cue51=[~UNUSED3~] OutputList2SigType51=Analog OutputList2Cue52=[~UNUSED3~] OutputList2SigType52=Analog OutputList2Cue53=[~UNUSED3~] OutputList2SigType53=Analog OutputList2Cue54=[~UNUSED3~] OutputList2SigType54=Analog OutputList2Cue55=[~UNUSED3~] OutputList2SigType55=Analog OutputList2Cue56=[~UNUSED3~] OutputList2SigType56=Analog OutputList2Cue57=[~UNUSED3~] OutputList2SigType57=Analog OutputList2Cue58=[~UNUSED3~] OutputList2SigType58=Analog OutputList2Cue59=[~UNUSED3~] OutputList2SigType59=Analog OutputList2Cue60=[~UNUSED3~] OutputList2SigType60=Analog OutputList2Cue61=[~UNUSED3~] OutputList2SigType61=Analog OutputList2Cue62=[~UNUSED3~] OutputList2SigType62=Analog OutputList2Cue63=[~UNUSED3~] OutputList2SigType63=Analog OutputList2Cue64=[~UNUSED3~] OutputList2SigType64=Analog OutputList2Cue65=[~UNUSED3~] OutputList2SigType65=Analog OutputList2Cue66=[~UNUSED3~] OutputList2SigType66=Analog OutputList2Cue67=[~UNUSED3~] OutputList2SigType67=Analog OutputList2Cue68=[~UNUSED3~] OutputList2SigType68=Analog OutputList2Cue69=[~UNUSED3~] OutputList2SigType69=Analog OutputList2Cue70=[~UNUSED3~] OutputList2SigType70=Analog OutputList2Cue71=[~UNUSED3~] OutputList2SigType71=Analog OutputList2Cue72=[~UNUSED3~] OutputList2SigType72=Analog OutputList2Cue73=[~UNUSED3~] OutputList2SigType73=Analog OutputList2Cue74=[~UNUSED3~] OutputList2SigType74=Analog OutputList2Cue75=[~UNUSED3~] OutputList2SigType75=Analog OutputList2Cue76=[~UNUSED3~] OutputList2SigType76=Analog OutputList2Cue77=[~UNUSED3~] OutputList2SigType77=Analog OutputList2Cue78=[~UNUSED3~] OutputList2SigType78=Analog OutputList2Cue79=[~UNUSED3~] OutputList2SigType79=Analog OutputList2Cue80=[~UNUSED3~] OutputList2SigType80=Analog OutputList2Cue81=[~UNUSED3~] OutputList2SigType81=Analog OutputList2Cue82=[~UNUSED3~] OutputList2SigType82=Analog OutputList2Cue83=[~UNUSED3~] OutputList2SigType83=Analog OutputList2Cue84=[~UNUSED3~] OutputList2SigType84=Analog OutputList2Cue85=[~UNUSED3~] OutputList2SigType85=Analog OutputList2Cue86=[~UNUSED3~] OutputList2SigType86=Analog OutputList2Cue87=[~UNUSED3~] OutputList2SigType87=Analog OutputList2Cue88=[~UNUSED3~] OutputList2SigType88=Analog OutputList2Cue89=[~UNUSED3~] OutputList2SigType89=Analog OutputList2Cue90=[~UNUSED3~] OutputList2SigType90=Analog OutputList2Cue91=[~UNUSED3~] OutputList2SigType91=Analog OutputList2Cue92=[~UNUSED3~] OutputList2SigType92=Analog OutputList2Cue93=[~UNUSED3~] OutputList2SigType93=Analog OutputList2Cue94=[~UNUSED3~] OutputList2SigType94=Analog OutputList2Cue95=[~UNUSED3~] OutputList2SigType95=Analog OutputList2Cue96=[~UNUSED3~] OutputList2SigType96=Analog OutputList2Cue97=[~UNUSED3~] OutputList2SigType97=Analog OutputList2Cue98=[~UNUSED3~] OutputList2SigType98=Analog OutputList2Cue99=[~UNUSED3~] OutputList2SigType99=Analog OutputList2Cue100=[~UNUSED3~] OutputList2SigType100=Analog OutputList2Cue101=[~UNUSED3~] OutputList2SigType101=Analog OutputList2Cue102=[~UNUSED3~] OutputList2SigType102=Analog OutputList2Cue103=[~UNUSED3~] OutputList2SigType103=Analog OutputList2Cue104=[~UNUSED3~] OutputList2SigType104=Analog OutputList2Cue105=[~UNUSED3~] OutputList2SigType105=Analog OutputList2Cue106=[~UNUSED3~] OutputList2SigType106=Analog OutputList2Cue107=[~UNUSED3~] OutputList2SigType107=Analog OutputList2Cue108=[~UNUSED3~] OutputList2SigType108=Analog OutputList2Cue109=[~UNUSED3~] OutputList2SigType109=Analog OutputList2Cue110=[~UNUSED3~] OutputList2SigType110=Analog OutputList2Cue111=[~UNUSED3~] OutputList2SigType111=Analog OutputList2Cue112=[~UNUSED2~] OutputList2SigType112=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=Set Item 11 Text InputList3SigType22=Serial InputList3Cue23=Set Item 12 Text InputList3SigType23=Serial InputList3Cue24=Set Item 13 Text InputList3SigType24=Serial InputList3Cue25=Set Item 14 Text InputList3SigType25=Serial InputList3Cue26=Set Item 15 Text InputList3SigType26=Serial InputList3Cue27=Set Item 16 Text InputList3SigType27=Serial InputList3Cue28=Set Item 17 Text InputList3SigType28=Serial InputList3Cue29=Set Item 18 Text InputList3SigType29=Serial InputList3Cue30=Set Item 19 Text InputList3SigType30=Serial InputList3Cue31=Set Item 20 Text InputList3SigType31=Serial InputList3Cue32=Set Item 21 Text InputList3SigType32=Serial InputList3Cue33=Set Item 22 Text InputList3SigType33=Serial InputList3Cue34=Set Item 23 Text InputList3SigType34=Serial InputList3Cue35=Set Item 24 Text InputList3SigType35=Serial InputList3Cue36=Set Item 25 Text InputList3SigType36=Serial InputList3Cue37=Set Item 26 Text InputList3SigType37=Serial InputList3Cue38=Set Item 27 Text InputList3SigType38=Serial InputList3Cue39=Set Item 28 Text InputList3SigType39=Serial InputList3Cue40=Set Item 29 Text InputList3SigType40=Serial InputList3Cue41=Set Item 30 Text InputList3SigType41=Serial InputList3Cue42=Set Item 31 Text InputList3SigType42=Serial InputList3Cue43=Set Item 32 Text InputList3SigType43=Serial InputList3Cue44=Set Item 33 Text InputList3SigType44=Serial InputList3Cue45=Set Item 34 Text InputList3SigType45=Serial InputList3Cue46=Set Item 35 Text InputList3SigType46=Serial InputList3Cue47=Set Item 36 Text InputList3SigType47=Serial InputList3Cue48=Set Item 37 Text InputList3SigType48=Serial InputList3Cue49=Set Item 38 Text InputList3SigType49=Serial InputList3Cue50=Set Item 39 Text InputList3SigType50=Serial InputList3Cue51=Set Item 40 Text InputList3SigType51=Serial InputList3Cue52=Set Item 41 Text InputList3SigType52=Serial InputList3Cue53=Set Item 42 Text InputList3SigType53=Serial InputList3Cue54=Set Item 43 Text InputList3SigType54=Serial InputList3Cue55=Set Item 44 Text InputList3SigType55=Serial InputList3Cue56=Set Item 45 Text InputList3SigType56=Serial InputList3Cue57=Set Item 46 Text InputList3SigType57=Serial InputList3Cue58=Set Item 47 Text InputList3SigType58=Serial InputList3Cue59=Set Item 48 Text InputList3SigType59=Serial InputList3Cue60=Set Item 49 Text InputList3SigType60=Serial InputList3Cue61=Set Item 50 Text InputList3SigType61=Serial InputList3Cue62=Set Item 51 Text InputList3SigType62=Serial InputList3Cue63=Set Item 52 Text InputList3SigType63=Serial InputList3Cue64=Set Item 53 Text InputList3SigType64=Serial InputList3Cue65=Set Item 54 Text InputList3SigType65=Serial InputList3Cue66=Set Item 55 Text InputList3SigType66=Serial InputList3Cue67=Set Item 56 Text InputList3SigType67=Serial InputList3Cue68=Set Item 57 Text InputList3SigType68=Serial InputList3Cue69=Set Item 58 Text InputList3SigType69=Serial InputList3Cue70=Set Item 59 Text InputList3SigType70=Serial InputList3Cue71=Set Item 60 Text InputList3SigType71=Serial InputList3Cue72=Set Item 61 Text InputList3SigType72=Serial InputList3Cue73=Set Item 62 Text InputList3SigType73=Serial InputList3Cue74=Set Item 63 Text InputList3SigType74=Serial InputList3Cue75=Set Item 64 Text InputList3SigType75=Serial InputList3Cue76=Set Item 65 Text InputList3SigType76=Serial InputList3Cue77=Set Item 66 Text InputList3SigType77=Serial InputList3Cue78=Set Item 67 Text InputList3SigType78=Serial InputList3Cue79=Set Item 68 Text InputList3SigType79=Serial InputList3Cue80=Set Item 69 Text InputList3SigType80=Serial InputList3Cue81=Set Item 70 Text InputList3SigType81=Serial InputList3Cue82=Set Item 71 Text InputList3SigType82=Serial InputList3Cue83=Set Item 72 Text InputList3SigType83=Serial InputList3Cue84=Set Item 73 Text InputList3SigType84=Serial InputList3Cue85=Set Item 74 Text InputList3SigType85=Serial InputList3Cue86=Set Item 75 Text InputList3SigType86=Serial InputList3Cue87=Set Item 76 Text InputList3SigType87=Serial InputList3Cue88=Set Item 77 Text InputList3SigType88=Serial InputList3Cue89=Set Item 78 Text InputList3SigType89=Serial InputList3Cue90=Set Item 79 Text InputList3SigType90=Serial InputList3Cue91=Set Item 80 Text InputList3SigType91=Serial InputList3Cue92=Set Item 81 Text InputList3SigType92=Serial InputList3Cue93=Set Item 82 Text InputList3SigType93=Serial InputList3Cue94=Set Item 83 Text InputList3SigType94=Serial InputList3Cue95=Set Item 84 Text InputList3SigType95=Serial InputList3Cue96=Set Item 85 Text InputList3SigType96=Serial InputList3Cue97=Set Item 86 Text InputList3SigType97=Serial InputList3Cue98=Set Item 87 Text InputList3SigType98=Serial InputList3Cue99=Set Item 88 Text InputList3SigType99=Serial InputList3Cue100=Set Item 89 Text InputList3SigType100=Serial InputList3Cue101=Set Item 90 Text InputList3SigType101=Serial InputList3Cue102=Set Item 91 Text InputList3SigType102=Serial InputList3Cue103=Set Item 92 Text InputList3SigType103=Serial InputList3Cue104=Set Item 93 Text InputList3SigType104=Serial InputList3Cue105=Set Item 94 Text InputList3SigType105=Serial InputList3Cue106=Set Item 95 Text InputList3SigType106=Serial InputList3Cue107=Set Item 96 Text InputList3SigType107=Serial InputList3Cue108=Set Item 97 Text InputList3SigType108=Serial InputList3Cue109=Set Item 98 Text InputList3SigType109=Serial InputList3Cue110=Set Item 99 Text InputList3SigType110=Serial InputList3Cue111=Set Item 100 Text InputList3SigType111=Serial InputList3Cue112=[~UNUSED2~] InputList3SigType112=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=Set Item 11 Icon Serial InputList3SigType2024=Serial InputList3Cue2025=Set Item 12 Icon Serial InputList3SigType2025=Serial InputList3Cue2026=Set Item 13 Icon Serial InputList3SigType2026=Serial InputList3Cue2027=Set Item 14 Icon Serial InputList3SigType2027=Serial InputList3Cue2028=Set Item 15 Icon Serial InputList3SigType2028=Serial InputList3Cue2029=Set Item 16 Icon Serial InputList3SigType2029=Serial InputList3Cue2030=Set Item 17 Icon Serial InputList3SigType2030=Serial InputList3Cue2031=Set Item 18 Icon Serial InputList3SigType2031=Serial InputList3Cue2032=Set Item 19 Icon Serial InputList3SigType2032=Serial InputList3Cue2033=Set Item 20 Icon Serial InputList3SigType2033=Serial InputList3Cue2034=Set Item 21 Icon Serial InputList3SigType2034=Serial InputList3Cue2035=Set Item 22 Icon Serial InputList3SigType2035=Serial InputList3Cue2036=Set Item 23 Icon Serial InputList3SigType2036=Serial InputList3Cue2037=Set Item 24 Icon Serial InputList3SigType2037=Serial InputList3Cue2038=Set Item 25 Icon Serial InputList3SigType2038=Serial InputList3Cue2039=Set Item 26 Icon Serial InputList3SigType2039=Serial InputList3Cue2040=Set Item 27 Icon Serial InputList3SigType2040=Serial InputList3Cue2041=Set Item 28 Icon Serial InputList3SigType2041=Serial InputList3Cue2042=Set Item 29 Icon Serial InputList3SigType2042=Serial InputList3Cue2043=Set Item 30 Icon Serial InputList3SigType2043=Serial InputList3Cue2044=Set Item 31 Icon Serial InputList3SigType2044=Serial InputList3Cue2045=Set Item 32 Icon Serial InputList3SigType2045=Serial InputList3Cue2046=Set Item 33 Icon Serial InputList3SigType2046=Serial InputList3Cue2047=Set Item 34 Icon Serial InputList3SigType2047=Serial InputList3Cue2048=Set Item 35 Icon Serial InputList3SigType2048=Serial InputList3Cue2049=Set Item 36 Icon Serial InputList3SigType2049=Serial InputList3Cue2050=Set Item 37 Icon Serial InputList3SigType2050=Serial InputList3Cue2051=Set Item 38 Icon Serial InputList3SigType2051=Serial InputList3Cue2052=Set Item 39 Icon Serial InputList3SigType2052=Serial InputList3Cue2053=Set Item 40 Icon Serial InputList3SigType2053=Serial InputList3Cue2054=Set Item 41 Icon Serial InputList3SigType2054=Serial InputList3Cue2055=Set Item 42 Icon Serial InputList3SigType2055=Serial InputList3Cue2056=Set Item 43 Icon Serial InputList3SigType2056=Serial InputList3Cue2057=Set Item 44 Icon Serial InputList3SigType2057=Serial InputList3Cue2058=Set Item 45 Icon Serial InputList3SigType2058=Serial InputList3Cue2059=Set Item 46 Icon Serial InputList3SigType2059=Serial InputList3Cue2060=Set Item 47 Icon Serial InputList3SigType2060=Serial InputList3Cue2061=Set Item 48 Icon Serial InputList3SigType2061=Serial InputList3Cue2062=Set Item 49 Icon Serial InputList3SigType2062=Serial InputList3Cue2063=Set Item 50 Icon Serial InputList3SigType2063=Serial InputList3Cue2064=Set Item 51 Icon Serial InputList3SigType2064=Serial InputList3Cue2065=Set Item 52 Icon Serial InputList3SigType2065=Serial InputList3Cue2066=Set Item 53 Icon Serial InputList3SigType2066=Serial InputList3Cue2067=Set Item 54 Icon Serial InputList3SigType2067=Serial InputList3Cue2068=Set Item 55 Icon Serial InputList3SigType2068=Serial InputList3Cue2069=Set Item 56 Icon Serial InputList3SigType2069=Serial InputList3Cue2070=Set Item 57 Icon Serial InputList3SigType2070=Serial InputList3Cue2071=Set Item 58 Icon Serial InputList3SigType2071=Serial InputList3Cue2072=Set Item 59 Icon Serial InputList3SigType2072=Serial InputList3Cue2073=Set Item 60 Icon Serial InputList3SigType2073=Serial InputList3Cue2074=Set Item 61 Icon Serial InputList3SigType2074=Serial InputList3Cue2075=Set Item 62 Icon Serial InputList3SigType2075=Serial InputList3Cue2076=Set Item 63 Icon Serial InputList3SigType2076=Serial InputList3Cue2077=Set Item 64 Icon Serial InputList3SigType2077=Serial InputList3Cue2078=Set Item 65 Icon Serial InputList3SigType2078=Serial InputList3Cue2079=Set Item 66 Icon Serial InputList3SigType2079=Serial InputList3Cue2080=Set Item 67 Icon Serial InputList3SigType2080=Serial InputList3Cue2081=Set Item 68 Icon Serial InputList3SigType2081=Serial InputList3Cue2082=Set Item 69 Icon Serial InputList3SigType2082=Serial InputList3Cue2083=Set Item 70 Icon Serial InputList3SigType2083=Serial InputList3Cue2084=Set Item 71 Icon Serial InputList3SigType2084=Serial InputList3Cue2085=Set Item 72 Icon Serial InputList3SigType2085=Serial InputList3Cue2086=Set Item 73 Icon Serial InputList3SigType2086=Serial InputList3Cue2087=Set Item 74 Icon Serial InputList3SigType2087=Serial InputList3Cue2088=Set Item 75 Icon Serial InputList3SigType2088=Serial InputList3Cue2089=Set Item 76 Icon Serial InputList3SigType2089=Serial InputList3Cue2090=Set Item 77 Icon Serial InputList3SigType2090=Serial InputList3Cue2091=Set Item 78 Icon Serial InputList3SigType2091=Serial InputList3Cue2092=Set Item 79 Icon Serial InputList3SigType2092=Serial InputList3Cue2093=Set Item 80 Icon Serial InputList3SigType2093=Serial InputList3Cue2094=Set Item 81 Icon Serial InputList3SigType2094=Serial InputList3Cue2095=Set Item 82 Icon Serial InputList3SigType2095=Serial InputList3Cue2096=Set Item 83 Icon Serial InputList3SigType2096=Serial InputList3Cue2097=Set Item 84 Icon Serial InputList3SigType2097=Serial InputList3Cue2098=Set Item 85 Icon Serial InputList3SigType2098=Serial InputList3Cue2099=Set Item 86 Icon Serial InputList3SigType2099=Serial InputList3Cue2100=Set Item 87 Icon Serial InputList3SigType2100=Serial InputList3Cue2101=Set Item 88 Icon Serial InputList3SigType2101=Serial InputList3Cue2102=Set Item 89 Icon Serial InputList3SigType2102=Serial InputList3Cue2103=Set Item 90 Icon Serial InputList3SigType2103=Serial InputList3Cue2104=Set Item 91 Icon Serial InputList3SigType2104=Serial InputList3Cue2105=Set Item 92 Icon Serial InputList3SigType2105=Serial InputList3Cue2106=Set Item 93 Icon Serial InputList3SigType2106=Serial InputList3Cue2107=Set Item 94 Icon Serial InputList3SigType2107=Serial InputList3Cue2108=Set Item 95 Icon Serial InputList3SigType2108=Serial InputList3Cue2109=Set Item 96 Icon Serial InputList3SigType2109=Serial InputList3Cue2110=Set Item 97 Icon Serial InputList3SigType2110=Serial InputList3Cue2111=Set Item 98 Icon Serial InputList3SigType2111=Serial InputList3Cue2112=Set Item 99 Icon Serial InputList3SigType2112=Serial InputList3Cue2113=Set Item 100 Icon Serial InputList3SigType2113=Serial InputList3Cue2114=[~UNUSED2~] InputList3SigType2114=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED3~] OutputList3SigType22=Serial OutputList3Cue23=[~UNUSED3~] OutputList3SigType23=Serial OutputList3Cue24=[~UNUSED3~] OutputList3SigType24=Serial OutputList3Cue25=[~UNUSED3~] OutputList3SigType25=Serial OutputList3Cue26=[~UNUSED3~] OutputList3SigType26=Serial OutputList3Cue27=[~UNUSED3~] OutputList3SigType27=Serial OutputList3Cue28=[~UNUSED3~] OutputList3SigType28=Serial OutputList3Cue29=[~UNUSED3~] OutputList3SigType29=Serial OutputList3Cue30=[~UNUSED3~] OutputList3SigType30=Serial OutputList3Cue31=[~UNUSED3~] OutputList3SigType31=Serial OutputList3Cue32=[~UNUSED3~] OutputList3SigType32=Serial OutputList3Cue33=[~UNUSED3~] OutputList3SigType33=Serial OutputList3Cue34=[~UNUSED3~] OutputList3SigType34=Serial OutputList3Cue35=[~UNUSED3~] OutputList3SigType35=Serial OutputList3Cue36=[~UNUSED3~] OutputList3SigType36=Serial OutputList3Cue37=[~UNUSED3~] OutputList3SigType37=Serial OutputList3Cue38=[~UNUSED3~] OutputList3SigType38=Serial OutputList3Cue39=[~UNUSED3~] OutputList3SigType39=Serial OutputList3Cue40=[~UNUSED3~] OutputList3SigType40=Serial OutputList3Cue41=[~UNUSED3~] OutputList3SigType41=Serial OutputList3Cue42=[~UNUSED3~] OutputList3SigType42=Serial OutputList3Cue43=[~UNUSED3~] OutputList3SigType43=Serial OutputList3Cue44=[~UNUSED3~] OutputList3SigType44=Serial OutputList3Cue45=[~UNUSED3~] OutputList3SigType45=Serial OutputList3Cue46=[~UNUSED3~] OutputList3SigType46=Serial OutputList3Cue47=[~UNUSED3~] OutputList3SigType47=Serial OutputList3Cue48=[~UNUSED3~] OutputList3SigType48=Serial OutputList3Cue49=[~UNUSED3~] OutputList3SigType49=Serial OutputList3Cue50=[~UNUSED3~] OutputList3SigType50=Serial OutputList3Cue51=[~UNUSED3~] OutputList3SigType51=Serial OutputList3Cue52=[~UNUSED3~] OutputList3SigType52=Serial OutputList3Cue53=[~UNUSED3~] OutputList3SigType53=Serial OutputList3Cue54=[~UNUSED3~] OutputList3SigType54=Serial OutputList3Cue55=[~UNUSED3~] OutputList3SigType55=Serial OutputList3Cue56=[~UNUSED3~] OutputList3SigType56=Serial OutputList3Cue57=[~UNUSED3~] OutputList3SigType57=Serial OutputList3Cue58=[~UNUSED3~] OutputList3SigType58=Serial OutputList3Cue59=[~UNUSED3~] OutputList3SigType59=Serial OutputList3Cue60=[~UNUSED3~] OutputList3SigType60=Serial OutputList3Cue61=[~UNUSED3~] OutputList3SigType61=Serial OutputList3Cue62=[~UNUSED3~] OutputList3SigType62=Serial OutputList3Cue63=[~UNUSED3~] OutputList3SigType63=Serial OutputList3Cue64=[~UNUSED3~] OutputList3SigType64=Serial OutputList3Cue65=[~UNUSED3~] OutputList3SigType65=Serial OutputList3Cue66=[~UNUSED3~] OutputList3SigType66=Serial OutputList3Cue67=[~UNUSED3~] OutputList3SigType67=Serial OutputList3Cue68=[~UNUSED3~] OutputList3SigType68=Serial OutputList3Cue69=[~UNUSED3~] OutputList3SigType69=Serial OutputList3Cue70=[~UNUSED3~] OutputList3SigType70=Serial OutputList3Cue71=[~UNUSED3~] OutputList3SigType71=Serial OutputList3Cue72=[~UNUSED3~] OutputList3SigType72=Serial OutputList3Cue73=[~UNUSED3~] OutputList3SigType73=Serial OutputList3Cue74=[~UNUSED3~] OutputList3SigType74=Serial OutputList3Cue75=[~UNUSED3~] OutputList3SigType75=Serial OutputList3Cue76=[~UNUSED3~] OutputList3SigType76=Serial OutputList3Cue77=[~UNUSED3~] OutputList3SigType77=Serial OutputList3Cue78=[~UNUSED3~] OutputList3SigType78=Serial OutputList3Cue79=[~UNUSED3~] OutputList3SigType79=Serial OutputList3Cue80=[~UNUSED3~] OutputList3SigType80=Serial OutputList3Cue81=[~UNUSED3~] OutputList3SigType81=Serial OutputList3Cue82=[~UNUSED3~] OutputList3SigType82=Serial OutputList3Cue83=[~UNUSED3~] OutputList3SigType83=Serial OutputList3Cue84=[~UNUSED3~] OutputList3SigType84=Serial OutputList3Cue85=[~UNUSED3~] OutputList3SigType85=Serial OutputList3Cue86=[~UNUSED3~] OutputList3SigType86=Serial OutputList3Cue87=[~UNUSED3~] OutputList3SigType87=Serial OutputList3Cue88=[~UNUSED3~] OutputList3SigType88=Serial OutputList3Cue89=[~UNUSED3~] OutputList3SigType89=Serial OutputList3Cue90=[~UNUSED3~] OutputList3SigType90=Serial OutputList3Cue91=[~UNUSED3~] OutputList3SigType91=Serial OutputList3Cue92=[~UNUSED3~] OutputList3SigType92=Serial OutputList3Cue93=[~UNUSED3~] OutputList3SigType93=Serial OutputList3Cue94=[~UNUSED3~] OutputList3SigType94=Serial OutputList3Cue95=[~UNUSED3~] OutputList3SigType95=Serial OutputList3Cue96=[~UNUSED3~] OutputList3SigType96=Serial OutputList3Cue97=[~UNUSED3~] OutputList3SigType97=Serial OutputList3Cue98=[~UNUSED3~] OutputList3SigType98=Serial OutputList3Cue99=[~UNUSED3~] OutputList3SigType99=Serial OutputList3Cue100=[~UNUSED3~] OutputList3SigType100=Serial OutputList3Cue101=[~UNUSED3~] OutputList3SigType101=Serial OutputList3Cue102=[~UNUSED3~] OutputList3SigType102=Serial OutputList3Cue103=[~UNUSED3~] OutputList3SigType103=Serial OutputList3Cue104=[~UNUSED3~] OutputList3SigType104=Serial OutputList3Cue105=[~UNUSED3~] OutputList3SigType105=Serial OutputList3Cue106=[~UNUSED3~] OutputList3SigType106=Serial OutputList3Cue107=[~UNUSED3~] OutputList3SigType107=Serial OutputList3Cue108=[~UNUSED3~] OutputList3SigType108=Serial OutputList3Cue109=[~UNUSED3~] OutputList3SigType109=Serial OutputList3Cue110=[~UNUSED3~] OutputList3SigType110=Serial OutputList3Cue111=[~UNUSED3~] OutputList3SigType111=Serial OutputList3Cue112=[~UNUSED2~] OutputList3SigType112=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED3~] OutputList3SigType2024=Serial OutputList3Cue2025=[~UNUSED3~] OutputList3SigType2025=Serial OutputList3Cue2026=[~UNUSED3~] OutputList3SigType2026=Serial OutputList3Cue2027=[~UNUSED3~] OutputList3SigType2027=Serial OutputList3Cue2028=[~UNUSED3~] OutputList3SigType2028=Serial OutputList3Cue2029=[~UNUSED3~] OutputList3SigType2029=Serial OutputList3Cue2030=[~UNUSED3~] OutputList3SigType2030=Serial OutputList3Cue2031=[~UNUSED3~] OutputList3SigType2031=Serial OutputList3Cue2032=[~UNUSED3~] OutputList3SigType2032=Serial OutputList3Cue2033=[~UNUSED3~] OutputList3SigType2033=Serial OutputList3Cue2034=[~UNUSED3~] OutputList3SigType2034=Serial OutputList3Cue2035=[~UNUSED3~] OutputList3SigType2035=Serial OutputList3Cue2036=[~UNUSED3~] OutputList3SigType2036=Serial OutputList3Cue2037=[~UNUSED3~] OutputList3SigType2037=Serial OutputList3Cue2038=[~UNUSED3~] OutputList3SigType2038=Serial OutputList3Cue2039=[~UNUSED3~] OutputList3SigType2039=Serial OutputList3Cue2040=[~UNUSED3~] OutputList3SigType2040=Serial OutputList3Cue2041=[~UNUSED3~] OutputList3SigType2041=Serial OutputList3Cue2042=[~UNUSED3~] OutputList3SigType2042=Serial OutputList3Cue2043=[~UNUSED3~] OutputList3SigType2043=Serial OutputList3Cue2044=[~UNUSED3~] OutputList3SigType2044=Serial OutputList3Cue2045=[~UNUSED3~] OutputList3SigType2045=Serial OutputList3Cue2046=[~UNUSED3~] OutputList3SigType2046=Serial OutputList3Cue2047=[~UNUSED3~] OutputList3SigType2047=Serial OutputList3Cue2048=[~UNUSED3~] OutputList3SigType2048=Serial OutputList3Cue2049=[~UNUSED3~] OutputList3SigType2049=Serial OutputList3Cue2050=[~UNUSED3~] OutputList3SigType2050=Serial OutputList3Cue2051=[~UNUSED3~] OutputList3SigType2051=Serial OutputList3Cue2052=[~UNUSED3~] OutputList3SigType2052=Serial OutputList3Cue2053=[~UNUSED3~] OutputList3SigType2053=Serial OutputList3Cue2054=[~UNUSED3~] OutputList3SigType2054=Serial OutputList3Cue2055=[~UNUSED3~] OutputList3SigType2055=Serial OutputList3Cue2056=[~UNUSED3~] OutputList3SigType2056=Serial OutputList3Cue2057=[~UNUSED3~] OutputList3SigType2057=Serial OutputList3Cue2058=[~UNUSED3~] OutputList3SigType2058=Serial OutputList3Cue2059=[~UNUSED3~] OutputList3SigType2059=Serial OutputList3Cue2060=[~UNUSED3~] OutputList3SigType2060=Serial OutputList3Cue2061=[~UNUSED3~] OutputList3SigType2061=Serial OutputList3Cue2062=[~UNUSED3~] OutputList3SigType2062=Serial OutputList3Cue2063=[~UNUSED3~] OutputList3SigType2063=Serial OutputList3Cue2064=[~UNUSED3~] OutputList3SigType2064=Serial OutputList3Cue2065=[~UNUSED3~] OutputList3SigType2065=Serial OutputList3Cue2066=[~UNUSED3~] OutputList3SigType2066=Serial OutputList3Cue2067=[~UNUSED3~] OutputList3SigType2067=Serial OutputList3Cue2068=[~UNUSED3~] OutputList3SigType2068=Serial OutputList3Cue2069=[~UNUSED3~] OutputList3SigType2069=Serial OutputList3Cue2070=[~UNUSED3~] OutputList3SigType2070=Serial OutputList3Cue2071=[~UNUSED3~] OutputList3SigType2071=Serial OutputList3Cue2072=[~UNUSED3~] OutputList3SigType2072=Serial OutputList3Cue2073=[~UNUSED3~] OutputList3SigType2073=Serial OutputList3Cue2074=[~UNUSED3~] OutputList3SigType2074=Serial OutputList3Cue2075=[~UNUSED3~] OutputList3SigType2075=Serial OutputList3Cue2076=[~UNUSED3~] OutputList3SigType2076=Serial OutputList3Cue2077=[~UNUSED3~] OutputList3SigType2077=Serial OutputList3Cue2078=[~UNUSED3~] OutputList3SigType2078=Serial OutputList3Cue2079=[~UNUSED3~] OutputList3SigType2079=Serial OutputList3Cue2080=[~UNUSED3~] OutputList3SigType2080=Serial OutputList3Cue2081=[~UNUSED3~] OutputList3SigType2081=Serial OutputList3Cue2082=[~UNUSED3~] OutputList3SigType2082=Serial OutputList3Cue2083=[~UNUSED3~] OutputList3SigType2083=Serial OutputList3Cue2084=[~UNUSED3~] OutputList3SigType2084=Serial OutputList3Cue2085=[~UNUSED3~] OutputList3SigType2085=Serial OutputList3Cue2086=[~UNUSED3~] OutputList3SigType2086=Serial OutputList3Cue2087=[~UNUSED3~] OutputList3SigType2087=Serial OutputList3Cue2088=[~UNUSED3~] OutputList3SigType2088=Serial OutputList3Cue2089=[~UNUSED3~] OutputList3SigType2089=Serial OutputList3Cue2090=[~UNUSED3~] OutputList3SigType2090=Serial OutputList3Cue2091=[~UNUSED3~] OutputList3SigType2091=Serial OutputList3Cue2092=[~UNUSED3~] OutputList3SigType2092=Serial OutputList3Cue2093=[~UNUSED3~] OutputList3SigType2093=Serial OutputList3Cue2094=[~UNUSED3~] OutputList3SigType2094=Serial OutputList3Cue2095=[~UNUSED3~] OutputList3SigType2095=Serial OutputList3Cue2096=[~UNUSED3~] OutputList3SigType2096=Serial OutputList3Cue2097=[~UNUSED3~] OutputList3SigType2097=Serial OutputList3Cue2098=[~UNUSED3~] OutputList3SigType2098=Serial OutputList3Cue2099=[~UNUSED3~] OutputList3SigType2099=Serial OutputList3Cue2100=[~UNUSED3~] OutputList3SigType2100=Serial OutputList3Cue2101=[~UNUSED3~] OutputList3SigType2101=Serial OutputList3Cue2102=[~UNUSED3~] OutputList3SigType2102=Serial OutputList3Cue2103=[~UNUSED3~] OutputList3SigType2103=Serial OutputList3Cue2104=[~UNUSED3~] OutputList3SigType2104=Serial OutputList3Cue2105=[~UNUSED3~] OutputList3SigType2105=Serial OutputList3Cue2106=[~UNUSED3~] OutputList3SigType2106=Serial OutputList3Cue2107=[~UNUSED3~] OutputList3SigType2107=Serial OutputList3Cue2108=[~UNUSED3~] OutputList3SigType2108=Serial OutputList3Cue2109=[~UNUSED3~] OutputList3SigType2109=Serial OutputList3Cue2110=[~UNUSED3~] OutputList3SigType2110=Serial OutputList3Cue2111=[~UNUSED3~] OutputList3SigType2111=Serial OutputList3Cue2112=[~UNUSED3~] OutputList3SigType2112=Serial OutputList3Cue2113=[~UNUSED3~] OutputList3SigType2113=Serial OutputList3Cue2114=[~UNUSED2~] OutputList3SigType2114=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=2 CedH=2 SmartObjId=1202d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=2 Tp=1 HD=TRUE DV=1202d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=2 Name=PepperDash Essentials TSW-760_[D.VC] Directory_Dynamic Button List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[D.VC] Keypad with favorites_VC DTMF Keypad.ced Hint=VC DTMF Keypad (Smart Object ID=1201) Code=3 SGControlType=Simple Keypad SGControlName=VC DTMF Keypad GUID=B4D53525-26EF-4326-8234-1D53F6E9BF04 SmplCName=PepperDash Essentials TSW-760_[D.VC] Keypad with favorites_VC DTMF Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=* OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=/# OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=3 CedH=3 SmartObjId=1201d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=3 Tp=1 HD=TRUE DV=1201d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=3 Name=PepperDash Essentials TSW-760_[D.VC] Keypad with favorites_VC DTMF Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[Z.Dialogs] PIN_PIN Keypad.ced Hint=PIN Keypad (Smart Object ID=3903) Code=4 SGControlType=Simple Keypad SGControlName=PIN Keypad GUID=D85E5DFB-DE45-45FE-93C5-2FA177B68BFB SmplCName=PepperDash Essentials TSW-760_[Z.Dialogs] PIN_PIN Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=Misc_1 OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=Misc_2 OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=4 CedH=4 SmartObjId=3903d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=4 Tp=1 HD=TRUE DV=3903d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=4 Name=PepperDash Essentials TSW-760_[Z.Dialogs] PIN_PIN Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced Hint=Subpage Reference List Vertical_3 (Smart Object ID=3902) Code=5 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_3 GUID=3490D547-0B98-444B-A284-D6C1BAB2FDCE SmplCName=PepperDash Essentials TSW-760_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4076 MaxVariableInputs=4076 MinVariableOutputs=4076 MaxVariableOutputs=4076 NumFixedParams=1 MinVariableInputsList2=72 MaxVariableInputsList2=72 MinVariableOutputsList2=72 MaxVariableOutputsList2=72 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=[~UNUSED2~] InputSigType32=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=[~UNUSED2~] InputSigType2034=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=[~EndGroup~]fb InputSigType4076=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED2~] OutputSigType32=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED2~] OutputSigType2034=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=[~EndGroup~]Press OutputSigType4076=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=an_fb37 InputList2SigType48=Analog InputList2Cue49=an_fb38 InputList2SigType49=Analog InputList2Cue50=an_fb39 InputList2SigType50=Analog InputList2Cue51=an_fb40 InputList2SigType51=Analog InputList2Cue52=an_fb41 InputList2SigType52=Analog InputList2Cue53=an_fb42 InputList2SigType53=Analog InputList2Cue54=an_fb43 InputList2SigType54=Analog InputList2Cue55=an_fb44 InputList2SigType55=Analog InputList2Cue56=an_fb45 InputList2SigType56=Analog InputList2Cue57=an_fb46 InputList2SigType57=Analog InputList2Cue58=an_fb47 InputList2SigType58=Analog InputList2Cue59=an_fb48 InputList2SigType59=Analog InputList2Cue60=an_fb49 InputList2SigType60=Analog InputList2Cue61=an_fb50 InputList2SigType61=Analog InputList2Cue62=an_fb51 InputList2SigType62=Analog InputList2Cue63=an_fb52 InputList2SigType63=Analog InputList2Cue64=an_fb53 InputList2SigType64=Analog InputList2Cue65=an_fb54 InputList2SigType65=Analog InputList2Cue66=an_fb55 InputList2SigType66=Analog InputList2Cue67=an_fb56 InputList2SigType67=Analog InputList2Cue68=an_fb57 InputList2SigType68=Analog InputList2Cue69=an_fb58 InputList2SigType69=Analog InputList2Cue70=an_fb59 InputList2SigType70=Analog InputList2Cue71=an_fb60 InputList2SigType71=Analog InputList2Cue72=[~EndGroup~]an_fb InputList2SigType72=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=an_act37 OutputList2SigType48=Analog OutputList2Cue49=an_act38 OutputList2SigType49=Analog OutputList2Cue50=an_act39 OutputList2SigType50=Analog OutputList2Cue51=an_act40 OutputList2SigType51=Analog OutputList2Cue52=an_act41 OutputList2SigType52=Analog OutputList2Cue53=an_act42 OutputList2SigType53=Analog OutputList2Cue54=an_act43 OutputList2SigType54=Analog OutputList2Cue55=an_act44 OutputList2SigType55=Analog OutputList2Cue56=an_act45 OutputList2SigType56=Analog OutputList2Cue57=an_act46 OutputList2SigType57=Analog OutputList2Cue58=an_act47 OutputList2SigType58=Analog OutputList2Cue59=an_act48 OutputList2SigType59=Analog OutputList2Cue60=an_act49 OutputList2SigType60=Analog OutputList2Cue61=an_act50 OutputList2SigType61=Analog OutputList2Cue62=an_act51 OutputList2SigType62=Analog OutputList2Cue63=an_act52 OutputList2SigType63=Analog OutputList2Cue64=an_act53 OutputList2SigType64=Analog OutputList2Cue65=an_act54 OutputList2SigType65=Analog OutputList2Cue66=an_act55 OutputList2SigType66=Analog OutputList2Cue67=an_act56 OutputList2SigType67=Analog OutputList2Cue68=an_act57 OutputList2SigType68=Analog OutputList2Cue69=an_act58 OutputList2SigType69=Analog OutputList2Cue70=an_act59 OutputList2SigType70=Analog OutputList2Cue71=an_act60 OutputList2SigType71=Analog OutputList2Cue72=[~EndGroup~]an_act OutputList2SigType72=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=5 CedH=5 SmartObjId=3902d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=5 Tp=1 HD=TRUE DV=3902d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=5 Name=PepperDash Essentials TSW-760_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced Hint=Subpage Reference List Vertical_4 (Smart Object ID=3904) Code=6 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_4 GUID=AC10DF35-3FD4-4F62-9708-0A06AE7A5A14 SmplCName=PepperDash Essentials TSW-760_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4116 MaxVariableInputs=4116 MinVariableOutputs=4116 MaxVariableOutputs=4116 NumFixedParams=1 MinVariableInputsList2=42 MaxVariableInputsList2=42 MinVariableOutputsList2=42 MaxVariableOutputsList2=42 MinVariableInputsList3=42 MaxVariableInputsList3=42 MinVariableOutputsList3=42 MaxVariableOutputsList3=42 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=[~UNUSED2~] InputSigType22=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=[~UNUSED2~] InputSigType2024=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=fb91 InputSigType4106=Digital InputCue4107=fb92 InputSigType4107=Digital InputCue4108=fb93 InputSigType4108=Digital InputCue4109=fb94 InputSigType4109=Digital InputCue4110=fb95 InputSigType4110=Digital InputCue4111=fb96 InputSigType4111=Digital InputCue4112=fb97 InputSigType4112=Digital InputCue4113=fb98 InputSigType4113=Digital InputCue4114=fb99 InputSigType4114=Digital InputCue4115=fb100 InputSigType4115=Digital InputCue4116=[~EndGroup~]fb InputSigType4116=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED2~] OutputSigType22=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED2~] OutputSigType2024=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=press91 OutputSigType4106=Digital OutputCue4107=press92 OutputSigType4107=Digital OutputCue4108=press93 OutputSigType4108=Digital OutputCue4109=press94 OutputSigType4109=Digital OutputCue4110=press95 OutputSigType4110=Digital OutputCue4111=press96 OutputSigType4111=Digital OutputCue4112=press97 OutputSigType4112=Digital OutputCue4113=press98 OutputSigType4113=Digital OutputCue4114=press99 OutputSigType4114=Digital OutputCue4115=press100 OutputSigType4115=Digital OutputCue4116=[~EndGroup~]Press OutputSigType4116=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=[~EndGroup~]an_fb InputList2SigType42=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=[~EndGroup~]an_act OutputList2SigType42=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=[~EndGroup~]text-o InputList3SigType42=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=[~EndGroup~]text-i OutputList3SigType42=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=6 CedH=6 SmartObjId=3904d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=6 Tp=1 HD=TRUE DV=3904d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=6 Name=PepperDash Essentials TSW-760_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[B.AV] Staging_Subpage Reference List Horizontal_3.ced Hint=Subpage Reference List Horizontal_3 (Smart Object ID=3200) Code=7 SGControlType=Subpage Reference List Horizontal SGControlName=Subpage Reference List Horizontal_3 GUID=D638D437-6722-43E1-B435-EF13DCE5ECF0 SmplCName=PepperDash Essentials TSW-760_[B.AV] Staging_Subpage Reference List Horizontal_3.ced SMWRev=4.02.20 Expand=expand_random HelpID=10124 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4076 MaxVariableInputs=4076 MinVariableOutputs=4076 MaxVariableOutputs=4076 NumFixedParams=1 MinVariableInputsList2=72 MaxVariableInputsList2=72 MinVariableOutputsList2=72 MaxVariableOutputsList2=72 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=[~UNUSED2~] InputSigType32=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=[~UNUSED2~] InputSigType2034=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=[~EndGroup~]fb InputSigType4076=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED2~] OutputSigType32=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED2~] OutputSigType2034=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=[~EndGroup~]Press OutputSigType4076=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=an_fb37 InputList2SigType48=Analog InputList2Cue49=an_fb38 InputList2SigType49=Analog InputList2Cue50=an_fb39 InputList2SigType50=Analog InputList2Cue51=an_fb40 InputList2SigType51=Analog InputList2Cue52=an_fb41 InputList2SigType52=Analog InputList2Cue53=an_fb42 InputList2SigType53=Analog InputList2Cue54=an_fb43 InputList2SigType54=Analog InputList2Cue55=an_fb44 InputList2SigType55=Analog InputList2Cue56=an_fb45 InputList2SigType56=Analog InputList2Cue57=an_fb46 InputList2SigType57=Analog InputList2Cue58=an_fb47 InputList2SigType58=Analog InputList2Cue59=an_fb48 InputList2SigType59=Analog InputList2Cue60=an_fb49 InputList2SigType60=Analog InputList2Cue61=an_fb50 InputList2SigType61=Analog InputList2Cue62=an_fb51 InputList2SigType62=Analog InputList2Cue63=an_fb52 InputList2SigType63=Analog InputList2Cue64=an_fb53 InputList2SigType64=Analog InputList2Cue65=an_fb54 InputList2SigType65=Analog InputList2Cue66=an_fb55 InputList2SigType66=Analog InputList2Cue67=an_fb56 InputList2SigType67=Analog InputList2Cue68=an_fb57 InputList2SigType68=Analog InputList2Cue69=an_fb58 InputList2SigType69=Analog InputList2Cue70=an_fb59 InputList2SigType70=Analog InputList2Cue71=an_fb60 InputList2SigType71=Analog InputList2Cue72=[~EndGroup~]an_fb InputList2SigType72=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=an_act37 OutputList2SigType48=Analog OutputList2Cue49=an_act38 OutputList2SigType49=Analog OutputList2Cue50=an_act39 OutputList2SigType50=Analog OutputList2Cue51=an_act40 OutputList2SigType51=Analog OutputList2Cue52=an_act41 OutputList2SigType52=Analog OutputList2Cue53=an_act42 OutputList2SigType53=Analog OutputList2Cue54=an_act43 OutputList2SigType54=Analog OutputList2Cue55=an_act44 OutputList2SigType55=Analog OutputList2Cue56=an_act45 OutputList2SigType56=Analog OutputList2Cue57=an_act46 OutputList2SigType57=Analog OutputList2Cue58=an_act47 OutputList2SigType58=Analog OutputList2Cue59=an_act48 OutputList2SigType59=Analog OutputList2Cue60=an_act49 OutputList2SigType60=Analog OutputList2Cue61=an_act50 OutputList2SigType61=Analog OutputList2Cue62=an_act51 OutputList2SigType62=Analog OutputList2Cue63=an_act52 OutputList2SigType63=Analog OutputList2Cue64=an_act53 OutputList2SigType64=Analog OutputList2Cue65=an_act54 OutputList2SigType65=Analog OutputList2Cue66=an_act55 OutputList2SigType66=Analog OutputList2Cue67=an_act56 OutputList2SigType67=Analog OutputList2Cue68=an_act57 OutputList2SigType68=Analog OutputList2Cue69=an_act58 OutputList2SigType69=Analog OutputList2Cue70=an_act59 OutputList2SigType70=Analog OutputList2Cue71=an_act60 OutputList2SigType71=Analog OutputList2Cue72=[~EndGroup~]an_act OutputList2SigType72=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=7 CedH=7 SmartObjId=3200d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=7 Tp=1 HD=TRUE DV=3200d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=7 Name=PepperDash Essentials TSW-760_[B.AV] Staging_Subpage Reference List Horizontal_3.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced Hint=Channel Preset List Basic (Smart Object ID=1806) Code=8 SGControlType=Subpage Reference List Vertical SGControlName=Channel Preset List Basic GUID=46C43CE4-6BB9-4B76-A13E-B4279202F998 SmplCName=PepperDash Essentials TSW-760_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4106 MaxVariableInputs=4106 MinVariableOutputs=4106 MaxVariableOutputs=4106 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=132 MaxVariableInputsList3=132 MinVariableOutputsList3=132 MaxVariableOutputsList3=132 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=[~EndGroup~]fb InputSigType4106=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=[~EndGroup~]Press OutputSigType4106=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=[~EndGroup~]text-o InputList3SigType132=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=[~EndGroup~]text-i OutputList3SigType132=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=8 CedH=8 SmartObjId=1806d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=8 Tp=1 HD=TRUE DV=1806d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=8 Name=PepperDash Essentials TSW-760_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced Hint=Modes Bottom Bar SRL (Smart Object ID=15022) Code=9 SGControlType=Subpage Reference List Horizontal SGControlName=Modes Bottom Bar SRL GUID=812FF0C4-486D-4ABC-90FA-405F19104323 SmplCName=PepperDash Essentials TSW-760_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced SMWRev=4.02.20 Expand=expand_random HelpID=10124 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4031 MaxVariableInputs=4031 MinVariableOutputs=4031 MaxVariableOutputs=4031 NumFixedParams=1 MinVariableInputsList2=27 MaxVariableInputsList2=27 MinVariableOutputsList2=27 MaxVariableOutputsList2=27 MinVariableInputsList3=27 MaxVariableInputsList3=27 MinVariableOutputsList3=27 MaxVariableOutputsList3=27 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=[~UNUSED2~] InputSigType17=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=[~UNUSED2~] InputSigType2019=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=[~EndGroup~]fb InputSigType4031=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED2~] OutputSigType17=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED2~] OutputSigType2019=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=[~EndGroup~]Press OutputSigType4031=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=[~EndGroup~]an_fb InputList2SigType27=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=[~EndGroup~]an_act OutputList2SigType27=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=[~EndGroup~]text-o InputList3SigType27=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=[~EndGroup~]text-i OutputList3SigType27=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=9 CedH=9 SmartObjId=15022d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=9 Tp=1 HD=TRUE DV=15022d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=9 Name=PepperDash Essentials TSW-760_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[B.AV] Object - Presets_CATV Icon List Vertical.ced Hint=CATV Icon List Vertical (Smart Object ID=10012) Code=10 SGControlType=Subpage Reference List Vertical SGControlName=CATV Icon List Vertical GUID=B34C4DC0-DD10-4C49-AEBA-F968934EFDC6 SmplCName=PepperDash Essentials TSW-760_[B.AV] Object - Presets_CATV Icon List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4316 MaxVariableInputs=4316 MinVariableOutputs=4316 MaxVariableOutputs=4316 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=412 MaxVariableInputsList3=412 MinVariableOutputsList3=412 MaxVariableOutputsList3=412 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=Item 31 Enable InputSigType42=Digital InputCue43=Item 32 Enable InputSigType43=Digital InputCue44=Item 33 Enable InputSigType44=Digital InputCue45=Item 34 Enable InputSigType45=Digital InputCue46=Item 35 Enable InputSigType46=Digital InputCue47=Item 36 Enable InputSigType47=Digital InputCue48=Item 37 Enable InputSigType48=Digital InputCue49=Item 38 Enable InputSigType49=Digital InputCue50=Item 39 Enable InputSigType50=Digital InputCue51=Item 40 Enable InputSigType51=Digital InputCue52=Item 41 Enable InputSigType52=Digital InputCue53=Item 42 Enable InputSigType53=Digital InputCue54=Item 43 Enable InputSigType54=Digital InputCue55=Item 44 Enable InputSigType55=Digital InputCue56=Item 45 Enable InputSigType56=Digital InputCue57=Item 46 Enable InputSigType57=Digital InputCue58=Item 47 Enable InputSigType58=Digital InputCue59=Item 48 Enable InputSigType59=Digital InputCue60=Item 49 Enable InputSigType60=Digital InputCue61=Item 50 Enable InputSigType61=Digital InputCue62=Item 51 Enable InputSigType62=Digital InputCue63=Item 52 Enable InputSigType63=Digital InputCue64=Item 53 Enable InputSigType64=Digital InputCue65=Item 54 Enable InputSigType65=Digital InputCue66=Item 55 Enable InputSigType66=Digital InputCue67=Item 56 Enable InputSigType67=Digital InputCue68=Item 57 Enable InputSigType68=Digital InputCue69=Item 58 Enable InputSigType69=Digital InputCue70=Item 59 Enable InputSigType70=Digital InputCue71=Item 60 Enable InputSigType71=Digital InputCue72=Item 61 Enable InputSigType72=Digital InputCue73=Item 62 Enable InputSigType73=Digital InputCue74=Item 63 Enable InputSigType74=Digital InputCue75=Item 64 Enable InputSigType75=Digital InputCue76=Item 65 Enable InputSigType76=Digital InputCue77=Item 66 Enable InputSigType77=Digital InputCue78=Item 67 Enable InputSigType78=Digital InputCue79=Item 68 Enable InputSigType79=Digital InputCue80=Item 69 Enable InputSigType80=Digital InputCue81=Item 70 Enable InputSigType81=Digital InputCue82=Item 71 Enable InputSigType82=Digital InputCue83=Item 72 Enable InputSigType83=Digital InputCue84=Item 73 Enable InputSigType84=Digital InputCue85=Item 74 Enable InputSigType85=Digital InputCue86=Item 75 Enable InputSigType86=Digital InputCue87=Item 76 Enable InputSigType87=Digital InputCue88=Item 77 Enable InputSigType88=Digital InputCue89=Item 78 Enable InputSigType89=Digital InputCue90=Item 79 Enable InputSigType90=Digital InputCue91=Item 80 Enable InputSigType91=Digital InputCue92=Item 81 Enable InputSigType92=Digital InputCue93=Item 82 Enable InputSigType93=Digital InputCue94=Item 83 Enable InputSigType94=Digital InputCue95=Item 84 Enable InputSigType95=Digital InputCue96=Item 85 Enable InputSigType96=Digital InputCue97=Item 86 Enable InputSigType97=Digital InputCue98=Item 87 Enable InputSigType98=Digital InputCue99=Item 88 Enable InputSigType99=Digital InputCue100=Item 89 Enable InputSigType100=Digital InputCue101=Item 90 Enable InputSigType101=Digital InputCue102=Item 91 Enable InputSigType102=Digital InputCue103=Item 92 Enable InputSigType103=Digital InputCue104=Item 93 Enable InputSigType104=Digital InputCue105=Item 94 Enable InputSigType105=Digital InputCue106=Item 95 Enable InputSigType106=Digital InputCue107=Item 96 Enable InputSigType107=Digital InputCue108=Item 97 Enable InputSigType108=Digital InputCue109=Item 98 Enable InputSigType109=Digital InputCue110=Item 99 Enable InputSigType110=Digital InputCue111=Item 100 Enable InputSigType111=Digital InputCue112=[~UNUSED2~] InputSigType112=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=Item 31 Visible InputSigType2044=Digital InputCue2045=Item 32 Visible InputSigType2045=Digital InputCue2046=Item 33 Visible InputSigType2046=Digital InputCue2047=Item 34 Visible InputSigType2047=Digital InputCue2048=Item 35 Visible InputSigType2048=Digital InputCue2049=Item 36 Visible InputSigType2049=Digital InputCue2050=Item 37 Visible InputSigType2050=Digital InputCue2051=Item 38 Visible InputSigType2051=Digital InputCue2052=Item 39 Visible InputSigType2052=Digital InputCue2053=Item 40 Visible InputSigType2053=Digital InputCue2054=Item 41 Visible InputSigType2054=Digital InputCue2055=Item 42 Visible InputSigType2055=Digital InputCue2056=Item 43 Visible InputSigType2056=Digital InputCue2057=Item 44 Visible InputSigType2057=Digital InputCue2058=Item 45 Visible InputSigType2058=Digital InputCue2059=Item 46 Visible InputSigType2059=Digital InputCue2060=Item 47 Visible InputSigType2060=Digital InputCue2061=Item 48 Visible InputSigType2061=Digital InputCue2062=Item 49 Visible InputSigType2062=Digital InputCue2063=Item 50 Visible InputSigType2063=Digital InputCue2064=Item 51 Visible InputSigType2064=Digital InputCue2065=Item 52 Visible InputSigType2065=Digital InputCue2066=Item 53 Visible InputSigType2066=Digital InputCue2067=Item 54 Visible InputSigType2067=Digital InputCue2068=Item 55 Visible InputSigType2068=Digital InputCue2069=Item 56 Visible InputSigType2069=Digital InputCue2070=Item 57 Visible InputSigType2070=Digital InputCue2071=Item 58 Visible InputSigType2071=Digital InputCue2072=Item 59 Visible InputSigType2072=Digital InputCue2073=Item 60 Visible InputSigType2073=Digital InputCue2074=Item 61 Visible InputSigType2074=Digital InputCue2075=Item 62 Visible InputSigType2075=Digital InputCue2076=Item 63 Visible InputSigType2076=Digital InputCue2077=Item 64 Visible InputSigType2077=Digital InputCue2078=Item 65 Visible InputSigType2078=Digital InputCue2079=Item 66 Visible InputSigType2079=Digital InputCue2080=Item 67 Visible InputSigType2080=Digital InputCue2081=Item 68 Visible InputSigType2081=Digital InputCue2082=Item 69 Visible InputSigType2082=Digital InputCue2083=Item 70 Visible InputSigType2083=Digital InputCue2084=Item 71 Visible InputSigType2084=Digital InputCue2085=Item 72 Visible InputSigType2085=Digital InputCue2086=Item 73 Visible InputSigType2086=Digital InputCue2087=Item 74 Visible InputSigType2087=Digital InputCue2088=Item 75 Visible InputSigType2088=Digital InputCue2089=Item 76 Visible InputSigType2089=Digital InputCue2090=Item 77 Visible InputSigType2090=Digital InputCue2091=Item 78 Visible InputSigType2091=Digital InputCue2092=Item 79 Visible InputSigType2092=Digital InputCue2093=Item 80 Visible InputSigType2093=Digital InputCue2094=Item 81 Visible InputSigType2094=Digital InputCue2095=Item 82 Visible InputSigType2095=Digital InputCue2096=Item 83 Visible InputSigType2096=Digital InputCue2097=Item 84 Visible InputSigType2097=Digital InputCue2098=Item 85 Visible InputSigType2098=Digital InputCue2099=Item 86 Visible InputSigType2099=Digital InputCue2100=Item 87 Visible InputSigType2100=Digital InputCue2101=Item 88 Visible InputSigType2101=Digital InputCue2102=Item 89 Visible InputSigType2102=Digital InputCue2103=Item 90 Visible InputSigType2103=Digital InputCue2104=Item 91 Visible InputSigType2104=Digital InputCue2105=Item 92 Visible InputSigType2105=Digital InputCue2106=Item 93 Visible InputSigType2106=Digital InputCue2107=Item 94 Visible InputSigType2107=Digital InputCue2108=Item 95 Visible InputSigType2108=Digital InputCue2109=Item 96 Visible InputSigType2109=Digital InputCue2110=Item 97 Visible InputSigType2110=Digital InputCue2111=Item 98 Visible InputSigType2111=Digital InputCue2112=Item 99 Visible InputSigType2112=Digital InputCue2113=Item 100 Visible InputSigType2113=Digital InputCue2114=[~UNUSED2~] InputSigType2114=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=fb91 InputSigType4106=Digital InputCue4107=fb92 InputSigType4107=Digital InputCue4108=fb93 InputSigType4108=Digital InputCue4109=fb94 InputSigType4109=Digital InputCue4110=fb95 InputSigType4110=Digital InputCue4111=fb96 InputSigType4111=Digital InputCue4112=fb97 InputSigType4112=Digital InputCue4113=fb98 InputSigType4113=Digital InputCue4114=fb99 InputSigType4114=Digital InputCue4115=fb100 InputSigType4115=Digital InputCue4116=fb101 InputSigType4116=Digital InputCue4117=fb102 InputSigType4117=Digital InputCue4118=fb103 InputSigType4118=Digital InputCue4119=fb104 InputSigType4119=Digital InputCue4120=fb105 InputSigType4120=Digital InputCue4121=fb106 InputSigType4121=Digital InputCue4122=fb107 InputSigType4122=Digital InputCue4123=fb108 InputSigType4123=Digital InputCue4124=fb109 InputSigType4124=Digital InputCue4125=fb110 InputSigType4125=Digital InputCue4126=fb111 InputSigType4126=Digital InputCue4127=fb112 InputSigType4127=Digital InputCue4128=fb113 InputSigType4128=Digital InputCue4129=fb114 InputSigType4129=Digital InputCue4130=fb115 InputSigType4130=Digital InputCue4131=fb116 InputSigType4131=Digital InputCue4132=fb117 InputSigType4132=Digital InputCue4133=fb118 InputSigType4133=Digital InputCue4134=fb119 InputSigType4134=Digital InputCue4135=fb120 InputSigType4135=Digital InputCue4136=fb121 InputSigType4136=Digital InputCue4137=fb122 InputSigType4137=Digital InputCue4138=fb123 InputSigType4138=Digital InputCue4139=fb124 InputSigType4139=Digital InputCue4140=fb125 InputSigType4140=Digital InputCue4141=fb126 InputSigType4141=Digital InputCue4142=fb127 InputSigType4142=Digital InputCue4143=fb128 InputSigType4143=Digital InputCue4144=fb129 InputSigType4144=Digital InputCue4145=fb130 InputSigType4145=Digital InputCue4146=fb131 InputSigType4146=Digital InputCue4147=fb132 InputSigType4147=Digital InputCue4148=fb133 InputSigType4148=Digital InputCue4149=fb134 InputSigType4149=Digital InputCue4150=fb135 InputSigType4150=Digital InputCue4151=fb136 InputSigType4151=Digital InputCue4152=fb137 InputSigType4152=Digital InputCue4153=fb138 InputSigType4153=Digital InputCue4154=fb139 InputSigType4154=Digital InputCue4155=fb140 InputSigType4155=Digital InputCue4156=fb141 InputSigType4156=Digital InputCue4157=fb142 InputSigType4157=Digital InputCue4158=fb143 InputSigType4158=Digital InputCue4159=fb144 InputSigType4159=Digital InputCue4160=fb145 InputSigType4160=Digital InputCue4161=fb146 InputSigType4161=Digital InputCue4162=fb147 InputSigType4162=Digital InputCue4163=fb148 InputSigType4163=Digital InputCue4164=fb149 InputSigType4164=Digital InputCue4165=fb150 InputSigType4165=Digital InputCue4166=fb151 InputSigType4166=Digital InputCue4167=fb152 InputSigType4167=Digital InputCue4168=fb153 InputSigType4168=Digital InputCue4169=fb154 InputSigType4169=Digital InputCue4170=fb155 InputSigType4170=Digital InputCue4171=fb156 InputSigType4171=Digital InputCue4172=fb157 InputSigType4172=Digital InputCue4173=fb158 InputSigType4173=Digital InputCue4174=fb159 InputSigType4174=Digital InputCue4175=fb160 InputSigType4175=Digital InputCue4176=fb161 InputSigType4176=Digital InputCue4177=fb162 InputSigType4177=Digital InputCue4178=fb163 InputSigType4178=Digital InputCue4179=fb164 InputSigType4179=Digital InputCue4180=fb165 InputSigType4180=Digital InputCue4181=fb166 InputSigType4181=Digital InputCue4182=fb167 InputSigType4182=Digital InputCue4183=fb168 InputSigType4183=Digital InputCue4184=fb169 InputSigType4184=Digital InputCue4185=fb170 InputSigType4185=Digital InputCue4186=fb171 InputSigType4186=Digital InputCue4187=fb172 InputSigType4187=Digital InputCue4188=fb173 InputSigType4188=Digital InputCue4189=fb174 InputSigType4189=Digital InputCue4190=fb175 InputSigType4190=Digital InputCue4191=fb176 InputSigType4191=Digital InputCue4192=fb177 InputSigType4192=Digital InputCue4193=fb178 InputSigType4193=Digital InputCue4194=fb179 InputSigType4194=Digital InputCue4195=fb180 InputSigType4195=Digital InputCue4196=fb181 InputSigType4196=Digital InputCue4197=fb182 InputSigType4197=Digital InputCue4198=fb183 InputSigType4198=Digital InputCue4199=fb184 InputSigType4199=Digital InputCue4200=fb185 InputSigType4200=Digital InputCue4201=fb186 InputSigType4201=Digital InputCue4202=fb187 InputSigType4202=Digital InputCue4203=fb188 InputSigType4203=Digital InputCue4204=fb189 InputSigType4204=Digital InputCue4205=fb190 InputSigType4205=Digital InputCue4206=fb191 InputSigType4206=Digital InputCue4207=fb192 InputSigType4207=Digital InputCue4208=fb193 InputSigType4208=Digital InputCue4209=fb194 InputSigType4209=Digital InputCue4210=fb195 InputSigType4210=Digital InputCue4211=fb196 InputSigType4211=Digital InputCue4212=fb197 InputSigType4212=Digital InputCue4213=fb198 InputSigType4213=Digital InputCue4214=fb199 InputSigType4214=Digital InputCue4215=fb200 InputSigType4215=Digital InputCue4216=fb201 InputSigType4216=Digital InputCue4217=fb202 InputSigType4217=Digital InputCue4218=fb203 InputSigType4218=Digital InputCue4219=fb204 InputSigType4219=Digital InputCue4220=fb205 InputSigType4220=Digital InputCue4221=fb206 InputSigType4221=Digital InputCue4222=fb207 InputSigType4222=Digital InputCue4223=fb208 InputSigType4223=Digital InputCue4224=fb209 InputSigType4224=Digital InputCue4225=fb210 InputSigType4225=Digital InputCue4226=fb211 InputSigType4226=Digital InputCue4227=fb212 InputSigType4227=Digital InputCue4228=fb213 InputSigType4228=Digital InputCue4229=fb214 InputSigType4229=Digital InputCue4230=fb215 InputSigType4230=Digital InputCue4231=fb216 InputSigType4231=Digital InputCue4232=fb217 InputSigType4232=Digital InputCue4233=fb218 InputSigType4233=Digital InputCue4234=fb219 InputSigType4234=Digital InputCue4235=fb220 InputSigType4235=Digital InputCue4236=fb221 InputSigType4236=Digital InputCue4237=fb222 InputSigType4237=Digital InputCue4238=fb223 InputSigType4238=Digital InputCue4239=fb224 InputSigType4239=Digital InputCue4240=fb225 InputSigType4240=Digital InputCue4241=fb226 InputSigType4241=Digital InputCue4242=fb227 InputSigType4242=Digital InputCue4243=fb228 InputSigType4243=Digital InputCue4244=fb229 InputSigType4244=Digital InputCue4245=fb230 InputSigType4245=Digital InputCue4246=fb231 InputSigType4246=Digital InputCue4247=fb232 InputSigType4247=Digital InputCue4248=fb233 InputSigType4248=Digital InputCue4249=fb234 InputSigType4249=Digital InputCue4250=fb235 InputSigType4250=Digital InputCue4251=fb236 InputSigType4251=Digital InputCue4252=fb237 InputSigType4252=Digital InputCue4253=fb238 InputSigType4253=Digital InputCue4254=fb239 InputSigType4254=Digital InputCue4255=fb240 InputSigType4255=Digital InputCue4256=fb241 InputSigType4256=Digital InputCue4257=fb242 InputSigType4257=Digital InputCue4258=fb243 InputSigType4258=Digital InputCue4259=fb244 InputSigType4259=Digital InputCue4260=fb245 InputSigType4260=Digital InputCue4261=fb246 InputSigType4261=Digital InputCue4262=fb247 InputSigType4262=Digital InputCue4263=fb248 InputSigType4263=Digital InputCue4264=fb249 InputSigType4264=Digital InputCue4265=fb250 InputSigType4265=Digital InputCue4266=fb251 InputSigType4266=Digital InputCue4267=fb252 InputSigType4267=Digital InputCue4268=fb253 InputSigType4268=Digital InputCue4269=fb254 InputSigType4269=Digital InputCue4270=fb255 InputSigType4270=Digital InputCue4271=fb256 InputSigType4271=Digital InputCue4272=fb257 InputSigType4272=Digital InputCue4273=fb258 InputSigType4273=Digital InputCue4274=fb259 InputSigType4274=Digital InputCue4275=fb260 InputSigType4275=Digital InputCue4276=fb261 InputSigType4276=Digital InputCue4277=fb262 InputSigType4277=Digital InputCue4278=fb263 InputSigType4278=Digital InputCue4279=fb264 InputSigType4279=Digital InputCue4280=fb265 InputSigType4280=Digital InputCue4281=fb266 InputSigType4281=Digital InputCue4282=fb267 InputSigType4282=Digital InputCue4283=fb268 InputSigType4283=Digital InputCue4284=fb269 InputSigType4284=Digital InputCue4285=fb270 InputSigType4285=Digital InputCue4286=fb271 InputSigType4286=Digital InputCue4287=fb272 InputSigType4287=Digital InputCue4288=fb273 InputSigType4288=Digital InputCue4289=fb274 InputSigType4289=Digital InputCue4290=fb275 InputSigType4290=Digital InputCue4291=fb276 InputSigType4291=Digital InputCue4292=fb277 InputSigType4292=Digital InputCue4293=fb278 InputSigType4293=Digital InputCue4294=fb279 InputSigType4294=Digital InputCue4295=fb280 InputSigType4295=Digital InputCue4296=fb281 InputSigType4296=Digital InputCue4297=fb282 InputSigType4297=Digital InputCue4298=fb283 InputSigType4298=Digital InputCue4299=fb284 InputSigType4299=Digital InputCue4300=fb285 InputSigType4300=Digital InputCue4301=fb286 InputSigType4301=Digital InputCue4302=fb287 InputSigType4302=Digital InputCue4303=fb288 InputSigType4303=Digital InputCue4304=fb289 InputSigType4304=Digital InputCue4305=fb290 InputSigType4305=Digital InputCue4306=fb291 InputSigType4306=Digital InputCue4307=fb292 InputSigType4307=Digital InputCue4308=fb293 InputSigType4308=Digital InputCue4309=fb294 InputSigType4309=Digital InputCue4310=fb295 InputSigType4310=Digital InputCue4311=fb296 InputSigType4311=Digital InputCue4312=fb297 InputSigType4312=Digital InputCue4313=fb298 InputSigType4313=Digital InputCue4314=fb299 InputSigType4314=Digital InputCue4315=fb300 InputSigType4315=Digital InputCue4316=[~EndGroup~]fb InputSigType4316=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED3~] OutputSigType42=Digital OutputCue43=[~UNUSED3~] OutputSigType43=Digital OutputCue44=[~UNUSED3~] OutputSigType44=Digital OutputCue45=[~UNUSED3~] OutputSigType45=Digital OutputCue46=[~UNUSED3~] OutputSigType46=Digital OutputCue47=[~UNUSED3~] OutputSigType47=Digital OutputCue48=[~UNUSED3~] OutputSigType48=Digital OutputCue49=[~UNUSED3~] OutputSigType49=Digital OutputCue50=[~UNUSED3~] OutputSigType50=Digital OutputCue51=[~UNUSED3~] OutputSigType51=Digital OutputCue52=[~UNUSED3~] OutputSigType52=Digital OutputCue53=[~UNUSED3~] OutputSigType53=Digital OutputCue54=[~UNUSED3~] OutputSigType54=Digital OutputCue55=[~UNUSED3~] OutputSigType55=Digital OutputCue56=[~UNUSED3~] OutputSigType56=Digital OutputCue57=[~UNUSED3~] OutputSigType57=Digital OutputCue58=[~UNUSED3~] OutputSigType58=Digital OutputCue59=[~UNUSED3~] OutputSigType59=Digital OutputCue60=[~UNUSED3~] OutputSigType60=Digital OutputCue61=[~UNUSED3~] OutputSigType61=Digital OutputCue62=[~UNUSED3~] OutputSigType62=Digital OutputCue63=[~UNUSED3~] OutputSigType63=Digital OutputCue64=[~UNUSED3~] OutputSigType64=Digital OutputCue65=[~UNUSED3~] OutputSigType65=Digital OutputCue66=[~UNUSED3~] OutputSigType66=Digital OutputCue67=[~UNUSED3~] OutputSigType67=Digital OutputCue68=[~UNUSED3~] OutputSigType68=Digital OutputCue69=[~UNUSED3~] OutputSigType69=Digital OutputCue70=[~UNUSED3~] OutputSigType70=Digital OutputCue71=[~UNUSED3~] OutputSigType71=Digital OutputCue72=[~UNUSED3~] OutputSigType72=Digital OutputCue73=[~UNUSED3~] OutputSigType73=Digital OutputCue74=[~UNUSED3~] OutputSigType74=Digital OutputCue75=[~UNUSED3~] OutputSigType75=Digital OutputCue76=[~UNUSED3~] OutputSigType76=Digital OutputCue77=[~UNUSED3~] OutputSigType77=Digital OutputCue78=[~UNUSED3~] OutputSigType78=Digital OutputCue79=[~UNUSED3~] OutputSigType79=Digital OutputCue80=[~UNUSED3~] OutputSigType80=Digital OutputCue81=[~UNUSED3~] OutputSigType81=Digital OutputCue82=[~UNUSED3~] OutputSigType82=Digital OutputCue83=[~UNUSED3~] OutputSigType83=Digital OutputCue84=[~UNUSED3~] OutputSigType84=Digital OutputCue85=[~UNUSED3~] OutputSigType85=Digital OutputCue86=[~UNUSED3~] OutputSigType86=Digital OutputCue87=[~UNUSED3~] OutputSigType87=Digital OutputCue88=[~UNUSED3~] OutputSigType88=Digital OutputCue89=[~UNUSED3~] OutputSigType89=Digital OutputCue90=[~UNUSED3~] OutputSigType90=Digital OutputCue91=[~UNUSED3~] OutputSigType91=Digital OutputCue92=[~UNUSED3~] OutputSigType92=Digital OutputCue93=[~UNUSED3~] OutputSigType93=Digital OutputCue94=[~UNUSED3~] OutputSigType94=Digital OutputCue95=[~UNUSED3~] OutputSigType95=Digital OutputCue96=[~UNUSED3~] OutputSigType96=Digital OutputCue97=[~UNUSED3~] OutputSigType97=Digital OutputCue98=[~UNUSED3~] OutputSigType98=Digital OutputCue99=[~UNUSED3~] OutputSigType99=Digital OutputCue100=[~UNUSED3~] OutputSigType100=Digital OutputCue101=[~UNUSED3~] OutputSigType101=Digital OutputCue102=[~UNUSED3~] OutputSigType102=Digital OutputCue103=[~UNUSED3~] OutputSigType103=Digital OutputCue104=[~UNUSED3~] OutputSigType104=Digital OutputCue105=[~UNUSED3~] OutputSigType105=Digital OutputCue106=[~UNUSED3~] OutputSigType106=Digital OutputCue107=[~UNUSED3~] OutputSigType107=Digital OutputCue108=[~UNUSED3~] OutputSigType108=Digital OutputCue109=[~UNUSED3~] OutputSigType109=Digital OutputCue110=[~UNUSED3~] OutputSigType110=Digital OutputCue111=[~UNUSED3~] OutputSigType111=Digital OutputCue112=[~UNUSED2~] OutputSigType112=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED3~] OutputSigType2044=Digital OutputCue2045=[~UNUSED3~] OutputSigType2045=Digital OutputCue2046=[~UNUSED3~] OutputSigType2046=Digital OutputCue2047=[~UNUSED3~] OutputSigType2047=Digital OutputCue2048=[~UNUSED3~] OutputSigType2048=Digital OutputCue2049=[~UNUSED3~] OutputSigType2049=Digital OutputCue2050=[~UNUSED3~] OutputSigType2050=Digital OutputCue2051=[~UNUSED3~] OutputSigType2051=Digital OutputCue2052=[~UNUSED3~] OutputSigType2052=Digital OutputCue2053=[~UNUSED3~] OutputSigType2053=Digital OutputCue2054=[~UNUSED3~] OutputSigType2054=Digital OutputCue2055=[~UNUSED3~] OutputSigType2055=Digital OutputCue2056=[~UNUSED3~] OutputSigType2056=Digital OutputCue2057=[~UNUSED3~] OutputSigType2057=Digital OutputCue2058=[~UNUSED3~] OutputSigType2058=Digital OutputCue2059=[~UNUSED3~] OutputSigType2059=Digital OutputCue2060=[~UNUSED3~] OutputSigType2060=Digital OutputCue2061=[~UNUSED3~] OutputSigType2061=Digital OutputCue2062=[~UNUSED3~] OutputSigType2062=Digital OutputCue2063=[~UNUSED3~] OutputSigType2063=Digital OutputCue2064=[~UNUSED3~] OutputSigType2064=Digital OutputCue2065=[~UNUSED3~] OutputSigType2065=Digital OutputCue2066=[~UNUSED3~] OutputSigType2066=Digital OutputCue2067=[~UNUSED3~] OutputSigType2067=Digital OutputCue2068=[~UNUSED3~] OutputSigType2068=Digital OutputCue2069=[~UNUSED3~] OutputSigType2069=Digital OutputCue2070=[~UNUSED3~] OutputSigType2070=Digital OutputCue2071=[~UNUSED3~] OutputSigType2071=Digital OutputCue2072=[~UNUSED3~] OutputSigType2072=Digital OutputCue2073=[~UNUSED3~] OutputSigType2073=Digital OutputCue2074=[~UNUSED3~] OutputSigType2074=Digital OutputCue2075=[~UNUSED3~] OutputSigType2075=Digital OutputCue2076=[~UNUSED3~] OutputSigType2076=Digital OutputCue2077=[~UNUSED3~] OutputSigType2077=Digital OutputCue2078=[~UNUSED3~] OutputSigType2078=Digital OutputCue2079=[~UNUSED3~] OutputSigType2079=Digital OutputCue2080=[~UNUSED3~] OutputSigType2080=Digital OutputCue2081=[~UNUSED3~] OutputSigType2081=Digital OutputCue2082=[~UNUSED3~] OutputSigType2082=Digital OutputCue2083=[~UNUSED3~] OutputSigType2083=Digital OutputCue2084=[~UNUSED3~] OutputSigType2084=Digital OutputCue2085=[~UNUSED3~] OutputSigType2085=Digital OutputCue2086=[~UNUSED3~] OutputSigType2086=Digital OutputCue2087=[~UNUSED3~] OutputSigType2087=Digital OutputCue2088=[~UNUSED3~] OutputSigType2088=Digital OutputCue2089=[~UNUSED3~] OutputSigType2089=Digital OutputCue2090=[~UNUSED3~] OutputSigType2090=Digital OutputCue2091=[~UNUSED3~] OutputSigType2091=Digital OutputCue2092=[~UNUSED3~] OutputSigType2092=Digital OutputCue2093=[~UNUSED3~] OutputSigType2093=Digital OutputCue2094=[~UNUSED3~] OutputSigType2094=Digital OutputCue2095=[~UNUSED3~] OutputSigType2095=Digital OutputCue2096=[~UNUSED3~] OutputSigType2096=Digital OutputCue2097=[~UNUSED3~] OutputSigType2097=Digital OutputCue2098=[~UNUSED3~] OutputSigType2098=Digital OutputCue2099=[~UNUSED3~] OutputSigType2099=Digital OutputCue2100=[~UNUSED3~] OutputSigType2100=Digital OutputCue2101=[~UNUSED3~] OutputSigType2101=Digital OutputCue2102=[~UNUSED3~] OutputSigType2102=Digital OutputCue2103=[~UNUSED3~] OutputSigType2103=Digital OutputCue2104=[~UNUSED3~] OutputSigType2104=Digital OutputCue2105=[~UNUSED3~] OutputSigType2105=Digital OutputCue2106=[~UNUSED3~] OutputSigType2106=Digital OutputCue2107=[~UNUSED3~] OutputSigType2107=Digital OutputCue2108=[~UNUSED3~] OutputSigType2108=Digital OutputCue2109=[~UNUSED3~] OutputSigType2109=Digital OutputCue2110=[~UNUSED3~] OutputSigType2110=Digital OutputCue2111=[~UNUSED3~] OutputSigType2111=Digital OutputCue2112=[~UNUSED3~] OutputSigType2112=Digital OutputCue2113=[~UNUSED3~] OutputSigType2113=Digital OutputCue2114=[~UNUSED2~] OutputSigType2114=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=press91 OutputSigType4106=Digital OutputCue4107=press92 OutputSigType4107=Digital OutputCue4108=press93 OutputSigType4108=Digital OutputCue4109=press94 OutputSigType4109=Digital OutputCue4110=press95 OutputSigType4110=Digital OutputCue4111=press96 OutputSigType4111=Digital OutputCue4112=press97 OutputSigType4112=Digital OutputCue4113=press98 OutputSigType4113=Digital OutputCue4114=press99 OutputSigType4114=Digital OutputCue4115=press100 OutputSigType4115=Digital OutputCue4116=press101 OutputSigType4116=Digital OutputCue4117=press102 OutputSigType4117=Digital OutputCue4118=press103 OutputSigType4118=Digital OutputCue4119=press104 OutputSigType4119=Digital OutputCue4120=press105 OutputSigType4120=Digital OutputCue4121=press106 OutputSigType4121=Digital OutputCue4122=press107 OutputSigType4122=Digital OutputCue4123=press108 OutputSigType4123=Digital OutputCue4124=press109 OutputSigType4124=Digital OutputCue4125=press110 OutputSigType4125=Digital OutputCue4126=press111 OutputSigType4126=Digital OutputCue4127=press112 OutputSigType4127=Digital OutputCue4128=press113 OutputSigType4128=Digital OutputCue4129=press114 OutputSigType4129=Digital OutputCue4130=press115 OutputSigType4130=Digital OutputCue4131=press116 OutputSigType4131=Digital OutputCue4132=press117 OutputSigType4132=Digital OutputCue4133=press118 OutputSigType4133=Digital OutputCue4134=press119 OutputSigType4134=Digital OutputCue4135=press120 OutputSigType4135=Digital OutputCue4136=press121 OutputSigType4136=Digital OutputCue4137=press122 OutputSigType4137=Digital OutputCue4138=press123 OutputSigType4138=Digital OutputCue4139=press124 OutputSigType4139=Digital OutputCue4140=press125 OutputSigType4140=Digital OutputCue4141=press126 OutputSigType4141=Digital OutputCue4142=press127 OutputSigType4142=Digital OutputCue4143=press128 OutputSigType4143=Digital OutputCue4144=press129 OutputSigType4144=Digital OutputCue4145=press130 OutputSigType4145=Digital OutputCue4146=press131 OutputSigType4146=Digital OutputCue4147=press132 OutputSigType4147=Digital OutputCue4148=press133 OutputSigType4148=Digital OutputCue4149=press134 OutputSigType4149=Digital OutputCue4150=press135 OutputSigType4150=Digital OutputCue4151=press136 OutputSigType4151=Digital OutputCue4152=press137 OutputSigType4152=Digital OutputCue4153=press138 OutputSigType4153=Digital OutputCue4154=press139 OutputSigType4154=Digital OutputCue4155=press140 OutputSigType4155=Digital OutputCue4156=press141 OutputSigType4156=Digital OutputCue4157=press142 OutputSigType4157=Digital OutputCue4158=press143 OutputSigType4158=Digital OutputCue4159=press144 OutputSigType4159=Digital OutputCue4160=press145 OutputSigType4160=Digital OutputCue4161=press146 OutputSigType4161=Digital OutputCue4162=press147 OutputSigType4162=Digital OutputCue4163=press148 OutputSigType4163=Digital OutputCue4164=press149 OutputSigType4164=Digital OutputCue4165=press150 OutputSigType4165=Digital OutputCue4166=press151 OutputSigType4166=Digital OutputCue4167=press152 OutputSigType4167=Digital OutputCue4168=press153 OutputSigType4168=Digital OutputCue4169=press154 OutputSigType4169=Digital OutputCue4170=press155 OutputSigType4170=Digital OutputCue4171=press156 OutputSigType4171=Digital OutputCue4172=press157 OutputSigType4172=Digital OutputCue4173=press158 OutputSigType4173=Digital OutputCue4174=press159 OutputSigType4174=Digital OutputCue4175=press160 OutputSigType4175=Digital OutputCue4176=press161 OutputSigType4176=Digital OutputCue4177=press162 OutputSigType4177=Digital OutputCue4178=press163 OutputSigType4178=Digital OutputCue4179=press164 OutputSigType4179=Digital OutputCue4180=press165 OutputSigType4180=Digital OutputCue4181=press166 OutputSigType4181=Digital OutputCue4182=press167 OutputSigType4182=Digital OutputCue4183=press168 OutputSigType4183=Digital OutputCue4184=press169 OutputSigType4184=Digital OutputCue4185=press170 OutputSigType4185=Digital OutputCue4186=press171 OutputSigType4186=Digital OutputCue4187=press172 OutputSigType4187=Digital OutputCue4188=press173 OutputSigType4188=Digital OutputCue4189=press174 OutputSigType4189=Digital OutputCue4190=press175 OutputSigType4190=Digital OutputCue4191=press176 OutputSigType4191=Digital OutputCue4192=press177 OutputSigType4192=Digital OutputCue4193=press178 OutputSigType4193=Digital OutputCue4194=press179 OutputSigType4194=Digital OutputCue4195=press180 OutputSigType4195=Digital OutputCue4196=press181 OutputSigType4196=Digital OutputCue4197=press182 OutputSigType4197=Digital OutputCue4198=press183 OutputSigType4198=Digital OutputCue4199=press184 OutputSigType4199=Digital OutputCue4200=press185 OutputSigType4200=Digital OutputCue4201=press186 OutputSigType4201=Digital OutputCue4202=press187 OutputSigType4202=Digital OutputCue4203=press188 OutputSigType4203=Digital OutputCue4204=press189 OutputSigType4204=Digital OutputCue4205=press190 OutputSigType4205=Digital OutputCue4206=press191 OutputSigType4206=Digital OutputCue4207=press192 OutputSigType4207=Digital OutputCue4208=press193 OutputSigType4208=Digital OutputCue4209=press194 OutputSigType4209=Digital OutputCue4210=press195 OutputSigType4210=Digital OutputCue4211=press196 OutputSigType4211=Digital OutputCue4212=press197 OutputSigType4212=Digital OutputCue4213=press198 OutputSigType4213=Digital OutputCue4214=press199 OutputSigType4214=Digital OutputCue4215=press200 OutputSigType4215=Digital OutputCue4216=press201 OutputSigType4216=Digital OutputCue4217=press202 OutputSigType4217=Digital OutputCue4218=press203 OutputSigType4218=Digital OutputCue4219=press204 OutputSigType4219=Digital OutputCue4220=press205 OutputSigType4220=Digital OutputCue4221=press206 OutputSigType4221=Digital OutputCue4222=press207 OutputSigType4222=Digital OutputCue4223=press208 OutputSigType4223=Digital OutputCue4224=press209 OutputSigType4224=Digital OutputCue4225=press210 OutputSigType4225=Digital OutputCue4226=press211 OutputSigType4226=Digital OutputCue4227=press212 OutputSigType4227=Digital OutputCue4228=press213 OutputSigType4228=Digital OutputCue4229=press214 OutputSigType4229=Digital OutputCue4230=press215 OutputSigType4230=Digital OutputCue4231=press216 OutputSigType4231=Digital OutputCue4232=press217 OutputSigType4232=Digital OutputCue4233=press218 OutputSigType4233=Digital OutputCue4234=press219 OutputSigType4234=Digital OutputCue4235=press220 OutputSigType4235=Digital OutputCue4236=press221 OutputSigType4236=Digital OutputCue4237=press222 OutputSigType4237=Digital OutputCue4238=press223 OutputSigType4238=Digital OutputCue4239=press224 OutputSigType4239=Digital OutputCue4240=press225 OutputSigType4240=Digital OutputCue4241=press226 OutputSigType4241=Digital OutputCue4242=press227 OutputSigType4242=Digital OutputCue4243=press228 OutputSigType4243=Digital OutputCue4244=press229 OutputSigType4244=Digital OutputCue4245=press230 OutputSigType4245=Digital OutputCue4246=press231 OutputSigType4246=Digital OutputCue4247=press232 OutputSigType4247=Digital OutputCue4248=press233 OutputSigType4248=Digital OutputCue4249=press234 OutputSigType4249=Digital OutputCue4250=press235 OutputSigType4250=Digital OutputCue4251=press236 OutputSigType4251=Digital OutputCue4252=press237 OutputSigType4252=Digital OutputCue4253=press238 OutputSigType4253=Digital OutputCue4254=press239 OutputSigType4254=Digital OutputCue4255=press240 OutputSigType4255=Digital OutputCue4256=press241 OutputSigType4256=Digital OutputCue4257=press242 OutputSigType4257=Digital OutputCue4258=press243 OutputSigType4258=Digital OutputCue4259=press244 OutputSigType4259=Digital OutputCue4260=press245 OutputSigType4260=Digital OutputCue4261=press246 OutputSigType4261=Digital OutputCue4262=press247 OutputSigType4262=Digital OutputCue4263=press248 OutputSigType4263=Digital OutputCue4264=press249 OutputSigType4264=Digital OutputCue4265=press250 OutputSigType4265=Digital OutputCue4266=press251 OutputSigType4266=Digital OutputCue4267=press252 OutputSigType4267=Digital OutputCue4268=press253 OutputSigType4268=Digital OutputCue4269=press254 OutputSigType4269=Digital OutputCue4270=press255 OutputSigType4270=Digital OutputCue4271=press256 OutputSigType4271=Digital OutputCue4272=press257 OutputSigType4272=Digital OutputCue4273=press258 OutputSigType4273=Digital OutputCue4274=press259 OutputSigType4274=Digital OutputCue4275=press260 OutputSigType4275=Digital OutputCue4276=press261 OutputSigType4276=Digital OutputCue4277=press262 OutputSigType4277=Digital OutputCue4278=press263 OutputSigType4278=Digital OutputCue4279=press264 OutputSigType4279=Digital OutputCue4280=press265 OutputSigType4280=Digital OutputCue4281=press266 OutputSigType4281=Digital OutputCue4282=press267 OutputSigType4282=Digital OutputCue4283=press268 OutputSigType4283=Digital OutputCue4284=press269 OutputSigType4284=Digital OutputCue4285=press270 OutputSigType4285=Digital OutputCue4286=press271 OutputSigType4286=Digital OutputCue4287=press272 OutputSigType4287=Digital OutputCue4288=press273 OutputSigType4288=Digital OutputCue4289=press274 OutputSigType4289=Digital OutputCue4290=press275 OutputSigType4290=Digital OutputCue4291=press276 OutputSigType4291=Digital OutputCue4292=press277 OutputSigType4292=Digital OutputCue4293=press278 OutputSigType4293=Digital OutputCue4294=press279 OutputSigType4294=Digital OutputCue4295=press280 OutputSigType4295=Digital OutputCue4296=press281 OutputSigType4296=Digital OutputCue4297=press282 OutputSigType4297=Digital OutputCue4298=press283 OutputSigType4298=Digital OutputCue4299=press284 OutputSigType4299=Digital OutputCue4300=press285 OutputSigType4300=Digital OutputCue4301=press286 OutputSigType4301=Digital OutputCue4302=press287 OutputSigType4302=Digital OutputCue4303=press288 OutputSigType4303=Digital OutputCue4304=press289 OutputSigType4304=Digital OutputCue4305=press290 OutputSigType4305=Digital OutputCue4306=press291 OutputSigType4306=Digital OutputCue4307=press292 OutputSigType4307=Digital OutputCue4308=press293 OutputSigType4308=Digital OutputCue4309=press294 OutputSigType4309=Digital OutputCue4310=press295 OutputSigType4310=Digital OutputCue4311=press296 OutputSigType4311=Digital OutputCue4312=press297 OutputSigType4312=Digital OutputCue4313=press298 OutputSigType4313=Digital OutputCue4314=press299 OutputSigType4314=Digital OutputCue4315=press300 OutputSigType4315=Digital OutputCue4316=[~EndGroup~]Press OutputSigType4316=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=text-o121 InputList3SigType132=Serial InputList3Cue133=text-o122 InputList3SigType133=Serial InputList3Cue134=text-o123 InputList3SigType134=Serial InputList3Cue135=text-o124 InputList3SigType135=Serial InputList3Cue136=text-o125 InputList3SigType136=Serial InputList3Cue137=text-o126 InputList3SigType137=Serial InputList3Cue138=text-o127 InputList3SigType138=Serial InputList3Cue139=text-o128 InputList3SigType139=Serial InputList3Cue140=text-o129 InputList3SigType140=Serial InputList3Cue141=text-o130 InputList3SigType141=Serial InputList3Cue142=text-o131 InputList3SigType142=Serial InputList3Cue143=text-o132 InputList3SigType143=Serial InputList3Cue144=text-o133 InputList3SigType144=Serial InputList3Cue145=text-o134 InputList3SigType145=Serial InputList3Cue146=text-o135 InputList3SigType146=Serial InputList3Cue147=text-o136 InputList3SigType147=Serial InputList3Cue148=text-o137 InputList3SigType148=Serial InputList3Cue149=text-o138 InputList3SigType149=Serial InputList3Cue150=text-o139 InputList3SigType150=Serial InputList3Cue151=text-o140 InputList3SigType151=Serial InputList3Cue152=text-o141 InputList3SigType152=Serial InputList3Cue153=text-o142 InputList3SigType153=Serial InputList3Cue154=text-o143 InputList3SigType154=Serial InputList3Cue155=text-o144 InputList3SigType155=Serial InputList3Cue156=text-o145 InputList3SigType156=Serial InputList3Cue157=text-o146 InputList3SigType157=Serial InputList3Cue158=text-o147 InputList3SigType158=Serial InputList3Cue159=text-o148 InputList3SigType159=Serial InputList3Cue160=text-o149 InputList3SigType160=Serial InputList3Cue161=text-o150 InputList3SigType161=Serial InputList3Cue162=text-o151 InputList3SigType162=Serial InputList3Cue163=text-o152 InputList3SigType163=Serial InputList3Cue164=text-o153 InputList3SigType164=Serial InputList3Cue165=text-o154 InputList3SigType165=Serial InputList3Cue166=text-o155 InputList3SigType166=Serial InputList3Cue167=text-o156 InputList3SigType167=Serial InputList3Cue168=text-o157 InputList3SigType168=Serial InputList3Cue169=text-o158 InputList3SigType169=Serial InputList3Cue170=text-o159 InputList3SigType170=Serial InputList3Cue171=text-o160 InputList3SigType171=Serial InputList3Cue172=text-o161 InputList3SigType172=Serial InputList3Cue173=text-o162 InputList3SigType173=Serial InputList3Cue174=text-o163 InputList3SigType174=Serial InputList3Cue175=text-o164 InputList3SigType175=Serial InputList3Cue176=text-o165 InputList3SigType176=Serial InputList3Cue177=text-o166 InputList3SigType177=Serial InputList3Cue178=text-o167 InputList3SigType178=Serial InputList3Cue179=text-o168 InputList3SigType179=Serial InputList3Cue180=text-o169 InputList3SigType180=Serial InputList3Cue181=text-o170 InputList3SigType181=Serial InputList3Cue182=text-o171 InputList3SigType182=Serial InputList3Cue183=text-o172 InputList3SigType183=Serial InputList3Cue184=text-o173 InputList3SigType184=Serial InputList3Cue185=text-o174 InputList3SigType185=Serial InputList3Cue186=text-o175 InputList3SigType186=Serial InputList3Cue187=text-o176 InputList3SigType187=Serial InputList3Cue188=text-o177 InputList3SigType188=Serial InputList3Cue189=text-o178 InputList3SigType189=Serial InputList3Cue190=text-o179 InputList3SigType190=Serial InputList3Cue191=text-o180 InputList3SigType191=Serial InputList3Cue192=text-o181 InputList3SigType192=Serial InputList3Cue193=text-o182 InputList3SigType193=Serial InputList3Cue194=text-o183 InputList3SigType194=Serial InputList3Cue195=text-o184 InputList3SigType195=Serial InputList3Cue196=text-o185 InputList3SigType196=Serial InputList3Cue197=text-o186 InputList3SigType197=Serial InputList3Cue198=text-o187 InputList3SigType198=Serial InputList3Cue199=text-o188 InputList3SigType199=Serial InputList3Cue200=text-o189 InputList3SigType200=Serial InputList3Cue201=text-o190 InputList3SigType201=Serial InputList3Cue202=text-o191 InputList3SigType202=Serial InputList3Cue203=text-o192 InputList3SigType203=Serial InputList3Cue204=text-o193 InputList3SigType204=Serial InputList3Cue205=text-o194 InputList3SigType205=Serial InputList3Cue206=text-o195 InputList3SigType206=Serial InputList3Cue207=text-o196 InputList3SigType207=Serial InputList3Cue208=text-o197 InputList3SigType208=Serial InputList3Cue209=text-o198 InputList3SigType209=Serial InputList3Cue210=text-o199 InputList3SigType210=Serial InputList3Cue211=text-o200 InputList3SigType211=Serial InputList3Cue212=text-o201 InputList3SigType212=Serial InputList3Cue213=text-o202 InputList3SigType213=Serial InputList3Cue214=text-o203 InputList3SigType214=Serial InputList3Cue215=text-o204 InputList3SigType215=Serial InputList3Cue216=text-o205 InputList3SigType216=Serial InputList3Cue217=text-o206 InputList3SigType217=Serial InputList3Cue218=text-o207 InputList3SigType218=Serial InputList3Cue219=text-o208 InputList3SigType219=Serial InputList3Cue220=text-o209 InputList3SigType220=Serial InputList3Cue221=text-o210 InputList3SigType221=Serial InputList3Cue222=text-o211 InputList3SigType222=Serial InputList3Cue223=text-o212 InputList3SigType223=Serial InputList3Cue224=text-o213 InputList3SigType224=Serial InputList3Cue225=text-o214 InputList3SigType225=Serial InputList3Cue226=text-o215 InputList3SigType226=Serial InputList3Cue227=text-o216 InputList3SigType227=Serial InputList3Cue228=text-o217 InputList3SigType228=Serial InputList3Cue229=text-o218 InputList3SigType229=Serial InputList3Cue230=text-o219 InputList3SigType230=Serial InputList3Cue231=text-o220 InputList3SigType231=Serial InputList3Cue232=text-o221 InputList3SigType232=Serial InputList3Cue233=text-o222 InputList3SigType233=Serial InputList3Cue234=text-o223 InputList3SigType234=Serial InputList3Cue235=text-o224 InputList3SigType235=Serial InputList3Cue236=text-o225 InputList3SigType236=Serial InputList3Cue237=text-o226 InputList3SigType237=Serial InputList3Cue238=text-o227 InputList3SigType238=Serial InputList3Cue239=text-o228 InputList3SigType239=Serial InputList3Cue240=text-o229 InputList3SigType240=Serial InputList3Cue241=text-o230 InputList3SigType241=Serial InputList3Cue242=text-o231 InputList3SigType242=Serial InputList3Cue243=text-o232 InputList3SigType243=Serial InputList3Cue244=text-o233 InputList3SigType244=Serial InputList3Cue245=text-o234 InputList3SigType245=Serial InputList3Cue246=text-o235 InputList3SigType246=Serial InputList3Cue247=text-o236 InputList3SigType247=Serial InputList3Cue248=text-o237 InputList3SigType248=Serial InputList3Cue249=text-o238 InputList3SigType249=Serial InputList3Cue250=text-o239 InputList3SigType250=Serial InputList3Cue251=text-o240 InputList3SigType251=Serial InputList3Cue252=text-o241 InputList3SigType252=Serial InputList3Cue253=text-o242 InputList3SigType253=Serial InputList3Cue254=text-o243 InputList3SigType254=Serial InputList3Cue255=text-o244 InputList3SigType255=Serial InputList3Cue256=text-o245 InputList3SigType256=Serial InputList3Cue257=text-o246 InputList3SigType257=Serial InputList3Cue258=text-o247 InputList3SigType258=Serial InputList3Cue259=text-o248 InputList3SigType259=Serial InputList3Cue260=text-o249 InputList3SigType260=Serial InputList3Cue261=text-o250 InputList3SigType261=Serial InputList3Cue262=text-o251 InputList3SigType262=Serial InputList3Cue263=text-o252 InputList3SigType263=Serial InputList3Cue264=text-o253 InputList3SigType264=Serial InputList3Cue265=text-o254 InputList3SigType265=Serial InputList3Cue266=text-o255 InputList3SigType266=Serial InputList3Cue267=text-o256 InputList3SigType267=Serial InputList3Cue268=text-o257 InputList3SigType268=Serial InputList3Cue269=text-o258 InputList3SigType269=Serial InputList3Cue270=text-o259 InputList3SigType270=Serial InputList3Cue271=text-o260 InputList3SigType271=Serial InputList3Cue272=text-o261 InputList3SigType272=Serial InputList3Cue273=text-o262 InputList3SigType273=Serial InputList3Cue274=text-o263 InputList3SigType274=Serial InputList3Cue275=text-o264 InputList3SigType275=Serial InputList3Cue276=text-o265 InputList3SigType276=Serial InputList3Cue277=text-o266 InputList3SigType277=Serial InputList3Cue278=text-o267 InputList3SigType278=Serial InputList3Cue279=text-o268 InputList3SigType279=Serial InputList3Cue280=text-o269 InputList3SigType280=Serial InputList3Cue281=text-o270 InputList3SigType281=Serial InputList3Cue282=text-o271 InputList3SigType282=Serial InputList3Cue283=text-o272 InputList3SigType283=Serial InputList3Cue284=text-o273 InputList3SigType284=Serial InputList3Cue285=text-o274 InputList3SigType285=Serial InputList3Cue286=text-o275 InputList3SigType286=Serial InputList3Cue287=text-o276 InputList3SigType287=Serial InputList3Cue288=text-o277 InputList3SigType288=Serial InputList3Cue289=text-o278 InputList3SigType289=Serial InputList3Cue290=text-o279 InputList3SigType290=Serial InputList3Cue291=text-o280 InputList3SigType291=Serial InputList3Cue292=text-o281 InputList3SigType292=Serial InputList3Cue293=text-o282 InputList3SigType293=Serial InputList3Cue294=text-o283 InputList3SigType294=Serial InputList3Cue295=text-o284 InputList3SigType295=Serial InputList3Cue296=text-o285 InputList3SigType296=Serial InputList3Cue297=text-o286 InputList3SigType297=Serial InputList3Cue298=text-o287 InputList3SigType298=Serial InputList3Cue299=text-o288 InputList3SigType299=Serial InputList3Cue300=text-o289 InputList3SigType300=Serial InputList3Cue301=text-o290 InputList3SigType301=Serial InputList3Cue302=text-o291 InputList3SigType302=Serial InputList3Cue303=text-o292 InputList3SigType303=Serial InputList3Cue304=text-o293 InputList3SigType304=Serial InputList3Cue305=text-o294 InputList3SigType305=Serial InputList3Cue306=text-o295 InputList3SigType306=Serial InputList3Cue307=text-o296 InputList3SigType307=Serial InputList3Cue308=text-o297 InputList3SigType308=Serial InputList3Cue309=text-o298 InputList3SigType309=Serial InputList3Cue310=text-o299 InputList3SigType310=Serial InputList3Cue311=text-o300 InputList3SigType311=Serial InputList3Cue312=text-o301 InputList3SigType312=Serial InputList3Cue313=text-o302 InputList3SigType313=Serial InputList3Cue314=text-o303 InputList3SigType314=Serial InputList3Cue315=text-o304 InputList3SigType315=Serial InputList3Cue316=text-o305 InputList3SigType316=Serial InputList3Cue317=text-o306 InputList3SigType317=Serial InputList3Cue318=text-o307 InputList3SigType318=Serial InputList3Cue319=text-o308 InputList3SigType319=Serial InputList3Cue320=text-o309 InputList3SigType320=Serial InputList3Cue321=text-o310 InputList3SigType321=Serial InputList3Cue322=text-o311 InputList3SigType322=Serial InputList3Cue323=text-o312 InputList3SigType323=Serial InputList3Cue324=text-o313 InputList3SigType324=Serial InputList3Cue325=text-o314 InputList3SigType325=Serial InputList3Cue326=text-o315 InputList3SigType326=Serial InputList3Cue327=text-o316 InputList3SigType327=Serial InputList3Cue328=text-o317 InputList3SigType328=Serial InputList3Cue329=text-o318 InputList3SigType329=Serial InputList3Cue330=text-o319 InputList3SigType330=Serial InputList3Cue331=text-o320 InputList3SigType331=Serial InputList3Cue332=text-o321 InputList3SigType332=Serial InputList3Cue333=text-o322 InputList3SigType333=Serial InputList3Cue334=text-o323 InputList3SigType334=Serial InputList3Cue335=text-o324 InputList3SigType335=Serial InputList3Cue336=text-o325 InputList3SigType336=Serial InputList3Cue337=text-o326 InputList3SigType337=Serial InputList3Cue338=text-o327 InputList3SigType338=Serial InputList3Cue339=text-o328 InputList3SigType339=Serial InputList3Cue340=text-o329 InputList3SigType340=Serial InputList3Cue341=text-o330 InputList3SigType341=Serial InputList3Cue342=text-o331 InputList3SigType342=Serial InputList3Cue343=text-o332 InputList3SigType343=Serial InputList3Cue344=text-o333 InputList3SigType344=Serial InputList3Cue345=text-o334 InputList3SigType345=Serial InputList3Cue346=text-o335 InputList3SigType346=Serial InputList3Cue347=text-o336 InputList3SigType347=Serial InputList3Cue348=text-o337 InputList3SigType348=Serial InputList3Cue349=text-o338 InputList3SigType349=Serial InputList3Cue350=text-o339 InputList3SigType350=Serial InputList3Cue351=text-o340 InputList3SigType351=Serial InputList3Cue352=text-o341 InputList3SigType352=Serial InputList3Cue353=text-o342 InputList3SigType353=Serial InputList3Cue354=text-o343 InputList3SigType354=Serial InputList3Cue355=text-o344 InputList3SigType355=Serial InputList3Cue356=text-o345 InputList3SigType356=Serial InputList3Cue357=text-o346 InputList3SigType357=Serial InputList3Cue358=text-o347 InputList3SigType358=Serial InputList3Cue359=text-o348 InputList3SigType359=Serial InputList3Cue360=text-o349 InputList3SigType360=Serial InputList3Cue361=text-o350 InputList3SigType361=Serial InputList3Cue362=text-o351 InputList3SigType362=Serial InputList3Cue363=text-o352 InputList3SigType363=Serial InputList3Cue364=text-o353 InputList3SigType364=Serial InputList3Cue365=text-o354 InputList3SigType365=Serial InputList3Cue366=text-o355 InputList3SigType366=Serial InputList3Cue367=text-o356 InputList3SigType367=Serial InputList3Cue368=text-o357 InputList3SigType368=Serial InputList3Cue369=text-o358 InputList3SigType369=Serial InputList3Cue370=text-o359 InputList3SigType370=Serial InputList3Cue371=text-o360 InputList3SigType371=Serial InputList3Cue372=text-o361 InputList3SigType372=Serial InputList3Cue373=text-o362 InputList3SigType373=Serial InputList3Cue374=text-o363 InputList3SigType374=Serial InputList3Cue375=text-o364 InputList3SigType375=Serial InputList3Cue376=text-o365 InputList3SigType376=Serial InputList3Cue377=text-o366 InputList3SigType377=Serial InputList3Cue378=text-o367 InputList3SigType378=Serial InputList3Cue379=text-o368 InputList3SigType379=Serial InputList3Cue380=text-o369 InputList3SigType380=Serial InputList3Cue381=text-o370 InputList3SigType381=Serial InputList3Cue382=text-o371 InputList3SigType382=Serial InputList3Cue383=text-o372 InputList3SigType383=Serial InputList3Cue384=text-o373 InputList3SigType384=Serial InputList3Cue385=text-o374 InputList3SigType385=Serial InputList3Cue386=text-o375 InputList3SigType386=Serial InputList3Cue387=text-o376 InputList3SigType387=Serial InputList3Cue388=text-o377 InputList3SigType388=Serial InputList3Cue389=text-o378 InputList3SigType389=Serial InputList3Cue390=text-o379 InputList3SigType390=Serial InputList3Cue391=text-o380 InputList3SigType391=Serial InputList3Cue392=text-o381 InputList3SigType392=Serial InputList3Cue393=text-o382 InputList3SigType393=Serial InputList3Cue394=text-o383 InputList3SigType394=Serial InputList3Cue395=text-o384 InputList3SigType395=Serial InputList3Cue396=text-o385 InputList3SigType396=Serial InputList3Cue397=text-o386 InputList3SigType397=Serial InputList3Cue398=text-o387 InputList3SigType398=Serial InputList3Cue399=text-o388 InputList3SigType399=Serial InputList3Cue400=text-o389 InputList3SigType400=Serial InputList3Cue401=text-o390 InputList3SigType401=Serial InputList3Cue402=text-o391 InputList3SigType402=Serial InputList3Cue403=text-o392 InputList3SigType403=Serial InputList3Cue404=text-o393 InputList3SigType404=Serial InputList3Cue405=text-o394 InputList3SigType405=Serial InputList3Cue406=text-o395 InputList3SigType406=Serial InputList3Cue407=text-o396 InputList3SigType407=Serial InputList3Cue408=text-o397 InputList3SigType408=Serial InputList3Cue409=text-o398 InputList3SigType409=Serial InputList3Cue410=text-o399 InputList3SigType410=Serial InputList3Cue411=text-o400 InputList3SigType411=Serial InputList3Cue412=[~EndGroup~]text-o InputList3SigType412=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=text-i121 OutputList3SigType132=Serial OutputList3Cue133=text-i122 OutputList3SigType133=Serial OutputList3Cue134=text-i123 OutputList3SigType134=Serial OutputList3Cue135=text-i124 OutputList3SigType135=Serial OutputList3Cue136=text-i125 OutputList3SigType136=Serial OutputList3Cue137=text-i126 OutputList3SigType137=Serial OutputList3Cue138=text-i127 OutputList3SigType138=Serial OutputList3Cue139=text-i128 OutputList3SigType139=Serial OutputList3Cue140=text-i129 OutputList3SigType140=Serial OutputList3Cue141=text-i130 OutputList3SigType141=Serial OutputList3Cue142=text-i131 OutputList3SigType142=Serial OutputList3Cue143=text-i132 OutputList3SigType143=Serial OutputList3Cue144=text-i133 OutputList3SigType144=Serial OutputList3Cue145=text-i134 OutputList3SigType145=Serial OutputList3Cue146=text-i135 OutputList3SigType146=Serial OutputList3Cue147=text-i136 OutputList3SigType147=Serial OutputList3Cue148=text-i137 OutputList3SigType148=Serial OutputList3Cue149=text-i138 OutputList3SigType149=Serial OutputList3Cue150=text-i139 OutputList3SigType150=Serial OutputList3Cue151=text-i140 OutputList3SigType151=Serial OutputList3Cue152=text-i141 OutputList3SigType152=Serial OutputList3Cue153=text-i142 OutputList3SigType153=Serial OutputList3Cue154=text-i143 OutputList3SigType154=Serial OutputList3Cue155=text-i144 OutputList3SigType155=Serial OutputList3Cue156=text-i145 OutputList3SigType156=Serial OutputList3Cue157=text-i146 OutputList3SigType157=Serial OutputList3Cue158=text-i147 OutputList3SigType158=Serial OutputList3Cue159=text-i148 OutputList3SigType159=Serial OutputList3Cue160=text-i149 OutputList3SigType160=Serial OutputList3Cue161=text-i150 OutputList3SigType161=Serial OutputList3Cue162=text-i151 OutputList3SigType162=Serial OutputList3Cue163=text-i152 OutputList3SigType163=Serial OutputList3Cue164=text-i153 OutputList3SigType164=Serial OutputList3Cue165=text-i154 OutputList3SigType165=Serial OutputList3Cue166=text-i155 OutputList3SigType166=Serial OutputList3Cue167=text-i156 OutputList3SigType167=Serial OutputList3Cue168=text-i157 OutputList3SigType168=Serial OutputList3Cue169=text-i158 OutputList3SigType169=Serial OutputList3Cue170=text-i159 OutputList3SigType170=Serial OutputList3Cue171=text-i160 OutputList3SigType171=Serial OutputList3Cue172=text-i161 OutputList3SigType172=Serial OutputList3Cue173=text-i162 OutputList3SigType173=Serial OutputList3Cue174=text-i163 OutputList3SigType174=Serial OutputList3Cue175=text-i164 OutputList3SigType175=Serial OutputList3Cue176=text-i165 OutputList3SigType176=Serial OutputList3Cue177=text-i166 OutputList3SigType177=Serial OutputList3Cue178=text-i167 OutputList3SigType178=Serial OutputList3Cue179=text-i168 OutputList3SigType179=Serial OutputList3Cue180=text-i169 OutputList3SigType180=Serial OutputList3Cue181=text-i170 OutputList3SigType181=Serial OutputList3Cue182=text-i171 OutputList3SigType182=Serial OutputList3Cue183=text-i172 OutputList3SigType183=Serial OutputList3Cue184=text-i173 OutputList3SigType184=Serial OutputList3Cue185=text-i174 OutputList3SigType185=Serial OutputList3Cue186=text-i175 OutputList3SigType186=Serial OutputList3Cue187=text-i176 OutputList3SigType187=Serial OutputList3Cue188=text-i177 OutputList3SigType188=Serial OutputList3Cue189=text-i178 OutputList3SigType189=Serial OutputList3Cue190=text-i179 OutputList3SigType190=Serial OutputList3Cue191=text-i180 OutputList3SigType191=Serial OutputList3Cue192=text-i181 OutputList3SigType192=Serial OutputList3Cue193=text-i182 OutputList3SigType193=Serial OutputList3Cue194=text-i183 OutputList3SigType194=Serial OutputList3Cue195=text-i184 OutputList3SigType195=Serial OutputList3Cue196=text-i185 OutputList3SigType196=Serial OutputList3Cue197=text-i186 OutputList3SigType197=Serial OutputList3Cue198=text-i187 OutputList3SigType198=Serial OutputList3Cue199=text-i188 OutputList3SigType199=Serial OutputList3Cue200=text-i189 OutputList3SigType200=Serial OutputList3Cue201=text-i190 OutputList3SigType201=Serial OutputList3Cue202=text-i191 OutputList3SigType202=Serial OutputList3Cue203=text-i192 OutputList3SigType203=Serial OutputList3Cue204=text-i193 OutputList3SigType204=Serial OutputList3Cue205=text-i194 OutputList3SigType205=Serial OutputList3Cue206=text-i195 OutputList3SigType206=Serial OutputList3Cue207=text-i196 OutputList3SigType207=Serial OutputList3Cue208=text-i197 OutputList3SigType208=Serial OutputList3Cue209=text-i198 OutputList3SigType209=Serial OutputList3Cue210=text-i199 OutputList3SigType210=Serial OutputList3Cue211=text-i200 OutputList3SigType211=Serial OutputList3Cue212=text-i201 OutputList3SigType212=Serial OutputList3Cue213=text-i202 OutputList3SigType213=Serial OutputList3Cue214=text-i203 OutputList3SigType214=Serial OutputList3Cue215=text-i204 OutputList3SigType215=Serial OutputList3Cue216=text-i205 OutputList3SigType216=Serial OutputList3Cue217=text-i206 OutputList3SigType217=Serial OutputList3Cue218=text-i207 OutputList3SigType218=Serial OutputList3Cue219=text-i208 OutputList3SigType219=Serial OutputList3Cue220=text-i209 OutputList3SigType220=Serial OutputList3Cue221=text-i210 OutputList3SigType221=Serial OutputList3Cue222=text-i211 OutputList3SigType222=Serial OutputList3Cue223=text-i212 OutputList3SigType223=Serial OutputList3Cue224=text-i213 OutputList3SigType224=Serial OutputList3Cue225=text-i214 OutputList3SigType225=Serial OutputList3Cue226=text-i215 OutputList3SigType226=Serial OutputList3Cue227=text-i216 OutputList3SigType227=Serial OutputList3Cue228=text-i217 OutputList3SigType228=Serial OutputList3Cue229=text-i218 OutputList3SigType229=Serial OutputList3Cue230=text-i219 OutputList3SigType230=Serial OutputList3Cue231=text-i220 OutputList3SigType231=Serial OutputList3Cue232=text-i221 OutputList3SigType232=Serial OutputList3Cue233=text-i222 OutputList3SigType233=Serial OutputList3Cue234=text-i223 OutputList3SigType234=Serial OutputList3Cue235=text-i224 OutputList3SigType235=Serial OutputList3Cue236=text-i225 OutputList3SigType236=Serial OutputList3Cue237=text-i226 OutputList3SigType237=Serial OutputList3Cue238=text-i227 OutputList3SigType238=Serial OutputList3Cue239=text-i228 OutputList3SigType239=Serial OutputList3Cue240=text-i229 OutputList3SigType240=Serial OutputList3Cue241=text-i230 OutputList3SigType241=Serial OutputList3Cue242=text-i231 OutputList3SigType242=Serial OutputList3Cue243=text-i232 OutputList3SigType243=Serial OutputList3Cue244=text-i233 OutputList3SigType244=Serial OutputList3Cue245=text-i234 OutputList3SigType245=Serial OutputList3Cue246=text-i235 OutputList3SigType246=Serial OutputList3Cue247=text-i236 OutputList3SigType247=Serial OutputList3Cue248=text-i237 OutputList3SigType248=Serial OutputList3Cue249=text-i238 OutputList3SigType249=Serial OutputList3Cue250=text-i239 OutputList3SigType250=Serial OutputList3Cue251=text-i240 OutputList3SigType251=Serial OutputList3Cue252=text-i241 OutputList3SigType252=Serial OutputList3Cue253=text-i242 OutputList3SigType253=Serial OutputList3Cue254=text-i243 OutputList3SigType254=Serial OutputList3Cue255=text-i244 OutputList3SigType255=Serial OutputList3Cue256=text-i245 OutputList3SigType256=Serial OutputList3Cue257=text-i246 OutputList3SigType257=Serial OutputList3Cue258=text-i247 OutputList3SigType258=Serial OutputList3Cue259=text-i248 OutputList3SigType259=Serial OutputList3Cue260=text-i249 OutputList3SigType260=Serial OutputList3Cue261=text-i250 OutputList3SigType261=Serial OutputList3Cue262=text-i251 OutputList3SigType262=Serial OutputList3Cue263=text-i252 OutputList3SigType263=Serial OutputList3Cue264=text-i253 OutputList3SigType264=Serial OutputList3Cue265=text-i254 OutputList3SigType265=Serial OutputList3Cue266=text-i255 OutputList3SigType266=Serial OutputList3Cue267=text-i256 OutputList3SigType267=Serial OutputList3Cue268=text-i257 OutputList3SigType268=Serial OutputList3Cue269=text-i258 OutputList3SigType269=Serial OutputList3Cue270=text-i259 OutputList3SigType270=Serial OutputList3Cue271=text-i260 OutputList3SigType271=Serial OutputList3Cue272=text-i261 OutputList3SigType272=Serial OutputList3Cue273=text-i262 OutputList3SigType273=Serial OutputList3Cue274=text-i263 OutputList3SigType274=Serial OutputList3Cue275=text-i264 OutputList3SigType275=Serial OutputList3Cue276=text-i265 OutputList3SigType276=Serial OutputList3Cue277=text-i266 OutputList3SigType277=Serial OutputList3Cue278=text-i267 OutputList3SigType278=Serial OutputList3Cue279=text-i268 OutputList3SigType279=Serial OutputList3Cue280=text-i269 OutputList3SigType280=Serial OutputList3Cue281=text-i270 OutputList3SigType281=Serial OutputList3Cue282=text-i271 OutputList3SigType282=Serial OutputList3Cue283=text-i272 OutputList3SigType283=Serial OutputList3Cue284=text-i273 OutputList3SigType284=Serial OutputList3Cue285=text-i274 OutputList3SigType285=Serial OutputList3Cue286=text-i275 OutputList3SigType286=Serial OutputList3Cue287=text-i276 OutputList3SigType287=Serial OutputList3Cue288=text-i277 OutputList3SigType288=Serial OutputList3Cue289=text-i278 OutputList3SigType289=Serial OutputList3Cue290=text-i279 OutputList3SigType290=Serial OutputList3Cue291=text-i280 OutputList3SigType291=Serial OutputList3Cue292=text-i281 OutputList3SigType292=Serial OutputList3Cue293=text-i282 OutputList3SigType293=Serial OutputList3Cue294=text-i283 OutputList3SigType294=Serial OutputList3Cue295=text-i284 OutputList3SigType295=Serial OutputList3Cue296=text-i285 OutputList3SigType296=Serial OutputList3Cue297=text-i286 OutputList3SigType297=Serial OutputList3Cue298=text-i287 OutputList3SigType298=Serial OutputList3Cue299=text-i288 OutputList3SigType299=Serial OutputList3Cue300=text-i289 OutputList3SigType300=Serial OutputList3Cue301=text-i290 OutputList3SigType301=Serial OutputList3Cue302=text-i291 OutputList3SigType302=Serial OutputList3Cue303=text-i292 OutputList3SigType303=Serial OutputList3Cue304=text-i293 OutputList3SigType304=Serial OutputList3Cue305=text-i294 OutputList3SigType305=Serial OutputList3Cue306=text-i295 OutputList3SigType306=Serial OutputList3Cue307=text-i296 OutputList3SigType307=Serial OutputList3Cue308=text-i297 OutputList3SigType308=Serial OutputList3Cue309=text-i298 OutputList3SigType309=Serial OutputList3Cue310=text-i299 OutputList3SigType310=Serial OutputList3Cue311=text-i300 OutputList3SigType311=Serial OutputList3Cue312=text-i301 OutputList3SigType312=Serial OutputList3Cue313=text-i302 OutputList3SigType313=Serial OutputList3Cue314=text-i303 OutputList3SigType314=Serial OutputList3Cue315=text-i304 OutputList3SigType315=Serial OutputList3Cue316=text-i305 OutputList3SigType316=Serial OutputList3Cue317=text-i306 OutputList3SigType317=Serial OutputList3Cue318=text-i307 OutputList3SigType318=Serial OutputList3Cue319=text-i308 OutputList3SigType319=Serial OutputList3Cue320=text-i309 OutputList3SigType320=Serial OutputList3Cue321=text-i310 OutputList3SigType321=Serial OutputList3Cue322=text-i311 OutputList3SigType322=Serial OutputList3Cue323=text-i312 OutputList3SigType323=Serial OutputList3Cue324=text-i313 OutputList3SigType324=Serial OutputList3Cue325=text-i314 OutputList3SigType325=Serial OutputList3Cue326=text-i315 OutputList3SigType326=Serial OutputList3Cue327=text-i316 OutputList3SigType327=Serial OutputList3Cue328=text-i317 OutputList3SigType328=Serial OutputList3Cue329=text-i318 OutputList3SigType329=Serial OutputList3Cue330=text-i319 OutputList3SigType330=Serial OutputList3Cue331=text-i320 OutputList3SigType331=Serial OutputList3Cue332=text-i321 OutputList3SigType332=Serial OutputList3Cue333=text-i322 OutputList3SigType333=Serial OutputList3Cue334=text-i323 OutputList3SigType334=Serial OutputList3Cue335=text-i324 OutputList3SigType335=Serial OutputList3Cue336=text-i325 OutputList3SigType336=Serial OutputList3Cue337=text-i326 OutputList3SigType337=Serial OutputList3Cue338=text-i327 OutputList3SigType338=Serial OutputList3Cue339=text-i328 OutputList3SigType339=Serial OutputList3Cue340=text-i329 OutputList3SigType340=Serial OutputList3Cue341=text-i330 OutputList3SigType341=Serial OutputList3Cue342=text-i331 OutputList3SigType342=Serial OutputList3Cue343=text-i332 OutputList3SigType343=Serial OutputList3Cue344=text-i333 OutputList3SigType344=Serial OutputList3Cue345=text-i334 OutputList3SigType345=Serial OutputList3Cue346=text-i335 OutputList3SigType346=Serial OutputList3Cue347=text-i336 OutputList3SigType347=Serial OutputList3Cue348=text-i337 OutputList3SigType348=Serial OutputList3Cue349=text-i338 OutputList3SigType349=Serial OutputList3Cue350=text-i339 OutputList3SigType350=Serial OutputList3Cue351=text-i340 OutputList3SigType351=Serial OutputList3Cue352=text-i341 OutputList3SigType352=Serial OutputList3Cue353=text-i342 OutputList3SigType353=Serial OutputList3Cue354=text-i343 OutputList3SigType354=Serial OutputList3Cue355=text-i344 OutputList3SigType355=Serial OutputList3Cue356=text-i345 OutputList3SigType356=Serial OutputList3Cue357=text-i346 OutputList3SigType357=Serial OutputList3Cue358=text-i347 OutputList3SigType358=Serial OutputList3Cue359=text-i348 OutputList3SigType359=Serial OutputList3Cue360=text-i349 OutputList3SigType360=Serial OutputList3Cue361=text-i350 OutputList3SigType361=Serial OutputList3Cue362=text-i351 OutputList3SigType362=Serial OutputList3Cue363=text-i352 OutputList3SigType363=Serial OutputList3Cue364=text-i353 OutputList3SigType364=Serial OutputList3Cue365=text-i354 OutputList3SigType365=Serial OutputList3Cue366=text-i355 OutputList3SigType366=Serial OutputList3Cue367=text-i356 OutputList3SigType367=Serial OutputList3Cue368=text-i357 OutputList3SigType368=Serial OutputList3Cue369=text-i358 OutputList3SigType369=Serial OutputList3Cue370=text-i359 OutputList3SigType370=Serial OutputList3Cue371=text-i360 OutputList3SigType371=Serial OutputList3Cue372=text-i361 OutputList3SigType372=Serial OutputList3Cue373=text-i362 OutputList3SigType373=Serial OutputList3Cue374=text-i363 OutputList3SigType374=Serial OutputList3Cue375=text-i364 OutputList3SigType375=Serial OutputList3Cue376=text-i365 OutputList3SigType376=Serial OutputList3Cue377=text-i366 OutputList3SigType377=Serial OutputList3Cue378=text-i367 OutputList3SigType378=Serial OutputList3Cue379=text-i368 OutputList3SigType379=Serial OutputList3Cue380=text-i369 OutputList3SigType380=Serial OutputList3Cue381=text-i370 OutputList3SigType381=Serial OutputList3Cue382=text-i371 OutputList3SigType382=Serial OutputList3Cue383=text-i372 OutputList3SigType383=Serial OutputList3Cue384=text-i373 OutputList3SigType384=Serial OutputList3Cue385=text-i374 OutputList3SigType385=Serial OutputList3Cue386=text-i375 OutputList3SigType386=Serial OutputList3Cue387=text-i376 OutputList3SigType387=Serial OutputList3Cue388=text-i377 OutputList3SigType388=Serial OutputList3Cue389=text-i378 OutputList3SigType389=Serial OutputList3Cue390=text-i379 OutputList3SigType390=Serial OutputList3Cue391=text-i380 OutputList3SigType391=Serial OutputList3Cue392=text-i381 OutputList3SigType392=Serial OutputList3Cue393=text-i382 OutputList3SigType393=Serial OutputList3Cue394=text-i383 OutputList3SigType394=Serial OutputList3Cue395=text-i384 OutputList3SigType395=Serial OutputList3Cue396=text-i385 OutputList3SigType396=Serial OutputList3Cue397=text-i386 OutputList3SigType397=Serial OutputList3Cue398=text-i387 OutputList3SigType398=Serial OutputList3Cue399=text-i388 OutputList3SigType399=Serial OutputList3Cue400=text-i389 OutputList3SigType400=Serial OutputList3Cue401=text-i390 OutputList3SigType401=Serial OutputList3Cue402=text-i391 OutputList3SigType402=Serial OutputList3Cue403=text-i392 OutputList3SigType403=Serial OutputList3Cue404=text-i393 OutputList3SigType404=Serial OutputList3Cue405=text-i394 OutputList3SigType405=Serial OutputList3Cue406=text-i395 OutputList3SigType406=Serial OutputList3Cue407=text-i396 OutputList3SigType407=Serial OutputList3Cue408=text-i397 OutputList3SigType408=Serial OutputList3Cue409=text-i398 OutputList3SigType409=Serial OutputList3Cue410=text-i399 OutputList3SigType410=Serial OutputList3Cue411=text-i400 OutputList3SigType411=Serial OutputList3Cue412=[~EndGroup~]text-i OutputList3SigType412=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=10 CedH=10 SmartObjId=10012d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=10 Tp=1 HD=TRUE DV=10012d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=10 Name=PepperDash Essentials TSW-760_[B.AV] Object - Presets_CATV Icon List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[B.AV] Object - DPad STB_STB DPad.ced Hint=STB DPad (Smart Object ID=10011) Code=11 SGControlType=DPad SGControlName=STB DPad GUID=F2340FAD-85E9-4E49-B46E-15E9B096F58B SmplCName=PepperDash Essentials TSW-760_[B.AV] Object - DPad STB_STB DPad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10015 ;Define the number of inputs, outputs and parameters MinVariableInputs=5 MaxVariableInputs=5 MinVariableOutputs=5 MaxVariableOutputs=5 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Up OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=Down OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Left OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=Right OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=OK OutputSigType5=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=11 CedH=11 SmartObjId=10011d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=11 Tp=1 HD=TRUE DV=10011d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=11 Name=PepperDash Essentials TSW-760_[B.AV] Object - DPad STB_STB DPad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced Hint=Tab Button Horizontal (Smart Object ID=10081) Code=12 SGControlType=Horizontal Tab Button SGControlName=Tab Button Horizontal GUID=198C97B0-9D0C-46C2-9557-27EA33C0BE9F SmplCName=PepperDash Essentials TSW-760_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced SMWRev=4.02.19 Expand=expand_random HelpID=10031 ;Define the number of inputs, outputs and parameters MinVariableInputs=4 MaxVariableInputs=4 MinVariableOutputs=4 MaxVariableOutputs=4 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Tab Button 1 Press OutputSigType1=Digital InputCue2=Tab Button 1 Select InputSigType2=Digital OutputCue2=[~UNUSED3~] OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Tab Button 2 Press OutputSigType3=Digital InputCue4=Tab Button 2 Select InputSigType4=Digital OutputCue4=[~UNUSED3~] OutputSigType4=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=12 CedH=12 SmartObjId=10081d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=12 Tp=1 HD=TRUE DV=10081d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=12 Name=PepperDash Essentials TSW-760_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[B.AV] Object - Dpad DVD_DVD DPad.ced Hint=DVD DPad (Smart Object ID=10411) Code=13 SGControlType=DPad SGControlName=DVD DPad GUID=D49BCF22-C770-4146-93E6-00867D885E1E SmplCName=PepperDash Essentials TSW-760_[B.AV] Object - Dpad DVD_DVD DPad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10015 ;Define the number of inputs, outputs and parameters MinVariableInputs=5 MaxVariableInputs=5 MinVariableOutputs=5 MaxVariableOutputs=5 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Up OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=Down OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Left OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=Right OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=OK OutputSigType5=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=13 CedH=13 SmartObjId=10411d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=13 Tp=1 HD=TRUE DV=10411d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=13 Name=PepperDash Essentials TSW-760_[B.AV] Object - Dpad DVD_DVD DPad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced Hint=CATV Keypad (Smart Object ID=10014) Code=14 SGControlType=Simple Keypad SGControlName=CATV Keypad GUID=5E33D4F4-5C5F-430C-879A-AE82529B3943 SmplCName=PepperDash Essentials TSW-760_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=Misc_1 OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=Misc_2 OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=14 CedH=14 SmartObjId=10014d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=14 Tp=1 HD=TRUE DV=10014d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=14 Name=PepperDash Essentials TSW-760_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced Hint=CATV Icon List Vertical (Smart Object ID=3333) Code=15 SGControlType=Subpage Reference List Vertical SGControlName=CATV Icon List Vertical GUID=D6A79678-BAD2-4F6D-8104-A941FBA9432F SmplCName=PepperDash Essentials TSW-760_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4106 MaxVariableInputs=4106 MinVariableOutputs=4106 MaxVariableOutputs=4106 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=132 MaxVariableInputsList3=132 MinVariableOutputsList3=132 MaxVariableOutputsList3=132 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=[~EndGroup~]fb InputSigType4106=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=[~EndGroup~]Press OutputSigType4106=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=[~EndGroup~]text-o InputList3SigType132=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=[~EndGroup~]text-i OutputList3SigType132=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=15 CedH=15 SmartObjId=3333d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=15 Tp=1 HD=TRUE DV=3333d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=15 Name=PepperDash Essentials TSW-760_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced Hint=Subpage Reference List Vertical_2 (Smart Object ID=1001) Code=16 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_2 GUID=5F63F5C2-A987-4957-9243-C28805CE297E SmplCName=PepperDash Essentials TSW-760_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4036 MaxVariableInputs=4036 MinVariableOutputs=4036 MaxVariableOutputs=4036 NumFixedParams=1 MinVariableInputsList2=32 MaxVariableInputsList2=32 MinVariableOutputsList2=32 MaxVariableOutputsList2=32 MinVariableInputsList3=32 MaxVariableInputsList3=32 MinVariableOutputsList3=32 MaxVariableOutputsList3=32 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=[~UNUSED2~] InputSigType16=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=[~UNUSED2~] InputSigType2018=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=[~EndGroup~]fb InputSigType4036=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED2~] OutputSigType16=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED2~] OutputSigType2018=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=[~EndGroup~]Press OutputSigType4036=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=[~EndGroup~]an_fb InputList2SigType32=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=[~EndGroup~]an_act OutputList2SigType32=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=[~EndGroup~]text-o InputList3SigType32=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=[~EndGroup~]text-i OutputList3SigType32=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=16 CedH=16 SmartObjId=1001d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=16 Tp=1 HD=TRUE DV=1001d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=16 Name=PepperDash Essentials TSW-760_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced Hint=Dynamic Button List Vertical (Smart Object ID=3901) Code=17 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical GUID=15B95903-FB30-472E-9D10-82A9C3A9D7C7 SmplCName=PepperDash Essentials TSW-760_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=[~UNUSED2~] InputSigType22=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=[~UNUSED2~] InputSigType2024=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=[~UNUSED2~] InputSigType4026=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=[~UNUSED2~] OutputSigType22=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED2~] OutputSigType2024=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED2~] OutputSigType4026=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=[~UNUSED2~] InputList2SigType22=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED2~] OutputList2SigType22=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=[~UNUSED2~] InputList3SigType22=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=[~UNUSED2~] InputList3SigType2024=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED2~] OutputList3SigType22=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED2~] OutputList3SigType2024=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=17 CedH=17 SmartObjId=3901d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=17 Tp=1 HD=TRUE DV=3901d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=17 Name=PepperDash Essentials TSW-760_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced Hint=Subpage Reference List Vertical (Smart Object ID=15023) Code=18 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical GUID=EC6E6B35-F033-4F14-9465-FEEBE20455CC SmplCName=PepperDash Essentials TSW-760_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4052 MaxVariableInputs=4052 MinVariableOutputs=4052 MaxVariableOutputs=4052 NumFixedParams=1 MinVariableInputsList2=48 MaxVariableInputsList2=48 MinVariableOutputsList2=48 MaxVariableOutputsList2=48 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=[~UNUSED2~] InputSigType24=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=[~UNUSED2~] InputSigType2026=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=[~EndGroup~]fb InputSigType4052=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED2~] OutputSigType24=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED2~] OutputSigType2026=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=[~EndGroup~]Press OutputSigType4052=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=[~EndGroup~]an_fb InputList2SigType48=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=[~EndGroup~]an_act OutputList2SigType48=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=18 CedH=18 SmartObjId=15023d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=18 Tp=1 HD=TRUE DV=15023d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=18 Name=PepperDash Essentials TSW-760_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials TSW-760_[D.VC] Recents_Dynamic Button List Vertical_2.ced Hint=Dynamic Button List Vertical_2 (Smart Object ID=1203) Code=19 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical_2 GUID=2C4B55E4-42AC-486D-BC6E-C7DD7D24C974 SmplCName=PepperDash Essentials TSW-760_[D.VC] Recents_Dynamic Button List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=Item 11 Selected InputSigType22=Digital InputCue23=Item 12 Selected InputSigType23=Digital InputCue24=Item 13 Selected InputSigType24=Digital InputCue25=Item 14 Selected InputSigType25=Digital InputCue26=Item 15 Selected InputSigType26=Digital InputCue27=Item 16 Selected InputSigType27=Digital InputCue28=Item 17 Selected InputSigType28=Digital InputCue29=Item 18 Selected InputSigType29=Digital InputCue30=Item 19 Selected InputSigType30=Digital InputCue31=Item 20 Selected InputSigType31=Digital InputCue32=Item 21 Selected InputSigType32=Digital InputCue33=Item 22 Selected InputSigType33=Digital InputCue34=Item 23 Selected InputSigType34=Digital InputCue35=Item 24 Selected InputSigType35=Digital InputCue36=Item 25 Selected InputSigType36=Digital InputCue37=Item 26 Selected InputSigType37=Digital InputCue38=Item 27 Selected InputSigType38=Digital InputCue39=Item 28 Selected InputSigType39=Digital InputCue40=Item 29 Selected InputSigType40=Digital InputCue41=Item 30 Selected InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=Item 11 Enabled InputSigType2024=Digital InputCue2025=Item 12 Enabled InputSigType2025=Digital InputCue2026=Item 13 Enabled InputSigType2026=Digital InputCue2027=Item 14 Enabled InputSigType2027=Digital InputCue2028=Item 15 Enabled InputSigType2028=Digital InputCue2029=Item 16 Enabled InputSigType2029=Digital InputCue2030=Item 17 Enabled InputSigType2030=Digital InputCue2031=Item 18 Enabled InputSigType2031=Digital InputCue2032=Item 19 Enabled InputSigType2032=Digital InputCue2033=Item 20 Enabled InputSigType2033=Digital InputCue2034=Item 21 Enabled InputSigType2034=Digital InputCue2035=Item 22 Enabled InputSigType2035=Digital InputCue2036=Item 23 Enabled InputSigType2036=Digital InputCue2037=Item 24 Enabled InputSigType2037=Digital InputCue2038=Item 25 Enabled InputSigType2038=Digital InputCue2039=Item 26 Enabled InputSigType2039=Digital InputCue2040=Item 27 Enabled InputSigType2040=Digital InputCue2041=Item 28 Enabled InputSigType2041=Digital InputCue2042=Item 29 Enabled InputSigType2042=Digital InputCue2043=Item 30 Enabled InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=Item 11 Visible InputSigType4026=Digital InputCue4027=Item 12 Visible InputSigType4027=Digital InputCue4028=Item 13 Visible InputSigType4028=Digital InputCue4029=Item 14 Visible InputSigType4029=Digital InputCue4030=Item 15 Visible InputSigType4030=Digital InputCue4031=Item 16 Visible InputSigType4031=Digital InputCue4032=Item 17 Visible InputSigType4032=Digital InputCue4033=Item 18 Visible InputSigType4033=Digital InputCue4034=Item 19 Visible InputSigType4034=Digital InputCue4035=Item 20 Visible InputSigType4035=Digital InputCue4036=Item 21 Visible InputSigType4036=Digital InputCue4037=Item 22 Visible InputSigType4037=Digital InputCue4038=Item 23 Visible InputSigType4038=Digital InputCue4039=Item 24 Visible InputSigType4039=Digital InputCue4040=Item 25 Visible InputSigType4040=Digital InputCue4041=Item 26 Visible InputSigType4041=Digital InputCue4042=Item 27 Visible InputSigType4042=Digital InputCue4043=Item 28 Visible InputSigType4043=Digital InputCue4044=Item 29 Visible InputSigType4044=Digital InputCue4045=Item 30 Visible InputSigType4045=Digital InputCue4046=[~UNUSED2~] InputSigType4046=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=Item 11 Pressed OutputSigType22=Digital OutputCue23=Item 12 Pressed OutputSigType23=Digital OutputCue24=Item 13 Pressed OutputSigType24=Digital OutputCue25=Item 14 Pressed OutputSigType25=Digital OutputCue26=Item 15 Pressed OutputSigType26=Digital OutputCue27=Item 16 Pressed OutputSigType27=Digital OutputCue28=Item 17 Pressed OutputSigType28=Digital OutputCue29=Item 18 Pressed OutputSigType29=Digital OutputCue30=Item 19 Pressed OutputSigType30=Digital OutputCue31=Item 20 Pressed OutputSigType31=Digital OutputCue32=Item 21 Pressed OutputSigType32=Digital OutputCue33=Item 22 Pressed OutputSigType33=Digital OutputCue34=Item 23 Pressed OutputSigType34=Digital OutputCue35=Item 24 Pressed OutputSigType35=Digital OutputCue36=Item 25 Pressed OutputSigType36=Digital OutputCue37=Item 26 Pressed OutputSigType37=Digital OutputCue38=Item 27 Pressed OutputSigType38=Digital OutputCue39=Item 28 Pressed OutputSigType39=Digital OutputCue40=Item 29 Pressed OutputSigType40=Digital OutputCue41=Item 30 Pressed OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED3~] OutputSigType4026=Digital OutputCue4027=[~UNUSED3~] OutputSigType4027=Digital OutputCue4028=[~UNUSED3~] OutputSigType4028=Digital OutputCue4029=[~UNUSED3~] OutputSigType4029=Digital OutputCue4030=[~UNUSED3~] OutputSigType4030=Digital OutputCue4031=[~UNUSED3~] OutputSigType4031=Digital OutputCue4032=[~UNUSED3~] OutputSigType4032=Digital OutputCue4033=[~UNUSED3~] OutputSigType4033=Digital OutputCue4034=[~UNUSED3~] OutputSigType4034=Digital OutputCue4035=[~UNUSED3~] OutputSigType4035=Digital OutputCue4036=[~UNUSED3~] OutputSigType4036=Digital OutputCue4037=[~UNUSED3~] OutputSigType4037=Digital OutputCue4038=[~UNUSED3~] OutputSigType4038=Digital OutputCue4039=[~UNUSED3~] OutputSigType4039=Digital OutputCue4040=[~UNUSED3~] OutputSigType4040=Digital OutputCue4041=[~UNUSED3~] OutputSigType4041=Digital OutputCue4042=[~UNUSED3~] OutputSigType4042=Digital OutputCue4043=[~UNUSED3~] OutputSigType4043=Digital OutputCue4044=[~UNUSED3~] OutputSigType4044=Digital OutputCue4045=[~UNUSED3~] OutputSigType4045=Digital OutputCue4046=[~UNUSED2~] OutputSigType4046=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=Set Item 11 Icon Analog InputList2SigType22=Analog InputList2Cue23=Set Item 12 Icon Analog InputList2SigType23=Analog InputList2Cue24=Set Item 13 Icon Analog InputList2SigType24=Analog InputList2Cue25=Set Item 14 Icon Analog InputList2SigType25=Analog InputList2Cue26=Set Item 15 Icon Analog InputList2SigType26=Analog InputList2Cue27=Set Item 16 Icon Analog InputList2SigType27=Analog InputList2Cue28=Set Item 17 Icon Analog InputList2SigType28=Analog InputList2Cue29=Set Item 18 Icon Analog InputList2SigType29=Analog InputList2Cue30=Set Item 19 Icon Analog InputList2SigType30=Analog InputList2Cue31=Set Item 20 Icon Analog InputList2SigType31=Analog InputList2Cue32=Set Item 21 Icon Analog InputList2SigType32=Analog InputList2Cue33=Set Item 22 Icon Analog InputList2SigType33=Analog InputList2Cue34=Set Item 23 Icon Analog InputList2SigType34=Analog InputList2Cue35=Set Item 24 Icon Analog InputList2SigType35=Analog InputList2Cue36=Set Item 25 Icon Analog InputList2SigType36=Analog InputList2Cue37=Set Item 26 Icon Analog InputList2SigType37=Analog InputList2Cue38=Set Item 27 Icon Analog InputList2SigType38=Analog InputList2Cue39=Set Item 28 Icon Analog InputList2SigType39=Analog InputList2Cue40=Set Item 29 Icon Analog InputList2SigType40=Analog InputList2Cue41=Set Item 30 Icon Analog InputList2SigType41=Analog InputList2Cue42=[~UNUSED2~] InputList2SigType42=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED3~] OutputList2SigType22=Analog OutputList2Cue23=[~UNUSED3~] OutputList2SigType23=Analog OutputList2Cue24=[~UNUSED3~] OutputList2SigType24=Analog OutputList2Cue25=[~UNUSED3~] OutputList2SigType25=Analog OutputList2Cue26=[~UNUSED3~] OutputList2SigType26=Analog OutputList2Cue27=[~UNUSED3~] OutputList2SigType27=Analog OutputList2Cue28=[~UNUSED3~] OutputList2SigType28=Analog OutputList2Cue29=[~UNUSED3~] OutputList2SigType29=Analog OutputList2Cue30=[~UNUSED3~] OutputList2SigType30=Analog OutputList2Cue31=[~UNUSED3~] OutputList2SigType31=Analog OutputList2Cue32=[~UNUSED3~] OutputList2SigType32=Analog OutputList2Cue33=[~UNUSED3~] OutputList2SigType33=Analog OutputList2Cue34=[~UNUSED3~] OutputList2SigType34=Analog OutputList2Cue35=[~UNUSED3~] OutputList2SigType35=Analog OutputList2Cue36=[~UNUSED3~] OutputList2SigType36=Analog OutputList2Cue37=[~UNUSED3~] OutputList2SigType37=Analog OutputList2Cue38=[~UNUSED3~] OutputList2SigType38=Analog OutputList2Cue39=[~UNUSED3~] OutputList2SigType39=Analog OutputList2Cue40=[~UNUSED3~] OutputList2SigType40=Analog OutputList2Cue41=[~UNUSED3~] OutputList2SigType41=Analog OutputList2Cue42=[~UNUSED2~] OutputList2SigType42=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=Set Item 11 Text InputList3SigType22=Serial InputList3Cue23=Set Item 12 Text InputList3SigType23=Serial InputList3Cue24=Set Item 13 Text InputList3SigType24=Serial InputList3Cue25=Set Item 14 Text InputList3SigType25=Serial InputList3Cue26=Set Item 15 Text InputList3SigType26=Serial InputList3Cue27=Set Item 16 Text InputList3SigType27=Serial InputList3Cue28=Set Item 17 Text InputList3SigType28=Serial InputList3Cue29=Set Item 18 Text InputList3SigType29=Serial InputList3Cue30=Set Item 19 Text InputList3SigType30=Serial InputList3Cue31=Set Item 20 Text InputList3SigType31=Serial InputList3Cue32=Set Item 21 Text InputList3SigType32=Serial InputList3Cue33=Set Item 22 Text InputList3SigType33=Serial InputList3Cue34=Set Item 23 Text InputList3SigType34=Serial InputList3Cue35=Set Item 24 Text InputList3SigType35=Serial InputList3Cue36=Set Item 25 Text InputList3SigType36=Serial InputList3Cue37=Set Item 26 Text InputList3SigType37=Serial InputList3Cue38=Set Item 27 Text InputList3SigType38=Serial InputList3Cue39=Set Item 28 Text InputList3SigType39=Serial InputList3Cue40=Set Item 29 Text InputList3SigType40=Serial InputList3Cue41=Set Item 30 Text InputList3SigType41=Serial InputList3Cue42=[~UNUSED2~] InputList3SigType42=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=Set Item 11 Icon Serial InputList3SigType2024=Serial InputList3Cue2025=Set Item 12 Icon Serial InputList3SigType2025=Serial InputList3Cue2026=Set Item 13 Icon Serial InputList3SigType2026=Serial InputList3Cue2027=Set Item 14 Icon Serial InputList3SigType2027=Serial InputList3Cue2028=Set Item 15 Icon Serial InputList3SigType2028=Serial InputList3Cue2029=Set Item 16 Icon Serial InputList3SigType2029=Serial InputList3Cue2030=Set Item 17 Icon Serial InputList3SigType2030=Serial InputList3Cue2031=Set Item 18 Icon Serial InputList3SigType2031=Serial InputList3Cue2032=Set Item 19 Icon Serial InputList3SigType2032=Serial InputList3Cue2033=Set Item 20 Icon Serial InputList3SigType2033=Serial InputList3Cue2034=Set Item 21 Icon Serial InputList3SigType2034=Serial InputList3Cue2035=Set Item 22 Icon Serial InputList3SigType2035=Serial InputList3Cue2036=Set Item 23 Icon Serial InputList3SigType2036=Serial InputList3Cue2037=Set Item 24 Icon Serial InputList3SigType2037=Serial InputList3Cue2038=Set Item 25 Icon Serial InputList3SigType2038=Serial InputList3Cue2039=Set Item 26 Icon Serial InputList3SigType2039=Serial InputList3Cue2040=Set Item 27 Icon Serial InputList3SigType2040=Serial InputList3Cue2041=Set Item 28 Icon Serial InputList3SigType2041=Serial InputList3Cue2042=Set Item 29 Icon Serial InputList3SigType2042=Serial InputList3Cue2043=Set Item 30 Icon Serial InputList3SigType2043=Serial InputList3Cue2044=[~UNUSED2~] InputList3SigType2044=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED3~] OutputList3SigType22=Serial OutputList3Cue23=[~UNUSED3~] OutputList3SigType23=Serial OutputList3Cue24=[~UNUSED3~] OutputList3SigType24=Serial OutputList3Cue25=[~UNUSED3~] OutputList3SigType25=Serial OutputList3Cue26=[~UNUSED3~] OutputList3SigType26=Serial OutputList3Cue27=[~UNUSED3~] OutputList3SigType27=Serial OutputList3Cue28=[~UNUSED3~] OutputList3SigType28=Serial OutputList3Cue29=[~UNUSED3~] OutputList3SigType29=Serial OutputList3Cue30=[~UNUSED3~] OutputList3SigType30=Serial OutputList3Cue31=[~UNUSED3~] OutputList3SigType31=Serial OutputList3Cue32=[~UNUSED3~] OutputList3SigType32=Serial OutputList3Cue33=[~UNUSED3~] OutputList3SigType33=Serial OutputList3Cue34=[~UNUSED3~] OutputList3SigType34=Serial OutputList3Cue35=[~UNUSED3~] OutputList3SigType35=Serial OutputList3Cue36=[~UNUSED3~] OutputList3SigType36=Serial OutputList3Cue37=[~UNUSED3~] OutputList3SigType37=Serial OutputList3Cue38=[~UNUSED3~] OutputList3SigType38=Serial OutputList3Cue39=[~UNUSED3~] OutputList3SigType39=Serial OutputList3Cue40=[~UNUSED3~] OutputList3SigType40=Serial OutputList3Cue41=[~UNUSED3~] OutputList3SigType41=Serial OutputList3Cue42=[~UNUSED2~] OutputList3SigType42=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED3~] OutputList3SigType2024=Serial OutputList3Cue2025=[~UNUSED3~] OutputList3SigType2025=Serial OutputList3Cue2026=[~UNUSED3~] OutputList3SigType2026=Serial OutputList3Cue2027=[~UNUSED3~] OutputList3SigType2027=Serial OutputList3Cue2028=[~UNUSED3~] OutputList3SigType2028=Serial OutputList3Cue2029=[~UNUSED3~] OutputList3SigType2029=Serial OutputList3Cue2030=[~UNUSED3~] OutputList3SigType2030=Serial OutputList3Cue2031=[~UNUSED3~] OutputList3SigType2031=Serial OutputList3Cue2032=[~UNUSED3~] OutputList3SigType2032=Serial OutputList3Cue2033=[~UNUSED3~] OutputList3SigType2033=Serial OutputList3Cue2034=[~UNUSED3~] OutputList3SigType2034=Serial OutputList3Cue2035=[~UNUSED3~] OutputList3SigType2035=Serial OutputList3Cue2036=[~UNUSED3~] OutputList3SigType2036=Serial OutputList3Cue2037=[~UNUSED3~] OutputList3SigType2037=Serial OutputList3Cue2038=[~UNUSED3~] OutputList3SigType2038=Serial OutputList3Cue2039=[~UNUSED3~] OutputList3SigType2039=Serial OutputList3Cue2040=[~UNUSED3~] OutputList3SigType2040=Serial OutputList3Cue2041=[~UNUSED3~] OutputList3SigType2041=Serial OutputList3Cue2042=[~UNUSED3~] OutputList3SigType2042=Serial OutputList3Cue2043=[~UNUSED3~] OutputList3SigType2043=Serial OutputList3Cue2044=[~UNUSED2~] OutputList3SigType2044=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=19 CedH=19 SmartObjId=1203d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=19 Tp=1 HD=TRUE DV=1203d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=19 Name=PepperDash Essentials TSW-760_[D.VC] Recents_Dynamic Button List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ================================================ FILE: src/PepperDash.Essentials/SGD/PepperDash Essentials iPad.sgd ================================================ [ ObjTp=FSgntr Sgntr=SGD RelVrs=3 VTProeVer=6.1.05 Schema=1 CRCGUID=BA116BF9-17DA-41E0-BF8A-42945AAA686D ] ;================================================================================ [ ObjTp=Hd ProjectFile=PepperDash Essentials iPad.vtp VtpGuid=D8D5F125-CB35-42E9-8AE3-4142597FD2C5 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[C.AC] Keypad_AC DTMF Keypad_2.ced Hint=AC DTMF Keypad_2 (Smart Object ID=1101) Code=1 SGControlType=Simple Keypad SGControlName=AC DTMF Keypad_2 GUID=F2A259FE-82AD-4085-B5A6-22D7B034458C SmplCName=PepperDash Essentials iPad_[C.AC] Keypad_AC DTMF Keypad_2.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=* OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=/# OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=1 CedH=1 SmartObjId=1101d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=1 Tp=1 HD=TRUE DV=1101d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=1 Name=PepperDash Essentials iPad_[C.AC] Keypad_AC DTMF Keypad_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[D.VC] Directory_Dynamic Button List Vertical_2.ced Hint=Dynamic Button List Vertical_2 (Smart Object ID=1202) Code=2 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical_2 GUID=79060F3C-D3A4-4A8D-ACF0-CB2376A31702 SmplCName=PepperDash Essentials iPad_[D.VC] Directory_Dynamic Button List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=Item 11 Selected InputSigType22=Digital InputCue23=Item 12 Selected InputSigType23=Digital InputCue24=Item 13 Selected InputSigType24=Digital InputCue25=Item 14 Selected InputSigType25=Digital InputCue26=Item 15 Selected InputSigType26=Digital InputCue27=Item 16 Selected InputSigType27=Digital InputCue28=Item 17 Selected InputSigType28=Digital InputCue29=Item 18 Selected InputSigType29=Digital InputCue30=Item 19 Selected InputSigType30=Digital InputCue31=Item 20 Selected InputSigType31=Digital InputCue32=Item 21 Selected InputSigType32=Digital InputCue33=Item 22 Selected InputSigType33=Digital InputCue34=Item 23 Selected InputSigType34=Digital InputCue35=Item 24 Selected InputSigType35=Digital InputCue36=Item 25 Selected InputSigType36=Digital InputCue37=Item 26 Selected InputSigType37=Digital InputCue38=Item 27 Selected InputSigType38=Digital InputCue39=Item 28 Selected InputSigType39=Digital InputCue40=Item 29 Selected InputSigType40=Digital InputCue41=Item 30 Selected InputSigType41=Digital InputCue42=Item 31 Selected InputSigType42=Digital InputCue43=Item 32 Selected InputSigType43=Digital InputCue44=Item 33 Selected InputSigType44=Digital InputCue45=Item 34 Selected InputSigType45=Digital InputCue46=Item 35 Selected InputSigType46=Digital InputCue47=Item 36 Selected InputSigType47=Digital InputCue48=Item 37 Selected InputSigType48=Digital InputCue49=Item 38 Selected InputSigType49=Digital InputCue50=Item 39 Selected InputSigType50=Digital InputCue51=Item 40 Selected InputSigType51=Digital InputCue52=Item 41 Selected InputSigType52=Digital InputCue53=Item 42 Selected InputSigType53=Digital InputCue54=Item 43 Selected InputSigType54=Digital InputCue55=Item 44 Selected InputSigType55=Digital InputCue56=Item 45 Selected InputSigType56=Digital InputCue57=Item 46 Selected InputSigType57=Digital InputCue58=Item 47 Selected InputSigType58=Digital InputCue59=Item 48 Selected InputSigType59=Digital InputCue60=Item 49 Selected InputSigType60=Digital InputCue61=Item 50 Selected InputSigType61=Digital InputCue62=Item 51 Selected InputSigType62=Digital InputCue63=Item 52 Selected InputSigType63=Digital InputCue64=Item 53 Selected InputSigType64=Digital InputCue65=Item 54 Selected InputSigType65=Digital InputCue66=Item 55 Selected InputSigType66=Digital InputCue67=Item 56 Selected InputSigType67=Digital InputCue68=Item 57 Selected InputSigType68=Digital InputCue69=Item 58 Selected InputSigType69=Digital InputCue70=Item 59 Selected InputSigType70=Digital InputCue71=Item 60 Selected InputSigType71=Digital InputCue72=Item 61 Selected InputSigType72=Digital InputCue73=Item 62 Selected InputSigType73=Digital InputCue74=Item 63 Selected InputSigType74=Digital InputCue75=Item 64 Selected InputSigType75=Digital InputCue76=Item 65 Selected InputSigType76=Digital InputCue77=Item 66 Selected InputSigType77=Digital InputCue78=Item 67 Selected InputSigType78=Digital InputCue79=Item 68 Selected InputSigType79=Digital InputCue80=Item 69 Selected InputSigType80=Digital InputCue81=Item 70 Selected InputSigType81=Digital InputCue82=Item 71 Selected InputSigType82=Digital InputCue83=Item 72 Selected InputSigType83=Digital InputCue84=Item 73 Selected InputSigType84=Digital InputCue85=Item 74 Selected InputSigType85=Digital InputCue86=Item 75 Selected InputSigType86=Digital InputCue87=Item 76 Selected InputSigType87=Digital InputCue88=Item 77 Selected InputSigType88=Digital InputCue89=Item 78 Selected InputSigType89=Digital InputCue90=Item 79 Selected InputSigType90=Digital InputCue91=Item 80 Selected InputSigType91=Digital InputCue92=Item 81 Selected InputSigType92=Digital InputCue93=Item 82 Selected InputSigType93=Digital InputCue94=Item 83 Selected InputSigType94=Digital InputCue95=Item 84 Selected InputSigType95=Digital InputCue96=Item 85 Selected InputSigType96=Digital InputCue97=Item 86 Selected InputSigType97=Digital InputCue98=Item 87 Selected InputSigType98=Digital InputCue99=Item 88 Selected InputSigType99=Digital InputCue100=Item 89 Selected InputSigType100=Digital InputCue101=Item 90 Selected InputSigType101=Digital InputCue102=Item 91 Selected InputSigType102=Digital InputCue103=Item 92 Selected InputSigType103=Digital InputCue104=Item 93 Selected InputSigType104=Digital InputCue105=Item 94 Selected InputSigType105=Digital InputCue106=Item 95 Selected InputSigType106=Digital InputCue107=Item 96 Selected InputSigType107=Digital InputCue108=Item 97 Selected InputSigType108=Digital InputCue109=Item 98 Selected InputSigType109=Digital InputCue110=Item 99 Selected InputSigType110=Digital InputCue111=Item 100 Selected InputSigType111=Digital InputCue112=Item 101 Selected InputSigType112=Digital InputCue113=Item 102 Selected InputSigType113=Digital InputCue114=Item 103 Selected InputSigType114=Digital InputCue115=Item 104 Selected InputSigType115=Digital InputCue116=Item 105 Selected InputSigType116=Digital InputCue117=Item 106 Selected InputSigType117=Digital InputCue118=Item 107 Selected InputSigType118=Digital InputCue119=Item 108 Selected InputSigType119=Digital InputCue120=Item 109 Selected InputSigType120=Digital InputCue121=Item 110 Selected InputSigType121=Digital InputCue122=Item 111 Selected InputSigType122=Digital InputCue123=Item 112 Selected InputSigType123=Digital InputCue124=Item 113 Selected InputSigType124=Digital InputCue125=Item 114 Selected InputSigType125=Digital InputCue126=Item 115 Selected InputSigType126=Digital InputCue127=Item 116 Selected InputSigType127=Digital InputCue128=Item 117 Selected InputSigType128=Digital InputCue129=Item 118 Selected InputSigType129=Digital InputCue130=Item 119 Selected InputSigType130=Digital InputCue131=Item 120 Selected InputSigType131=Digital InputCue132=Item 121 Selected InputSigType132=Digital InputCue133=Item 122 Selected InputSigType133=Digital InputCue134=Item 123 Selected InputSigType134=Digital InputCue135=Item 124 Selected InputSigType135=Digital InputCue136=Item 125 Selected InputSigType136=Digital InputCue137=Item 126 Selected InputSigType137=Digital InputCue138=Item 127 Selected InputSigType138=Digital InputCue139=Item 128 Selected InputSigType139=Digital InputCue140=Item 129 Selected InputSigType140=Digital InputCue141=Item 130 Selected InputSigType141=Digital InputCue142=Item 131 Selected InputSigType142=Digital InputCue143=Item 132 Selected InputSigType143=Digital InputCue144=Item 133 Selected InputSigType144=Digital InputCue145=Item 134 Selected InputSigType145=Digital InputCue146=Item 135 Selected InputSigType146=Digital InputCue147=Item 136 Selected InputSigType147=Digital InputCue148=Item 137 Selected InputSigType148=Digital InputCue149=Item 138 Selected InputSigType149=Digital InputCue150=Item 139 Selected InputSigType150=Digital InputCue151=Item 140 Selected InputSigType151=Digital InputCue152=Item 141 Selected InputSigType152=Digital InputCue153=Item 142 Selected InputSigType153=Digital InputCue154=Item 143 Selected InputSigType154=Digital InputCue155=Item 144 Selected InputSigType155=Digital InputCue156=Item 145 Selected InputSigType156=Digital InputCue157=Item 146 Selected InputSigType157=Digital InputCue158=Item 147 Selected InputSigType158=Digital InputCue159=Item 148 Selected InputSigType159=Digital InputCue160=Item 149 Selected InputSigType160=Digital InputCue161=Item 150 Selected InputSigType161=Digital InputCue162=Item 151 Selected InputSigType162=Digital InputCue163=Item 152 Selected InputSigType163=Digital InputCue164=Item 153 Selected InputSigType164=Digital InputCue165=Item 154 Selected InputSigType165=Digital InputCue166=Item 155 Selected InputSigType166=Digital InputCue167=Item 156 Selected InputSigType167=Digital InputCue168=Item 157 Selected InputSigType168=Digital InputCue169=Item 158 Selected InputSigType169=Digital InputCue170=Item 159 Selected InputSigType170=Digital InputCue171=Item 160 Selected InputSigType171=Digital InputCue172=Item 161 Selected InputSigType172=Digital InputCue173=Item 162 Selected InputSigType173=Digital InputCue174=Item 163 Selected InputSigType174=Digital InputCue175=Item 164 Selected InputSigType175=Digital InputCue176=Item 165 Selected InputSigType176=Digital InputCue177=Item 166 Selected InputSigType177=Digital InputCue178=Item 167 Selected InputSigType178=Digital InputCue179=Item 168 Selected InputSigType179=Digital InputCue180=Item 169 Selected InputSigType180=Digital InputCue181=Item 170 Selected InputSigType181=Digital InputCue182=Item 171 Selected InputSigType182=Digital InputCue183=Item 172 Selected InputSigType183=Digital InputCue184=Item 173 Selected InputSigType184=Digital InputCue185=Item 174 Selected InputSigType185=Digital InputCue186=Item 175 Selected InputSigType186=Digital InputCue187=Item 176 Selected InputSigType187=Digital InputCue188=Item 177 Selected InputSigType188=Digital InputCue189=Item 178 Selected InputSigType189=Digital InputCue190=Item 179 Selected InputSigType190=Digital InputCue191=Item 180 Selected InputSigType191=Digital InputCue192=Item 181 Selected InputSigType192=Digital InputCue193=Item 182 Selected InputSigType193=Digital InputCue194=Item 183 Selected InputSigType194=Digital InputCue195=Item 184 Selected InputSigType195=Digital InputCue196=Item 185 Selected InputSigType196=Digital InputCue197=Item 186 Selected InputSigType197=Digital InputCue198=Item 187 Selected InputSigType198=Digital InputCue199=Item 188 Selected InputSigType199=Digital InputCue200=Item 189 Selected InputSigType200=Digital InputCue201=Item 190 Selected InputSigType201=Digital InputCue202=Item 191 Selected InputSigType202=Digital InputCue203=Item 192 Selected InputSigType203=Digital InputCue204=Item 193 Selected InputSigType204=Digital InputCue205=Item 194 Selected InputSigType205=Digital InputCue206=Item 195 Selected InputSigType206=Digital InputCue207=Item 196 Selected InputSigType207=Digital InputCue208=Item 197 Selected InputSigType208=Digital InputCue209=Item 198 Selected InputSigType209=Digital InputCue210=Item 199 Selected InputSigType210=Digital InputCue211=Item 200 Selected InputSigType211=Digital InputCue212=Item 201 Selected InputSigType212=Digital InputCue213=Item 202 Selected InputSigType213=Digital InputCue214=Item 203 Selected InputSigType214=Digital InputCue215=Item 204 Selected InputSigType215=Digital InputCue216=Item 205 Selected InputSigType216=Digital InputCue217=Item 206 Selected InputSigType217=Digital InputCue218=Item 207 Selected InputSigType218=Digital InputCue219=Item 208 Selected InputSigType219=Digital InputCue220=Item 209 Selected InputSigType220=Digital InputCue221=Item 210 Selected InputSigType221=Digital InputCue222=Item 211 Selected InputSigType222=Digital InputCue223=Item 212 Selected InputSigType223=Digital InputCue224=Item 213 Selected InputSigType224=Digital InputCue225=Item 214 Selected InputSigType225=Digital InputCue226=Item 215 Selected InputSigType226=Digital InputCue227=Item 216 Selected InputSigType227=Digital InputCue228=Item 217 Selected InputSigType228=Digital InputCue229=Item 218 Selected InputSigType229=Digital InputCue230=Item 219 Selected InputSigType230=Digital InputCue231=Item 220 Selected InputSigType231=Digital InputCue232=Item 221 Selected InputSigType232=Digital InputCue233=Item 222 Selected InputSigType233=Digital InputCue234=Item 223 Selected InputSigType234=Digital InputCue235=Item 224 Selected InputSigType235=Digital InputCue236=Item 225 Selected InputSigType236=Digital InputCue237=Item 226 Selected InputSigType237=Digital InputCue238=Item 227 Selected InputSigType238=Digital InputCue239=Item 228 Selected InputSigType239=Digital InputCue240=Item 229 Selected InputSigType240=Digital InputCue241=Item 230 Selected InputSigType241=Digital InputCue242=Item 231 Selected InputSigType242=Digital InputCue243=Item 232 Selected InputSigType243=Digital InputCue244=Item 233 Selected InputSigType244=Digital InputCue245=Item 234 Selected InputSigType245=Digital InputCue246=Item 235 Selected InputSigType246=Digital InputCue247=Item 236 Selected InputSigType247=Digital InputCue248=Item 237 Selected InputSigType248=Digital InputCue249=Item 238 Selected InputSigType249=Digital InputCue250=Item 239 Selected InputSigType250=Digital InputCue251=Item 240 Selected InputSigType251=Digital InputCue252=Item 241 Selected InputSigType252=Digital InputCue253=Item 242 Selected InputSigType253=Digital InputCue254=Item 243 Selected InputSigType254=Digital InputCue255=Item 244 Selected InputSigType255=Digital InputCue256=Item 245 Selected InputSigType256=Digital InputCue257=Item 246 Selected InputSigType257=Digital InputCue258=Item 247 Selected InputSigType258=Digital InputCue259=Item 248 Selected InputSigType259=Digital InputCue260=Item 249 Selected InputSigType260=Digital InputCue261=Item 250 Selected InputSigType261=Digital InputCue262=Item 251 Selected InputSigType262=Digital InputCue263=Item 252 Selected InputSigType263=Digital InputCue264=Item 253 Selected InputSigType264=Digital InputCue265=Item 254 Selected InputSigType265=Digital InputCue266=Item 255 Selected InputSigType266=Digital InputCue267=[~UNUSED2~] InputSigType267=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=Item 11 Enabled InputSigType2024=Digital InputCue2025=Item 12 Enabled InputSigType2025=Digital InputCue2026=Item 13 Enabled InputSigType2026=Digital InputCue2027=Item 14 Enabled InputSigType2027=Digital InputCue2028=Item 15 Enabled InputSigType2028=Digital InputCue2029=Item 16 Enabled InputSigType2029=Digital InputCue2030=Item 17 Enabled InputSigType2030=Digital InputCue2031=Item 18 Enabled InputSigType2031=Digital InputCue2032=Item 19 Enabled InputSigType2032=Digital InputCue2033=Item 20 Enabled InputSigType2033=Digital InputCue2034=Item 21 Enabled InputSigType2034=Digital InputCue2035=Item 22 Enabled InputSigType2035=Digital InputCue2036=Item 23 Enabled InputSigType2036=Digital InputCue2037=Item 24 Enabled InputSigType2037=Digital InputCue2038=Item 25 Enabled InputSigType2038=Digital InputCue2039=Item 26 Enabled InputSigType2039=Digital InputCue2040=Item 27 Enabled InputSigType2040=Digital InputCue2041=Item 28 Enabled InputSigType2041=Digital InputCue2042=Item 29 Enabled InputSigType2042=Digital InputCue2043=Item 30 Enabled InputSigType2043=Digital InputCue2044=Item 31 Enabled InputSigType2044=Digital InputCue2045=Item 32 Enabled InputSigType2045=Digital InputCue2046=Item 33 Enabled InputSigType2046=Digital InputCue2047=Item 34 Enabled InputSigType2047=Digital InputCue2048=Item 35 Enabled InputSigType2048=Digital InputCue2049=Item 36 Enabled InputSigType2049=Digital InputCue2050=Item 37 Enabled InputSigType2050=Digital InputCue2051=Item 38 Enabled InputSigType2051=Digital InputCue2052=Item 39 Enabled InputSigType2052=Digital InputCue2053=Item 40 Enabled InputSigType2053=Digital InputCue2054=Item 41 Enabled InputSigType2054=Digital InputCue2055=Item 42 Enabled InputSigType2055=Digital InputCue2056=Item 43 Enabled InputSigType2056=Digital InputCue2057=Item 44 Enabled InputSigType2057=Digital InputCue2058=Item 45 Enabled InputSigType2058=Digital InputCue2059=Item 46 Enabled InputSigType2059=Digital InputCue2060=Item 47 Enabled InputSigType2060=Digital InputCue2061=Item 48 Enabled InputSigType2061=Digital InputCue2062=Item 49 Enabled InputSigType2062=Digital InputCue2063=Item 50 Enabled InputSigType2063=Digital InputCue2064=Item 51 Enabled InputSigType2064=Digital InputCue2065=Item 52 Enabled InputSigType2065=Digital InputCue2066=Item 53 Enabled InputSigType2066=Digital InputCue2067=Item 54 Enabled InputSigType2067=Digital InputCue2068=Item 55 Enabled InputSigType2068=Digital InputCue2069=Item 56 Enabled InputSigType2069=Digital InputCue2070=Item 57 Enabled InputSigType2070=Digital InputCue2071=Item 58 Enabled InputSigType2071=Digital InputCue2072=Item 59 Enabled InputSigType2072=Digital InputCue2073=Item 60 Enabled InputSigType2073=Digital InputCue2074=Item 61 Enabled InputSigType2074=Digital InputCue2075=Item 62 Enabled InputSigType2075=Digital InputCue2076=Item 63 Enabled InputSigType2076=Digital InputCue2077=Item 64 Enabled InputSigType2077=Digital InputCue2078=Item 65 Enabled InputSigType2078=Digital InputCue2079=Item 66 Enabled InputSigType2079=Digital InputCue2080=Item 67 Enabled InputSigType2080=Digital InputCue2081=Item 68 Enabled InputSigType2081=Digital InputCue2082=Item 69 Enabled InputSigType2082=Digital InputCue2083=Item 70 Enabled InputSigType2083=Digital InputCue2084=Item 71 Enabled InputSigType2084=Digital InputCue2085=Item 72 Enabled InputSigType2085=Digital InputCue2086=Item 73 Enabled InputSigType2086=Digital InputCue2087=Item 74 Enabled InputSigType2087=Digital InputCue2088=Item 75 Enabled InputSigType2088=Digital InputCue2089=Item 76 Enabled InputSigType2089=Digital InputCue2090=Item 77 Enabled InputSigType2090=Digital InputCue2091=Item 78 Enabled InputSigType2091=Digital InputCue2092=Item 79 Enabled InputSigType2092=Digital InputCue2093=Item 80 Enabled InputSigType2093=Digital InputCue2094=Item 81 Enabled InputSigType2094=Digital InputCue2095=Item 82 Enabled InputSigType2095=Digital InputCue2096=Item 83 Enabled InputSigType2096=Digital InputCue2097=Item 84 Enabled InputSigType2097=Digital InputCue2098=Item 85 Enabled InputSigType2098=Digital InputCue2099=Item 86 Enabled InputSigType2099=Digital InputCue2100=Item 87 Enabled InputSigType2100=Digital InputCue2101=Item 88 Enabled InputSigType2101=Digital InputCue2102=Item 89 Enabled InputSigType2102=Digital InputCue2103=Item 90 Enabled InputSigType2103=Digital InputCue2104=Item 91 Enabled InputSigType2104=Digital InputCue2105=Item 92 Enabled InputSigType2105=Digital InputCue2106=Item 93 Enabled InputSigType2106=Digital InputCue2107=Item 94 Enabled InputSigType2107=Digital InputCue2108=Item 95 Enabled InputSigType2108=Digital InputCue2109=Item 96 Enabled InputSigType2109=Digital InputCue2110=Item 97 Enabled InputSigType2110=Digital InputCue2111=Item 98 Enabled InputSigType2111=Digital InputCue2112=Item 99 Enabled InputSigType2112=Digital InputCue2113=Item 100 Enabled InputSigType2113=Digital InputCue2114=Item 101 Enabled InputSigType2114=Digital InputCue2115=Item 102 Enabled InputSigType2115=Digital InputCue2116=Item 103 Enabled InputSigType2116=Digital InputCue2117=Item 104 Enabled InputSigType2117=Digital InputCue2118=Item 105 Enabled InputSigType2118=Digital InputCue2119=Item 106 Enabled InputSigType2119=Digital InputCue2120=Item 107 Enabled InputSigType2120=Digital InputCue2121=Item 108 Enabled InputSigType2121=Digital InputCue2122=Item 109 Enabled InputSigType2122=Digital InputCue2123=Item 110 Enabled InputSigType2123=Digital InputCue2124=Item 111 Enabled InputSigType2124=Digital InputCue2125=Item 112 Enabled InputSigType2125=Digital InputCue2126=Item 113 Enabled InputSigType2126=Digital InputCue2127=Item 114 Enabled InputSigType2127=Digital InputCue2128=Item 115 Enabled InputSigType2128=Digital InputCue2129=Item 116 Enabled InputSigType2129=Digital InputCue2130=Item 117 Enabled InputSigType2130=Digital InputCue2131=Item 118 Enabled InputSigType2131=Digital InputCue2132=Item 119 Enabled InputSigType2132=Digital InputCue2133=Item 120 Enabled InputSigType2133=Digital InputCue2134=Item 121 Enabled InputSigType2134=Digital InputCue2135=Item 122 Enabled InputSigType2135=Digital InputCue2136=Item 123 Enabled InputSigType2136=Digital InputCue2137=Item 124 Enabled InputSigType2137=Digital InputCue2138=Item 125 Enabled InputSigType2138=Digital InputCue2139=Item 126 Enabled InputSigType2139=Digital InputCue2140=Item 127 Enabled InputSigType2140=Digital InputCue2141=Item 128 Enabled InputSigType2141=Digital InputCue2142=Item 129 Enabled InputSigType2142=Digital InputCue2143=Item 130 Enabled InputSigType2143=Digital InputCue2144=Item 131 Enabled InputSigType2144=Digital InputCue2145=Item 132 Enabled InputSigType2145=Digital InputCue2146=Item 133 Enabled InputSigType2146=Digital InputCue2147=Item 134 Enabled InputSigType2147=Digital InputCue2148=Item 135 Enabled InputSigType2148=Digital InputCue2149=Item 136 Enabled InputSigType2149=Digital InputCue2150=Item 137 Enabled InputSigType2150=Digital InputCue2151=Item 138 Enabled InputSigType2151=Digital InputCue2152=Item 139 Enabled InputSigType2152=Digital InputCue2153=Item 140 Enabled InputSigType2153=Digital InputCue2154=Item 141 Enabled InputSigType2154=Digital InputCue2155=Item 142 Enabled InputSigType2155=Digital InputCue2156=Item 143 Enabled InputSigType2156=Digital InputCue2157=Item 144 Enabled InputSigType2157=Digital InputCue2158=Item 145 Enabled InputSigType2158=Digital InputCue2159=Item 146 Enabled InputSigType2159=Digital InputCue2160=Item 147 Enabled InputSigType2160=Digital InputCue2161=Item 148 Enabled InputSigType2161=Digital InputCue2162=Item 149 Enabled InputSigType2162=Digital InputCue2163=Item 150 Enabled InputSigType2163=Digital InputCue2164=Item 151 Enabled InputSigType2164=Digital InputCue2165=Item 152 Enabled InputSigType2165=Digital InputCue2166=Item 153 Enabled InputSigType2166=Digital InputCue2167=Item 154 Enabled InputSigType2167=Digital InputCue2168=Item 155 Enabled InputSigType2168=Digital InputCue2169=Item 156 Enabled InputSigType2169=Digital InputCue2170=Item 157 Enabled InputSigType2170=Digital InputCue2171=Item 158 Enabled InputSigType2171=Digital InputCue2172=Item 159 Enabled InputSigType2172=Digital InputCue2173=Item 160 Enabled InputSigType2173=Digital InputCue2174=Item 161 Enabled InputSigType2174=Digital InputCue2175=Item 162 Enabled InputSigType2175=Digital InputCue2176=Item 163 Enabled InputSigType2176=Digital InputCue2177=Item 164 Enabled InputSigType2177=Digital InputCue2178=Item 165 Enabled InputSigType2178=Digital InputCue2179=Item 166 Enabled InputSigType2179=Digital InputCue2180=Item 167 Enabled InputSigType2180=Digital InputCue2181=Item 168 Enabled InputSigType2181=Digital InputCue2182=Item 169 Enabled InputSigType2182=Digital InputCue2183=Item 170 Enabled InputSigType2183=Digital InputCue2184=Item 171 Enabled InputSigType2184=Digital InputCue2185=Item 172 Enabled InputSigType2185=Digital InputCue2186=Item 173 Enabled InputSigType2186=Digital InputCue2187=Item 174 Enabled InputSigType2187=Digital InputCue2188=Item 175 Enabled InputSigType2188=Digital InputCue2189=Item 176 Enabled InputSigType2189=Digital InputCue2190=Item 177 Enabled InputSigType2190=Digital InputCue2191=Item 178 Enabled InputSigType2191=Digital InputCue2192=Item 179 Enabled InputSigType2192=Digital InputCue2193=Item 180 Enabled InputSigType2193=Digital InputCue2194=Item 181 Enabled InputSigType2194=Digital InputCue2195=Item 182 Enabled InputSigType2195=Digital InputCue2196=Item 183 Enabled InputSigType2196=Digital InputCue2197=Item 184 Enabled InputSigType2197=Digital InputCue2198=Item 185 Enabled InputSigType2198=Digital InputCue2199=Item 186 Enabled InputSigType2199=Digital InputCue2200=Item 187 Enabled InputSigType2200=Digital InputCue2201=Item 188 Enabled InputSigType2201=Digital InputCue2202=Item 189 Enabled InputSigType2202=Digital InputCue2203=Item 190 Enabled InputSigType2203=Digital InputCue2204=Item 191 Enabled InputSigType2204=Digital InputCue2205=Item 192 Enabled InputSigType2205=Digital InputCue2206=Item 193 Enabled InputSigType2206=Digital InputCue2207=Item 194 Enabled InputSigType2207=Digital InputCue2208=Item 195 Enabled InputSigType2208=Digital InputCue2209=Item 196 Enabled InputSigType2209=Digital InputCue2210=Item 197 Enabled InputSigType2210=Digital InputCue2211=Item 198 Enabled InputSigType2211=Digital InputCue2212=Item 199 Enabled InputSigType2212=Digital InputCue2213=Item 200 Enabled InputSigType2213=Digital InputCue2214=Item 201 Enabled InputSigType2214=Digital InputCue2215=Item 202 Enabled InputSigType2215=Digital InputCue2216=Item 203 Enabled InputSigType2216=Digital InputCue2217=Item 204 Enabled InputSigType2217=Digital InputCue2218=Item 205 Enabled InputSigType2218=Digital InputCue2219=Item 206 Enabled InputSigType2219=Digital InputCue2220=Item 207 Enabled InputSigType2220=Digital InputCue2221=Item 208 Enabled InputSigType2221=Digital InputCue2222=Item 209 Enabled InputSigType2222=Digital InputCue2223=Item 210 Enabled InputSigType2223=Digital InputCue2224=Item 211 Enabled InputSigType2224=Digital InputCue2225=Item 212 Enabled InputSigType2225=Digital InputCue2226=Item 213 Enabled InputSigType2226=Digital InputCue2227=Item 214 Enabled InputSigType2227=Digital InputCue2228=Item 215 Enabled InputSigType2228=Digital InputCue2229=Item 216 Enabled InputSigType2229=Digital InputCue2230=Item 217 Enabled InputSigType2230=Digital InputCue2231=Item 218 Enabled InputSigType2231=Digital InputCue2232=Item 219 Enabled InputSigType2232=Digital InputCue2233=Item 220 Enabled InputSigType2233=Digital InputCue2234=Item 221 Enabled InputSigType2234=Digital InputCue2235=Item 222 Enabled InputSigType2235=Digital InputCue2236=Item 223 Enabled InputSigType2236=Digital InputCue2237=Item 224 Enabled InputSigType2237=Digital InputCue2238=Item 225 Enabled InputSigType2238=Digital InputCue2239=Item 226 Enabled InputSigType2239=Digital InputCue2240=Item 227 Enabled InputSigType2240=Digital InputCue2241=Item 228 Enabled InputSigType2241=Digital InputCue2242=Item 229 Enabled InputSigType2242=Digital InputCue2243=Item 230 Enabled InputSigType2243=Digital InputCue2244=Item 231 Enabled InputSigType2244=Digital InputCue2245=Item 232 Enabled InputSigType2245=Digital InputCue2246=Item 233 Enabled InputSigType2246=Digital InputCue2247=Item 234 Enabled InputSigType2247=Digital InputCue2248=Item 235 Enabled InputSigType2248=Digital InputCue2249=Item 236 Enabled InputSigType2249=Digital InputCue2250=Item 237 Enabled InputSigType2250=Digital InputCue2251=Item 238 Enabled InputSigType2251=Digital InputCue2252=Item 239 Enabled InputSigType2252=Digital InputCue2253=Item 240 Enabled InputSigType2253=Digital InputCue2254=Item 241 Enabled InputSigType2254=Digital InputCue2255=Item 242 Enabled InputSigType2255=Digital InputCue2256=Item 243 Enabled InputSigType2256=Digital InputCue2257=Item 244 Enabled InputSigType2257=Digital InputCue2258=Item 245 Enabled InputSigType2258=Digital InputCue2259=Item 246 Enabled InputSigType2259=Digital InputCue2260=Item 247 Enabled InputSigType2260=Digital InputCue2261=Item 248 Enabled InputSigType2261=Digital InputCue2262=Item 249 Enabled InputSigType2262=Digital InputCue2263=Item 250 Enabled InputSigType2263=Digital InputCue2264=Item 251 Enabled InputSigType2264=Digital InputCue2265=Item 252 Enabled InputSigType2265=Digital InputCue2266=Item 253 Enabled InputSigType2266=Digital InputCue2267=Item 254 Enabled InputSigType2267=Digital InputCue2268=Item 255 Enabled InputSigType2268=Digital InputCue2269=[~UNUSED2~] InputSigType2269=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=Item 11 Visible InputSigType4026=Digital InputCue4027=Item 12 Visible InputSigType4027=Digital InputCue4028=Item 13 Visible InputSigType4028=Digital InputCue4029=Item 14 Visible InputSigType4029=Digital InputCue4030=Item 15 Visible InputSigType4030=Digital InputCue4031=Item 16 Visible InputSigType4031=Digital InputCue4032=Item 17 Visible InputSigType4032=Digital InputCue4033=Item 18 Visible InputSigType4033=Digital InputCue4034=Item 19 Visible InputSigType4034=Digital InputCue4035=Item 20 Visible InputSigType4035=Digital InputCue4036=Item 21 Visible InputSigType4036=Digital InputCue4037=Item 22 Visible InputSigType4037=Digital InputCue4038=Item 23 Visible InputSigType4038=Digital InputCue4039=Item 24 Visible InputSigType4039=Digital InputCue4040=Item 25 Visible InputSigType4040=Digital InputCue4041=Item 26 Visible InputSigType4041=Digital InputCue4042=Item 27 Visible InputSigType4042=Digital InputCue4043=Item 28 Visible InputSigType4043=Digital InputCue4044=Item 29 Visible InputSigType4044=Digital InputCue4045=Item 30 Visible InputSigType4045=Digital InputCue4046=Item 31 Visible InputSigType4046=Digital InputCue4047=Item 32 Visible InputSigType4047=Digital InputCue4048=Item 33 Visible InputSigType4048=Digital InputCue4049=Item 34 Visible InputSigType4049=Digital InputCue4050=Item 35 Visible InputSigType4050=Digital InputCue4051=Item 36 Visible InputSigType4051=Digital InputCue4052=Item 37 Visible InputSigType4052=Digital InputCue4053=Item 38 Visible InputSigType4053=Digital InputCue4054=Item 39 Visible InputSigType4054=Digital InputCue4055=Item 40 Visible InputSigType4055=Digital InputCue4056=Item 41 Visible InputSigType4056=Digital InputCue4057=Item 42 Visible InputSigType4057=Digital InputCue4058=Item 43 Visible InputSigType4058=Digital InputCue4059=Item 44 Visible InputSigType4059=Digital InputCue4060=Item 45 Visible InputSigType4060=Digital InputCue4061=Item 46 Visible InputSigType4061=Digital InputCue4062=Item 47 Visible InputSigType4062=Digital InputCue4063=Item 48 Visible InputSigType4063=Digital InputCue4064=Item 49 Visible InputSigType4064=Digital InputCue4065=Item 50 Visible InputSigType4065=Digital InputCue4066=Item 51 Visible InputSigType4066=Digital InputCue4067=Item 52 Visible InputSigType4067=Digital InputCue4068=Item 53 Visible InputSigType4068=Digital InputCue4069=Item 54 Visible InputSigType4069=Digital InputCue4070=Item 55 Visible InputSigType4070=Digital InputCue4071=Item 56 Visible InputSigType4071=Digital InputCue4072=Item 57 Visible InputSigType4072=Digital InputCue4073=Item 58 Visible InputSigType4073=Digital InputCue4074=Item 59 Visible InputSigType4074=Digital InputCue4075=Item 60 Visible InputSigType4075=Digital InputCue4076=Item 61 Visible InputSigType4076=Digital InputCue4077=Item 62 Visible InputSigType4077=Digital InputCue4078=Item 63 Visible InputSigType4078=Digital InputCue4079=Item 64 Visible InputSigType4079=Digital InputCue4080=Item 65 Visible InputSigType4080=Digital InputCue4081=Item 66 Visible InputSigType4081=Digital InputCue4082=Item 67 Visible InputSigType4082=Digital InputCue4083=Item 68 Visible InputSigType4083=Digital InputCue4084=Item 69 Visible InputSigType4084=Digital InputCue4085=Item 70 Visible InputSigType4085=Digital InputCue4086=Item 71 Visible InputSigType4086=Digital InputCue4087=Item 72 Visible InputSigType4087=Digital InputCue4088=Item 73 Visible InputSigType4088=Digital InputCue4089=Item 74 Visible InputSigType4089=Digital InputCue4090=Item 75 Visible InputSigType4090=Digital InputCue4091=Item 76 Visible InputSigType4091=Digital InputCue4092=Item 77 Visible InputSigType4092=Digital InputCue4093=Item 78 Visible InputSigType4093=Digital InputCue4094=Item 79 Visible InputSigType4094=Digital InputCue4095=Item 80 Visible InputSigType4095=Digital InputCue4096=Item 81 Visible InputSigType4096=Digital InputCue4097=Item 82 Visible InputSigType4097=Digital InputCue4098=Item 83 Visible InputSigType4098=Digital InputCue4099=Item 84 Visible InputSigType4099=Digital InputCue4100=Item 85 Visible InputSigType4100=Digital InputCue4101=Item 86 Visible InputSigType4101=Digital InputCue4102=Item 87 Visible InputSigType4102=Digital InputCue4103=Item 88 Visible InputSigType4103=Digital InputCue4104=Item 89 Visible InputSigType4104=Digital InputCue4105=Item 90 Visible InputSigType4105=Digital InputCue4106=Item 91 Visible InputSigType4106=Digital InputCue4107=Item 92 Visible InputSigType4107=Digital InputCue4108=Item 93 Visible InputSigType4108=Digital InputCue4109=Item 94 Visible InputSigType4109=Digital InputCue4110=Item 95 Visible InputSigType4110=Digital InputCue4111=Item 96 Visible InputSigType4111=Digital InputCue4112=Item 97 Visible InputSigType4112=Digital InputCue4113=Item 98 Visible InputSigType4113=Digital InputCue4114=Item 99 Visible InputSigType4114=Digital InputCue4115=Item 100 Visible InputSigType4115=Digital InputCue4116=Item 101 Visible InputSigType4116=Digital InputCue4117=Item 102 Visible InputSigType4117=Digital InputCue4118=Item 103 Visible InputSigType4118=Digital InputCue4119=Item 104 Visible InputSigType4119=Digital InputCue4120=Item 105 Visible InputSigType4120=Digital InputCue4121=Item 106 Visible InputSigType4121=Digital InputCue4122=Item 107 Visible InputSigType4122=Digital InputCue4123=Item 108 Visible InputSigType4123=Digital InputCue4124=Item 109 Visible InputSigType4124=Digital InputCue4125=Item 110 Visible InputSigType4125=Digital InputCue4126=Item 111 Visible InputSigType4126=Digital InputCue4127=Item 112 Visible InputSigType4127=Digital InputCue4128=Item 113 Visible InputSigType4128=Digital InputCue4129=Item 114 Visible InputSigType4129=Digital InputCue4130=Item 115 Visible InputSigType4130=Digital InputCue4131=Item 116 Visible InputSigType4131=Digital InputCue4132=Item 117 Visible InputSigType4132=Digital InputCue4133=Item 118 Visible InputSigType4133=Digital InputCue4134=Item 119 Visible InputSigType4134=Digital InputCue4135=Item 120 Visible InputSigType4135=Digital InputCue4136=Item 121 Visible InputSigType4136=Digital InputCue4137=Item 122 Visible InputSigType4137=Digital InputCue4138=Item 123 Visible InputSigType4138=Digital InputCue4139=Item 124 Visible InputSigType4139=Digital InputCue4140=Item 125 Visible InputSigType4140=Digital InputCue4141=Item 126 Visible InputSigType4141=Digital InputCue4142=Item 127 Visible InputSigType4142=Digital InputCue4143=Item 128 Visible InputSigType4143=Digital InputCue4144=Item 129 Visible InputSigType4144=Digital InputCue4145=Item 130 Visible InputSigType4145=Digital InputCue4146=Item 131 Visible InputSigType4146=Digital InputCue4147=Item 132 Visible InputSigType4147=Digital InputCue4148=Item 133 Visible InputSigType4148=Digital InputCue4149=Item 134 Visible InputSigType4149=Digital InputCue4150=Item 135 Visible InputSigType4150=Digital InputCue4151=Item 136 Visible InputSigType4151=Digital InputCue4152=Item 137 Visible InputSigType4152=Digital InputCue4153=Item 138 Visible InputSigType4153=Digital InputCue4154=Item 139 Visible InputSigType4154=Digital InputCue4155=Item 140 Visible InputSigType4155=Digital InputCue4156=Item 141 Visible InputSigType4156=Digital InputCue4157=Item 142 Visible InputSigType4157=Digital InputCue4158=Item 143 Visible InputSigType4158=Digital InputCue4159=Item 144 Visible InputSigType4159=Digital InputCue4160=Item 145 Visible InputSigType4160=Digital InputCue4161=Item 146 Visible InputSigType4161=Digital InputCue4162=Item 147 Visible InputSigType4162=Digital InputCue4163=Item 148 Visible InputSigType4163=Digital InputCue4164=Item 149 Visible InputSigType4164=Digital InputCue4165=Item 150 Visible InputSigType4165=Digital InputCue4166=Item 151 Visible InputSigType4166=Digital InputCue4167=Item 152 Visible InputSigType4167=Digital InputCue4168=Item 153 Visible InputSigType4168=Digital InputCue4169=Item 154 Visible InputSigType4169=Digital InputCue4170=Item 155 Visible InputSigType4170=Digital InputCue4171=Item 156 Visible InputSigType4171=Digital InputCue4172=Item 157 Visible InputSigType4172=Digital InputCue4173=Item 158 Visible InputSigType4173=Digital InputCue4174=Item 159 Visible InputSigType4174=Digital InputCue4175=Item 160 Visible InputSigType4175=Digital InputCue4176=Item 161 Visible InputSigType4176=Digital InputCue4177=Item 162 Visible InputSigType4177=Digital InputCue4178=Item 163 Visible InputSigType4178=Digital InputCue4179=Item 164 Visible InputSigType4179=Digital InputCue4180=Item 165 Visible InputSigType4180=Digital InputCue4181=Item 166 Visible InputSigType4181=Digital InputCue4182=Item 167 Visible InputSigType4182=Digital InputCue4183=Item 168 Visible InputSigType4183=Digital InputCue4184=Item 169 Visible InputSigType4184=Digital InputCue4185=Item 170 Visible InputSigType4185=Digital InputCue4186=Item 171 Visible InputSigType4186=Digital InputCue4187=Item 172 Visible InputSigType4187=Digital InputCue4188=Item 173 Visible InputSigType4188=Digital InputCue4189=Item 174 Visible InputSigType4189=Digital InputCue4190=Item 175 Visible InputSigType4190=Digital InputCue4191=Item 176 Visible InputSigType4191=Digital InputCue4192=Item 177 Visible InputSigType4192=Digital InputCue4193=Item 178 Visible InputSigType4193=Digital InputCue4194=Item 179 Visible InputSigType4194=Digital InputCue4195=Item 180 Visible InputSigType4195=Digital InputCue4196=Item 181 Visible InputSigType4196=Digital InputCue4197=Item 182 Visible InputSigType4197=Digital InputCue4198=Item 183 Visible InputSigType4198=Digital InputCue4199=Item 184 Visible InputSigType4199=Digital InputCue4200=Item 185 Visible InputSigType4200=Digital InputCue4201=Item 186 Visible InputSigType4201=Digital InputCue4202=Item 187 Visible InputSigType4202=Digital InputCue4203=Item 188 Visible InputSigType4203=Digital InputCue4204=Item 189 Visible InputSigType4204=Digital InputCue4205=Item 190 Visible InputSigType4205=Digital InputCue4206=Item 191 Visible InputSigType4206=Digital InputCue4207=Item 192 Visible InputSigType4207=Digital InputCue4208=Item 193 Visible InputSigType4208=Digital InputCue4209=Item 194 Visible InputSigType4209=Digital InputCue4210=Item 195 Visible InputSigType4210=Digital InputCue4211=Item 196 Visible InputSigType4211=Digital InputCue4212=Item 197 Visible InputSigType4212=Digital InputCue4213=Item 198 Visible InputSigType4213=Digital InputCue4214=Item 199 Visible InputSigType4214=Digital InputCue4215=Item 200 Visible InputSigType4215=Digital InputCue4216=Item 201 Visible InputSigType4216=Digital InputCue4217=Item 202 Visible InputSigType4217=Digital InputCue4218=Item 203 Visible InputSigType4218=Digital InputCue4219=Item 204 Visible InputSigType4219=Digital InputCue4220=Item 205 Visible InputSigType4220=Digital InputCue4221=Item 206 Visible InputSigType4221=Digital InputCue4222=Item 207 Visible InputSigType4222=Digital InputCue4223=Item 208 Visible InputSigType4223=Digital InputCue4224=Item 209 Visible InputSigType4224=Digital InputCue4225=Item 210 Visible InputSigType4225=Digital InputCue4226=Item 211 Visible InputSigType4226=Digital InputCue4227=Item 212 Visible InputSigType4227=Digital InputCue4228=Item 213 Visible InputSigType4228=Digital InputCue4229=Item 214 Visible InputSigType4229=Digital InputCue4230=Item 215 Visible InputSigType4230=Digital InputCue4231=Item 216 Visible InputSigType4231=Digital InputCue4232=Item 217 Visible InputSigType4232=Digital InputCue4233=Item 218 Visible InputSigType4233=Digital InputCue4234=Item 219 Visible InputSigType4234=Digital InputCue4235=Item 220 Visible InputSigType4235=Digital InputCue4236=Item 221 Visible InputSigType4236=Digital InputCue4237=Item 222 Visible InputSigType4237=Digital InputCue4238=Item 223 Visible InputSigType4238=Digital InputCue4239=Item 224 Visible InputSigType4239=Digital InputCue4240=Item 225 Visible InputSigType4240=Digital InputCue4241=Item 226 Visible InputSigType4241=Digital InputCue4242=Item 227 Visible InputSigType4242=Digital InputCue4243=Item 228 Visible InputSigType4243=Digital InputCue4244=Item 229 Visible InputSigType4244=Digital InputCue4245=Item 230 Visible InputSigType4245=Digital InputCue4246=Item 231 Visible InputSigType4246=Digital InputCue4247=Item 232 Visible InputSigType4247=Digital InputCue4248=Item 233 Visible InputSigType4248=Digital InputCue4249=Item 234 Visible InputSigType4249=Digital InputCue4250=Item 235 Visible InputSigType4250=Digital InputCue4251=Item 236 Visible InputSigType4251=Digital InputCue4252=Item 237 Visible InputSigType4252=Digital InputCue4253=Item 238 Visible InputSigType4253=Digital InputCue4254=Item 239 Visible InputSigType4254=Digital InputCue4255=Item 240 Visible InputSigType4255=Digital InputCue4256=Item 241 Visible InputSigType4256=Digital InputCue4257=Item 242 Visible InputSigType4257=Digital InputCue4258=Item 243 Visible InputSigType4258=Digital InputCue4259=Item 244 Visible InputSigType4259=Digital InputCue4260=Item 245 Visible InputSigType4260=Digital InputCue4261=Item 246 Visible InputSigType4261=Digital InputCue4262=Item 247 Visible InputSigType4262=Digital InputCue4263=Item 248 Visible InputSigType4263=Digital InputCue4264=Item 249 Visible InputSigType4264=Digital InputCue4265=Item 250 Visible InputSigType4265=Digital InputCue4266=Item 251 Visible InputSigType4266=Digital InputCue4267=Item 252 Visible InputSigType4267=Digital InputCue4268=Item 253 Visible InputSigType4268=Digital InputCue4269=Item 254 Visible InputSigType4269=Digital InputCue4270=Item 255 Visible InputSigType4270=Digital InputCue4271=[~UNUSED2~] InputSigType4271=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=Item 11 Pressed OutputSigType22=Digital OutputCue23=Item 12 Pressed OutputSigType23=Digital OutputCue24=Item 13 Pressed OutputSigType24=Digital OutputCue25=Item 14 Pressed OutputSigType25=Digital OutputCue26=Item 15 Pressed OutputSigType26=Digital OutputCue27=Item 16 Pressed OutputSigType27=Digital OutputCue28=Item 17 Pressed OutputSigType28=Digital OutputCue29=Item 18 Pressed OutputSigType29=Digital OutputCue30=Item 19 Pressed OutputSigType30=Digital OutputCue31=Item 20 Pressed OutputSigType31=Digital OutputCue32=Item 21 Pressed OutputSigType32=Digital OutputCue33=Item 22 Pressed OutputSigType33=Digital OutputCue34=Item 23 Pressed OutputSigType34=Digital OutputCue35=Item 24 Pressed OutputSigType35=Digital OutputCue36=Item 25 Pressed OutputSigType36=Digital OutputCue37=Item 26 Pressed OutputSigType37=Digital OutputCue38=Item 27 Pressed OutputSigType38=Digital OutputCue39=Item 28 Pressed OutputSigType39=Digital OutputCue40=Item 29 Pressed OutputSigType40=Digital OutputCue41=Item 30 Pressed OutputSigType41=Digital OutputCue42=Item 31 Pressed OutputSigType42=Digital OutputCue43=Item 32 Pressed OutputSigType43=Digital OutputCue44=Item 33 Pressed OutputSigType44=Digital OutputCue45=Item 34 Pressed OutputSigType45=Digital OutputCue46=Item 35 Pressed OutputSigType46=Digital OutputCue47=Item 36 Pressed OutputSigType47=Digital OutputCue48=Item 37 Pressed OutputSigType48=Digital OutputCue49=Item 38 Pressed OutputSigType49=Digital OutputCue50=Item 39 Pressed OutputSigType50=Digital OutputCue51=Item 40 Pressed OutputSigType51=Digital OutputCue52=Item 41 Pressed OutputSigType52=Digital OutputCue53=Item 42 Pressed OutputSigType53=Digital OutputCue54=Item 43 Pressed OutputSigType54=Digital OutputCue55=Item 44 Pressed OutputSigType55=Digital OutputCue56=Item 45 Pressed OutputSigType56=Digital OutputCue57=Item 46 Pressed OutputSigType57=Digital OutputCue58=Item 47 Pressed OutputSigType58=Digital OutputCue59=Item 48 Pressed OutputSigType59=Digital OutputCue60=Item 49 Pressed OutputSigType60=Digital OutputCue61=Item 50 Pressed OutputSigType61=Digital OutputCue62=Item 51 Pressed OutputSigType62=Digital OutputCue63=Item 52 Pressed OutputSigType63=Digital OutputCue64=Item 53 Pressed OutputSigType64=Digital OutputCue65=Item 54 Pressed OutputSigType65=Digital OutputCue66=Item 55 Pressed OutputSigType66=Digital OutputCue67=Item 56 Pressed OutputSigType67=Digital OutputCue68=Item 57 Pressed OutputSigType68=Digital OutputCue69=Item 58 Pressed OutputSigType69=Digital OutputCue70=Item 59 Pressed OutputSigType70=Digital OutputCue71=Item 60 Pressed OutputSigType71=Digital OutputCue72=Item 61 Pressed OutputSigType72=Digital OutputCue73=Item 62 Pressed OutputSigType73=Digital OutputCue74=Item 63 Pressed OutputSigType74=Digital OutputCue75=Item 64 Pressed OutputSigType75=Digital OutputCue76=Item 65 Pressed OutputSigType76=Digital OutputCue77=Item 66 Pressed OutputSigType77=Digital OutputCue78=Item 67 Pressed OutputSigType78=Digital OutputCue79=Item 68 Pressed OutputSigType79=Digital OutputCue80=Item 69 Pressed OutputSigType80=Digital OutputCue81=Item 70 Pressed OutputSigType81=Digital OutputCue82=Item 71 Pressed OutputSigType82=Digital OutputCue83=Item 72 Pressed OutputSigType83=Digital OutputCue84=Item 73 Pressed OutputSigType84=Digital OutputCue85=Item 74 Pressed OutputSigType85=Digital OutputCue86=Item 75 Pressed OutputSigType86=Digital OutputCue87=Item 76 Pressed OutputSigType87=Digital OutputCue88=Item 77 Pressed OutputSigType88=Digital OutputCue89=Item 78 Pressed OutputSigType89=Digital OutputCue90=Item 79 Pressed OutputSigType90=Digital OutputCue91=Item 80 Pressed OutputSigType91=Digital OutputCue92=Item 81 Pressed OutputSigType92=Digital OutputCue93=Item 82 Pressed OutputSigType93=Digital OutputCue94=Item 83 Pressed OutputSigType94=Digital OutputCue95=Item 84 Pressed OutputSigType95=Digital OutputCue96=Item 85 Pressed OutputSigType96=Digital OutputCue97=Item 86 Pressed OutputSigType97=Digital OutputCue98=Item 87 Pressed OutputSigType98=Digital OutputCue99=Item 88 Pressed OutputSigType99=Digital OutputCue100=Item 89 Pressed OutputSigType100=Digital OutputCue101=Item 90 Pressed OutputSigType101=Digital OutputCue102=Item 91 Pressed OutputSigType102=Digital OutputCue103=Item 92 Pressed OutputSigType103=Digital OutputCue104=Item 93 Pressed OutputSigType104=Digital OutputCue105=Item 94 Pressed OutputSigType105=Digital OutputCue106=Item 95 Pressed OutputSigType106=Digital OutputCue107=Item 96 Pressed OutputSigType107=Digital OutputCue108=Item 97 Pressed OutputSigType108=Digital OutputCue109=Item 98 Pressed OutputSigType109=Digital OutputCue110=Item 99 Pressed OutputSigType110=Digital OutputCue111=Item 100 Pressed OutputSigType111=Digital OutputCue112=Item 101 Pressed OutputSigType112=Digital OutputCue113=Item 102 Pressed OutputSigType113=Digital OutputCue114=Item 103 Pressed OutputSigType114=Digital OutputCue115=Item 104 Pressed OutputSigType115=Digital OutputCue116=Item 105 Pressed OutputSigType116=Digital OutputCue117=Item 106 Pressed OutputSigType117=Digital OutputCue118=Item 107 Pressed OutputSigType118=Digital OutputCue119=Item 108 Pressed OutputSigType119=Digital OutputCue120=Item 109 Pressed OutputSigType120=Digital OutputCue121=Item 110 Pressed OutputSigType121=Digital OutputCue122=Item 111 Pressed OutputSigType122=Digital OutputCue123=Item 112 Pressed OutputSigType123=Digital OutputCue124=Item 113 Pressed OutputSigType124=Digital OutputCue125=Item 114 Pressed OutputSigType125=Digital OutputCue126=Item 115 Pressed OutputSigType126=Digital OutputCue127=Item 116 Pressed OutputSigType127=Digital OutputCue128=Item 117 Pressed OutputSigType128=Digital OutputCue129=Item 118 Pressed OutputSigType129=Digital OutputCue130=Item 119 Pressed OutputSigType130=Digital OutputCue131=Item 120 Pressed OutputSigType131=Digital OutputCue132=Item 121 Pressed OutputSigType132=Digital OutputCue133=Item 122 Pressed OutputSigType133=Digital OutputCue134=Item 123 Pressed OutputSigType134=Digital OutputCue135=Item 124 Pressed OutputSigType135=Digital OutputCue136=Item 125 Pressed OutputSigType136=Digital OutputCue137=Item 126 Pressed OutputSigType137=Digital OutputCue138=Item 127 Pressed OutputSigType138=Digital OutputCue139=Item 128 Pressed OutputSigType139=Digital OutputCue140=Item 129 Pressed OutputSigType140=Digital OutputCue141=Item 130 Pressed OutputSigType141=Digital OutputCue142=Item 131 Pressed OutputSigType142=Digital OutputCue143=Item 132 Pressed OutputSigType143=Digital OutputCue144=Item 133 Pressed OutputSigType144=Digital OutputCue145=Item 134 Pressed OutputSigType145=Digital OutputCue146=Item 135 Pressed OutputSigType146=Digital OutputCue147=Item 136 Pressed OutputSigType147=Digital OutputCue148=Item 137 Pressed OutputSigType148=Digital OutputCue149=Item 138 Pressed OutputSigType149=Digital OutputCue150=Item 139 Pressed OutputSigType150=Digital OutputCue151=Item 140 Pressed OutputSigType151=Digital OutputCue152=Item 141 Pressed OutputSigType152=Digital OutputCue153=Item 142 Pressed OutputSigType153=Digital OutputCue154=Item 143 Pressed OutputSigType154=Digital OutputCue155=Item 144 Pressed OutputSigType155=Digital OutputCue156=Item 145 Pressed OutputSigType156=Digital OutputCue157=Item 146 Pressed OutputSigType157=Digital OutputCue158=Item 147 Pressed OutputSigType158=Digital OutputCue159=Item 148 Pressed OutputSigType159=Digital OutputCue160=Item 149 Pressed OutputSigType160=Digital OutputCue161=Item 150 Pressed OutputSigType161=Digital OutputCue162=Item 151 Pressed OutputSigType162=Digital OutputCue163=Item 152 Pressed OutputSigType163=Digital OutputCue164=Item 153 Pressed OutputSigType164=Digital OutputCue165=Item 154 Pressed OutputSigType165=Digital OutputCue166=Item 155 Pressed OutputSigType166=Digital OutputCue167=Item 156 Pressed OutputSigType167=Digital OutputCue168=Item 157 Pressed OutputSigType168=Digital OutputCue169=Item 158 Pressed OutputSigType169=Digital OutputCue170=Item 159 Pressed OutputSigType170=Digital OutputCue171=Item 160 Pressed OutputSigType171=Digital OutputCue172=Item 161 Pressed OutputSigType172=Digital OutputCue173=Item 162 Pressed OutputSigType173=Digital OutputCue174=Item 163 Pressed OutputSigType174=Digital OutputCue175=Item 164 Pressed OutputSigType175=Digital OutputCue176=Item 165 Pressed OutputSigType176=Digital OutputCue177=Item 166 Pressed OutputSigType177=Digital OutputCue178=Item 167 Pressed OutputSigType178=Digital OutputCue179=Item 168 Pressed OutputSigType179=Digital OutputCue180=Item 169 Pressed OutputSigType180=Digital OutputCue181=Item 170 Pressed OutputSigType181=Digital OutputCue182=Item 171 Pressed OutputSigType182=Digital OutputCue183=Item 172 Pressed OutputSigType183=Digital OutputCue184=Item 173 Pressed OutputSigType184=Digital OutputCue185=Item 174 Pressed OutputSigType185=Digital OutputCue186=Item 175 Pressed OutputSigType186=Digital OutputCue187=Item 176 Pressed OutputSigType187=Digital OutputCue188=Item 177 Pressed OutputSigType188=Digital OutputCue189=Item 178 Pressed OutputSigType189=Digital OutputCue190=Item 179 Pressed OutputSigType190=Digital OutputCue191=Item 180 Pressed OutputSigType191=Digital OutputCue192=Item 181 Pressed OutputSigType192=Digital OutputCue193=Item 182 Pressed OutputSigType193=Digital OutputCue194=Item 183 Pressed OutputSigType194=Digital OutputCue195=Item 184 Pressed OutputSigType195=Digital OutputCue196=Item 185 Pressed OutputSigType196=Digital OutputCue197=Item 186 Pressed OutputSigType197=Digital OutputCue198=Item 187 Pressed OutputSigType198=Digital OutputCue199=Item 188 Pressed OutputSigType199=Digital OutputCue200=Item 189 Pressed OutputSigType200=Digital OutputCue201=Item 190 Pressed OutputSigType201=Digital OutputCue202=Item 191 Pressed OutputSigType202=Digital OutputCue203=Item 192 Pressed OutputSigType203=Digital OutputCue204=Item 193 Pressed OutputSigType204=Digital OutputCue205=Item 194 Pressed OutputSigType205=Digital OutputCue206=Item 195 Pressed OutputSigType206=Digital OutputCue207=Item 196 Pressed OutputSigType207=Digital OutputCue208=Item 197 Pressed OutputSigType208=Digital OutputCue209=Item 198 Pressed OutputSigType209=Digital OutputCue210=Item 199 Pressed OutputSigType210=Digital OutputCue211=Item 200 Pressed OutputSigType211=Digital OutputCue212=Item 201 Pressed OutputSigType212=Digital OutputCue213=Item 202 Pressed OutputSigType213=Digital OutputCue214=Item 203 Pressed OutputSigType214=Digital OutputCue215=Item 204 Pressed OutputSigType215=Digital OutputCue216=Item 205 Pressed OutputSigType216=Digital OutputCue217=Item 206 Pressed OutputSigType217=Digital OutputCue218=Item 207 Pressed OutputSigType218=Digital OutputCue219=Item 208 Pressed OutputSigType219=Digital OutputCue220=Item 209 Pressed OutputSigType220=Digital OutputCue221=Item 210 Pressed OutputSigType221=Digital OutputCue222=Item 211 Pressed OutputSigType222=Digital OutputCue223=Item 212 Pressed OutputSigType223=Digital OutputCue224=Item 213 Pressed OutputSigType224=Digital OutputCue225=Item 214 Pressed OutputSigType225=Digital OutputCue226=Item 215 Pressed OutputSigType226=Digital OutputCue227=Item 216 Pressed OutputSigType227=Digital OutputCue228=Item 217 Pressed OutputSigType228=Digital OutputCue229=Item 218 Pressed OutputSigType229=Digital OutputCue230=Item 219 Pressed OutputSigType230=Digital OutputCue231=Item 220 Pressed OutputSigType231=Digital OutputCue232=Item 221 Pressed OutputSigType232=Digital OutputCue233=Item 222 Pressed OutputSigType233=Digital OutputCue234=Item 223 Pressed OutputSigType234=Digital OutputCue235=Item 224 Pressed OutputSigType235=Digital OutputCue236=Item 225 Pressed OutputSigType236=Digital OutputCue237=Item 226 Pressed OutputSigType237=Digital OutputCue238=Item 227 Pressed OutputSigType238=Digital OutputCue239=Item 228 Pressed OutputSigType239=Digital OutputCue240=Item 229 Pressed OutputSigType240=Digital OutputCue241=Item 230 Pressed OutputSigType241=Digital OutputCue242=Item 231 Pressed OutputSigType242=Digital OutputCue243=Item 232 Pressed OutputSigType243=Digital OutputCue244=Item 233 Pressed OutputSigType244=Digital OutputCue245=Item 234 Pressed OutputSigType245=Digital OutputCue246=Item 235 Pressed OutputSigType246=Digital OutputCue247=Item 236 Pressed OutputSigType247=Digital OutputCue248=Item 237 Pressed OutputSigType248=Digital OutputCue249=Item 238 Pressed OutputSigType249=Digital OutputCue250=Item 239 Pressed OutputSigType250=Digital OutputCue251=Item 240 Pressed OutputSigType251=Digital OutputCue252=Item 241 Pressed OutputSigType252=Digital OutputCue253=Item 242 Pressed OutputSigType253=Digital OutputCue254=Item 243 Pressed OutputSigType254=Digital OutputCue255=Item 244 Pressed OutputSigType255=Digital OutputCue256=Item 245 Pressed OutputSigType256=Digital OutputCue257=Item 246 Pressed OutputSigType257=Digital OutputCue258=Item 247 Pressed OutputSigType258=Digital OutputCue259=Item 248 Pressed OutputSigType259=Digital OutputCue260=Item 249 Pressed OutputSigType260=Digital OutputCue261=Item 250 Pressed OutputSigType261=Digital OutputCue262=Item 251 Pressed OutputSigType262=Digital OutputCue263=Item 252 Pressed OutputSigType263=Digital OutputCue264=Item 253 Pressed OutputSigType264=Digital OutputCue265=Item 254 Pressed OutputSigType265=Digital OutputCue266=Item 255 Pressed OutputSigType266=Digital OutputCue267=[~UNUSED2~] OutputSigType267=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED3~] OutputSigType2044=Digital OutputCue2045=[~UNUSED3~] OutputSigType2045=Digital OutputCue2046=[~UNUSED3~] OutputSigType2046=Digital OutputCue2047=[~UNUSED3~] OutputSigType2047=Digital OutputCue2048=[~UNUSED3~] OutputSigType2048=Digital OutputCue2049=[~UNUSED3~] OutputSigType2049=Digital OutputCue2050=[~UNUSED3~] OutputSigType2050=Digital OutputCue2051=[~UNUSED3~] OutputSigType2051=Digital OutputCue2052=[~UNUSED3~] OutputSigType2052=Digital OutputCue2053=[~UNUSED3~] OutputSigType2053=Digital OutputCue2054=[~UNUSED3~] OutputSigType2054=Digital OutputCue2055=[~UNUSED3~] OutputSigType2055=Digital OutputCue2056=[~UNUSED3~] OutputSigType2056=Digital OutputCue2057=[~UNUSED3~] OutputSigType2057=Digital OutputCue2058=[~UNUSED3~] OutputSigType2058=Digital OutputCue2059=[~UNUSED3~] OutputSigType2059=Digital OutputCue2060=[~UNUSED3~] OutputSigType2060=Digital OutputCue2061=[~UNUSED3~] OutputSigType2061=Digital OutputCue2062=[~UNUSED3~] OutputSigType2062=Digital OutputCue2063=[~UNUSED3~] OutputSigType2063=Digital OutputCue2064=[~UNUSED3~] OutputSigType2064=Digital OutputCue2065=[~UNUSED3~] OutputSigType2065=Digital OutputCue2066=[~UNUSED3~] OutputSigType2066=Digital OutputCue2067=[~UNUSED3~] OutputSigType2067=Digital OutputCue2068=[~UNUSED3~] OutputSigType2068=Digital OutputCue2069=[~UNUSED3~] OutputSigType2069=Digital OutputCue2070=[~UNUSED3~] OutputSigType2070=Digital OutputCue2071=[~UNUSED3~] OutputSigType2071=Digital OutputCue2072=[~UNUSED3~] OutputSigType2072=Digital OutputCue2073=[~UNUSED3~] OutputSigType2073=Digital OutputCue2074=[~UNUSED3~] OutputSigType2074=Digital OutputCue2075=[~UNUSED3~] OutputSigType2075=Digital OutputCue2076=[~UNUSED3~] OutputSigType2076=Digital OutputCue2077=[~UNUSED3~] OutputSigType2077=Digital OutputCue2078=[~UNUSED3~] OutputSigType2078=Digital OutputCue2079=[~UNUSED3~] OutputSigType2079=Digital OutputCue2080=[~UNUSED3~] OutputSigType2080=Digital OutputCue2081=[~UNUSED3~] OutputSigType2081=Digital OutputCue2082=[~UNUSED3~] OutputSigType2082=Digital OutputCue2083=[~UNUSED3~] OutputSigType2083=Digital OutputCue2084=[~UNUSED3~] OutputSigType2084=Digital OutputCue2085=[~UNUSED3~] OutputSigType2085=Digital OutputCue2086=[~UNUSED3~] OutputSigType2086=Digital OutputCue2087=[~UNUSED3~] OutputSigType2087=Digital OutputCue2088=[~UNUSED3~] OutputSigType2088=Digital OutputCue2089=[~UNUSED3~] OutputSigType2089=Digital OutputCue2090=[~UNUSED3~] OutputSigType2090=Digital OutputCue2091=[~UNUSED3~] OutputSigType2091=Digital OutputCue2092=[~UNUSED3~] OutputSigType2092=Digital OutputCue2093=[~UNUSED3~] OutputSigType2093=Digital OutputCue2094=[~UNUSED3~] OutputSigType2094=Digital OutputCue2095=[~UNUSED3~] OutputSigType2095=Digital OutputCue2096=[~UNUSED3~] OutputSigType2096=Digital OutputCue2097=[~UNUSED3~] OutputSigType2097=Digital OutputCue2098=[~UNUSED3~] OutputSigType2098=Digital OutputCue2099=[~UNUSED3~] OutputSigType2099=Digital OutputCue2100=[~UNUSED3~] OutputSigType2100=Digital OutputCue2101=[~UNUSED3~] OutputSigType2101=Digital OutputCue2102=[~UNUSED3~] OutputSigType2102=Digital OutputCue2103=[~UNUSED3~] OutputSigType2103=Digital OutputCue2104=[~UNUSED3~] OutputSigType2104=Digital OutputCue2105=[~UNUSED3~] OutputSigType2105=Digital OutputCue2106=[~UNUSED3~] OutputSigType2106=Digital OutputCue2107=[~UNUSED3~] OutputSigType2107=Digital OutputCue2108=[~UNUSED3~] OutputSigType2108=Digital OutputCue2109=[~UNUSED3~] OutputSigType2109=Digital OutputCue2110=[~UNUSED3~] OutputSigType2110=Digital OutputCue2111=[~UNUSED3~] OutputSigType2111=Digital OutputCue2112=[~UNUSED3~] OutputSigType2112=Digital OutputCue2113=[~UNUSED3~] OutputSigType2113=Digital OutputCue2114=[~UNUSED3~] OutputSigType2114=Digital OutputCue2115=[~UNUSED3~] OutputSigType2115=Digital OutputCue2116=[~UNUSED3~] OutputSigType2116=Digital OutputCue2117=[~UNUSED3~] OutputSigType2117=Digital OutputCue2118=[~UNUSED3~] OutputSigType2118=Digital OutputCue2119=[~UNUSED3~] OutputSigType2119=Digital OutputCue2120=[~UNUSED3~] OutputSigType2120=Digital OutputCue2121=[~UNUSED3~] OutputSigType2121=Digital OutputCue2122=[~UNUSED3~] OutputSigType2122=Digital OutputCue2123=[~UNUSED3~] OutputSigType2123=Digital OutputCue2124=[~UNUSED3~] OutputSigType2124=Digital OutputCue2125=[~UNUSED3~] OutputSigType2125=Digital OutputCue2126=[~UNUSED3~] OutputSigType2126=Digital OutputCue2127=[~UNUSED3~] OutputSigType2127=Digital OutputCue2128=[~UNUSED3~] OutputSigType2128=Digital OutputCue2129=[~UNUSED3~] OutputSigType2129=Digital OutputCue2130=[~UNUSED3~] OutputSigType2130=Digital OutputCue2131=[~UNUSED3~] OutputSigType2131=Digital OutputCue2132=[~UNUSED3~] OutputSigType2132=Digital OutputCue2133=[~UNUSED3~] OutputSigType2133=Digital OutputCue2134=[~UNUSED3~] OutputSigType2134=Digital OutputCue2135=[~UNUSED3~] OutputSigType2135=Digital OutputCue2136=[~UNUSED3~] OutputSigType2136=Digital OutputCue2137=[~UNUSED3~] OutputSigType2137=Digital OutputCue2138=[~UNUSED3~] OutputSigType2138=Digital OutputCue2139=[~UNUSED3~] OutputSigType2139=Digital OutputCue2140=[~UNUSED3~] OutputSigType2140=Digital OutputCue2141=[~UNUSED3~] OutputSigType2141=Digital OutputCue2142=[~UNUSED3~] OutputSigType2142=Digital OutputCue2143=[~UNUSED3~] OutputSigType2143=Digital OutputCue2144=[~UNUSED3~] OutputSigType2144=Digital OutputCue2145=[~UNUSED3~] OutputSigType2145=Digital OutputCue2146=[~UNUSED3~] OutputSigType2146=Digital OutputCue2147=[~UNUSED3~] OutputSigType2147=Digital OutputCue2148=[~UNUSED3~] OutputSigType2148=Digital OutputCue2149=[~UNUSED3~] OutputSigType2149=Digital OutputCue2150=[~UNUSED3~] OutputSigType2150=Digital OutputCue2151=[~UNUSED3~] OutputSigType2151=Digital OutputCue2152=[~UNUSED3~] OutputSigType2152=Digital OutputCue2153=[~UNUSED3~] OutputSigType2153=Digital OutputCue2154=[~UNUSED3~] OutputSigType2154=Digital OutputCue2155=[~UNUSED3~] OutputSigType2155=Digital OutputCue2156=[~UNUSED3~] OutputSigType2156=Digital OutputCue2157=[~UNUSED3~] OutputSigType2157=Digital OutputCue2158=[~UNUSED3~] OutputSigType2158=Digital OutputCue2159=[~UNUSED3~] OutputSigType2159=Digital OutputCue2160=[~UNUSED3~] OutputSigType2160=Digital OutputCue2161=[~UNUSED3~] OutputSigType2161=Digital OutputCue2162=[~UNUSED3~] OutputSigType2162=Digital OutputCue2163=[~UNUSED3~] OutputSigType2163=Digital OutputCue2164=[~UNUSED3~] OutputSigType2164=Digital OutputCue2165=[~UNUSED3~] OutputSigType2165=Digital OutputCue2166=[~UNUSED3~] OutputSigType2166=Digital OutputCue2167=[~UNUSED3~] OutputSigType2167=Digital OutputCue2168=[~UNUSED3~] OutputSigType2168=Digital OutputCue2169=[~UNUSED3~] OutputSigType2169=Digital OutputCue2170=[~UNUSED3~] OutputSigType2170=Digital OutputCue2171=[~UNUSED3~] OutputSigType2171=Digital OutputCue2172=[~UNUSED3~] OutputSigType2172=Digital OutputCue2173=[~UNUSED3~] OutputSigType2173=Digital OutputCue2174=[~UNUSED3~] OutputSigType2174=Digital OutputCue2175=[~UNUSED3~] OutputSigType2175=Digital OutputCue2176=[~UNUSED3~] OutputSigType2176=Digital OutputCue2177=[~UNUSED3~] OutputSigType2177=Digital OutputCue2178=[~UNUSED3~] OutputSigType2178=Digital OutputCue2179=[~UNUSED3~] OutputSigType2179=Digital OutputCue2180=[~UNUSED3~] OutputSigType2180=Digital OutputCue2181=[~UNUSED3~] OutputSigType2181=Digital OutputCue2182=[~UNUSED3~] OutputSigType2182=Digital OutputCue2183=[~UNUSED3~] OutputSigType2183=Digital OutputCue2184=[~UNUSED3~] OutputSigType2184=Digital OutputCue2185=[~UNUSED3~] OutputSigType2185=Digital OutputCue2186=[~UNUSED3~] OutputSigType2186=Digital OutputCue2187=[~UNUSED3~] OutputSigType2187=Digital OutputCue2188=[~UNUSED3~] OutputSigType2188=Digital OutputCue2189=[~UNUSED3~] OutputSigType2189=Digital OutputCue2190=[~UNUSED3~] OutputSigType2190=Digital OutputCue2191=[~UNUSED3~] OutputSigType2191=Digital OutputCue2192=[~UNUSED3~] OutputSigType2192=Digital OutputCue2193=[~UNUSED3~] OutputSigType2193=Digital OutputCue2194=[~UNUSED3~] OutputSigType2194=Digital OutputCue2195=[~UNUSED3~] OutputSigType2195=Digital OutputCue2196=[~UNUSED3~] OutputSigType2196=Digital OutputCue2197=[~UNUSED3~] OutputSigType2197=Digital OutputCue2198=[~UNUSED3~] OutputSigType2198=Digital OutputCue2199=[~UNUSED3~] OutputSigType2199=Digital OutputCue2200=[~UNUSED3~] OutputSigType2200=Digital OutputCue2201=[~UNUSED3~] OutputSigType2201=Digital OutputCue2202=[~UNUSED3~] OutputSigType2202=Digital OutputCue2203=[~UNUSED3~] OutputSigType2203=Digital OutputCue2204=[~UNUSED3~] OutputSigType2204=Digital OutputCue2205=[~UNUSED3~] OutputSigType2205=Digital OutputCue2206=[~UNUSED3~] OutputSigType2206=Digital OutputCue2207=[~UNUSED3~] OutputSigType2207=Digital OutputCue2208=[~UNUSED3~] OutputSigType2208=Digital OutputCue2209=[~UNUSED3~] OutputSigType2209=Digital OutputCue2210=[~UNUSED3~] OutputSigType2210=Digital OutputCue2211=[~UNUSED3~] OutputSigType2211=Digital OutputCue2212=[~UNUSED3~] OutputSigType2212=Digital OutputCue2213=[~UNUSED3~] OutputSigType2213=Digital OutputCue2214=[~UNUSED3~] OutputSigType2214=Digital OutputCue2215=[~UNUSED3~] OutputSigType2215=Digital OutputCue2216=[~UNUSED3~] OutputSigType2216=Digital OutputCue2217=[~UNUSED3~] OutputSigType2217=Digital OutputCue2218=[~UNUSED3~] OutputSigType2218=Digital OutputCue2219=[~UNUSED3~] OutputSigType2219=Digital OutputCue2220=[~UNUSED3~] OutputSigType2220=Digital OutputCue2221=[~UNUSED3~] OutputSigType2221=Digital OutputCue2222=[~UNUSED3~] OutputSigType2222=Digital OutputCue2223=[~UNUSED3~] OutputSigType2223=Digital OutputCue2224=[~UNUSED3~] OutputSigType2224=Digital OutputCue2225=[~UNUSED3~] OutputSigType2225=Digital OutputCue2226=[~UNUSED3~] OutputSigType2226=Digital OutputCue2227=[~UNUSED3~] OutputSigType2227=Digital OutputCue2228=[~UNUSED3~] OutputSigType2228=Digital OutputCue2229=[~UNUSED3~] OutputSigType2229=Digital OutputCue2230=[~UNUSED3~] OutputSigType2230=Digital OutputCue2231=[~UNUSED3~] OutputSigType2231=Digital OutputCue2232=[~UNUSED3~] OutputSigType2232=Digital OutputCue2233=[~UNUSED3~] OutputSigType2233=Digital OutputCue2234=[~UNUSED3~] OutputSigType2234=Digital OutputCue2235=[~UNUSED3~] OutputSigType2235=Digital OutputCue2236=[~UNUSED3~] OutputSigType2236=Digital OutputCue2237=[~UNUSED3~] OutputSigType2237=Digital OutputCue2238=[~UNUSED3~] OutputSigType2238=Digital OutputCue2239=[~UNUSED3~] OutputSigType2239=Digital OutputCue2240=[~UNUSED3~] OutputSigType2240=Digital OutputCue2241=[~UNUSED3~] OutputSigType2241=Digital OutputCue2242=[~UNUSED3~] OutputSigType2242=Digital OutputCue2243=[~UNUSED3~] OutputSigType2243=Digital OutputCue2244=[~UNUSED3~] OutputSigType2244=Digital OutputCue2245=[~UNUSED3~] OutputSigType2245=Digital OutputCue2246=[~UNUSED3~] OutputSigType2246=Digital OutputCue2247=[~UNUSED3~] OutputSigType2247=Digital OutputCue2248=[~UNUSED3~] OutputSigType2248=Digital OutputCue2249=[~UNUSED3~] OutputSigType2249=Digital OutputCue2250=[~UNUSED3~] OutputSigType2250=Digital OutputCue2251=[~UNUSED3~] OutputSigType2251=Digital OutputCue2252=[~UNUSED3~] OutputSigType2252=Digital OutputCue2253=[~UNUSED3~] OutputSigType2253=Digital OutputCue2254=[~UNUSED3~] OutputSigType2254=Digital OutputCue2255=[~UNUSED3~] OutputSigType2255=Digital OutputCue2256=[~UNUSED3~] OutputSigType2256=Digital OutputCue2257=[~UNUSED3~] OutputSigType2257=Digital OutputCue2258=[~UNUSED3~] OutputSigType2258=Digital OutputCue2259=[~UNUSED3~] OutputSigType2259=Digital OutputCue2260=[~UNUSED3~] OutputSigType2260=Digital OutputCue2261=[~UNUSED3~] OutputSigType2261=Digital OutputCue2262=[~UNUSED3~] OutputSigType2262=Digital OutputCue2263=[~UNUSED3~] OutputSigType2263=Digital OutputCue2264=[~UNUSED3~] OutputSigType2264=Digital OutputCue2265=[~UNUSED3~] OutputSigType2265=Digital OutputCue2266=[~UNUSED3~] OutputSigType2266=Digital OutputCue2267=[~UNUSED3~] OutputSigType2267=Digital OutputCue2268=[~UNUSED3~] OutputSigType2268=Digital OutputCue2269=[~UNUSED2~] OutputSigType2269=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED3~] OutputSigType4026=Digital OutputCue4027=[~UNUSED3~] OutputSigType4027=Digital OutputCue4028=[~UNUSED3~] OutputSigType4028=Digital OutputCue4029=[~UNUSED3~] OutputSigType4029=Digital OutputCue4030=[~UNUSED3~] OutputSigType4030=Digital OutputCue4031=[~UNUSED3~] OutputSigType4031=Digital OutputCue4032=[~UNUSED3~] OutputSigType4032=Digital OutputCue4033=[~UNUSED3~] OutputSigType4033=Digital OutputCue4034=[~UNUSED3~] OutputSigType4034=Digital OutputCue4035=[~UNUSED3~] OutputSigType4035=Digital OutputCue4036=[~UNUSED3~] OutputSigType4036=Digital OutputCue4037=[~UNUSED3~] OutputSigType4037=Digital OutputCue4038=[~UNUSED3~] OutputSigType4038=Digital OutputCue4039=[~UNUSED3~] OutputSigType4039=Digital OutputCue4040=[~UNUSED3~] OutputSigType4040=Digital OutputCue4041=[~UNUSED3~] OutputSigType4041=Digital OutputCue4042=[~UNUSED3~] OutputSigType4042=Digital OutputCue4043=[~UNUSED3~] OutputSigType4043=Digital OutputCue4044=[~UNUSED3~] OutputSigType4044=Digital OutputCue4045=[~UNUSED3~] OutputSigType4045=Digital OutputCue4046=[~UNUSED3~] OutputSigType4046=Digital OutputCue4047=[~UNUSED3~] OutputSigType4047=Digital OutputCue4048=[~UNUSED3~] OutputSigType4048=Digital OutputCue4049=[~UNUSED3~] OutputSigType4049=Digital OutputCue4050=[~UNUSED3~] OutputSigType4050=Digital OutputCue4051=[~UNUSED3~] OutputSigType4051=Digital OutputCue4052=[~UNUSED3~] OutputSigType4052=Digital OutputCue4053=[~UNUSED3~] OutputSigType4053=Digital OutputCue4054=[~UNUSED3~] OutputSigType4054=Digital OutputCue4055=[~UNUSED3~] OutputSigType4055=Digital OutputCue4056=[~UNUSED3~] OutputSigType4056=Digital OutputCue4057=[~UNUSED3~] OutputSigType4057=Digital OutputCue4058=[~UNUSED3~] OutputSigType4058=Digital OutputCue4059=[~UNUSED3~] OutputSigType4059=Digital OutputCue4060=[~UNUSED3~] OutputSigType4060=Digital OutputCue4061=[~UNUSED3~] OutputSigType4061=Digital OutputCue4062=[~UNUSED3~] OutputSigType4062=Digital OutputCue4063=[~UNUSED3~] OutputSigType4063=Digital OutputCue4064=[~UNUSED3~] OutputSigType4064=Digital OutputCue4065=[~UNUSED3~] OutputSigType4065=Digital OutputCue4066=[~UNUSED3~] OutputSigType4066=Digital OutputCue4067=[~UNUSED3~] OutputSigType4067=Digital OutputCue4068=[~UNUSED3~] OutputSigType4068=Digital OutputCue4069=[~UNUSED3~] OutputSigType4069=Digital OutputCue4070=[~UNUSED3~] OutputSigType4070=Digital OutputCue4071=[~UNUSED3~] OutputSigType4071=Digital OutputCue4072=[~UNUSED3~] OutputSigType4072=Digital OutputCue4073=[~UNUSED3~] OutputSigType4073=Digital OutputCue4074=[~UNUSED3~] OutputSigType4074=Digital OutputCue4075=[~UNUSED3~] OutputSigType4075=Digital OutputCue4076=[~UNUSED3~] OutputSigType4076=Digital OutputCue4077=[~UNUSED3~] OutputSigType4077=Digital OutputCue4078=[~UNUSED3~] OutputSigType4078=Digital OutputCue4079=[~UNUSED3~] OutputSigType4079=Digital OutputCue4080=[~UNUSED3~] OutputSigType4080=Digital OutputCue4081=[~UNUSED3~] OutputSigType4081=Digital OutputCue4082=[~UNUSED3~] OutputSigType4082=Digital OutputCue4083=[~UNUSED3~] OutputSigType4083=Digital OutputCue4084=[~UNUSED3~] OutputSigType4084=Digital OutputCue4085=[~UNUSED3~] OutputSigType4085=Digital OutputCue4086=[~UNUSED3~] OutputSigType4086=Digital OutputCue4087=[~UNUSED3~] OutputSigType4087=Digital OutputCue4088=[~UNUSED3~] OutputSigType4088=Digital OutputCue4089=[~UNUSED3~] OutputSigType4089=Digital OutputCue4090=[~UNUSED3~] OutputSigType4090=Digital OutputCue4091=[~UNUSED3~] OutputSigType4091=Digital OutputCue4092=[~UNUSED3~] OutputSigType4092=Digital OutputCue4093=[~UNUSED3~] OutputSigType4093=Digital OutputCue4094=[~UNUSED3~] OutputSigType4094=Digital OutputCue4095=[~UNUSED3~] OutputSigType4095=Digital OutputCue4096=[~UNUSED3~] OutputSigType4096=Digital OutputCue4097=[~UNUSED3~] OutputSigType4097=Digital OutputCue4098=[~UNUSED3~] OutputSigType4098=Digital OutputCue4099=[~UNUSED3~] OutputSigType4099=Digital OutputCue4100=[~UNUSED3~] OutputSigType4100=Digital OutputCue4101=[~UNUSED3~] OutputSigType4101=Digital OutputCue4102=[~UNUSED3~] OutputSigType4102=Digital OutputCue4103=[~UNUSED3~] OutputSigType4103=Digital OutputCue4104=[~UNUSED3~] OutputSigType4104=Digital OutputCue4105=[~UNUSED3~] OutputSigType4105=Digital OutputCue4106=[~UNUSED3~] OutputSigType4106=Digital OutputCue4107=[~UNUSED3~] OutputSigType4107=Digital OutputCue4108=[~UNUSED3~] OutputSigType4108=Digital OutputCue4109=[~UNUSED3~] OutputSigType4109=Digital OutputCue4110=[~UNUSED3~] OutputSigType4110=Digital OutputCue4111=[~UNUSED3~] OutputSigType4111=Digital OutputCue4112=[~UNUSED3~] OutputSigType4112=Digital OutputCue4113=[~UNUSED3~] OutputSigType4113=Digital OutputCue4114=[~UNUSED3~] OutputSigType4114=Digital OutputCue4115=[~UNUSED3~] OutputSigType4115=Digital OutputCue4116=[~UNUSED3~] OutputSigType4116=Digital OutputCue4117=[~UNUSED3~] OutputSigType4117=Digital OutputCue4118=[~UNUSED3~] OutputSigType4118=Digital OutputCue4119=[~UNUSED3~] OutputSigType4119=Digital OutputCue4120=[~UNUSED3~] OutputSigType4120=Digital OutputCue4121=[~UNUSED3~] OutputSigType4121=Digital OutputCue4122=[~UNUSED3~] OutputSigType4122=Digital OutputCue4123=[~UNUSED3~] OutputSigType4123=Digital OutputCue4124=[~UNUSED3~] OutputSigType4124=Digital OutputCue4125=[~UNUSED3~] OutputSigType4125=Digital OutputCue4126=[~UNUSED3~] OutputSigType4126=Digital OutputCue4127=[~UNUSED3~] OutputSigType4127=Digital OutputCue4128=[~UNUSED3~] OutputSigType4128=Digital OutputCue4129=[~UNUSED3~] OutputSigType4129=Digital OutputCue4130=[~UNUSED3~] OutputSigType4130=Digital OutputCue4131=[~UNUSED3~] OutputSigType4131=Digital OutputCue4132=[~UNUSED3~] OutputSigType4132=Digital OutputCue4133=[~UNUSED3~] OutputSigType4133=Digital OutputCue4134=[~UNUSED3~] OutputSigType4134=Digital OutputCue4135=[~UNUSED3~] OutputSigType4135=Digital OutputCue4136=[~UNUSED3~] OutputSigType4136=Digital OutputCue4137=[~UNUSED3~] OutputSigType4137=Digital OutputCue4138=[~UNUSED3~] OutputSigType4138=Digital OutputCue4139=[~UNUSED3~] OutputSigType4139=Digital OutputCue4140=[~UNUSED3~] OutputSigType4140=Digital OutputCue4141=[~UNUSED3~] OutputSigType4141=Digital OutputCue4142=[~UNUSED3~] OutputSigType4142=Digital OutputCue4143=[~UNUSED3~] OutputSigType4143=Digital OutputCue4144=[~UNUSED3~] OutputSigType4144=Digital OutputCue4145=[~UNUSED3~] OutputSigType4145=Digital OutputCue4146=[~UNUSED3~] OutputSigType4146=Digital OutputCue4147=[~UNUSED3~] OutputSigType4147=Digital OutputCue4148=[~UNUSED3~] OutputSigType4148=Digital OutputCue4149=[~UNUSED3~] OutputSigType4149=Digital OutputCue4150=[~UNUSED3~] OutputSigType4150=Digital OutputCue4151=[~UNUSED3~] OutputSigType4151=Digital OutputCue4152=[~UNUSED3~] OutputSigType4152=Digital OutputCue4153=[~UNUSED3~] OutputSigType4153=Digital OutputCue4154=[~UNUSED3~] OutputSigType4154=Digital OutputCue4155=[~UNUSED3~] OutputSigType4155=Digital OutputCue4156=[~UNUSED3~] OutputSigType4156=Digital OutputCue4157=[~UNUSED3~] OutputSigType4157=Digital OutputCue4158=[~UNUSED3~] OutputSigType4158=Digital OutputCue4159=[~UNUSED3~] OutputSigType4159=Digital OutputCue4160=[~UNUSED3~] OutputSigType4160=Digital OutputCue4161=[~UNUSED3~] OutputSigType4161=Digital OutputCue4162=[~UNUSED3~] OutputSigType4162=Digital OutputCue4163=[~UNUSED3~] OutputSigType4163=Digital OutputCue4164=[~UNUSED3~] OutputSigType4164=Digital OutputCue4165=[~UNUSED3~] OutputSigType4165=Digital OutputCue4166=[~UNUSED3~] OutputSigType4166=Digital OutputCue4167=[~UNUSED3~] OutputSigType4167=Digital OutputCue4168=[~UNUSED3~] OutputSigType4168=Digital OutputCue4169=[~UNUSED3~] OutputSigType4169=Digital OutputCue4170=[~UNUSED3~] OutputSigType4170=Digital OutputCue4171=[~UNUSED3~] OutputSigType4171=Digital OutputCue4172=[~UNUSED3~] OutputSigType4172=Digital OutputCue4173=[~UNUSED3~] OutputSigType4173=Digital OutputCue4174=[~UNUSED3~] OutputSigType4174=Digital OutputCue4175=[~UNUSED3~] OutputSigType4175=Digital OutputCue4176=[~UNUSED3~] OutputSigType4176=Digital OutputCue4177=[~UNUSED3~] OutputSigType4177=Digital OutputCue4178=[~UNUSED3~] OutputSigType4178=Digital OutputCue4179=[~UNUSED3~] OutputSigType4179=Digital OutputCue4180=[~UNUSED3~] OutputSigType4180=Digital OutputCue4181=[~UNUSED3~] OutputSigType4181=Digital OutputCue4182=[~UNUSED3~] OutputSigType4182=Digital OutputCue4183=[~UNUSED3~] OutputSigType4183=Digital OutputCue4184=[~UNUSED3~] OutputSigType4184=Digital OutputCue4185=[~UNUSED3~] OutputSigType4185=Digital OutputCue4186=[~UNUSED3~] OutputSigType4186=Digital OutputCue4187=[~UNUSED3~] OutputSigType4187=Digital OutputCue4188=[~UNUSED3~] OutputSigType4188=Digital OutputCue4189=[~UNUSED3~] OutputSigType4189=Digital OutputCue4190=[~UNUSED3~] OutputSigType4190=Digital OutputCue4191=[~UNUSED3~] OutputSigType4191=Digital OutputCue4192=[~UNUSED3~] OutputSigType4192=Digital OutputCue4193=[~UNUSED3~] OutputSigType4193=Digital OutputCue4194=[~UNUSED3~] OutputSigType4194=Digital OutputCue4195=[~UNUSED3~] OutputSigType4195=Digital OutputCue4196=[~UNUSED3~] OutputSigType4196=Digital OutputCue4197=[~UNUSED3~] OutputSigType4197=Digital OutputCue4198=[~UNUSED3~] OutputSigType4198=Digital OutputCue4199=[~UNUSED3~] OutputSigType4199=Digital OutputCue4200=[~UNUSED3~] OutputSigType4200=Digital OutputCue4201=[~UNUSED3~] OutputSigType4201=Digital OutputCue4202=[~UNUSED3~] OutputSigType4202=Digital OutputCue4203=[~UNUSED3~] OutputSigType4203=Digital OutputCue4204=[~UNUSED3~] OutputSigType4204=Digital OutputCue4205=[~UNUSED3~] OutputSigType4205=Digital OutputCue4206=[~UNUSED3~] OutputSigType4206=Digital OutputCue4207=[~UNUSED3~] OutputSigType4207=Digital OutputCue4208=[~UNUSED3~] OutputSigType4208=Digital OutputCue4209=[~UNUSED3~] OutputSigType4209=Digital OutputCue4210=[~UNUSED3~] OutputSigType4210=Digital OutputCue4211=[~UNUSED3~] OutputSigType4211=Digital OutputCue4212=[~UNUSED3~] OutputSigType4212=Digital OutputCue4213=[~UNUSED3~] OutputSigType4213=Digital OutputCue4214=[~UNUSED3~] OutputSigType4214=Digital OutputCue4215=[~UNUSED3~] OutputSigType4215=Digital OutputCue4216=[~UNUSED3~] OutputSigType4216=Digital OutputCue4217=[~UNUSED3~] OutputSigType4217=Digital OutputCue4218=[~UNUSED3~] OutputSigType4218=Digital OutputCue4219=[~UNUSED3~] OutputSigType4219=Digital OutputCue4220=[~UNUSED3~] OutputSigType4220=Digital OutputCue4221=[~UNUSED3~] OutputSigType4221=Digital OutputCue4222=[~UNUSED3~] OutputSigType4222=Digital OutputCue4223=[~UNUSED3~] OutputSigType4223=Digital OutputCue4224=[~UNUSED3~] OutputSigType4224=Digital OutputCue4225=[~UNUSED3~] OutputSigType4225=Digital OutputCue4226=[~UNUSED3~] OutputSigType4226=Digital OutputCue4227=[~UNUSED3~] OutputSigType4227=Digital OutputCue4228=[~UNUSED3~] OutputSigType4228=Digital OutputCue4229=[~UNUSED3~] OutputSigType4229=Digital OutputCue4230=[~UNUSED3~] OutputSigType4230=Digital OutputCue4231=[~UNUSED3~] OutputSigType4231=Digital OutputCue4232=[~UNUSED3~] OutputSigType4232=Digital OutputCue4233=[~UNUSED3~] OutputSigType4233=Digital OutputCue4234=[~UNUSED3~] OutputSigType4234=Digital OutputCue4235=[~UNUSED3~] OutputSigType4235=Digital OutputCue4236=[~UNUSED3~] OutputSigType4236=Digital OutputCue4237=[~UNUSED3~] OutputSigType4237=Digital OutputCue4238=[~UNUSED3~] OutputSigType4238=Digital OutputCue4239=[~UNUSED3~] OutputSigType4239=Digital OutputCue4240=[~UNUSED3~] OutputSigType4240=Digital OutputCue4241=[~UNUSED3~] OutputSigType4241=Digital OutputCue4242=[~UNUSED3~] OutputSigType4242=Digital OutputCue4243=[~UNUSED3~] OutputSigType4243=Digital OutputCue4244=[~UNUSED3~] OutputSigType4244=Digital OutputCue4245=[~UNUSED3~] OutputSigType4245=Digital OutputCue4246=[~UNUSED3~] OutputSigType4246=Digital OutputCue4247=[~UNUSED3~] OutputSigType4247=Digital OutputCue4248=[~UNUSED3~] OutputSigType4248=Digital OutputCue4249=[~UNUSED3~] OutputSigType4249=Digital OutputCue4250=[~UNUSED3~] OutputSigType4250=Digital OutputCue4251=[~UNUSED3~] OutputSigType4251=Digital OutputCue4252=[~UNUSED3~] OutputSigType4252=Digital OutputCue4253=[~UNUSED3~] OutputSigType4253=Digital OutputCue4254=[~UNUSED3~] OutputSigType4254=Digital OutputCue4255=[~UNUSED3~] OutputSigType4255=Digital OutputCue4256=[~UNUSED3~] OutputSigType4256=Digital OutputCue4257=[~UNUSED3~] OutputSigType4257=Digital OutputCue4258=[~UNUSED3~] OutputSigType4258=Digital OutputCue4259=[~UNUSED3~] OutputSigType4259=Digital OutputCue4260=[~UNUSED3~] OutputSigType4260=Digital OutputCue4261=[~UNUSED3~] OutputSigType4261=Digital OutputCue4262=[~UNUSED3~] OutputSigType4262=Digital OutputCue4263=[~UNUSED3~] OutputSigType4263=Digital OutputCue4264=[~UNUSED3~] OutputSigType4264=Digital OutputCue4265=[~UNUSED3~] OutputSigType4265=Digital OutputCue4266=[~UNUSED3~] OutputSigType4266=Digital OutputCue4267=[~UNUSED3~] OutputSigType4267=Digital OutputCue4268=[~UNUSED3~] OutputSigType4268=Digital OutputCue4269=[~UNUSED3~] OutputSigType4269=Digital OutputCue4270=[~UNUSED3~] OutputSigType4270=Digital OutputCue4271=[~UNUSED2~] OutputSigType4271=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=Set Item 11 Icon Analog InputList2SigType22=Analog InputList2Cue23=Set Item 12 Icon Analog InputList2SigType23=Analog InputList2Cue24=Set Item 13 Icon Analog InputList2SigType24=Analog InputList2Cue25=Set Item 14 Icon Analog InputList2SigType25=Analog InputList2Cue26=Set Item 15 Icon Analog InputList2SigType26=Analog InputList2Cue27=Set Item 16 Icon Analog InputList2SigType27=Analog InputList2Cue28=Set Item 17 Icon Analog InputList2SigType28=Analog InputList2Cue29=Set Item 18 Icon Analog InputList2SigType29=Analog InputList2Cue30=Set Item 19 Icon Analog InputList2SigType30=Analog InputList2Cue31=Set Item 20 Icon Analog InputList2SigType31=Analog InputList2Cue32=Set Item 21 Icon Analog InputList2SigType32=Analog InputList2Cue33=Set Item 22 Icon Analog InputList2SigType33=Analog InputList2Cue34=Set Item 23 Icon Analog InputList2SigType34=Analog InputList2Cue35=Set Item 24 Icon Analog InputList2SigType35=Analog InputList2Cue36=Set Item 25 Icon Analog InputList2SigType36=Analog InputList2Cue37=Set Item 26 Icon Analog InputList2SigType37=Analog InputList2Cue38=Set Item 27 Icon Analog InputList2SigType38=Analog InputList2Cue39=Set Item 28 Icon Analog InputList2SigType39=Analog InputList2Cue40=Set Item 29 Icon Analog InputList2SigType40=Analog InputList2Cue41=Set Item 30 Icon Analog InputList2SigType41=Analog InputList2Cue42=Set Item 31 Icon Analog InputList2SigType42=Analog InputList2Cue43=Set Item 32 Icon Analog InputList2SigType43=Analog InputList2Cue44=Set Item 33 Icon Analog InputList2SigType44=Analog InputList2Cue45=Set Item 34 Icon Analog InputList2SigType45=Analog InputList2Cue46=Set Item 35 Icon Analog InputList2SigType46=Analog InputList2Cue47=Set Item 36 Icon Analog InputList2SigType47=Analog InputList2Cue48=Set Item 37 Icon Analog InputList2SigType48=Analog InputList2Cue49=Set Item 38 Icon Analog InputList2SigType49=Analog InputList2Cue50=Set Item 39 Icon Analog InputList2SigType50=Analog InputList2Cue51=Set Item 40 Icon Analog InputList2SigType51=Analog InputList2Cue52=Set Item 41 Icon Analog InputList2SigType52=Analog InputList2Cue53=Set Item 42 Icon Analog InputList2SigType53=Analog InputList2Cue54=Set Item 43 Icon Analog InputList2SigType54=Analog InputList2Cue55=Set Item 44 Icon Analog InputList2SigType55=Analog InputList2Cue56=Set Item 45 Icon Analog InputList2SigType56=Analog InputList2Cue57=Set Item 46 Icon Analog InputList2SigType57=Analog InputList2Cue58=Set Item 47 Icon Analog InputList2SigType58=Analog InputList2Cue59=Set Item 48 Icon Analog InputList2SigType59=Analog InputList2Cue60=Set Item 49 Icon Analog InputList2SigType60=Analog InputList2Cue61=Set Item 50 Icon Analog InputList2SigType61=Analog InputList2Cue62=Set Item 51 Icon Analog InputList2SigType62=Analog InputList2Cue63=Set Item 52 Icon Analog InputList2SigType63=Analog InputList2Cue64=Set Item 53 Icon Analog InputList2SigType64=Analog InputList2Cue65=Set Item 54 Icon Analog InputList2SigType65=Analog InputList2Cue66=Set Item 55 Icon Analog InputList2SigType66=Analog InputList2Cue67=Set Item 56 Icon Analog InputList2SigType67=Analog InputList2Cue68=Set Item 57 Icon Analog InputList2SigType68=Analog InputList2Cue69=Set Item 58 Icon Analog InputList2SigType69=Analog InputList2Cue70=Set Item 59 Icon Analog InputList2SigType70=Analog InputList2Cue71=Set Item 60 Icon Analog InputList2SigType71=Analog InputList2Cue72=Set Item 61 Icon Analog InputList2SigType72=Analog InputList2Cue73=Set Item 62 Icon Analog InputList2SigType73=Analog InputList2Cue74=Set Item 63 Icon Analog InputList2SigType74=Analog InputList2Cue75=Set Item 64 Icon Analog InputList2SigType75=Analog InputList2Cue76=Set Item 65 Icon Analog InputList2SigType76=Analog InputList2Cue77=Set Item 66 Icon Analog InputList2SigType77=Analog InputList2Cue78=Set Item 67 Icon Analog InputList2SigType78=Analog InputList2Cue79=Set Item 68 Icon Analog InputList2SigType79=Analog InputList2Cue80=Set Item 69 Icon Analog InputList2SigType80=Analog InputList2Cue81=Set Item 70 Icon Analog InputList2SigType81=Analog InputList2Cue82=Set Item 71 Icon Analog InputList2SigType82=Analog InputList2Cue83=Set Item 72 Icon Analog InputList2SigType83=Analog InputList2Cue84=Set Item 73 Icon Analog InputList2SigType84=Analog InputList2Cue85=Set Item 74 Icon Analog InputList2SigType85=Analog InputList2Cue86=Set Item 75 Icon Analog InputList2SigType86=Analog InputList2Cue87=Set Item 76 Icon Analog InputList2SigType87=Analog InputList2Cue88=Set Item 77 Icon Analog InputList2SigType88=Analog InputList2Cue89=Set Item 78 Icon Analog InputList2SigType89=Analog InputList2Cue90=Set Item 79 Icon Analog InputList2SigType90=Analog InputList2Cue91=Set Item 80 Icon Analog InputList2SigType91=Analog InputList2Cue92=Set Item 81 Icon Analog InputList2SigType92=Analog InputList2Cue93=Set Item 82 Icon Analog InputList2SigType93=Analog InputList2Cue94=Set Item 83 Icon Analog InputList2SigType94=Analog InputList2Cue95=Set Item 84 Icon Analog InputList2SigType95=Analog InputList2Cue96=Set Item 85 Icon Analog InputList2SigType96=Analog InputList2Cue97=Set Item 86 Icon Analog InputList2SigType97=Analog InputList2Cue98=Set Item 87 Icon Analog InputList2SigType98=Analog InputList2Cue99=Set Item 88 Icon Analog InputList2SigType99=Analog InputList2Cue100=Set Item 89 Icon Analog InputList2SigType100=Analog InputList2Cue101=Set Item 90 Icon Analog InputList2SigType101=Analog InputList2Cue102=Set Item 91 Icon Analog InputList2SigType102=Analog InputList2Cue103=Set Item 92 Icon Analog InputList2SigType103=Analog InputList2Cue104=Set Item 93 Icon Analog InputList2SigType104=Analog InputList2Cue105=Set Item 94 Icon Analog InputList2SigType105=Analog InputList2Cue106=Set Item 95 Icon Analog InputList2SigType106=Analog InputList2Cue107=Set Item 96 Icon Analog InputList2SigType107=Analog InputList2Cue108=Set Item 97 Icon Analog InputList2SigType108=Analog InputList2Cue109=Set Item 98 Icon Analog InputList2SigType109=Analog InputList2Cue110=Set Item 99 Icon Analog InputList2SigType110=Analog InputList2Cue111=Set Item 100 Icon Analog InputList2SigType111=Analog InputList2Cue112=Set Item 101 Icon Analog InputList2SigType112=Analog InputList2Cue113=Set Item 102 Icon Analog InputList2SigType113=Analog InputList2Cue114=Set Item 103 Icon Analog InputList2SigType114=Analog InputList2Cue115=Set Item 104 Icon Analog InputList2SigType115=Analog InputList2Cue116=Set Item 105 Icon Analog InputList2SigType116=Analog InputList2Cue117=Set Item 106 Icon Analog InputList2SigType117=Analog InputList2Cue118=Set Item 107 Icon Analog InputList2SigType118=Analog InputList2Cue119=Set Item 108 Icon Analog InputList2SigType119=Analog InputList2Cue120=Set Item 109 Icon Analog InputList2SigType120=Analog InputList2Cue121=Set Item 110 Icon Analog InputList2SigType121=Analog InputList2Cue122=Set Item 111 Icon Analog InputList2SigType122=Analog InputList2Cue123=Set Item 112 Icon Analog InputList2SigType123=Analog InputList2Cue124=Set Item 113 Icon Analog InputList2SigType124=Analog InputList2Cue125=Set Item 114 Icon Analog InputList2SigType125=Analog InputList2Cue126=Set Item 115 Icon Analog InputList2SigType126=Analog InputList2Cue127=Set Item 116 Icon Analog InputList2SigType127=Analog InputList2Cue128=Set Item 117 Icon Analog InputList2SigType128=Analog InputList2Cue129=Set Item 118 Icon Analog InputList2SigType129=Analog InputList2Cue130=Set Item 119 Icon Analog InputList2SigType130=Analog InputList2Cue131=Set Item 120 Icon Analog InputList2SigType131=Analog InputList2Cue132=Set Item 121 Icon Analog InputList2SigType132=Analog InputList2Cue133=Set Item 122 Icon Analog InputList2SigType133=Analog InputList2Cue134=Set Item 123 Icon Analog InputList2SigType134=Analog InputList2Cue135=Set Item 124 Icon Analog InputList2SigType135=Analog InputList2Cue136=Set Item 125 Icon Analog InputList2SigType136=Analog InputList2Cue137=Set Item 126 Icon Analog InputList2SigType137=Analog InputList2Cue138=Set Item 127 Icon Analog InputList2SigType138=Analog InputList2Cue139=Set Item 128 Icon Analog InputList2SigType139=Analog InputList2Cue140=Set Item 129 Icon Analog InputList2SigType140=Analog InputList2Cue141=Set Item 130 Icon Analog InputList2SigType141=Analog InputList2Cue142=Set Item 131 Icon Analog InputList2SigType142=Analog InputList2Cue143=Set Item 132 Icon Analog InputList2SigType143=Analog InputList2Cue144=Set Item 133 Icon Analog InputList2SigType144=Analog InputList2Cue145=Set Item 134 Icon Analog InputList2SigType145=Analog InputList2Cue146=Set Item 135 Icon Analog InputList2SigType146=Analog InputList2Cue147=Set Item 136 Icon Analog InputList2SigType147=Analog InputList2Cue148=Set Item 137 Icon Analog InputList2SigType148=Analog InputList2Cue149=Set Item 138 Icon Analog InputList2SigType149=Analog InputList2Cue150=Set Item 139 Icon Analog InputList2SigType150=Analog InputList2Cue151=Set Item 140 Icon Analog InputList2SigType151=Analog InputList2Cue152=Set Item 141 Icon Analog InputList2SigType152=Analog InputList2Cue153=Set Item 142 Icon Analog InputList2SigType153=Analog InputList2Cue154=Set Item 143 Icon Analog InputList2SigType154=Analog InputList2Cue155=Set Item 144 Icon Analog InputList2SigType155=Analog InputList2Cue156=Set Item 145 Icon Analog InputList2SigType156=Analog InputList2Cue157=Set Item 146 Icon Analog InputList2SigType157=Analog InputList2Cue158=Set Item 147 Icon Analog InputList2SigType158=Analog InputList2Cue159=Set Item 148 Icon Analog InputList2SigType159=Analog InputList2Cue160=Set Item 149 Icon Analog InputList2SigType160=Analog InputList2Cue161=Set Item 150 Icon Analog InputList2SigType161=Analog InputList2Cue162=Set Item 151 Icon Analog InputList2SigType162=Analog InputList2Cue163=Set Item 152 Icon Analog InputList2SigType163=Analog InputList2Cue164=Set Item 153 Icon Analog InputList2SigType164=Analog InputList2Cue165=Set Item 154 Icon Analog InputList2SigType165=Analog InputList2Cue166=Set Item 155 Icon Analog InputList2SigType166=Analog InputList2Cue167=Set Item 156 Icon Analog InputList2SigType167=Analog InputList2Cue168=Set Item 157 Icon Analog InputList2SigType168=Analog InputList2Cue169=Set Item 158 Icon Analog InputList2SigType169=Analog InputList2Cue170=Set Item 159 Icon Analog InputList2SigType170=Analog InputList2Cue171=Set Item 160 Icon Analog InputList2SigType171=Analog InputList2Cue172=Set Item 161 Icon Analog InputList2SigType172=Analog InputList2Cue173=Set Item 162 Icon Analog InputList2SigType173=Analog InputList2Cue174=Set Item 163 Icon Analog InputList2SigType174=Analog InputList2Cue175=Set Item 164 Icon Analog InputList2SigType175=Analog InputList2Cue176=Set Item 165 Icon Analog InputList2SigType176=Analog InputList2Cue177=Set Item 166 Icon Analog InputList2SigType177=Analog InputList2Cue178=Set Item 167 Icon Analog InputList2SigType178=Analog InputList2Cue179=Set Item 168 Icon Analog InputList2SigType179=Analog InputList2Cue180=Set Item 169 Icon Analog InputList2SigType180=Analog InputList2Cue181=Set Item 170 Icon Analog InputList2SigType181=Analog InputList2Cue182=Set Item 171 Icon Analog InputList2SigType182=Analog InputList2Cue183=Set Item 172 Icon Analog InputList2SigType183=Analog InputList2Cue184=Set Item 173 Icon Analog InputList2SigType184=Analog InputList2Cue185=Set Item 174 Icon Analog InputList2SigType185=Analog InputList2Cue186=Set Item 175 Icon Analog InputList2SigType186=Analog InputList2Cue187=Set Item 176 Icon Analog InputList2SigType187=Analog InputList2Cue188=Set Item 177 Icon Analog InputList2SigType188=Analog InputList2Cue189=Set Item 178 Icon Analog InputList2SigType189=Analog InputList2Cue190=Set Item 179 Icon Analog InputList2SigType190=Analog InputList2Cue191=Set Item 180 Icon Analog InputList2SigType191=Analog InputList2Cue192=Set Item 181 Icon Analog InputList2SigType192=Analog InputList2Cue193=Set Item 182 Icon Analog InputList2SigType193=Analog InputList2Cue194=Set Item 183 Icon Analog InputList2SigType194=Analog InputList2Cue195=Set Item 184 Icon Analog InputList2SigType195=Analog InputList2Cue196=Set Item 185 Icon Analog InputList2SigType196=Analog InputList2Cue197=Set Item 186 Icon Analog InputList2SigType197=Analog InputList2Cue198=Set Item 187 Icon Analog InputList2SigType198=Analog InputList2Cue199=Set Item 188 Icon Analog InputList2SigType199=Analog InputList2Cue200=Set Item 189 Icon Analog InputList2SigType200=Analog InputList2Cue201=Set Item 190 Icon Analog InputList2SigType201=Analog InputList2Cue202=Set Item 191 Icon Analog InputList2SigType202=Analog InputList2Cue203=Set Item 192 Icon Analog InputList2SigType203=Analog InputList2Cue204=Set Item 193 Icon Analog InputList2SigType204=Analog InputList2Cue205=Set Item 194 Icon Analog InputList2SigType205=Analog InputList2Cue206=Set Item 195 Icon Analog InputList2SigType206=Analog InputList2Cue207=Set Item 196 Icon Analog InputList2SigType207=Analog InputList2Cue208=Set Item 197 Icon Analog InputList2SigType208=Analog InputList2Cue209=Set Item 198 Icon Analog InputList2SigType209=Analog InputList2Cue210=Set Item 199 Icon Analog InputList2SigType210=Analog InputList2Cue211=Set Item 200 Icon Analog InputList2SigType211=Analog InputList2Cue212=Set Item 201 Icon Analog InputList2SigType212=Analog InputList2Cue213=Set Item 202 Icon Analog InputList2SigType213=Analog InputList2Cue214=Set Item 203 Icon Analog InputList2SigType214=Analog InputList2Cue215=Set Item 204 Icon Analog InputList2SigType215=Analog InputList2Cue216=Set Item 205 Icon Analog InputList2SigType216=Analog InputList2Cue217=Set Item 206 Icon Analog InputList2SigType217=Analog InputList2Cue218=Set Item 207 Icon Analog InputList2SigType218=Analog InputList2Cue219=Set Item 208 Icon Analog InputList2SigType219=Analog InputList2Cue220=Set Item 209 Icon Analog InputList2SigType220=Analog InputList2Cue221=Set Item 210 Icon Analog InputList2SigType221=Analog InputList2Cue222=Set Item 211 Icon Analog InputList2SigType222=Analog InputList2Cue223=Set Item 212 Icon Analog InputList2SigType223=Analog InputList2Cue224=Set Item 213 Icon Analog InputList2SigType224=Analog InputList2Cue225=Set Item 214 Icon Analog InputList2SigType225=Analog InputList2Cue226=Set Item 215 Icon Analog InputList2SigType226=Analog InputList2Cue227=Set Item 216 Icon Analog InputList2SigType227=Analog InputList2Cue228=Set Item 217 Icon Analog InputList2SigType228=Analog InputList2Cue229=Set Item 218 Icon Analog InputList2SigType229=Analog InputList2Cue230=Set Item 219 Icon Analog InputList2SigType230=Analog InputList2Cue231=Set Item 220 Icon Analog InputList2SigType231=Analog InputList2Cue232=Set Item 221 Icon Analog InputList2SigType232=Analog InputList2Cue233=Set Item 222 Icon Analog InputList2SigType233=Analog InputList2Cue234=Set Item 223 Icon Analog InputList2SigType234=Analog InputList2Cue235=Set Item 224 Icon Analog InputList2SigType235=Analog InputList2Cue236=Set Item 225 Icon Analog InputList2SigType236=Analog InputList2Cue237=Set Item 226 Icon Analog InputList2SigType237=Analog InputList2Cue238=Set Item 227 Icon Analog InputList2SigType238=Analog InputList2Cue239=Set Item 228 Icon Analog InputList2SigType239=Analog InputList2Cue240=Set Item 229 Icon Analog InputList2SigType240=Analog InputList2Cue241=Set Item 230 Icon Analog InputList2SigType241=Analog InputList2Cue242=Set Item 231 Icon Analog InputList2SigType242=Analog InputList2Cue243=Set Item 232 Icon Analog InputList2SigType243=Analog InputList2Cue244=Set Item 233 Icon Analog InputList2SigType244=Analog InputList2Cue245=Set Item 234 Icon Analog InputList2SigType245=Analog InputList2Cue246=Set Item 235 Icon Analog InputList2SigType246=Analog InputList2Cue247=Set Item 236 Icon Analog InputList2SigType247=Analog InputList2Cue248=Set Item 237 Icon Analog InputList2SigType248=Analog InputList2Cue249=Set Item 238 Icon Analog InputList2SigType249=Analog InputList2Cue250=Set Item 239 Icon Analog InputList2SigType250=Analog InputList2Cue251=Set Item 240 Icon Analog InputList2SigType251=Analog InputList2Cue252=Set Item 241 Icon Analog InputList2SigType252=Analog InputList2Cue253=Set Item 242 Icon Analog InputList2SigType253=Analog InputList2Cue254=Set Item 243 Icon Analog InputList2SigType254=Analog InputList2Cue255=Set Item 244 Icon Analog InputList2SigType255=Analog InputList2Cue256=Set Item 245 Icon Analog InputList2SigType256=Analog InputList2Cue257=Set Item 246 Icon Analog InputList2SigType257=Analog InputList2Cue258=Set Item 247 Icon Analog InputList2SigType258=Analog InputList2Cue259=Set Item 248 Icon Analog InputList2SigType259=Analog InputList2Cue260=Set Item 249 Icon Analog InputList2SigType260=Analog InputList2Cue261=Set Item 250 Icon Analog InputList2SigType261=Analog InputList2Cue262=Set Item 251 Icon Analog InputList2SigType262=Analog InputList2Cue263=Set Item 252 Icon Analog InputList2SigType263=Analog InputList2Cue264=Set Item 253 Icon Analog InputList2SigType264=Analog InputList2Cue265=Set Item 254 Icon Analog InputList2SigType265=Analog InputList2Cue266=Set Item 255 Icon Analog InputList2SigType266=Analog InputList2Cue267=[~UNUSED2~] InputList2SigType267=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED3~] OutputList2SigType22=Analog OutputList2Cue23=[~UNUSED3~] OutputList2SigType23=Analog OutputList2Cue24=[~UNUSED3~] OutputList2SigType24=Analog OutputList2Cue25=[~UNUSED3~] OutputList2SigType25=Analog OutputList2Cue26=[~UNUSED3~] OutputList2SigType26=Analog OutputList2Cue27=[~UNUSED3~] OutputList2SigType27=Analog OutputList2Cue28=[~UNUSED3~] OutputList2SigType28=Analog OutputList2Cue29=[~UNUSED3~] OutputList2SigType29=Analog OutputList2Cue30=[~UNUSED3~] OutputList2SigType30=Analog OutputList2Cue31=[~UNUSED3~] OutputList2SigType31=Analog OutputList2Cue32=[~UNUSED3~] OutputList2SigType32=Analog OutputList2Cue33=[~UNUSED3~] OutputList2SigType33=Analog OutputList2Cue34=[~UNUSED3~] OutputList2SigType34=Analog OutputList2Cue35=[~UNUSED3~] OutputList2SigType35=Analog OutputList2Cue36=[~UNUSED3~] OutputList2SigType36=Analog OutputList2Cue37=[~UNUSED3~] OutputList2SigType37=Analog OutputList2Cue38=[~UNUSED3~] OutputList2SigType38=Analog OutputList2Cue39=[~UNUSED3~] OutputList2SigType39=Analog OutputList2Cue40=[~UNUSED3~] OutputList2SigType40=Analog OutputList2Cue41=[~UNUSED3~] OutputList2SigType41=Analog OutputList2Cue42=[~UNUSED3~] OutputList2SigType42=Analog OutputList2Cue43=[~UNUSED3~] OutputList2SigType43=Analog OutputList2Cue44=[~UNUSED3~] OutputList2SigType44=Analog OutputList2Cue45=[~UNUSED3~] OutputList2SigType45=Analog OutputList2Cue46=[~UNUSED3~] OutputList2SigType46=Analog OutputList2Cue47=[~UNUSED3~] OutputList2SigType47=Analog OutputList2Cue48=[~UNUSED3~] OutputList2SigType48=Analog OutputList2Cue49=[~UNUSED3~] OutputList2SigType49=Analog OutputList2Cue50=[~UNUSED3~] OutputList2SigType50=Analog OutputList2Cue51=[~UNUSED3~] OutputList2SigType51=Analog OutputList2Cue52=[~UNUSED3~] OutputList2SigType52=Analog OutputList2Cue53=[~UNUSED3~] OutputList2SigType53=Analog OutputList2Cue54=[~UNUSED3~] OutputList2SigType54=Analog OutputList2Cue55=[~UNUSED3~] OutputList2SigType55=Analog OutputList2Cue56=[~UNUSED3~] OutputList2SigType56=Analog OutputList2Cue57=[~UNUSED3~] OutputList2SigType57=Analog OutputList2Cue58=[~UNUSED3~] OutputList2SigType58=Analog OutputList2Cue59=[~UNUSED3~] OutputList2SigType59=Analog OutputList2Cue60=[~UNUSED3~] OutputList2SigType60=Analog OutputList2Cue61=[~UNUSED3~] OutputList2SigType61=Analog OutputList2Cue62=[~UNUSED3~] OutputList2SigType62=Analog OutputList2Cue63=[~UNUSED3~] OutputList2SigType63=Analog OutputList2Cue64=[~UNUSED3~] OutputList2SigType64=Analog OutputList2Cue65=[~UNUSED3~] OutputList2SigType65=Analog OutputList2Cue66=[~UNUSED3~] OutputList2SigType66=Analog OutputList2Cue67=[~UNUSED3~] OutputList2SigType67=Analog OutputList2Cue68=[~UNUSED3~] OutputList2SigType68=Analog OutputList2Cue69=[~UNUSED3~] OutputList2SigType69=Analog OutputList2Cue70=[~UNUSED3~] OutputList2SigType70=Analog OutputList2Cue71=[~UNUSED3~] OutputList2SigType71=Analog OutputList2Cue72=[~UNUSED3~] OutputList2SigType72=Analog OutputList2Cue73=[~UNUSED3~] OutputList2SigType73=Analog OutputList2Cue74=[~UNUSED3~] OutputList2SigType74=Analog OutputList2Cue75=[~UNUSED3~] OutputList2SigType75=Analog OutputList2Cue76=[~UNUSED3~] OutputList2SigType76=Analog OutputList2Cue77=[~UNUSED3~] OutputList2SigType77=Analog OutputList2Cue78=[~UNUSED3~] OutputList2SigType78=Analog OutputList2Cue79=[~UNUSED3~] OutputList2SigType79=Analog OutputList2Cue80=[~UNUSED3~] OutputList2SigType80=Analog OutputList2Cue81=[~UNUSED3~] OutputList2SigType81=Analog OutputList2Cue82=[~UNUSED3~] OutputList2SigType82=Analog OutputList2Cue83=[~UNUSED3~] OutputList2SigType83=Analog OutputList2Cue84=[~UNUSED3~] OutputList2SigType84=Analog OutputList2Cue85=[~UNUSED3~] OutputList2SigType85=Analog OutputList2Cue86=[~UNUSED3~] OutputList2SigType86=Analog OutputList2Cue87=[~UNUSED3~] OutputList2SigType87=Analog OutputList2Cue88=[~UNUSED3~] OutputList2SigType88=Analog OutputList2Cue89=[~UNUSED3~] OutputList2SigType89=Analog OutputList2Cue90=[~UNUSED3~] OutputList2SigType90=Analog OutputList2Cue91=[~UNUSED3~] OutputList2SigType91=Analog OutputList2Cue92=[~UNUSED3~] OutputList2SigType92=Analog OutputList2Cue93=[~UNUSED3~] OutputList2SigType93=Analog OutputList2Cue94=[~UNUSED3~] OutputList2SigType94=Analog OutputList2Cue95=[~UNUSED3~] OutputList2SigType95=Analog OutputList2Cue96=[~UNUSED3~] OutputList2SigType96=Analog OutputList2Cue97=[~UNUSED3~] OutputList2SigType97=Analog OutputList2Cue98=[~UNUSED3~] OutputList2SigType98=Analog OutputList2Cue99=[~UNUSED3~] OutputList2SigType99=Analog OutputList2Cue100=[~UNUSED3~] OutputList2SigType100=Analog OutputList2Cue101=[~UNUSED3~] OutputList2SigType101=Analog OutputList2Cue102=[~UNUSED3~] OutputList2SigType102=Analog OutputList2Cue103=[~UNUSED3~] OutputList2SigType103=Analog OutputList2Cue104=[~UNUSED3~] OutputList2SigType104=Analog OutputList2Cue105=[~UNUSED3~] OutputList2SigType105=Analog OutputList2Cue106=[~UNUSED3~] OutputList2SigType106=Analog OutputList2Cue107=[~UNUSED3~] OutputList2SigType107=Analog OutputList2Cue108=[~UNUSED3~] OutputList2SigType108=Analog OutputList2Cue109=[~UNUSED3~] OutputList2SigType109=Analog OutputList2Cue110=[~UNUSED3~] OutputList2SigType110=Analog OutputList2Cue111=[~UNUSED3~] OutputList2SigType111=Analog OutputList2Cue112=[~UNUSED3~] OutputList2SigType112=Analog OutputList2Cue113=[~UNUSED3~] OutputList2SigType113=Analog OutputList2Cue114=[~UNUSED3~] OutputList2SigType114=Analog OutputList2Cue115=[~UNUSED3~] OutputList2SigType115=Analog OutputList2Cue116=[~UNUSED3~] OutputList2SigType116=Analog OutputList2Cue117=[~UNUSED3~] OutputList2SigType117=Analog OutputList2Cue118=[~UNUSED3~] OutputList2SigType118=Analog OutputList2Cue119=[~UNUSED3~] OutputList2SigType119=Analog OutputList2Cue120=[~UNUSED3~] OutputList2SigType120=Analog OutputList2Cue121=[~UNUSED3~] OutputList2SigType121=Analog OutputList2Cue122=[~UNUSED3~] OutputList2SigType122=Analog OutputList2Cue123=[~UNUSED3~] OutputList2SigType123=Analog OutputList2Cue124=[~UNUSED3~] OutputList2SigType124=Analog OutputList2Cue125=[~UNUSED3~] OutputList2SigType125=Analog OutputList2Cue126=[~UNUSED3~] OutputList2SigType126=Analog OutputList2Cue127=[~UNUSED3~] OutputList2SigType127=Analog OutputList2Cue128=[~UNUSED3~] OutputList2SigType128=Analog OutputList2Cue129=[~UNUSED3~] OutputList2SigType129=Analog OutputList2Cue130=[~UNUSED3~] OutputList2SigType130=Analog OutputList2Cue131=[~UNUSED3~] OutputList2SigType131=Analog OutputList2Cue132=[~UNUSED3~] OutputList2SigType132=Analog OutputList2Cue133=[~UNUSED3~] OutputList2SigType133=Analog OutputList2Cue134=[~UNUSED3~] OutputList2SigType134=Analog OutputList2Cue135=[~UNUSED3~] OutputList2SigType135=Analog OutputList2Cue136=[~UNUSED3~] OutputList2SigType136=Analog OutputList2Cue137=[~UNUSED3~] OutputList2SigType137=Analog OutputList2Cue138=[~UNUSED3~] OutputList2SigType138=Analog OutputList2Cue139=[~UNUSED3~] OutputList2SigType139=Analog OutputList2Cue140=[~UNUSED3~] OutputList2SigType140=Analog OutputList2Cue141=[~UNUSED3~] OutputList2SigType141=Analog OutputList2Cue142=[~UNUSED3~] OutputList2SigType142=Analog OutputList2Cue143=[~UNUSED3~] OutputList2SigType143=Analog OutputList2Cue144=[~UNUSED3~] OutputList2SigType144=Analog OutputList2Cue145=[~UNUSED3~] OutputList2SigType145=Analog OutputList2Cue146=[~UNUSED3~] OutputList2SigType146=Analog OutputList2Cue147=[~UNUSED3~] OutputList2SigType147=Analog OutputList2Cue148=[~UNUSED3~] OutputList2SigType148=Analog OutputList2Cue149=[~UNUSED3~] OutputList2SigType149=Analog OutputList2Cue150=[~UNUSED3~] OutputList2SigType150=Analog OutputList2Cue151=[~UNUSED3~] OutputList2SigType151=Analog OutputList2Cue152=[~UNUSED3~] OutputList2SigType152=Analog OutputList2Cue153=[~UNUSED3~] OutputList2SigType153=Analog OutputList2Cue154=[~UNUSED3~] OutputList2SigType154=Analog OutputList2Cue155=[~UNUSED3~] OutputList2SigType155=Analog OutputList2Cue156=[~UNUSED3~] OutputList2SigType156=Analog OutputList2Cue157=[~UNUSED3~] OutputList2SigType157=Analog OutputList2Cue158=[~UNUSED3~] OutputList2SigType158=Analog OutputList2Cue159=[~UNUSED3~] OutputList2SigType159=Analog OutputList2Cue160=[~UNUSED3~] OutputList2SigType160=Analog OutputList2Cue161=[~UNUSED3~] OutputList2SigType161=Analog OutputList2Cue162=[~UNUSED3~] OutputList2SigType162=Analog OutputList2Cue163=[~UNUSED3~] OutputList2SigType163=Analog OutputList2Cue164=[~UNUSED3~] OutputList2SigType164=Analog OutputList2Cue165=[~UNUSED3~] OutputList2SigType165=Analog OutputList2Cue166=[~UNUSED3~] OutputList2SigType166=Analog OutputList2Cue167=[~UNUSED3~] OutputList2SigType167=Analog OutputList2Cue168=[~UNUSED3~] OutputList2SigType168=Analog OutputList2Cue169=[~UNUSED3~] OutputList2SigType169=Analog OutputList2Cue170=[~UNUSED3~] OutputList2SigType170=Analog OutputList2Cue171=[~UNUSED3~] OutputList2SigType171=Analog OutputList2Cue172=[~UNUSED3~] OutputList2SigType172=Analog OutputList2Cue173=[~UNUSED3~] OutputList2SigType173=Analog OutputList2Cue174=[~UNUSED3~] OutputList2SigType174=Analog OutputList2Cue175=[~UNUSED3~] OutputList2SigType175=Analog OutputList2Cue176=[~UNUSED3~] OutputList2SigType176=Analog OutputList2Cue177=[~UNUSED3~] OutputList2SigType177=Analog OutputList2Cue178=[~UNUSED3~] OutputList2SigType178=Analog OutputList2Cue179=[~UNUSED3~] OutputList2SigType179=Analog OutputList2Cue180=[~UNUSED3~] OutputList2SigType180=Analog OutputList2Cue181=[~UNUSED3~] OutputList2SigType181=Analog OutputList2Cue182=[~UNUSED3~] OutputList2SigType182=Analog OutputList2Cue183=[~UNUSED3~] OutputList2SigType183=Analog OutputList2Cue184=[~UNUSED3~] OutputList2SigType184=Analog OutputList2Cue185=[~UNUSED3~] OutputList2SigType185=Analog OutputList2Cue186=[~UNUSED3~] OutputList2SigType186=Analog OutputList2Cue187=[~UNUSED3~] OutputList2SigType187=Analog OutputList2Cue188=[~UNUSED3~] OutputList2SigType188=Analog OutputList2Cue189=[~UNUSED3~] OutputList2SigType189=Analog OutputList2Cue190=[~UNUSED3~] OutputList2SigType190=Analog OutputList2Cue191=[~UNUSED3~] OutputList2SigType191=Analog OutputList2Cue192=[~UNUSED3~] OutputList2SigType192=Analog OutputList2Cue193=[~UNUSED3~] OutputList2SigType193=Analog OutputList2Cue194=[~UNUSED3~] OutputList2SigType194=Analog OutputList2Cue195=[~UNUSED3~] OutputList2SigType195=Analog OutputList2Cue196=[~UNUSED3~] OutputList2SigType196=Analog OutputList2Cue197=[~UNUSED3~] OutputList2SigType197=Analog OutputList2Cue198=[~UNUSED3~] OutputList2SigType198=Analog OutputList2Cue199=[~UNUSED3~] OutputList2SigType199=Analog OutputList2Cue200=[~UNUSED3~] OutputList2SigType200=Analog OutputList2Cue201=[~UNUSED3~] OutputList2SigType201=Analog OutputList2Cue202=[~UNUSED3~] OutputList2SigType202=Analog OutputList2Cue203=[~UNUSED3~] OutputList2SigType203=Analog OutputList2Cue204=[~UNUSED3~] OutputList2SigType204=Analog OutputList2Cue205=[~UNUSED3~] OutputList2SigType205=Analog OutputList2Cue206=[~UNUSED3~] OutputList2SigType206=Analog OutputList2Cue207=[~UNUSED3~] OutputList2SigType207=Analog OutputList2Cue208=[~UNUSED3~] OutputList2SigType208=Analog OutputList2Cue209=[~UNUSED3~] OutputList2SigType209=Analog OutputList2Cue210=[~UNUSED3~] OutputList2SigType210=Analog OutputList2Cue211=[~UNUSED3~] OutputList2SigType211=Analog OutputList2Cue212=[~UNUSED3~] OutputList2SigType212=Analog OutputList2Cue213=[~UNUSED3~] OutputList2SigType213=Analog OutputList2Cue214=[~UNUSED3~] OutputList2SigType214=Analog OutputList2Cue215=[~UNUSED3~] OutputList2SigType215=Analog OutputList2Cue216=[~UNUSED3~] OutputList2SigType216=Analog OutputList2Cue217=[~UNUSED3~] OutputList2SigType217=Analog OutputList2Cue218=[~UNUSED3~] OutputList2SigType218=Analog OutputList2Cue219=[~UNUSED3~] OutputList2SigType219=Analog OutputList2Cue220=[~UNUSED3~] OutputList2SigType220=Analog OutputList2Cue221=[~UNUSED3~] OutputList2SigType221=Analog OutputList2Cue222=[~UNUSED3~] OutputList2SigType222=Analog OutputList2Cue223=[~UNUSED3~] OutputList2SigType223=Analog OutputList2Cue224=[~UNUSED3~] OutputList2SigType224=Analog OutputList2Cue225=[~UNUSED3~] OutputList2SigType225=Analog OutputList2Cue226=[~UNUSED3~] OutputList2SigType226=Analog OutputList2Cue227=[~UNUSED3~] OutputList2SigType227=Analog OutputList2Cue228=[~UNUSED3~] OutputList2SigType228=Analog OutputList2Cue229=[~UNUSED3~] OutputList2SigType229=Analog OutputList2Cue230=[~UNUSED3~] OutputList2SigType230=Analog OutputList2Cue231=[~UNUSED3~] OutputList2SigType231=Analog OutputList2Cue232=[~UNUSED3~] OutputList2SigType232=Analog OutputList2Cue233=[~UNUSED3~] OutputList2SigType233=Analog OutputList2Cue234=[~UNUSED3~] OutputList2SigType234=Analog OutputList2Cue235=[~UNUSED3~] OutputList2SigType235=Analog OutputList2Cue236=[~UNUSED3~] OutputList2SigType236=Analog OutputList2Cue237=[~UNUSED3~] OutputList2SigType237=Analog OutputList2Cue238=[~UNUSED3~] OutputList2SigType238=Analog OutputList2Cue239=[~UNUSED3~] OutputList2SigType239=Analog OutputList2Cue240=[~UNUSED3~] OutputList2SigType240=Analog OutputList2Cue241=[~UNUSED3~] OutputList2SigType241=Analog OutputList2Cue242=[~UNUSED3~] OutputList2SigType242=Analog OutputList2Cue243=[~UNUSED3~] OutputList2SigType243=Analog OutputList2Cue244=[~UNUSED3~] OutputList2SigType244=Analog OutputList2Cue245=[~UNUSED3~] OutputList2SigType245=Analog OutputList2Cue246=[~UNUSED3~] OutputList2SigType246=Analog OutputList2Cue247=[~UNUSED3~] OutputList2SigType247=Analog OutputList2Cue248=[~UNUSED3~] OutputList2SigType248=Analog OutputList2Cue249=[~UNUSED3~] OutputList2SigType249=Analog OutputList2Cue250=[~UNUSED3~] OutputList2SigType250=Analog OutputList2Cue251=[~UNUSED3~] OutputList2SigType251=Analog OutputList2Cue252=[~UNUSED3~] OutputList2SigType252=Analog OutputList2Cue253=[~UNUSED3~] OutputList2SigType253=Analog OutputList2Cue254=[~UNUSED3~] OutputList2SigType254=Analog OutputList2Cue255=[~UNUSED3~] OutputList2SigType255=Analog OutputList2Cue256=[~UNUSED3~] OutputList2SigType256=Analog OutputList2Cue257=[~UNUSED3~] OutputList2SigType257=Analog OutputList2Cue258=[~UNUSED3~] OutputList2SigType258=Analog OutputList2Cue259=[~UNUSED3~] OutputList2SigType259=Analog OutputList2Cue260=[~UNUSED3~] OutputList2SigType260=Analog OutputList2Cue261=[~UNUSED3~] OutputList2SigType261=Analog OutputList2Cue262=[~UNUSED3~] OutputList2SigType262=Analog OutputList2Cue263=[~UNUSED3~] OutputList2SigType263=Analog OutputList2Cue264=[~UNUSED3~] OutputList2SigType264=Analog OutputList2Cue265=[~UNUSED3~] OutputList2SigType265=Analog OutputList2Cue266=[~UNUSED3~] OutputList2SigType266=Analog OutputList2Cue267=[~UNUSED2~] OutputList2SigType267=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=Set Item 11 Text InputList3SigType22=Serial InputList3Cue23=Set Item 12 Text InputList3SigType23=Serial InputList3Cue24=Set Item 13 Text InputList3SigType24=Serial InputList3Cue25=Set Item 14 Text InputList3SigType25=Serial InputList3Cue26=Set Item 15 Text InputList3SigType26=Serial InputList3Cue27=Set Item 16 Text InputList3SigType27=Serial InputList3Cue28=Set Item 17 Text InputList3SigType28=Serial InputList3Cue29=Set Item 18 Text InputList3SigType29=Serial InputList3Cue30=Set Item 19 Text InputList3SigType30=Serial InputList3Cue31=Set Item 20 Text InputList3SigType31=Serial InputList3Cue32=Set Item 21 Text InputList3SigType32=Serial InputList3Cue33=Set Item 22 Text InputList3SigType33=Serial InputList3Cue34=Set Item 23 Text InputList3SigType34=Serial InputList3Cue35=Set Item 24 Text InputList3SigType35=Serial InputList3Cue36=Set Item 25 Text InputList3SigType36=Serial InputList3Cue37=Set Item 26 Text InputList3SigType37=Serial InputList3Cue38=Set Item 27 Text InputList3SigType38=Serial InputList3Cue39=Set Item 28 Text InputList3SigType39=Serial InputList3Cue40=Set Item 29 Text InputList3SigType40=Serial InputList3Cue41=Set Item 30 Text InputList3SigType41=Serial InputList3Cue42=Set Item 31 Text InputList3SigType42=Serial InputList3Cue43=Set Item 32 Text InputList3SigType43=Serial InputList3Cue44=Set Item 33 Text InputList3SigType44=Serial InputList3Cue45=Set Item 34 Text InputList3SigType45=Serial InputList3Cue46=Set Item 35 Text InputList3SigType46=Serial InputList3Cue47=Set Item 36 Text InputList3SigType47=Serial InputList3Cue48=Set Item 37 Text InputList3SigType48=Serial InputList3Cue49=Set Item 38 Text InputList3SigType49=Serial InputList3Cue50=Set Item 39 Text InputList3SigType50=Serial InputList3Cue51=Set Item 40 Text InputList3SigType51=Serial InputList3Cue52=Set Item 41 Text InputList3SigType52=Serial InputList3Cue53=Set Item 42 Text InputList3SigType53=Serial InputList3Cue54=Set Item 43 Text InputList3SigType54=Serial InputList3Cue55=Set Item 44 Text InputList3SigType55=Serial InputList3Cue56=Set Item 45 Text InputList3SigType56=Serial InputList3Cue57=Set Item 46 Text InputList3SigType57=Serial InputList3Cue58=Set Item 47 Text InputList3SigType58=Serial InputList3Cue59=Set Item 48 Text InputList3SigType59=Serial InputList3Cue60=Set Item 49 Text InputList3SigType60=Serial InputList3Cue61=Set Item 50 Text InputList3SigType61=Serial InputList3Cue62=Set Item 51 Text InputList3SigType62=Serial InputList3Cue63=Set Item 52 Text InputList3SigType63=Serial InputList3Cue64=Set Item 53 Text InputList3SigType64=Serial InputList3Cue65=Set Item 54 Text InputList3SigType65=Serial InputList3Cue66=Set Item 55 Text InputList3SigType66=Serial InputList3Cue67=Set Item 56 Text InputList3SigType67=Serial InputList3Cue68=Set Item 57 Text InputList3SigType68=Serial InputList3Cue69=Set Item 58 Text InputList3SigType69=Serial InputList3Cue70=Set Item 59 Text InputList3SigType70=Serial InputList3Cue71=Set Item 60 Text InputList3SigType71=Serial InputList3Cue72=Set Item 61 Text InputList3SigType72=Serial InputList3Cue73=Set Item 62 Text InputList3SigType73=Serial InputList3Cue74=Set Item 63 Text InputList3SigType74=Serial InputList3Cue75=Set Item 64 Text InputList3SigType75=Serial InputList3Cue76=Set Item 65 Text InputList3SigType76=Serial InputList3Cue77=Set Item 66 Text InputList3SigType77=Serial InputList3Cue78=Set Item 67 Text InputList3SigType78=Serial InputList3Cue79=Set Item 68 Text InputList3SigType79=Serial InputList3Cue80=Set Item 69 Text InputList3SigType80=Serial InputList3Cue81=Set Item 70 Text InputList3SigType81=Serial InputList3Cue82=Set Item 71 Text InputList3SigType82=Serial InputList3Cue83=Set Item 72 Text InputList3SigType83=Serial InputList3Cue84=Set Item 73 Text InputList3SigType84=Serial InputList3Cue85=Set Item 74 Text InputList3SigType85=Serial InputList3Cue86=Set Item 75 Text InputList3SigType86=Serial InputList3Cue87=Set Item 76 Text InputList3SigType87=Serial InputList3Cue88=Set Item 77 Text InputList3SigType88=Serial InputList3Cue89=Set Item 78 Text InputList3SigType89=Serial InputList3Cue90=Set Item 79 Text InputList3SigType90=Serial InputList3Cue91=Set Item 80 Text InputList3SigType91=Serial InputList3Cue92=Set Item 81 Text InputList3SigType92=Serial InputList3Cue93=Set Item 82 Text InputList3SigType93=Serial InputList3Cue94=Set Item 83 Text InputList3SigType94=Serial InputList3Cue95=Set Item 84 Text InputList3SigType95=Serial InputList3Cue96=Set Item 85 Text InputList3SigType96=Serial InputList3Cue97=Set Item 86 Text InputList3SigType97=Serial InputList3Cue98=Set Item 87 Text InputList3SigType98=Serial InputList3Cue99=Set Item 88 Text InputList3SigType99=Serial InputList3Cue100=Set Item 89 Text InputList3SigType100=Serial InputList3Cue101=Set Item 90 Text InputList3SigType101=Serial InputList3Cue102=Set Item 91 Text InputList3SigType102=Serial InputList3Cue103=Set Item 92 Text InputList3SigType103=Serial InputList3Cue104=Set Item 93 Text InputList3SigType104=Serial InputList3Cue105=Set Item 94 Text InputList3SigType105=Serial InputList3Cue106=Set Item 95 Text InputList3SigType106=Serial InputList3Cue107=Set Item 96 Text InputList3SigType107=Serial InputList3Cue108=Set Item 97 Text InputList3SigType108=Serial InputList3Cue109=Set Item 98 Text InputList3SigType109=Serial InputList3Cue110=Set Item 99 Text InputList3SigType110=Serial InputList3Cue111=Set Item 100 Text InputList3SigType111=Serial InputList3Cue112=Set Item 101 Text InputList3SigType112=Serial InputList3Cue113=Set Item 102 Text InputList3SigType113=Serial InputList3Cue114=Set Item 103 Text InputList3SigType114=Serial InputList3Cue115=Set Item 104 Text InputList3SigType115=Serial InputList3Cue116=Set Item 105 Text InputList3SigType116=Serial InputList3Cue117=Set Item 106 Text InputList3SigType117=Serial InputList3Cue118=Set Item 107 Text InputList3SigType118=Serial InputList3Cue119=Set Item 108 Text InputList3SigType119=Serial InputList3Cue120=Set Item 109 Text InputList3SigType120=Serial InputList3Cue121=Set Item 110 Text InputList3SigType121=Serial InputList3Cue122=Set Item 111 Text InputList3SigType122=Serial InputList3Cue123=Set Item 112 Text InputList3SigType123=Serial InputList3Cue124=Set Item 113 Text InputList3SigType124=Serial InputList3Cue125=Set Item 114 Text InputList3SigType125=Serial InputList3Cue126=Set Item 115 Text InputList3SigType126=Serial InputList3Cue127=Set Item 116 Text InputList3SigType127=Serial InputList3Cue128=Set Item 117 Text InputList3SigType128=Serial InputList3Cue129=Set Item 118 Text InputList3SigType129=Serial InputList3Cue130=Set Item 119 Text InputList3SigType130=Serial InputList3Cue131=Set Item 120 Text InputList3SigType131=Serial InputList3Cue132=Set Item 121 Text InputList3SigType132=Serial InputList3Cue133=Set Item 122 Text InputList3SigType133=Serial InputList3Cue134=Set Item 123 Text InputList3SigType134=Serial InputList3Cue135=Set Item 124 Text InputList3SigType135=Serial InputList3Cue136=Set Item 125 Text InputList3SigType136=Serial InputList3Cue137=Set Item 126 Text InputList3SigType137=Serial InputList3Cue138=Set Item 127 Text InputList3SigType138=Serial InputList3Cue139=Set Item 128 Text InputList3SigType139=Serial InputList3Cue140=Set Item 129 Text InputList3SigType140=Serial InputList3Cue141=Set Item 130 Text InputList3SigType141=Serial InputList3Cue142=Set Item 131 Text InputList3SigType142=Serial InputList3Cue143=Set Item 132 Text InputList3SigType143=Serial InputList3Cue144=Set Item 133 Text InputList3SigType144=Serial InputList3Cue145=Set Item 134 Text InputList3SigType145=Serial InputList3Cue146=Set Item 135 Text InputList3SigType146=Serial InputList3Cue147=Set Item 136 Text InputList3SigType147=Serial InputList3Cue148=Set Item 137 Text InputList3SigType148=Serial InputList3Cue149=Set Item 138 Text InputList3SigType149=Serial InputList3Cue150=Set Item 139 Text InputList3SigType150=Serial InputList3Cue151=Set Item 140 Text InputList3SigType151=Serial InputList3Cue152=Set Item 141 Text InputList3SigType152=Serial InputList3Cue153=Set Item 142 Text InputList3SigType153=Serial InputList3Cue154=Set Item 143 Text InputList3SigType154=Serial InputList3Cue155=Set Item 144 Text InputList3SigType155=Serial InputList3Cue156=Set Item 145 Text InputList3SigType156=Serial InputList3Cue157=Set Item 146 Text InputList3SigType157=Serial InputList3Cue158=Set Item 147 Text InputList3SigType158=Serial InputList3Cue159=Set Item 148 Text InputList3SigType159=Serial InputList3Cue160=Set Item 149 Text InputList3SigType160=Serial InputList3Cue161=Set Item 150 Text InputList3SigType161=Serial InputList3Cue162=Set Item 151 Text InputList3SigType162=Serial InputList3Cue163=Set Item 152 Text InputList3SigType163=Serial InputList3Cue164=Set Item 153 Text InputList3SigType164=Serial InputList3Cue165=Set Item 154 Text InputList3SigType165=Serial InputList3Cue166=Set Item 155 Text InputList3SigType166=Serial InputList3Cue167=Set Item 156 Text InputList3SigType167=Serial InputList3Cue168=Set Item 157 Text InputList3SigType168=Serial InputList3Cue169=Set Item 158 Text InputList3SigType169=Serial InputList3Cue170=Set Item 159 Text InputList3SigType170=Serial InputList3Cue171=Set Item 160 Text InputList3SigType171=Serial InputList3Cue172=Set Item 161 Text InputList3SigType172=Serial InputList3Cue173=Set Item 162 Text InputList3SigType173=Serial InputList3Cue174=Set Item 163 Text InputList3SigType174=Serial InputList3Cue175=Set Item 164 Text InputList3SigType175=Serial InputList3Cue176=Set Item 165 Text InputList3SigType176=Serial InputList3Cue177=Set Item 166 Text InputList3SigType177=Serial InputList3Cue178=Set Item 167 Text InputList3SigType178=Serial InputList3Cue179=Set Item 168 Text InputList3SigType179=Serial InputList3Cue180=Set Item 169 Text InputList3SigType180=Serial InputList3Cue181=Set Item 170 Text InputList3SigType181=Serial InputList3Cue182=Set Item 171 Text InputList3SigType182=Serial InputList3Cue183=Set Item 172 Text InputList3SigType183=Serial InputList3Cue184=Set Item 173 Text InputList3SigType184=Serial InputList3Cue185=Set Item 174 Text InputList3SigType185=Serial InputList3Cue186=Set Item 175 Text InputList3SigType186=Serial InputList3Cue187=Set Item 176 Text InputList3SigType187=Serial InputList3Cue188=Set Item 177 Text InputList3SigType188=Serial InputList3Cue189=Set Item 178 Text InputList3SigType189=Serial InputList3Cue190=Set Item 179 Text InputList3SigType190=Serial InputList3Cue191=Set Item 180 Text InputList3SigType191=Serial InputList3Cue192=Set Item 181 Text InputList3SigType192=Serial InputList3Cue193=Set Item 182 Text InputList3SigType193=Serial InputList3Cue194=Set Item 183 Text InputList3SigType194=Serial InputList3Cue195=Set Item 184 Text InputList3SigType195=Serial InputList3Cue196=Set Item 185 Text InputList3SigType196=Serial InputList3Cue197=Set Item 186 Text InputList3SigType197=Serial InputList3Cue198=Set Item 187 Text InputList3SigType198=Serial InputList3Cue199=Set Item 188 Text InputList3SigType199=Serial InputList3Cue200=Set Item 189 Text InputList3SigType200=Serial InputList3Cue201=Set Item 190 Text InputList3SigType201=Serial InputList3Cue202=Set Item 191 Text InputList3SigType202=Serial InputList3Cue203=Set Item 192 Text InputList3SigType203=Serial InputList3Cue204=Set Item 193 Text InputList3SigType204=Serial InputList3Cue205=Set Item 194 Text InputList3SigType205=Serial InputList3Cue206=Set Item 195 Text InputList3SigType206=Serial InputList3Cue207=Set Item 196 Text InputList3SigType207=Serial InputList3Cue208=Set Item 197 Text InputList3SigType208=Serial InputList3Cue209=Set Item 198 Text InputList3SigType209=Serial InputList3Cue210=Set Item 199 Text InputList3SigType210=Serial InputList3Cue211=Set Item 200 Text InputList3SigType211=Serial InputList3Cue212=Set Item 201 Text InputList3SigType212=Serial InputList3Cue213=Set Item 202 Text InputList3SigType213=Serial InputList3Cue214=Set Item 203 Text InputList3SigType214=Serial InputList3Cue215=Set Item 204 Text InputList3SigType215=Serial InputList3Cue216=Set Item 205 Text InputList3SigType216=Serial InputList3Cue217=Set Item 206 Text InputList3SigType217=Serial InputList3Cue218=Set Item 207 Text InputList3SigType218=Serial InputList3Cue219=Set Item 208 Text InputList3SigType219=Serial InputList3Cue220=Set Item 209 Text InputList3SigType220=Serial InputList3Cue221=Set Item 210 Text InputList3SigType221=Serial InputList3Cue222=Set Item 211 Text InputList3SigType222=Serial InputList3Cue223=Set Item 212 Text InputList3SigType223=Serial InputList3Cue224=Set Item 213 Text InputList3SigType224=Serial InputList3Cue225=Set Item 214 Text InputList3SigType225=Serial InputList3Cue226=Set Item 215 Text InputList3SigType226=Serial InputList3Cue227=Set Item 216 Text InputList3SigType227=Serial InputList3Cue228=Set Item 217 Text InputList3SigType228=Serial InputList3Cue229=Set Item 218 Text InputList3SigType229=Serial InputList3Cue230=Set Item 219 Text InputList3SigType230=Serial InputList3Cue231=Set Item 220 Text InputList3SigType231=Serial InputList3Cue232=Set Item 221 Text InputList3SigType232=Serial InputList3Cue233=Set Item 222 Text InputList3SigType233=Serial InputList3Cue234=Set Item 223 Text InputList3SigType234=Serial InputList3Cue235=Set Item 224 Text InputList3SigType235=Serial InputList3Cue236=Set Item 225 Text InputList3SigType236=Serial InputList3Cue237=Set Item 226 Text InputList3SigType237=Serial InputList3Cue238=Set Item 227 Text InputList3SigType238=Serial InputList3Cue239=Set Item 228 Text InputList3SigType239=Serial InputList3Cue240=Set Item 229 Text InputList3SigType240=Serial InputList3Cue241=Set Item 230 Text InputList3SigType241=Serial InputList3Cue242=Set Item 231 Text InputList3SigType242=Serial InputList3Cue243=Set Item 232 Text InputList3SigType243=Serial InputList3Cue244=Set Item 233 Text InputList3SigType244=Serial InputList3Cue245=Set Item 234 Text InputList3SigType245=Serial InputList3Cue246=Set Item 235 Text InputList3SigType246=Serial InputList3Cue247=Set Item 236 Text InputList3SigType247=Serial InputList3Cue248=Set Item 237 Text InputList3SigType248=Serial InputList3Cue249=Set Item 238 Text InputList3SigType249=Serial InputList3Cue250=Set Item 239 Text InputList3SigType250=Serial InputList3Cue251=Set Item 240 Text InputList3SigType251=Serial InputList3Cue252=Set Item 241 Text InputList3SigType252=Serial InputList3Cue253=Set Item 242 Text InputList3SigType253=Serial InputList3Cue254=Set Item 243 Text InputList3SigType254=Serial InputList3Cue255=Set Item 244 Text InputList3SigType255=Serial InputList3Cue256=Set Item 245 Text InputList3SigType256=Serial InputList3Cue257=Set Item 246 Text InputList3SigType257=Serial InputList3Cue258=Set Item 247 Text InputList3SigType258=Serial InputList3Cue259=Set Item 248 Text InputList3SigType259=Serial InputList3Cue260=Set Item 249 Text InputList3SigType260=Serial InputList3Cue261=Set Item 250 Text InputList3SigType261=Serial InputList3Cue262=Set Item 251 Text InputList3SigType262=Serial InputList3Cue263=Set Item 252 Text InputList3SigType263=Serial InputList3Cue264=Set Item 253 Text InputList3SigType264=Serial InputList3Cue265=Set Item 254 Text InputList3SigType265=Serial InputList3Cue266=Set Item 255 Text InputList3SigType266=Serial InputList3Cue267=[~UNUSED2~] InputList3SigType267=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=Set Item 11 Icon Serial InputList3SigType2024=Serial InputList3Cue2025=Set Item 12 Icon Serial InputList3SigType2025=Serial InputList3Cue2026=Set Item 13 Icon Serial InputList3SigType2026=Serial InputList3Cue2027=Set Item 14 Icon Serial InputList3SigType2027=Serial InputList3Cue2028=Set Item 15 Icon Serial InputList3SigType2028=Serial InputList3Cue2029=Set Item 16 Icon Serial InputList3SigType2029=Serial InputList3Cue2030=Set Item 17 Icon Serial InputList3SigType2030=Serial InputList3Cue2031=Set Item 18 Icon Serial InputList3SigType2031=Serial InputList3Cue2032=Set Item 19 Icon Serial InputList3SigType2032=Serial InputList3Cue2033=Set Item 20 Icon Serial InputList3SigType2033=Serial InputList3Cue2034=Set Item 21 Icon Serial InputList3SigType2034=Serial InputList3Cue2035=Set Item 22 Icon Serial InputList3SigType2035=Serial InputList3Cue2036=Set Item 23 Icon Serial InputList3SigType2036=Serial InputList3Cue2037=Set Item 24 Icon Serial InputList3SigType2037=Serial InputList3Cue2038=Set Item 25 Icon Serial InputList3SigType2038=Serial InputList3Cue2039=Set Item 26 Icon Serial InputList3SigType2039=Serial InputList3Cue2040=Set Item 27 Icon Serial InputList3SigType2040=Serial InputList3Cue2041=Set Item 28 Icon Serial InputList3SigType2041=Serial InputList3Cue2042=Set Item 29 Icon Serial InputList3SigType2042=Serial InputList3Cue2043=Set Item 30 Icon Serial InputList3SigType2043=Serial InputList3Cue2044=Set Item 31 Icon Serial InputList3SigType2044=Serial InputList3Cue2045=Set Item 32 Icon Serial InputList3SigType2045=Serial InputList3Cue2046=Set Item 33 Icon Serial InputList3SigType2046=Serial InputList3Cue2047=Set Item 34 Icon Serial InputList3SigType2047=Serial InputList3Cue2048=Set Item 35 Icon Serial InputList3SigType2048=Serial InputList3Cue2049=Set Item 36 Icon Serial InputList3SigType2049=Serial InputList3Cue2050=Set Item 37 Icon Serial InputList3SigType2050=Serial InputList3Cue2051=Set Item 38 Icon Serial InputList3SigType2051=Serial InputList3Cue2052=Set Item 39 Icon Serial InputList3SigType2052=Serial InputList3Cue2053=Set Item 40 Icon Serial InputList3SigType2053=Serial InputList3Cue2054=Set Item 41 Icon Serial InputList3SigType2054=Serial InputList3Cue2055=Set Item 42 Icon Serial InputList3SigType2055=Serial InputList3Cue2056=Set Item 43 Icon Serial InputList3SigType2056=Serial InputList3Cue2057=Set Item 44 Icon Serial InputList3SigType2057=Serial InputList3Cue2058=Set Item 45 Icon Serial InputList3SigType2058=Serial InputList3Cue2059=Set Item 46 Icon Serial InputList3SigType2059=Serial InputList3Cue2060=Set Item 47 Icon Serial InputList3SigType2060=Serial InputList3Cue2061=Set Item 48 Icon Serial InputList3SigType2061=Serial InputList3Cue2062=Set Item 49 Icon Serial InputList3SigType2062=Serial InputList3Cue2063=Set Item 50 Icon Serial InputList3SigType2063=Serial InputList3Cue2064=Set Item 51 Icon Serial InputList3SigType2064=Serial InputList3Cue2065=Set Item 52 Icon Serial InputList3SigType2065=Serial InputList3Cue2066=Set Item 53 Icon Serial InputList3SigType2066=Serial InputList3Cue2067=Set Item 54 Icon Serial InputList3SigType2067=Serial InputList3Cue2068=Set Item 55 Icon Serial InputList3SigType2068=Serial InputList3Cue2069=Set Item 56 Icon Serial InputList3SigType2069=Serial InputList3Cue2070=Set Item 57 Icon Serial InputList3SigType2070=Serial InputList3Cue2071=Set Item 58 Icon Serial InputList3SigType2071=Serial InputList3Cue2072=Set Item 59 Icon Serial InputList3SigType2072=Serial InputList3Cue2073=Set Item 60 Icon Serial InputList3SigType2073=Serial InputList3Cue2074=Set Item 61 Icon Serial InputList3SigType2074=Serial InputList3Cue2075=Set Item 62 Icon Serial InputList3SigType2075=Serial InputList3Cue2076=Set Item 63 Icon Serial InputList3SigType2076=Serial InputList3Cue2077=Set Item 64 Icon Serial InputList3SigType2077=Serial InputList3Cue2078=Set Item 65 Icon Serial InputList3SigType2078=Serial InputList3Cue2079=Set Item 66 Icon Serial InputList3SigType2079=Serial InputList3Cue2080=Set Item 67 Icon Serial InputList3SigType2080=Serial InputList3Cue2081=Set Item 68 Icon Serial InputList3SigType2081=Serial InputList3Cue2082=Set Item 69 Icon Serial InputList3SigType2082=Serial InputList3Cue2083=Set Item 70 Icon Serial InputList3SigType2083=Serial InputList3Cue2084=Set Item 71 Icon Serial InputList3SigType2084=Serial InputList3Cue2085=Set Item 72 Icon Serial InputList3SigType2085=Serial InputList3Cue2086=Set Item 73 Icon Serial InputList3SigType2086=Serial InputList3Cue2087=Set Item 74 Icon Serial InputList3SigType2087=Serial InputList3Cue2088=Set Item 75 Icon Serial InputList3SigType2088=Serial InputList3Cue2089=Set Item 76 Icon Serial InputList3SigType2089=Serial InputList3Cue2090=Set Item 77 Icon Serial InputList3SigType2090=Serial InputList3Cue2091=Set Item 78 Icon Serial InputList3SigType2091=Serial InputList3Cue2092=Set Item 79 Icon Serial InputList3SigType2092=Serial InputList3Cue2093=Set Item 80 Icon Serial InputList3SigType2093=Serial InputList3Cue2094=Set Item 81 Icon Serial InputList3SigType2094=Serial InputList3Cue2095=Set Item 82 Icon Serial InputList3SigType2095=Serial InputList3Cue2096=Set Item 83 Icon Serial InputList3SigType2096=Serial InputList3Cue2097=Set Item 84 Icon Serial InputList3SigType2097=Serial InputList3Cue2098=Set Item 85 Icon Serial InputList3SigType2098=Serial InputList3Cue2099=Set Item 86 Icon Serial InputList3SigType2099=Serial InputList3Cue2100=Set Item 87 Icon Serial InputList3SigType2100=Serial InputList3Cue2101=Set Item 88 Icon Serial InputList3SigType2101=Serial InputList3Cue2102=Set Item 89 Icon Serial InputList3SigType2102=Serial InputList3Cue2103=Set Item 90 Icon Serial InputList3SigType2103=Serial InputList3Cue2104=Set Item 91 Icon Serial InputList3SigType2104=Serial InputList3Cue2105=Set Item 92 Icon Serial InputList3SigType2105=Serial InputList3Cue2106=Set Item 93 Icon Serial InputList3SigType2106=Serial InputList3Cue2107=Set Item 94 Icon Serial InputList3SigType2107=Serial InputList3Cue2108=Set Item 95 Icon Serial InputList3SigType2108=Serial InputList3Cue2109=Set Item 96 Icon Serial InputList3SigType2109=Serial InputList3Cue2110=Set Item 97 Icon Serial InputList3SigType2110=Serial InputList3Cue2111=Set Item 98 Icon Serial InputList3SigType2111=Serial InputList3Cue2112=Set Item 99 Icon Serial InputList3SigType2112=Serial InputList3Cue2113=Set Item 100 Icon Serial InputList3SigType2113=Serial InputList3Cue2114=Set Item 101 Icon Serial InputList3SigType2114=Serial InputList3Cue2115=Set Item 102 Icon Serial InputList3SigType2115=Serial InputList3Cue2116=Set Item 103 Icon Serial InputList3SigType2116=Serial InputList3Cue2117=Set Item 104 Icon Serial InputList3SigType2117=Serial InputList3Cue2118=Set Item 105 Icon Serial InputList3SigType2118=Serial InputList3Cue2119=Set Item 106 Icon Serial InputList3SigType2119=Serial InputList3Cue2120=Set Item 107 Icon Serial InputList3SigType2120=Serial InputList3Cue2121=Set Item 108 Icon Serial InputList3SigType2121=Serial InputList3Cue2122=Set Item 109 Icon Serial InputList3SigType2122=Serial InputList3Cue2123=Set Item 110 Icon Serial InputList3SigType2123=Serial InputList3Cue2124=Set Item 111 Icon Serial InputList3SigType2124=Serial InputList3Cue2125=Set Item 112 Icon Serial InputList3SigType2125=Serial InputList3Cue2126=Set Item 113 Icon Serial InputList3SigType2126=Serial InputList3Cue2127=Set Item 114 Icon Serial InputList3SigType2127=Serial InputList3Cue2128=Set Item 115 Icon Serial InputList3SigType2128=Serial InputList3Cue2129=Set Item 116 Icon Serial InputList3SigType2129=Serial InputList3Cue2130=Set Item 117 Icon Serial InputList3SigType2130=Serial InputList3Cue2131=Set Item 118 Icon Serial InputList3SigType2131=Serial InputList3Cue2132=Set Item 119 Icon Serial InputList3SigType2132=Serial InputList3Cue2133=Set Item 120 Icon Serial InputList3SigType2133=Serial InputList3Cue2134=Set Item 121 Icon Serial InputList3SigType2134=Serial InputList3Cue2135=Set Item 122 Icon Serial InputList3SigType2135=Serial InputList3Cue2136=Set Item 123 Icon Serial InputList3SigType2136=Serial InputList3Cue2137=Set Item 124 Icon Serial InputList3SigType2137=Serial InputList3Cue2138=Set Item 125 Icon Serial InputList3SigType2138=Serial InputList3Cue2139=Set Item 126 Icon Serial InputList3SigType2139=Serial InputList3Cue2140=Set Item 127 Icon Serial InputList3SigType2140=Serial InputList3Cue2141=Set Item 128 Icon Serial InputList3SigType2141=Serial InputList3Cue2142=Set Item 129 Icon Serial InputList3SigType2142=Serial InputList3Cue2143=Set Item 130 Icon Serial InputList3SigType2143=Serial InputList3Cue2144=Set Item 131 Icon Serial InputList3SigType2144=Serial InputList3Cue2145=Set Item 132 Icon Serial InputList3SigType2145=Serial InputList3Cue2146=Set Item 133 Icon Serial InputList3SigType2146=Serial InputList3Cue2147=Set Item 134 Icon Serial InputList3SigType2147=Serial InputList3Cue2148=Set Item 135 Icon Serial InputList3SigType2148=Serial InputList3Cue2149=Set Item 136 Icon Serial InputList3SigType2149=Serial InputList3Cue2150=Set Item 137 Icon Serial InputList3SigType2150=Serial InputList3Cue2151=Set Item 138 Icon Serial InputList3SigType2151=Serial InputList3Cue2152=Set Item 139 Icon Serial InputList3SigType2152=Serial InputList3Cue2153=Set Item 140 Icon Serial InputList3SigType2153=Serial InputList3Cue2154=Set Item 141 Icon Serial InputList3SigType2154=Serial InputList3Cue2155=Set Item 142 Icon Serial InputList3SigType2155=Serial InputList3Cue2156=Set Item 143 Icon Serial InputList3SigType2156=Serial InputList3Cue2157=Set Item 144 Icon Serial InputList3SigType2157=Serial InputList3Cue2158=Set Item 145 Icon Serial InputList3SigType2158=Serial InputList3Cue2159=Set Item 146 Icon Serial InputList3SigType2159=Serial InputList3Cue2160=Set Item 147 Icon Serial InputList3SigType2160=Serial InputList3Cue2161=Set Item 148 Icon Serial InputList3SigType2161=Serial InputList3Cue2162=Set Item 149 Icon Serial InputList3SigType2162=Serial InputList3Cue2163=Set Item 150 Icon Serial InputList3SigType2163=Serial InputList3Cue2164=Set Item 151 Icon Serial InputList3SigType2164=Serial InputList3Cue2165=Set Item 152 Icon Serial InputList3SigType2165=Serial InputList3Cue2166=Set Item 153 Icon Serial InputList3SigType2166=Serial InputList3Cue2167=Set Item 154 Icon Serial InputList3SigType2167=Serial InputList3Cue2168=Set Item 155 Icon Serial InputList3SigType2168=Serial InputList3Cue2169=Set Item 156 Icon Serial InputList3SigType2169=Serial InputList3Cue2170=Set Item 157 Icon Serial InputList3SigType2170=Serial InputList3Cue2171=Set Item 158 Icon Serial InputList3SigType2171=Serial InputList3Cue2172=Set Item 159 Icon Serial InputList3SigType2172=Serial InputList3Cue2173=Set Item 160 Icon Serial InputList3SigType2173=Serial InputList3Cue2174=Set Item 161 Icon Serial InputList3SigType2174=Serial InputList3Cue2175=Set Item 162 Icon Serial InputList3SigType2175=Serial InputList3Cue2176=Set Item 163 Icon Serial InputList3SigType2176=Serial InputList3Cue2177=Set Item 164 Icon Serial InputList3SigType2177=Serial InputList3Cue2178=Set Item 165 Icon Serial InputList3SigType2178=Serial InputList3Cue2179=Set Item 166 Icon Serial InputList3SigType2179=Serial InputList3Cue2180=Set Item 167 Icon Serial InputList3SigType2180=Serial InputList3Cue2181=Set Item 168 Icon Serial InputList3SigType2181=Serial InputList3Cue2182=Set Item 169 Icon Serial InputList3SigType2182=Serial InputList3Cue2183=Set Item 170 Icon Serial InputList3SigType2183=Serial InputList3Cue2184=Set Item 171 Icon Serial InputList3SigType2184=Serial InputList3Cue2185=Set Item 172 Icon Serial InputList3SigType2185=Serial InputList3Cue2186=Set Item 173 Icon Serial InputList3SigType2186=Serial InputList3Cue2187=Set Item 174 Icon Serial InputList3SigType2187=Serial InputList3Cue2188=Set Item 175 Icon Serial InputList3SigType2188=Serial InputList3Cue2189=Set Item 176 Icon Serial InputList3SigType2189=Serial InputList3Cue2190=Set Item 177 Icon Serial InputList3SigType2190=Serial InputList3Cue2191=Set Item 178 Icon Serial InputList3SigType2191=Serial InputList3Cue2192=Set Item 179 Icon Serial InputList3SigType2192=Serial InputList3Cue2193=Set Item 180 Icon Serial InputList3SigType2193=Serial InputList3Cue2194=Set Item 181 Icon Serial InputList3SigType2194=Serial InputList3Cue2195=Set Item 182 Icon Serial InputList3SigType2195=Serial InputList3Cue2196=Set Item 183 Icon Serial InputList3SigType2196=Serial InputList3Cue2197=Set Item 184 Icon Serial InputList3SigType2197=Serial InputList3Cue2198=Set Item 185 Icon Serial InputList3SigType2198=Serial InputList3Cue2199=Set Item 186 Icon Serial InputList3SigType2199=Serial InputList3Cue2200=Set Item 187 Icon Serial InputList3SigType2200=Serial InputList3Cue2201=Set Item 188 Icon Serial InputList3SigType2201=Serial InputList3Cue2202=Set Item 189 Icon Serial InputList3SigType2202=Serial InputList3Cue2203=Set Item 190 Icon Serial InputList3SigType2203=Serial InputList3Cue2204=Set Item 191 Icon Serial InputList3SigType2204=Serial InputList3Cue2205=Set Item 192 Icon Serial InputList3SigType2205=Serial InputList3Cue2206=Set Item 193 Icon Serial InputList3SigType2206=Serial InputList3Cue2207=Set Item 194 Icon Serial InputList3SigType2207=Serial InputList3Cue2208=Set Item 195 Icon Serial InputList3SigType2208=Serial InputList3Cue2209=Set Item 196 Icon Serial InputList3SigType2209=Serial InputList3Cue2210=Set Item 197 Icon Serial InputList3SigType2210=Serial InputList3Cue2211=Set Item 198 Icon Serial InputList3SigType2211=Serial InputList3Cue2212=Set Item 199 Icon Serial InputList3SigType2212=Serial InputList3Cue2213=Set Item 200 Icon Serial InputList3SigType2213=Serial InputList3Cue2214=Set Item 201 Icon Serial InputList3SigType2214=Serial InputList3Cue2215=Set Item 202 Icon Serial InputList3SigType2215=Serial InputList3Cue2216=Set Item 203 Icon Serial InputList3SigType2216=Serial InputList3Cue2217=Set Item 204 Icon Serial InputList3SigType2217=Serial InputList3Cue2218=Set Item 205 Icon Serial InputList3SigType2218=Serial InputList3Cue2219=Set Item 206 Icon Serial InputList3SigType2219=Serial InputList3Cue2220=Set Item 207 Icon Serial InputList3SigType2220=Serial InputList3Cue2221=Set Item 208 Icon Serial InputList3SigType2221=Serial InputList3Cue2222=Set Item 209 Icon Serial InputList3SigType2222=Serial InputList3Cue2223=Set Item 210 Icon Serial InputList3SigType2223=Serial InputList3Cue2224=Set Item 211 Icon Serial InputList3SigType2224=Serial InputList3Cue2225=Set Item 212 Icon Serial InputList3SigType2225=Serial InputList3Cue2226=Set Item 213 Icon Serial InputList3SigType2226=Serial InputList3Cue2227=Set Item 214 Icon Serial InputList3SigType2227=Serial InputList3Cue2228=Set Item 215 Icon Serial InputList3SigType2228=Serial InputList3Cue2229=Set Item 216 Icon Serial InputList3SigType2229=Serial InputList3Cue2230=Set Item 217 Icon Serial InputList3SigType2230=Serial InputList3Cue2231=Set Item 218 Icon Serial InputList3SigType2231=Serial InputList3Cue2232=Set Item 219 Icon Serial InputList3SigType2232=Serial InputList3Cue2233=Set Item 220 Icon Serial InputList3SigType2233=Serial InputList3Cue2234=Set Item 221 Icon Serial InputList3SigType2234=Serial InputList3Cue2235=Set Item 222 Icon Serial InputList3SigType2235=Serial InputList3Cue2236=Set Item 223 Icon Serial InputList3SigType2236=Serial InputList3Cue2237=Set Item 224 Icon Serial InputList3SigType2237=Serial InputList3Cue2238=Set Item 225 Icon Serial InputList3SigType2238=Serial InputList3Cue2239=Set Item 226 Icon Serial InputList3SigType2239=Serial InputList3Cue2240=Set Item 227 Icon Serial InputList3SigType2240=Serial InputList3Cue2241=Set Item 228 Icon Serial InputList3SigType2241=Serial InputList3Cue2242=Set Item 229 Icon Serial InputList3SigType2242=Serial InputList3Cue2243=Set Item 230 Icon Serial InputList3SigType2243=Serial InputList3Cue2244=Set Item 231 Icon Serial InputList3SigType2244=Serial InputList3Cue2245=Set Item 232 Icon Serial InputList3SigType2245=Serial InputList3Cue2246=Set Item 233 Icon Serial InputList3SigType2246=Serial InputList3Cue2247=Set Item 234 Icon Serial InputList3SigType2247=Serial InputList3Cue2248=Set Item 235 Icon Serial InputList3SigType2248=Serial InputList3Cue2249=Set Item 236 Icon Serial InputList3SigType2249=Serial InputList3Cue2250=Set Item 237 Icon Serial InputList3SigType2250=Serial InputList3Cue2251=Set Item 238 Icon Serial InputList3SigType2251=Serial InputList3Cue2252=Set Item 239 Icon Serial InputList3SigType2252=Serial InputList3Cue2253=Set Item 240 Icon Serial InputList3SigType2253=Serial InputList3Cue2254=Set Item 241 Icon Serial InputList3SigType2254=Serial InputList3Cue2255=Set Item 242 Icon Serial InputList3SigType2255=Serial InputList3Cue2256=Set Item 243 Icon Serial InputList3SigType2256=Serial InputList3Cue2257=Set Item 244 Icon Serial InputList3SigType2257=Serial InputList3Cue2258=Set Item 245 Icon Serial InputList3SigType2258=Serial InputList3Cue2259=Set Item 246 Icon Serial InputList3SigType2259=Serial InputList3Cue2260=Set Item 247 Icon Serial InputList3SigType2260=Serial InputList3Cue2261=Set Item 248 Icon Serial InputList3SigType2261=Serial InputList3Cue2262=Set Item 249 Icon Serial InputList3SigType2262=Serial InputList3Cue2263=Set Item 250 Icon Serial InputList3SigType2263=Serial InputList3Cue2264=Set Item 251 Icon Serial InputList3SigType2264=Serial InputList3Cue2265=Set Item 252 Icon Serial InputList3SigType2265=Serial InputList3Cue2266=Set Item 253 Icon Serial InputList3SigType2266=Serial InputList3Cue2267=Set Item 254 Icon Serial InputList3SigType2267=Serial InputList3Cue2268=Set Item 255 Icon Serial InputList3SigType2268=Serial InputList3Cue2269=[~UNUSED2~] InputList3SigType2269=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED3~] OutputList3SigType22=Serial OutputList3Cue23=[~UNUSED3~] OutputList3SigType23=Serial OutputList3Cue24=[~UNUSED3~] OutputList3SigType24=Serial OutputList3Cue25=[~UNUSED3~] OutputList3SigType25=Serial OutputList3Cue26=[~UNUSED3~] OutputList3SigType26=Serial OutputList3Cue27=[~UNUSED3~] OutputList3SigType27=Serial OutputList3Cue28=[~UNUSED3~] OutputList3SigType28=Serial OutputList3Cue29=[~UNUSED3~] OutputList3SigType29=Serial OutputList3Cue30=[~UNUSED3~] OutputList3SigType30=Serial OutputList3Cue31=[~UNUSED3~] OutputList3SigType31=Serial OutputList3Cue32=[~UNUSED3~] OutputList3SigType32=Serial OutputList3Cue33=[~UNUSED3~] OutputList3SigType33=Serial OutputList3Cue34=[~UNUSED3~] OutputList3SigType34=Serial OutputList3Cue35=[~UNUSED3~] OutputList3SigType35=Serial OutputList3Cue36=[~UNUSED3~] OutputList3SigType36=Serial OutputList3Cue37=[~UNUSED3~] OutputList3SigType37=Serial OutputList3Cue38=[~UNUSED3~] OutputList3SigType38=Serial OutputList3Cue39=[~UNUSED3~] OutputList3SigType39=Serial OutputList3Cue40=[~UNUSED3~] OutputList3SigType40=Serial OutputList3Cue41=[~UNUSED3~] OutputList3SigType41=Serial OutputList3Cue42=[~UNUSED3~] OutputList3SigType42=Serial OutputList3Cue43=[~UNUSED3~] OutputList3SigType43=Serial OutputList3Cue44=[~UNUSED3~] OutputList3SigType44=Serial OutputList3Cue45=[~UNUSED3~] OutputList3SigType45=Serial OutputList3Cue46=[~UNUSED3~] OutputList3SigType46=Serial OutputList3Cue47=[~UNUSED3~] OutputList3SigType47=Serial OutputList3Cue48=[~UNUSED3~] OutputList3SigType48=Serial OutputList3Cue49=[~UNUSED3~] OutputList3SigType49=Serial OutputList3Cue50=[~UNUSED3~] OutputList3SigType50=Serial OutputList3Cue51=[~UNUSED3~] OutputList3SigType51=Serial OutputList3Cue52=[~UNUSED3~] OutputList3SigType52=Serial OutputList3Cue53=[~UNUSED3~] OutputList3SigType53=Serial OutputList3Cue54=[~UNUSED3~] OutputList3SigType54=Serial OutputList3Cue55=[~UNUSED3~] OutputList3SigType55=Serial OutputList3Cue56=[~UNUSED3~] OutputList3SigType56=Serial OutputList3Cue57=[~UNUSED3~] OutputList3SigType57=Serial OutputList3Cue58=[~UNUSED3~] OutputList3SigType58=Serial OutputList3Cue59=[~UNUSED3~] OutputList3SigType59=Serial OutputList3Cue60=[~UNUSED3~] OutputList3SigType60=Serial OutputList3Cue61=[~UNUSED3~] OutputList3SigType61=Serial OutputList3Cue62=[~UNUSED3~] OutputList3SigType62=Serial OutputList3Cue63=[~UNUSED3~] OutputList3SigType63=Serial OutputList3Cue64=[~UNUSED3~] OutputList3SigType64=Serial OutputList3Cue65=[~UNUSED3~] OutputList3SigType65=Serial OutputList3Cue66=[~UNUSED3~] OutputList3SigType66=Serial OutputList3Cue67=[~UNUSED3~] OutputList3SigType67=Serial OutputList3Cue68=[~UNUSED3~] OutputList3SigType68=Serial OutputList3Cue69=[~UNUSED3~] OutputList3SigType69=Serial OutputList3Cue70=[~UNUSED3~] OutputList3SigType70=Serial OutputList3Cue71=[~UNUSED3~] OutputList3SigType71=Serial OutputList3Cue72=[~UNUSED3~] OutputList3SigType72=Serial OutputList3Cue73=[~UNUSED3~] OutputList3SigType73=Serial OutputList3Cue74=[~UNUSED3~] OutputList3SigType74=Serial OutputList3Cue75=[~UNUSED3~] OutputList3SigType75=Serial OutputList3Cue76=[~UNUSED3~] OutputList3SigType76=Serial OutputList3Cue77=[~UNUSED3~] OutputList3SigType77=Serial OutputList3Cue78=[~UNUSED3~] OutputList3SigType78=Serial OutputList3Cue79=[~UNUSED3~] OutputList3SigType79=Serial OutputList3Cue80=[~UNUSED3~] OutputList3SigType80=Serial OutputList3Cue81=[~UNUSED3~] OutputList3SigType81=Serial OutputList3Cue82=[~UNUSED3~] OutputList3SigType82=Serial OutputList3Cue83=[~UNUSED3~] OutputList3SigType83=Serial OutputList3Cue84=[~UNUSED3~] OutputList3SigType84=Serial OutputList3Cue85=[~UNUSED3~] OutputList3SigType85=Serial OutputList3Cue86=[~UNUSED3~] OutputList3SigType86=Serial OutputList3Cue87=[~UNUSED3~] OutputList3SigType87=Serial OutputList3Cue88=[~UNUSED3~] OutputList3SigType88=Serial OutputList3Cue89=[~UNUSED3~] OutputList3SigType89=Serial OutputList3Cue90=[~UNUSED3~] OutputList3SigType90=Serial OutputList3Cue91=[~UNUSED3~] OutputList3SigType91=Serial OutputList3Cue92=[~UNUSED3~] OutputList3SigType92=Serial OutputList3Cue93=[~UNUSED3~] OutputList3SigType93=Serial OutputList3Cue94=[~UNUSED3~] OutputList3SigType94=Serial OutputList3Cue95=[~UNUSED3~] OutputList3SigType95=Serial OutputList3Cue96=[~UNUSED3~] OutputList3SigType96=Serial OutputList3Cue97=[~UNUSED3~] OutputList3SigType97=Serial OutputList3Cue98=[~UNUSED3~] OutputList3SigType98=Serial OutputList3Cue99=[~UNUSED3~] OutputList3SigType99=Serial OutputList3Cue100=[~UNUSED3~] OutputList3SigType100=Serial OutputList3Cue101=[~UNUSED3~] OutputList3SigType101=Serial OutputList3Cue102=[~UNUSED3~] OutputList3SigType102=Serial OutputList3Cue103=[~UNUSED3~] OutputList3SigType103=Serial OutputList3Cue104=[~UNUSED3~] OutputList3SigType104=Serial OutputList3Cue105=[~UNUSED3~] OutputList3SigType105=Serial OutputList3Cue106=[~UNUSED3~] OutputList3SigType106=Serial OutputList3Cue107=[~UNUSED3~] OutputList3SigType107=Serial OutputList3Cue108=[~UNUSED3~] OutputList3SigType108=Serial OutputList3Cue109=[~UNUSED3~] OutputList3SigType109=Serial OutputList3Cue110=[~UNUSED3~] OutputList3SigType110=Serial OutputList3Cue111=[~UNUSED3~] OutputList3SigType111=Serial OutputList3Cue112=[~UNUSED3~] OutputList3SigType112=Serial OutputList3Cue113=[~UNUSED3~] OutputList3SigType113=Serial OutputList3Cue114=[~UNUSED3~] OutputList3SigType114=Serial OutputList3Cue115=[~UNUSED3~] OutputList3SigType115=Serial OutputList3Cue116=[~UNUSED3~] OutputList3SigType116=Serial OutputList3Cue117=[~UNUSED3~] OutputList3SigType117=Serial OutputList3Cue118=[~UNUSED3~] OutputList3SigType118=Serial OutputList3Cue119=[~UNUSED3~] OutputList3SigType119=Serial OutputList3Cue120=[~UNUSED3~] OutputList3SigType120=Serial OutputList3Cue121=[~UNUSED3~] OutputList3SigType121=Serial OutputList3Cue122=[~UNUSED3~] OutputList3SigType122=Serial OutputList3Cue123=[~UNUSED3~] OutputList3SigType123=Serial OutputList3Cue124=[~UNUSED3~] OutputList3SigType124=Serial OutputList3Cue125=[~UNUSED3~] OutputList3SigType125=Serial OutputList3Cue126=[~UNUSED3~] OutputList3SigType126=Serial OutputList3Cue127=[~UNUSED3~] OutputList3SigType127=Serial OutputList3Cue128=[~UNUSED3~] OutputList3SigType128=Serial OutputList3Cue129=[~UNUSED3~] OutputList3SigType129=Serial OutputList3Cue130=[~UNUSED3~] OutputList3SigType130=Serial OutputList3Cue131=[~UNUSED3~] OutputList3SigType131=Serial OutputList3Cue132=[~UNUSED3~] OutputList3SigType132=Serial OutputList3Cue133=[~UNUSED3~] OutputList3SigType133=Serial OutputList3Cue134=[~UNUSED3~] OutputList3SigType134=Serial OutputList3Cue135=[~UNUSED3~] OutputList3SigType135=Serial OutputList3Cue136=[~UNUSED3~] OutputList3SigType136=Serial OutputList3Cue137=[~UNUSED3~] OutputList3SigType137=Serial OutputList3Cue138=[~UNUSED3~] OutputList3SigType138=Serial OutputList3Cue139=[~UNUSED3~] OutputList3SigType139=Serial OutputList3Cue140=[~UNUSED3~] OutputList3SigType140=Serial OutputList3Cue141=[~UNUSED3~] OutputList3SigType141=Serial OutputList3Cue142=[~UNUSED3~] OutputList3SigType142=Serial OutputList3Cue143=[~UNUSED3~] OutputList3SigType143=Serial OutputList3Cue144=[~UNUSED3~] OutputList3SigType144=Serial OutputList3Cue145=[~UNUSED3~] OutputList3SigType145=Serial OutputList3Cue146=[~UNUSED3~] OutputList3SigType146=Serial OutputList3Cue147=[~UNUSED3~] OutputList3SigType147=Serial OutputList3Cue148=[~UNUSED3~] OutputList3SigType148=Serial OutputList3Cue149=[~UNUSED3~] OutputList3SigType149=Serial OutputList3Cue150=[~UNUSED3~] OutputList3SigType150=Serial OutputList3Cue151=[~UNUSED3~] OutputList3SigType151=Serial OutputList3Cue152=[~UNUSED3~] OutputList3SigType152=Serial OutputList3Cue153=[~UNUSED3~] OutputList3SigType153=Serial OutputList3Cue154=[~UNUSED3~] OutputList3SigType154=Serial OutputList3Cue155=[~UNUSED3~] OutputList3SigType155=Serial OutputList3Cue156=[~UNUSED3~] OutputList3SigType156=Serial OutputList3Cue157=[~UNUSED3~] OutputList3SigType157=Serial OutputList3Cue158=[~UNUSED3~] OutputList3SigType158=Serial OutputList3Cue159=[~UNUSED3~] OutputList3SigType159=Serial OutputList3Cue160=[~UNUSED3~] OutputList3SigType160=Serial OutputList3Cue161=[~UNUSED3~] OutputList3SigType161=Serial OutputList3Cue162=[~UNUSED3~] OutputList3SigType162=Serial OutputList3Cue163=[~UNUSED3~] OutputList3SigType163=Serial OutputList3Cue164=[~UNUSED3~] OutputList3SigType164=Serial OutputList3Cue165=[~UNUSED3~] OutputList3SigType165=Serial OutputList3Cue166=[~UNUSED3~] OutputList3SigType166=Serial OutputList3Cue167=[~UNUSED3~] OutputList3SigType167=Serial OutputList3Cue168=[~UNUSED3~] OutputList3SigType168=Serial OutputList3Cue169=[~UNUSED3~] OutputList3SigType169=Serial OutputList3Cue170=[~UNUSED3~] OutputList3SigType170=Serial OutputList3Cue171=[~UNUSED3~] OutputList3SigType171=Serial OutputList3Cue172=[~UNUSED3~] OutputList3SigType172=Serial OutputList3Cue173=[~UNUSED3~] OutputList3SigType173=Serial OutputList3Cue174=[~UNUSED3~] OutputList3SigType174=Serial OutputList3Cue175=[~UNUSED3~] OutputList3SigType175=Serial OutputList3Cue176=[~UNUSED3~] OutputList3SigType176=Serial OutputList3Cue177=[~UNUSED3~] OutputList3SigType177=Serial OutputList3Cue178=[~UNUSED3~] OutputList3SigType178=Serial OutputList3Cue179=[~UNUSED3~] OutputList3SigType179=Serial OutputList3Cue180=[~UNUSED3~] OutputList3SigType180=Serial OutputList3Cue181=[~UNUSED3~] OutputList3SigType181=Serial OutputList3Cue182=[~UNUSED3~] OutputList3SigType182=Serial OutputList3Cue183=[~UNUSED3~] OutputList3SigType183=Serial OutputList3Cue184=[~UNUSED3~] OutputList3SigType184=Serial OutputList3Cue185=[~UNUSED3~] OutputList3SigType185=Serial OutputList3Cue186=[~UNUSED3~] OutputList3SigType186=Serial OutputList3Cue187=[~UNUSED3~] OutputList3SigType187=Serial OutputList3Cue188=[~UNUSED3~] OutputList3SigType188=Serial OutputList3Cue189=[~UNUSED3~] OutputList3SigType189=Serial OutputList3Cue190=[~UNUSED3~] OutputList3SigType190=Serial OutputList3Cue191=[~UNUSED3~] OutputList3SigType191=Serial OutputList3Cue192=[~UNUSED3~] OutputList3SigType192=Serial OutputList3Cue193=[~UNUSED3~] OutputList3SigType193=Serial OutputList3Cue194=[~UNUSED3~] OutputList3SigType194=Serial OutputList3Cue195=[~UNUSED3~] OutputList3SigType195=Serial OutputList3Cue196=[~UNUSED3~] OutputList3SigType196=Serial OutputList3Cue197=[~UNUSED3~] OutputList3SigType197=Serial OutputList3Cue198=[~UNUSED3~] OutputList3SigType198=Serial OutputList3Cue199=[~UNUSED3~] OutputList3SigType199=Serial OutputList3Cue200=[~UNUSED3~] OutputList3SigType200=Serial OutputList3Cue201=[~UNUSED3~] OutputList3SigType201=Serial OutputList3Cue202=[~UNUSED3~] OutputList3SigType202=Serial OutputList3Cue203=[~UNUSED3~] OutputList3SigType203=Serial OutputList3Cue204=[~UNUSED3~] OutputList3SigType204=Serial OutputList3Cue205=[~UNUSED3~] OutputList3SigType205=Serial OutputList3Cue206=[~UNUSED3~] OutputList3SigType206=Serial OutputList3Cue207=[~UNUSED3~] OutputList3SigType207=Serial OutputList3Cue208=[~UNUSED3~] OutputList3SigType208=Serial OutputList3Cue209=[~UNUSED3~] OutputList3SigType209=Serial OutputList3Cue210=[~UNUSED3~] OutputList3SigType210=Serial OutputList3Cue211=[~UNUSED3~] OutputList3SigType211=Serial OutputList3Cue212=[~UNUSED3~] OutputList3SigType212=Serial OutputList3Cue213=[~UNUSED3~] OutputList3SigType213=Serial OutputList3Cue214=[~UNUSED3~] OutputList3SigType214=Serial OutputList3Cue215=[~UNUSED3~] OutputList3SigType215=Serial OutputList3Cue216=[~UNUSED3~] OutputList3SigType216=Serial OutputList3Cue217=[~UNUSED3~] OutputList3SigType217=Serial OutputList3Cue218=[~UNUSED3~] OutputList3SigType218=Serial OutputList3Cue219=[~UNUSED3~] OutputList3SigType219=Serial OutputList3Cue220=[~UNUSED3~] OutputList3SigType220=Serial OutputList3Cue221=[~UNUSED3~] OutputList3SigType221=Serial OutputList3Cue222=[~UNUSED3~] OutputList3SigType222=Serial OutputList3Cue223=[~UNUSED3~] OutputList3SigType223=Serial OutputList3Cue224=[~UNUSED3~] OutputList3SigType224=Serial OutputList3Cue225=[~UNUSED3~] OutputList3SigType225=Serial OutputList3Cue226=[~UNUSED3~] OutputList3SigType226=Serial OutputList3Cue227=[~UNUSED3~] OutputList3SigType227=Serial OutputList3Cue228=[~UNUSED3~] OutputList3SigType228=Serial OutputList3Cue229=[~UNUSED3~] OutputList3SigType229=Serial OutputList3Cue230=[~UNUSED3~] OutputList3SigType230=Serial OutputList3Cue231=[~UNUSED3~] OutputList3SigType231=Serial OutputList3Cue232=[~UNUSED3~] OutputList3SigType232=Serial OutputList3Cue233=[~UNUSED3~] OutputList3SigType233=Serial OutputList3Cue234=[~UNUSED3~] OutputList3SigType234=Serial OutputList3Cue235=[~UNUSED3~] OutputList3SigType235=Serial OutputList3Cue236=[~UNUSED3~] OutputList3SigType236=Serial OutputList3Cue237=[~UNUSED3~] OutputList3SigType237=Serial OutputList3Cue238=[~UNUSED3~] OutputList3SigType238=Serial OutputList3Cue239=[~UNUSED3~] OutputList3SigType239=Serial OutputList3Cue240=[~UNUSED3~] OutputList3SigType240=Serial OutputList3Cue241=[~UNUSED3~] OutputList3SigType241=Serial OutputList3Cue242=[~UNUSED3~] OutputList3SigType242=Serial OutputList3Cue243=[~UNUSED3~] OutputList3SigType243=Serial OutputList3Cue244=[~UNUSED3~] OutputList3SigType244=Serial OutputList3Cue245=[~UNUSED3~] OutputList3SigType245=Serial OutputList3Cue246=[~UNUSED3~] OutputList3SigType246=Serial OutputList3Cue247=[~UNUSED3~] OutputList3SigType247=Serial OutputList3Cue248=[~UNUSED3~] OutputList3SigType248=Serial OutputList3Cue249=[~UNUSED3~] OutputList3SigType249=Serial OutputList3Cue250=[~UNUSED3~] OutputList3SigType250=Serial OutputList3Cue251=[~UNUSED3~] OutputList3SigType251=Serial OutputList3Cue252=[~UNUSED3~] OutputList3SigType252=Serial OutputList3Cue253=[~UNUSED3~] OutputList3SigType253=Serial OutputList3Cue254=[~UNUSED3~] OutputList3SigType254=Serial OutputList3Cue255=[~UNUSED3~] OutputList3SigType255=Serial OutputList3Cue256=[~UNUSED3~] OutputList3SigType256=Serial OutputList3Cue257=[~UNUSED3~] OutputList3SigType257=Serial OutputList3Cue258=[~UNUSED3~] OutputList3SigType258=Serial OutputList3Cue259=[~UNUSED3~] OutputList3SigType259=Serial OutputList3Cue260=[~UNUSED3~] OutputList3SigType260=Serial OutputList3Cue261=[~UNUSED3~] OutputList3SigType261=Serial OutputList3Cue262=[~UNUSED3~] OutputList3SigType262=Serial OutputList3Cue263=[~UNUSED3~] OutputList3SigType263=Serial OutputList3Cue264=[~UNUSED3~] OutputList3SigType264=Serial OutputList3Cue265=[~UNUSED3~] OutputList3SigType265=Serial OutputList3Cue266=[~UNUSED3~] OutputList3SigType266=Serial OutputList3Cue267=[~UNUSED2~] OutputList3SigType267=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED3~] OutputList3SigType2024=Serial OutputList3Cue2025=[~UNUSED3~] OutputList3SigType2025=Serial OutputList3Cue2026=[~UNUSED3~] OutputList3SigType2026=Serial OutputList3Cue2027=[~UNUSED3~] OutputList3SigType2027=Serial OutputList3Cue2028=[~UNUSED3~] OutputList3SigType2028=Serial OutputList3Cue2029=[~UNUSED3~] OutputList3SigType2029=Serial OutputList3Cue2030=[~UNUSED3~] OutputList3SigType2030=Serial OutputList3Cue2031=[~UNUSED3~] OutputList3SigType2031=Serial OutputList3Cue2032=[~UNUSED3~] OutputList3SigType2032=Serial OutputList3Cue2033=[~UNUSED3~] OutputList3SigType2033=Serial OutputList3Cue2034=[~UNUSED3~] OutputList3SigType2034=Serial OutputList3Cue2035=[~UNUSED3~] OutputList3SigType2035=Serial OutputList3Cue2036=[~UNUSED3~] OutputList3SigType2036=Serial OutputList3Cue2037=[~UNUSED3~] OutputList3SigType2037=Serial OutputList3Cue2038=[~UNUSED3~] OutputList3SigType2038=Serial OutputList3Cue2039=[~UNUSED3~] OutputList3SigType2039=Serial OutputList3Cue2040=[~UNUSED3~] OutputList3SigType2040=Serial OutputList3Cue2041=[~UNUSED3~] OutputList3SigType2041=Serial OutputList3Cue2042=[~UNUSED3~] OutputList3SigType2042=Serial OutputList3Cue2043=[~UNUSED3~] OutputList3SigType2043=Serial OutputList3Cue2044=[~UNUSED3~] OutputList3SigType2044=Serial OutputList3Cue2045=[~UNUSED3~] OutputList3SigType2045=Serial OutputList3Cue2046=[~UNUSED3~] OutputList3SigType2046=Serial OutputList3Cue2047=[~UNUSED3~] OutputList3SigType2047=Serial OutputList3Cue2048=[~UNUSED3~] OutputList3SigType2048=Serial OutputList3Cue2049=[~UNUSED3~] OutputList3SigType2049=Serial OutputList3Cue2050=[~UNUSED3~] OutputList3SigType2050=Serial OutputList3Cue2051=[~UNUSED3~] OutputList3SigType2051=Serial OutputList3Cue2052=[~UNUSED3~] OutputList3SigType2052=Serial OutputList3Cue2053=[~UNUSED3~] OutputList3SigType2053=Serial OutputList3Cue2054=[~UNUSED3~] OutputList3SigType2054=Serial OutputList3Cue2055=[~UNUSED3~] OutputList3SigType2055=Serial OutputList3Cue2056=[~UNUSED3~] OutputList3SigType2056=Serial OutputList3Cue2057=[~UNUSED3~] OutputList3SigType2057=Serial OutputList3Cue2058=[~UNUSED3~] OutputList3SigType2058=Serial OutputList3Cue2059=[~UNUSED3~] OutputList3SigType2059=Serial OutputList3Cue2060=[~UNUSED3~] OutputList3SigType2060=Serial OutputList3Cue2061=[~UNUSED3~] OutputList3SigType2061=Serial OutputList3Cue2062=[~UNUSED3~] OutputList3SigType2062=Serial OutputList3Cue2063=[~UNUSED3~] OutputList3SigType2063=Serial OutputList3Cue2064=[~UNUSED3~] OutputList3SigType2064=Serial OutputList3Cue2065=[~UNUSED3~] OutputList3SigType2065=Serial OutputList3Cue2066=[~UNUSED3~] OutputList3SigType2066=Serial OutputList3Cue2067=[~UNUSED3~] OutputList3SigType2067=Serial OutputList3Cue2068=[~UNUSED3~] OutputList3SigType2068=Serial OutputList3Cue2069=[~UNUSED3~] OutputList3SigType2069=Serial OutputList3Cue2070=[~UNUSED3~] OutputList3SigType2070=Serial OutputList3Cue2071=[~UNUSED3~] OutputList3SigType2071=Serial OutputList3Cue2072=[~UNUSED3~] OutputList3SigType2072=Serial OutputList3Cue2073=[~UNUSED3~] OutputList3SigType2073=Serial OutputList3Cue2074=[~UNUSED3~] OutputList3SigType2074=Serial OutputList3Cue2075=[~UNUSED3~] OutputList3SigType2075=Serial OutputList3Cue2076=[~UNUSED3~] OutputList3SigType2076=Serial OutputList3Cue2077=[~UNUSED3~] OutputList3SigType2077=Serial OutputList3Cue2078=[~UNUSED3~] OutputList3SigType2078=Serial OutputList3Cue2079=[~UNUSED3~] OutputList3SigType2079=Serial OutputList3Cue2080=[~UNUSED3~] OutputList3SigType2080=Serial OutputList3Cue2081=[~UNUSED3~] OutputList3SigType2081=Serial OutputList3Cue2082=[~UNUSED3~] OutputList3SigType2082=Serial OutputList3Cue2083=[~UNUSED3~] OutputList3SigType2083=Serial OutputList3Cue2084=[~UNUSED3~] OutputList3SigType2084=Serial OutputList3Cue2085=[~UNUSED3~] OutputList3SigType2085=Serial OutputList3Cue2086=[~UNUSED3~] OutputList3SigType2086=Serial OutputList3Cue2087=[~UNUSED3~] OutputList3SigType2087=Serial OutputList3Cue2088=[~UNUSED3~] OutputList3SigType2088=Serial OutputList3Cue2089=[~UNUSED3~] OutputList3SigType2089=Serial OutputList3Cue2090=[~UNUSED3~] OutputList3SigType2090=Serial OutputList3Cue2091=[~UNUSED3~] OutputList3SigType2091=Serial OutputList3Cue2092=[~UNUSED3~] OutputList3SigType2092=Serial OutputList3Cue2093=[~UNUSED3~] OutputList3SigType2093=Serial OutputList3Cue2094=[~UNUSED3~] OutputList3SigType2094=Serial OutputList3Cue2095=[~UNUSED3~] OutputList3SigType2095=Serial OutputList3Cue2096=[~UNUSED3~] OutputList3SigType2096=Serial OutputList3Cue2097=[~UNUSED3~] OutputList3SigType2097=Serial OutputList3Cue2098=[~UNUSED3~] OutputList3SigType2098=Serial OutputList3Cue2099=[~UNUSED3~] OutputList3SigType2099=Serial OutputList3Cue2100=[~UNUSED3~] OutputList3SigType2100=Serial OutputList3Cue2101=[~UNUSED3~] OutputList3SigType2101=Serial OutputList3Cue2102=[~UNUSED3~] OutputList3SigType2102=Serial OutputList3Cue2103=[~UNUSED3~] OutputList3SigType2103=Serial OutputList3Cue2104=[~UNUSED3~] OutputList3SigType2104=Serial OutputList3Cue2105=[~UNUSED3~] OutputList3SigType2105=Serial OutputList3Cue2106=[~UNUSED3~] OutputList3SigType2106=Serial OutputList3Cue2107=[~UNUSED3~] OutputList3SigType2107=Serial OutputList3Cue2108=[~UNUSED3~] OutputList3SigType2108=Serial OutputList3Cue2109=[~UNUSED3~] OutputList3SigType2109=Serial OutputList3Cue2110=[~UNUSED3~] OutputList3SigType2110=Serial OutputList3Cue2111=[~UNUSED3~] OutputList3SigType2111=Serial OutputList3Cue2112=[~UNUSED3~] OutputList3SigType2112=Serial OutputList3Cue2113=[~UNUSED3~] OutputList3SigType2113=Serial OutputList3Cue2114=[~UNUSED3~] OutputList3SigType2114=Serial OutputList3Cue2115=[~UNUSED3~] OutputList3SigType2115=Serial OutputList3Cue2116=[~UNUSED3~] OutputList3SigType2116=Serial OutputList3Cue2117=[~UNUSED3~] OutputList3SigType2117=Serial OutputList3Cue2118=[~UNUSED3~] OutputList3SigType2118=Serial OutputList3Cue2119=[~UNUSED3~] OutputList3SigType2119=Serial OutputList3Cue2120=[~UNUSED3~] OutputList3SigType2120=Serial OutputList3Cue2121=[~UNUSED3~] OutputList3SigType2121=Serial OutputList3Cue2122=[~UNUSED3~] OutputList3SigType2122=Serial OutputList3Cue2123=[~UNUSED3~] OutputList3SigType2123=Serial OutputList3Cue2124=[~UNUSED3~] OutputList3SigType2124=Serial OutputList3Cue2125=[~UNUSED3~] OutputList3SigType2125=Serial OutputList3Cue2126=[~UNUSED3~] OutputList3SigType2126=Serial OutputList3Cue2127=[~UNUSED3~] OutputList3SigType2127=Serial OutputList3Cue2128=[~UNUSED3~] OutputList3SigType2128=Serial OutputList3Cue2129=[~UNUSED3~] OutputList3SigType2129=Serial OutputList3Cue2130=[~UNUSED3~] OutputList3SigType2130=Serial OutputList3Cue2131=[~UNUSED3~] OutputList3SigType2131=Serial OutputList3Cue2132=[~UNUSED3~] OutputList3SigType2132=Serial OutputList3Cue2133=[~UNUSED3~] OutputList3SigType2133=Serial OutputList3Cue2134=[~UNUSED3~] OutputList3SigType2134=Serial OutputList3Cue2135=[~UNUSED3~] OutputList3SigType2135=Serial OutputList3Cue2136=[~UNUSED3~] OutputList3SigType2136=Serial OutputList3Cue2137=[~UNUSED3~] OutputList3SigType2137=Serial OutputList3Cue2138=[~UNUSED3~] OutputList3SigType2138=Serial OutputList3Cue2139=[~UNUSED3~] OutputList3SigType2139=Serial OutputList3Cue2140=[~UNUSED3~] OutputList3SigType2140=Serial OutputList3Cue2141=[~UNUSED3~] OutputList3SigType2141=Serial OutputList3Cue2142=[~UNUSED3~] OutputList3SigType2142=Serial OutputList3Cue2143=[~UNUSED3~] OutputList3SigType2143=Serial OutputList3Cue2144=[~UNUSED3~] OutputList3SigType2144=Serial OutputList3Cue2145=[~UNUSED3~] OutputList3SigType2145=Serial OutputList3Cue2146=[~UNUSED3~] OutputList3SigType2146=Serial OutputList3Cue2147=[~UNUSED3~] OutputList3SigType2147=Serial OutputList3Cue2148=[~UNUSED3~] OutputList3SigType2148=Serial OutputList3Cue2149=[~UNUSED3~] OutputList3SigType2149=Serial OutputList3Cue2150=[~UNUSED3~] OutputList3SigType2150=Serial OutputList3Cue2151=[~UNUSED3~] OutputList3SigType2151=Serial OutputList3Cue2152=[~UNUSED3~] OutputList3SigType2152=Serial OutputList3Cue2153=[~UNUSED3~] OutputList3SigType2153=Serial OutputList3Cue2154=[~UNUSED3~] OutputList3SigType2154=Serial OutputList3Cue2155=[~UNUSED3~] OutputList3SigType2155=Serial OutputList3Cue2156=[~UNUSED3~] OutputList3SigType2156=Serial OutputList3Cue2157=[~UNUSED3~] OutputList3SigType2157=Serial OutputList3Cue2158=[~UNUSED3~] OutputList3SigType2158=Serial OutputList3Cue2159=[~UNUSED3~] OutputList3SigType2159=Serial OutputList3Cue2160=[~UNUSED3~] OutputList3SigType2160=Serial OutputList3Cue2161=[~UNUSED3~] OutputList3SigType2161=Serial OutputList3Cue2162=[~UNUSED3~] OutputList3SigType2162=Serial OutputList3Cue2163=[~UNUSED3~] OutputList3SigType2163=Serial OutputList3Cue2164=[~UNUSED3~] OutputList3SigType2164=Serial OutputList3Cue2165=[~UNUSED3~] OutputList3SigType2165=Serial OutputList3Cue2166=[~UNUSED3~] OutputList3SigType2166=Serial OutputList3Cue2167=[~UNUSED3~] OutputList3SigType2167=Serial OutputList3Cue2168=[~UNUSED3~] OutputList3SigType2168=Serial OutputList3Cue2169=[~UNUSED3~] OutputList3SigType2169=Serial OutputList3Cue2170=[~UNUSED3~] OutputList3SigType2170=Serial OutputList3Cue2171=[~UNUSED3~] OutputList3SigType2171=Serial OutputList3Cue2172=[~UNUSED3~] OutputList3SigType2172=Serial OutputList3Cue2173=[~UNUSED3~] OutputList3SigType2173=Serial OutputList3Cue2174=[~UNUSED3~] OutputList3SigType2174=Serial OutputList3Cue2175=[~UNUSED3~] OutputList3SigType2175=Serial OutputList3Cue2176=[~UNUSED3~] OutputList3SigType2176=Serial OutputList3Cue2177=[~UNUSED3~] OutputList3SigType2177=Serial OutputList3Cue2178=[~UNUSED3~] OutputList3SigType2178=Serial OutputList3Cue2179=[~UNUSED3~] OutputList3SigType2179=Serial OutputList3Cue2180=[~UNUSED3~] OutputList3SigType2180=Serial OutputList3Cue2181=[~UNUSED3~] OutputList3SigType2181=Serial OutputList3Cue2182=[~UNUSED3~] OutputList3SigType2182=Serial OutputList3Cue2183=[~UNUSED3~] OutputList3SigType2183=Serial OutputList3Cue2184=[~UNUSED3~] OutputList3SigType2184=Serial OutputList3Cue2185=[~UNUSED3~] OutputList3SigType2185=Serial OutputList3Cue2186=[~UNUSED3~] OutputList3SigType2186=Serial OutputList3Cue2187=[~UNUSED3~] OutputList3SigType2187=Serial OutputList3Cue2188=[~UNUSED3~] OutputList3SigType2188=Serial OutputList3Cue2189=[~UNUSED3~] OutputList3SigType2189=Serial OutputList3Cue2190=[~UNUSED3~] OutputList3SigType2190=Serial OutputList3Cue2191=[~UNUSED3~] OutputList3SigType2191=Serial OutputList3Cue2192=[~UNUSED3~] OutputList3SigType2192=Serial OutputList3Cue2193=[~UNUSED3~] OutputList3SigType2193=Serial OutputList3Cue2194=[~UNUSED3~] OutputList3SigType2194=Serial OutputList3Cue2195=[~UNUSED3~] OutputList3SigType2195=Serial OutputList3Cue2196=[~UNUSED3~] OutputList3SigType2196=Serial OutputList3Cue2197=[~UNUSED3~] OutputList3SigType2197=Serial OutputList3Cue2198=[~UNUSED3~] OutputList3SigType2198=Serial OutputList3Cue2199=[~UNUSED3~] OutputList3SigType2199=Serial OutputList3Cue2200=[~UNUSED3~] OutputList3SigType2200=Serial OutputList3Cue2201=[~UNUSED3~] OutputList3SigType2201=Serial OutputList3Cue2202=[~UNUSED3~] OutputList3SigType2202=Serial OutputList3Cue2203=[~UNUSED3~] OutputList3SigType2203=Serial OutputList3Cue2204=[~UNUSED3~] OutputList3SigType2204=Serial OutputList3Cue2205=[~UNUSED3~] OutputList3SigType2205=Serial OutputList3Cue2206=[~UNUSED3~] OutputList3SigType2206=Serial OutputList3Cue2207=[~UNUSED3~] OutputList3SigType2207=Serial OutputList3Cue2208=[~UNUSED3~] OutputList3SigType2208=Serial OutputList3Cue2209=[~UNUSED3~] OutputList3SigType2209=Serial OutputList3Cue2210=[~UNUSED3~] OutputList3SigType2210=Serial OutputList3Cue2211=[~UNUSED3~] OutputList3SigType2211=Serial OutputList3Cue2212=[~UNUSED3~] OutputList3SigType2212=Serial OutputList3Cue2213=[~UNUSED3~] OutputList3SigType2213=Serial OutputList3Cue2214=[~UNUSED3~] OutputList3SigType2214=Serial OutputList3Cue2215=[~UNUSED3~] OutputList3SigType2215=Serial OutputList3Cue2216=[~UNUSED3~] OutputList3SigType2216=Serial OutputList3Cue2217=[~UNUSED3~] OutputList3SigType2217=Serial OutputList3Cue2218=[~UNUSED3~] OutputList3SigType2218=Serial OutputList3Cue2219=[~UNUSED3~] OutputList3SigType2219=Serial OutputList3Cue2220=[~UNUSED3~] OutputList3SigType2220=Serial OutputList3Cue2221=[~UNUSED3~] OutputList3SigType2221=Serial OutputList3Cue2222=[~UNUSED3~] OutputList3SigType2222=Serial OutputList3Cue2223=[~UNUSED3~] OutputList3SigType2223=Serial OutputList3Cue2224=[~UNUSED3~] OutputList3SigType2224=Serial OutputList3Cue2225=[~UNUSED3~] OutputList3SigType2225=Serial OutputList3Cue2226=[~UNUSED3~] OutputList3SigType2226=Serial OutputList3Cue2227=[~UNUSED3~] OutputList3SigType2227=Serial OutputList3Cue2228=[~UNUSED3~] OutputList3SigType2228=Serial OutputList3Cue2229=[~UNUSED3~] OutputList3SigType2229=Serial OutputList3Cue2230=[~UNUSED3~] OutputList3SigType2230=Serial OutputList3Cue2231=[~UNUSED3~] OutputList3SigType2231=Serial OutputList3Cue2232=[~UNUSED3~] OutputList3SigType2232=Serial OutputList3Cue2233=[~UNUSED3~] OutputList3SigType2233=Serial OutputList3Cue2234=[~UNUSED3~] OutputList3SigType2234=Serial OutputList3Cue2235=[~UNUSED3~] OutputList3SigType2235=Serial OutputList3Cue2236=[~UNUSED3~] OutputList3SigType2236=Serial OutputList3Cue2237=[~UNUSED3~] OutputList3SigType2237=Serial OutputList3Cue2238=[~UNUSED3~] OutputList3SigType2238=Serial OutputList3Cue2239=[~UNUSED3~] OutputList3SigType2239=Serial OutputList3Cue2240=[~UNUSED3~] OutputList3SigType2240=Serial OutputList3Cue2241=[~UNUSED3~] OutputList3SigType2241=Serial OutputList3Cue2242=[~UNUSED3~] OutputList3SigType2242=Serial OutputList3Cue2243=[~UNUSED3~] OutputList3SigType2243=Serial OutputList3Cue2244=[~UNUSED3~] OutputList3SigType2244=Serial OutputList3Cue2245=[~UNUSED3~] OutputList3SigType2245=Serial OutputList3Cue2246=[~UNUSED3~] OutputList3SigType2246=Serial OutputList3Cue2247=[~UNUSED3~] OutputList3SigType2247=Serial OutputList3Cue2248=[~UNUSED3~] OutputList3SigType2248=Serial OutputList3Cue2249=[~UNUSED3~] OutputList3SigType2249=Serial OutputList3Cue2250=[~UNUSED3~] OutputList3SigType2250=Serial OutputList3Cue2251=[~UNUSED3~] OutputList3SigType2251=Serial OutputList3Cue2252=[~UNUSED3~] OutputList3SigType2252=Serial OutputList3Cue2253=[~UNUSED3~] OutputList3SigType2253=Serial OutputList3Cue2254=[~UNUSED3~] OutputList3SigType2254=Serial OutputList3Cue2255=[~UNUSED3~] OutputList3SigType2255=Serial OutputList3Cue2256=[~UNUSED3~] OutputList3SigType2256=Serial OutputList3Cue2257=[~UNUSED3~] OutputList3SigType2257=Serial OutputList3Cue2258=[~UNUSED3~] OutputList3SigType2258=Serial OutputList3Cue2259=[~UNUSED3~] OutputList3SigType2259=Serial OutputList3Cue2260=[~UNUSED3~] OutputList3SigType2260=Serial OutputList3Cue2261=[~UNUSED3~] OutputList3SigType2261=Serial OutputList3Cue2262=[~UNUSED3~] OutputList3SigType2262=Serial OutputList3Cue2263=[~UNUSED3~] OutputList3SigType2263=Serial OutputList3Cue2264=[~UNUSED3~] OutputList3SigType2264=Serial OutputList3Cue2265=[~UNUSED3~] OutputList3SigType2265=Serial OutputList3Cue2266=[~UNUSED3~] OutputList3SigType2266=Serial OutputList3Cue2267=[~UNUSED3~] OutputList3SigType2267=Serial OutputList3Cue2268=[~UNUSED3~] OutputList3SigType2268=Serial OutputList3Cue2269=[~UNUSED2~] OutputList3SigType2269=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=2 CedH=2 SmartObjId=1202d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=2 Tp=1 HD=TRUE DV=1202d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=2 Name=PepperDash Essentials iPad_[D.VC] Directory_Dynamic Button List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[D.VC] Keypad with favorites_VC DTMF Keypad.ced Hint=VC DTMF Keypad (Smart Object ID=1201) Code=3 SGControlType=Simple Keypad SGControlName=VC DTMF Keypad GUID=B4D53525-26EF-4326-8234-1D53F6E9BF04 SmplCName=PepperDash Essentials iPad_[D.VC] Keypad with favorites_VC DTMF Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=* OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=/# OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=3 CedH=3 SmartObjId=1201d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=3 Tp=1 HD=TRUE DV=1201d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=3 Name=PepperDash Essentials iPad_[D.VC] Keypad with favorites_VC DTMF Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[Z.Dialogs] PIN_PIN Keypad.ced Hint=PIN Keypad (Smart Object ID=3903) Code=4 SGControlType=Simple Keypad SGControlName=PIN Keypad GUID=D85E5DFB-DE45-45FE-93C5-2FA177B68BFB SmplCName=PepperDash Essentials iPad_[Z.Dialogs] PIN_PIN Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=Misc_1 OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=Misc_2 OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=4 CedH=4 SmartObjId=3903d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=4 Tp=1 HD=TRUE DV=3903d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=4 Name=PepperDash Essentials iPad_[Z.Dialogs] PIN_PIN Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced Hint=Subpage Reference List Vertical_3 (Smart Object ID=3902) Code=5 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_3 GUID=3490D547-0B98-444B-A284-D6C1BAB2FDCE SmplCName=PepperDash Essentials iPad_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4076 MaxVariableInputs=4076 MinVariableOutputs=4076 MaxVariableOutputs=4076 NumFixedParams=1 MinVariableInputsList2=72 MaxVariableInputsList2=72 MinVariableOutputsList2=72 MaxVariableOutputsList2=72 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=[~UNUSED2~] InputSigType32=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=[~UNUSED2~] InputSigType2034=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=[~EndGroup~]fb InputSigType4076=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED2~] OutputSigType32=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED2~] OutputSigType2034=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=[~EndGroup~]Press OutputSigType4076=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=an_fb37 InputList2SigType48=Analog InputList2Cue49=an_fb38 InputList2SigType49=Analog InputList2Cue50=an_fb39 InputList2SigType50=Analog InputList2Cue51=an_fb40 InputList2SigType51=Analog InputList2Cue52=an_fb41 InputList2SigType52=Analog InputList2Cue53=an_fb42 InputList2SigType53=Analog InputList2Cue54=an_fb43 InputList2SigType54=Analog InputList2Cue55=an_fb44 InputList2SigType55=Analog InputList2Cue56=an_fb45 InputList2SigType56=Analog InputList2Cue57=an_fb46 InputList2SigType57=Analog InputList2Cue58=an_fb47 InputList2SigType58=Analog InputList2Cue59=an_fb48 InputList2SigType59=Analog InputList2Cue60=an_fb49 InputList2SigType60=Analog InputList2Cue61=an_fb50 InputList2SigType61=Analog InputList2Cue62=an_fb51 InputList2SigType62=Analog InputList2Cue63=an_fb52 InputList2SigType63=Analog InputList2Cue64=an_fb53 InputList2SigType64=Analog InputList2Cue65=an_fb54 InputList2SigType65=Analog InputList2Cue66=an_fb55 InputList2SigType66=Analog InputList2Cue67=an_fb56 InputList2SigType67=Analog InputList2Cue68=an_fb57 InputList2SigType68=Analog InputList2Cue69=an_fb58 InputList2SigType69=Analog InputList2Cue70=an_fb59 InputList2SigType70=Analog InputList2Cue71=an_fb60 InputList2SigType71=Analog InputList2Cue72=[~EndGroup~]an_fb InputList2SigType72=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=an_act37 OutputList2SigType48=Analog OutputList2Cue49=an_act38 OutputList2SigType49=Analog OutputList2Cue50=an_act39 OutputList2SigType50=Analog OutputList2Cue51=an_act40 OutputList2SigType51=Analog OutputList2Cue52=an_act41 OutputList2SigType52=Analog OutputList2Cue53=an_act42 OutputList2SigType53=Analog OutputList2Cue54=an_act43 OutputList2SigType54=Analog OutputList2Cue55=an_act44 OutputList2SigType55=Analog OutputList2Cue56=an_act45 OutputList2SigType56=Analog OutputList2Cue57=an_act46 OutputList2SigType57=Analog OutputList2Cue58=an_act47 OutputList2SigType58=Analog OutputList2Cue59=an_act48 OutputList2SigType59=Analog OutputList2Cue60=an_act49 OutputList2SigType60=Analog OutputList2Cue61=an_act50 OutputList2SigType61=Analog OutputList2Cue62=an_act51 OutputList2SigType62=Analog OutputList2Cue63=an_act52 OutputList2SigType63=Analog OutputList2Cue64=an_act53 OutputList2SigType64=Analog OutputList2Cue65=an_act54 OutputList2SigType65=Analog OutputList2Cue66=an_act55 OutputList2SigType66=Analog OutputList2Cue67=an_act56 OutputList2SigType67=Analog OutputList2Cue68=an_act57 OutputList2SigType68=Analog OutputList2Cue69=an_act58 OutputList2SigType69=Analog OutputList2Cue70=an_act59 OutputList2SigType70=Analog OutputList2Cue71=an_act60 OutputList2SigType71=Analog OutputList2Cue72=[~EndGroup~]an_act OutputList2SigType72=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=5 CedH=5 SmartObjId=3902d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=5 Tp=1 HD=TRUE DV=3902d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=5 Name=PepperDash Essentials iPad_[E.Technician Controls] Sys Status_Subpage Reference List Vertical_3.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced Hint=Subpage Reference List Vertical_4 (Smart Object ID=3904) Code=6 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_4 GUID=AC10DF35-3FD4-4F62-9708-0A06AE7A5A14 SmplCName=PepperDash Essentials iPad_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4116 MaxVariableInputs=4116 MinVariableOutputs=4116 MaxVariableOutputs=4116 NumFixedParams=1 MinVariableInputsList2=42 MaxVariableInputsList2=42 MinVariableOutputsList2=42 MaxVariableOutputsList2=42 MinVariableInputsList3=42 MaxVariableInputsList3=42 MinVariableOutputsList3=42 MaxVariableOutputsList3=42 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=[~UNUSED2~] InputSigType22=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=[~UNUSED2~] InputSigType2024=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=fb91 InputSigType4106=Digital InputCue4107=fb92 InputSigType4107=Digital InputCue4108=fb93 InputSigType4108=Digital InputCue4109=fb94 InputSigType4109=Digital InputCue4110=fb95 InputSigType4110=Digital InputCue4111=fb96 InputSigType4111=Digital InputCue4112=fb97 InputSigType4112=Digital InputCue4113=fb98 InputSigType4113=Digital InputCue4114=fb99 InputSigType4114=Digital InputCue4115=fb100 InputSigType4115=Digital InputCue4116=[~EndGroup~]fb InputSigType4116=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED2~] OutputSigType22=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED2~] OutputSigType2024=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=press91 OutputSigType4106=Digital OutputCue4107=press92 OutputSigType4107=Digital OutputCue4108=press93 OutputSigType4108=Digital OutputCue4109=press94 OutputSigType4109=Digital OutputCue4110=press95 OutputSigType4110=Digital OutputCue4111=press96 OutputSigType4111=Digital OutputCue4112=press97 OutputSigType4112=Digital OutputCue4113=press98 OutputSigType4113=Digital OutputCue4114=press99 OutputSigType4114=Digital OutputCue4115=press100 OutputSigType4115=Digital OutputCue4116=[~EndGroup~]Press OutputSigType4116=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=[~EndGroup~]an_fb InputList2SigType42=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=[~EndGroup~]an_act OutputList2SigType42=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=[~EndGroup~]text-o InputList3SigType42=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=[~EndGroup~]text-i OutputList3SigType42=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=6 CedH=6 SmartObjId=3904d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=6 Tp=1 HD=TRUE DV=3904d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=6 Name=PepperDash Essentials iPad_[E.Technician Controls] Display Controls_Subpage Reference List Vertical_4.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[B.AV] Staging_Subpage Reference List Horizontal_3.ced Hint=Subpage Reference List Horizontal_3 (Smart Object ID=3200) Code=7 SGControlType=Subpage Reference List Horizontal SGControlName=Subpage Reference List Horizontal_3 GUID=D638D437-6722-43E1-B435-EF13DCE5ECF0 SmplCName=PepperDash Essentials iPad_[B.AV] Staging_Subpage Reference List Horizontal_3.ced SMWRev=4.02.20 Expand=expand_random HelpID=10124 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4076 MaxVariableInputs=4076 MinVariableOutputs=4076 MaxVariableOutputs=4076 NumFixedParams=1 MinVariableInputsList2=72 MaxVariableInputsList2=72 MinVariableOutputsList2=72 MaxVariableOutputsList2=72 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=[~UNUSED2~] InputSigType32=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=[~UNUSED2~] InputSigType2034=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=[~EndGroup~]fb InputSigType4076=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED2~] OutputSigType32=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED2~] OutputSigType2034=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=[~EndGroup~]Press OutputSigType4076=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=an_fb37 InputList2SigType48=Analog InputList2Cue49=an_fb38 InputList2SigType49=Analog InputList2Cue50=an_fb39 InputList2SigType50=Analog InputList2Cue51=an_fb40 InputList2SigType51=Analog InputList2Cue52=an_fb41 InputList2SigType52=Analog InputList2Cue53=an_fb42 InputList2SigType53=Analog InputList2Cue54=an_fb43 InputList2SigType54=Analog InputList2Cue55=an_fb44 InputList2SigType55=Analog InputList2Cue56=an_fb45 InputList2SigType56=Analog InputList2Cue57=an_fb46 InputList2SigType57=Analog InputList2Cue58=an_fb47 InputList2SigType58=Analog InputList2Cue59=an_fb48 InputList2SigType59=Analog InputList2Cue60=an_fb49 InputList2SigType60=Analog InputList2Cue61=an_fb50 InputList2SigType61=Analog InputList2Cue62=an_fb51 InputList2SigType62=Analog InputList2Cue63=an_fb52 InputList2SigType63=Analog InputList2Cue64=an_fb53 InputList2SigType64=Analog InputList2Cue65=an_fb54 InputList2SigType65=Analog InputList2Cue66=an_fb55 InputList2SigType66=Analog InputList2Cue67=an_fb56 InputList2SigType67=Analog InputList2Cue68=an_fb57 InputList2SigType68=Analog InputList2Cue69=an_fb58 InputList2SigType69=Analog InputList2Cue70=an_fb59 InputList2SigType70=Analog InputList2Cue71=an_fb60 InputList2SigType71=Analog InputList2Cue72=[~EndGroup~]an_fb InputList2SigType72=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=an_act37 OutputList2SigType48=Analog OutputList2Cue49=an_act38 OutputList2SigType49=Analog OutputList2Cue50=an_act39 OutputList2SigType50=Analog OutputList2Cue51=an_act40 OutputList2SigType51=Analog OutputList2Cue52=an_act41 OutputList2SigType52=Analog OutputList2Cue53=an_act42 OutputList2SigType53=Analog OutputList2Cue54=an_act43 OutputList2SigType54=Analog OutputList2Cue55=an_act44 OutputList2SigType55=Analog OutputList2Cue56=an_act45 OutputList2SigType56=Analog OutputList2Cue57=an_act46 OutputList2SigType57=Analog OutputList2Cue58=an_act47 OutputList2SigType58=Analog OutputList2Cue59=an_act48 OutputList2SigType59=Analog OutputList2Cue60=an_act49 OutputList2SigType60=Analog OutputList2Cue61=an_act50 OutputList2SigType61=Analog OutputList2Cue62=an_act51 OutputList2SigType62=Analog OutputList2Cue63=an_act52 OutputList2SigType63=Analog OutputList2Cue64=an_act53 OutputList2SigType64=Analog OutputList2Cue65=an_act54 OutputList2SigType65=Analog OutputList2Cue66=an_act55 OutputList2SigType66=Analog OutputList2Cue67=an_act56 OutputList2SigType67=Analog OutputList2Cue68=an_act57 OutputList2SigType68=Analog OutputList2Cue69=an_act58 OutputList2SigType69=Analog OutputList2Cue70=an_act59 OutputList2SigType70=Analog OutputList2Cue71=an_act60 OutputList2SigType71=Analog OutputList2Cue72=[~EndGroup~]an_act OutputList2SigType72=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=7 CedH=7 SmartObjId=3200d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=7 Tp=1 HD=TRUE DV=3200d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=7 Name=PepperDash Essentials iPad_[B.AV] Staging_Subpage Reference List Horizontal_3.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced Hint=Channel Preset List Basic (Smart Object ID=1806) Code=8 SGControlType=Subpage Reference List Vertical SGControlName=Channel Preset List Basic GUID=46C43CE4-6BB9-4B76-A13E-B4279202F998 SmplCName=PepperDash Essentials iPad_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4106 MaxVariableInputs=4106 MinVariableOutputs=4106 MaxVariableOutputs=4106 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=132 MaxVariableInputsList3=132 MinVariableOutputsList3=132 MaxVariableOutputsList3=132 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=[~EndGroup~]fb InputSigType4106=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=[~EndGroup~]Press OutputSigType4106=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=[~EndGroup~]text-o InputList3SigType132=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=[~EndGroup~]text-i OutputList3SigType132=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=8 CedH=8 SmartObjId=1806d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=8 Tp=1 HD=TRUE DV=1806d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=8 Name=PepperDash Essentials iPad_[B.AV] Source Ctrl-CATV-Basic_Channel Preset List Basic.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced Hint=Modes Bottom Bar SRL (Smart Object ID=15022) Code=9 SGControlType=Subpage Reference List Horizontal SGControlName=Modes Bottom Bar SRL GUID=812FF0C4-486D-4ABC-90FA-405F19104323 SmplCName=PepperDash Essentials iPad_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced SMWRev=4.02.20 Expand=expand_random HelpID=10124 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4028 MaxVariableInputs=4028 MinVariableOutputs=4028 MaxVariableOutputs=4028 NumFixedParams=1 MinVariableInputsList2=24 MaxVariableInputsList2=24 MinVariableOutputsList2=24 MaxVariableOutputsList2=24 MinVariableInputsList3=24 MaxVariableInputsList3=24 MinVariableOutputsList3=24 MaxVariableOutputsList3=24 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=[~UNUSED2~] InputSigType16=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=[~UNUSED2~] InputSigType2018=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=[~EndGroup~]fb InputSigType4028=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED2~] OutputSigType16=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED2~] OutputSigType2018=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=[~EndGroup~]Press OutputSigType4028=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=[~EndGroup~]an_fb InputList2SigType24=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=[~EndGroup~]an_act OutputList2SigType24=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=[~EndGroup~]text-o InputList3SigType24=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=[~EndGroup~]text-i OutputList3SigType24=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=9 CedH=9 SmartObjId=15022d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=9 Tp=1 HD=TRUE DV=15022d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=9 Name=PepperDash Essentials iPad_[A.Global] Activity Footer SRL_Modes Bottom Bar SRL.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[B.AV] Object - Presets_CATV Icon List Vertical.ced Hint=CATV Icon List Vertical (Smart Object ID=10012) Code=10 SGControlType=Subpage Reference List Vertical SGControlName=CATV Icon List Vertical GUID=B34C4DC0-DD10-4C49-AEBA-F968934EFDC6 SmplCName=PepperDash Essentials iPad_[B.AV] Object - Presets_CATV Icon List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4316 MaxVariableInputs=4316 MinVariableOutputs=4316 MaxVariableOutputs=4316 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=412 MaxVariableInputsList3=412 MinVariableOutputsList3=412 MaxVariableOutputsList3=412 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=Item 31 Enable InputSigType42=Digital InputCue43=Item 32 Enable InputSigType43=Digital InputCue44=Item 33 Enable InputSigType44=Digital InputCue45=Item 34 Enable InputSigType45=Digital InputCue46=Item 35 Enable InputSigType46=Digital InputCue47=Item 36 Enable InputSigType47=Digital InputCue48=Item 37 Enable InputSigType48=Digital InputCue49=Item 38 Enable InputSigType49=Digital InputCue50=Item 39 Enable InputSigType50=Digital InputCue51=Item 40 Enable InputSigType51=Digital InputCue52=Item 41 Enable InputSigType52=Digital InputCue53=Item 42 Enable InputSigType53=Digital InputCue54=Item 43 Enable InputSigType54=Digital InputCue55=Item 44 Enable InputSigType55=Digital InputCue56=Item 45 Enable InputSigType56=Digital InputCue57=Item 46 Enable InputSigType57=Digital InputCue58=Item 47 Enable InputSigType58=Digital InputCue59=Item 48 Enable InputSigType59=Digital InputCue60=Item 49 Enable InputSigType60=Digital InputCue61=Item 50 Enable InputSigType61=Digital InputCue62=Item 51 Enable InputSigType62=Digital InputCue63=Item 52 Enable InputSigType63=Digital InputCue64=Item 53 Enable InputSigType64=Digital InputCue65=Item 54 Enable InputSigType65=Digital InputCue66=Item 55 Enable InputSigType66=Digital InputCue67=Item 56 Enable InputSigType67=Digital InputCue68=Item 57 Enable InputSigType68=Digital InputCue69=Item 58 Enable InputSigType69=Digital InputCue70=Item 59 Enable InputSigType70=Digital InputCue71=Item 60 Enable InputSigType71=Digital InputCue72=Item 61 Enable InputSigType72=Digital InputCue73=Item 62 Enable InputSigType73=Digital InputCue74=Item 63 Enable InputSigType74=Digital InputCue75=Item 64 Enable InputSigType75=Digital InputCue76=Item 65 Enable InputSigType76=Digital InputCue77=Item 66 Enable InputSigType77=Digital InputCue78=Item 67 Enable InputSigType78=Digital InputCue79=Item 68 Enable InputSigType79=Digital InputCue80=Item 69 Enable InputSigType80=Digital InputCue81=Item 70 Enable InputSigType81=Digital InputCue82=Item 71 Enable InputSigType82=Digital InputCue83=Item 72 Enable InputSigType83=Digital InputCue84=Item 73 Enable InputSigType84=Digital InputCue85=Item 74 Enable InputSigType85=Digital InputCue86=Item 75 Enable InputSigType86=Digital InputCue87=Item 76 Enable InputSigType87=Digital InputCue88=Item 77 Enable InputSigType88=Digital InputCue89=Item 78 Enable InputSigType89=Digital InputCue90=Item 79 Enable InputSigType90=Digital InputCue91=Item 80 Enable InputSigType91=Digital InputCue92=Item 81 Enable InputSigType92=Digital InputCue93=Item 82 Enable InputSigType93=Digital InputCue94=Item 83 Enable InputSigType94=Digital InputCue95=Item 84 Enable InputSigType95=Digital InputCue96=Item 85 Enable InputSigType96=Digital InputCue97=Item 86 Enable InputSigType97=Digital InputCue98=Item 87 Enable InputSigType98=Digital InputCue99=Item 88 Enable InputSigType99=Digital InputCue100=Item 89 Enable InputSigType100=Digital InputCue101=Item 90 Enable InputSigType101=Digital InputCue102=Item 91 Enable InputSigType102=Digital InputCue103=Item 92 Enable InputSigType103=Digital InputCue104=Item 93 Enable InputSigType104=Digital InputCue105=Item 94 Enable InputSigType105=Digital InputCue106=Item 95 Enable InputSigType106=Digital InputCue107=Item 96 Enable InputSigType107=Digital InputCue108=Item 97 Enable InputSigType108=Digital InputCue109=Item 98 Enable InputSigType109=Digital InputCue110=Item 99 Enable InputSigType110=Digital InputCue111=Item 100 Enable InputSigType111=Digital InputCue112=[~UNUSED2~] InputSigType112=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=Item 31 Visible InputSigType2044=Digital InputCue2045=Item 32 Visible InputSigType2045=Digital InputCue2046=Item 33 Visible InputSigType2046=Digital InputCue2047=Item 34 Visible InputSigType2047=Digital InputCue2048=Item 35 Visible InputSigType2048=Digital InputCue2049=Item 36 Visible InputSigType2049=Digital InputCue2050=Item 37 Visible InputSigType2050=Digital InputCue2051=Item 38 Visible InputSigType2051=Digital InputCue2052=Item 39 Visible InputSigType2052=Digital InputCue2053=Item 40 Visible InputSigType2053=Digital InputCue2054=Item 41 Visible InputSigType2054=Digital InputCue2055=Item 42 Visible InputSigType2055=Digital InputCue2056=Item 43 Visible InputSigType2056=Digital InputCue2057=Item 44 Visible InputSigType2057=Digital InputCue2058=Item 45 Visible InputSigType2058=Digital InputCue2059=Item 46 Visible InputSigType2059=Digital InputCue2060=Item 47 Visible InputSigType2060=Digital InputCue2061=Item 48 Visible InputSigType2061=Digital InputCue2062=Item 49 Visible InputSigType2062=Digital InputCue2063=Item 50 Visible InputSigType2063=Digital InputCue2064=Item 51 Visible InputSigType2064=Digital InputCue2065=Item 52 Visible InputSigType2065=Digital InputCue2066=Item 53 Visible InputSigType2066=Digital InputCue2067=Item 54 Visible InputSigType2067=Digital InputCue2068=Item 55 Visible InputSigType2068=Digital InputCue2069=Item 56 Visible InputSigType2069=Digital InputCue2070=Item 57 Visible InputSigType2070=Digital InputCue2071=Item 58 Visible InputSigType2071=Digital InputCue2072=Item 59 Visible InputSigType2072=Digital InputCue2073=Item 60 Visible InputSigType2073=Digital InputCue2074=Item 61 Visible InputSigType2074=Digital InputCue2075=Item 62 Visible InputSigType2075=Digital InputCue2076=Item 63 Visible InputSigType2076=Digital InputCue2077=Item 64 Visible InputSigType2077=Digital InputCue2078=Item 65 Visible InputSigType2078=Digital InputCue2079=Item 66 Visible InputSigType2079=Digital InputCue2080=Item 67 Visible InputSigType2080=Digital InputCue2081=Item 68 Visible InputSigType2081=Digital InputCue2082=Item 69 Visible InputSigType2082=Digital InputCue2083=Item 70 Visible InputSigType2083=Digital InputCue2084=Item 71 Visible InputSigType2084=Digital InputCue2085=Item 72 Visible InputSigType2085=Digital InputCue2086=Item 73 Visible InputSigType2086=Digital InputCue2087=Item 74 Visible InputSigType2087=Digital InputCue2088=Item 75 Visible InputSigType2088=Digital InputCue2089=Item 76 Visible InputSigType2089=Digital InputCue2090=Item 77 Visible InputSigType2090=Digital InputCue2091=Item 78 Visible InputSigType2091=Digital InputCue2092=Item 79 Visible InputSigType2092=Digital InputCue2093=Item 80 Visible InputSigType2093=Digital InputCue2094=Item 81 Visible InputSigType2094=Digital InputCue2095=Item 82 Visible InputSigType2095=Digital InputCue2096=Item 83 Visible InputSigType2096=Digital InputCue2097=Item 84 Visible InputSigType2097=Digital InputCue2098=Item 85 Visible InputSigType2098=Digital InputCue2099=Item 86 Visible InputSigType2099=Digital InputCue2100=Item 87 Visible InputSigType2100=Digital InputCue2101=Item 88 Visible InputSigType2101=Digital InputCue2102=Item 89 Visible InputSigType2102=Digital InputCue2103=Item 90 Visible InputSigType2103=Digital InputCue2104=Item 91 Visible InputSigType2104=Digital InputCue2105=Item 92 Visible InputSigType2105=Digital InputCue2106=Item 93 Visible InputSigType2106=Digital InputCue2107=Item 94 Visible InputSigType2107=Digital InputCue2108=Item 95 Visible InputSigType2108=Digital InputCue2109=Item 96 Visible InputSigType2109=Digital InputCue2110=Item 97 Visible InputSigType2110=Digital InputCue2111=Item 98 Visible InputSigType2111=Digital InputCue2112=Item 99 Visible InputSigType2112=Digital InputCue2113=Item 100 Visible InputSigType2113=Digital InputCue2114=[~UNUSED2~] InputSigType2114=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=fb91 InputSigType4106=Digital InputCue4107=fb92 InputSigType4107=Digital InputCue4108=fb93 InputSigType4108=Digital InputCue4109=fb94 InputSigType4109=Digital InputCue4110=fb95 InputSigType4110=Digital InputCue4111=fb96 InputSigType4111=Digital InputCue4112=fb97 InputSigType4112=Digital InputCue4113=fb98 InputSigType4113=Digital InputCue4114=fb99 InputSigType4114=Digital InputCue4115=fb100 InputSigType4115=Digital InputCue4116=fb101 InputSigType4116=Digital InputCue4117=fb102 InputSigType4117=Digital InputCue4118=fb103 InputSigType4118=Digital InputCue4119=fb104 InputSigType4119=Digital InputCue4120=fb105 InputSigType4120=Digital InputCue4121=fb106 InputSigType4121=Digital InputCue4122=fb107 InputSigType4122=Digital InputCue4123=fb108 InputSigType4123=Digital InputCue4124=fb109 InputSigType4124=Digital InputCue4125=fb110 InputSigType4125=Digital InputCue4126=fb111 InputSigType4126=Digital InputCue4127=fb112 InputSigType4127=Digital InputCue4128=fb113 InputSigType4128=Digital InputCue4129=fb114 InputSigType4129=Digital InputCue4130=fb115 InputSigType4130=Digital InputCue4131=fb116 InputSigType4131=Digital InputCue4132=fb117 InputSigType4132=Digital InputCue4133=fb118 InputSigType4133=Digital InputCue4134=fb119 InputSigType4134=Digital InputCue4135=fb120 InputSigType4135=Digital InputCue4136=fb121 InputSigType4136=Digital InputCue4137=fb122 InputSigType4137=Digital InputCue4138=fb123 InputSigType4138=Digital InputCue4139=fb124 InputSigType4139=Digital InputCue4140=fb125 InputSigType4140=Digital InputCue4141=fb126 InputSigType4141=Digital InputCue4142=fb127 InputSigType4142=Digital InputCue4143=fb128 InputSigType4143=Digital InputCue4144=fb129 InputSigType4144=Digital InputCue4145=fb130 InputSigType4145=Digital InputCue4146=fb131 InputSigType4146=Digital InputCue4147=fb132 InputSigType4147=Digital InputCue4148=fb133 InputSigType4148=Digital InputCue4149=fb134 InputSigType4149=Digital InputCue4150=fb135 InputSigType4150=Digital InputCue4151=fb136 InputSigType4151=Digital InputCue4152=fb137 InputSigType4152=Digital InputCue4153=fb138 InputSigType4153=Digital InputCue4154=fb139 InputSigType4154=Digital InputCue4155=fb140 InputSigType4155=Digital InputCue4156=fb141 InputSigType4156=Digital InputCue4157=fb142 InputSigType4157=Digital InputCue4158=fb143 InputSigType4158=Digital InputCue4159=fb144 InputSigType4159=Digital InputCue4160=fb145 InputSigType4160=Digital InputCue4161=fb146 InputSigType4161=Digital InputCue4162=fb147 InputSigType4162=Digital InputCue4163=fb148 InputSigType4163=Digital InputCue4164=fb149 InputSigType4164=Digital InputCue4165=fb150 InputSigType4165=Digital InputCue4166=fb151 InputSigType4166=Digital InputCue4167=fb152 InputSigType4167=Digital InputCue4168=fb153 InputSigType4168=Digital InputCue4169=fb154 InputSigType4169=Digital InputCue4170=fb155 InputSigType4170=Digital InputCue4171=fb156 InputSigType4171=Digital InputCue4172=fb157 InputSigType4172=Digital InputCue4173=fb158 InputSigType4173=Digital InputCue4174=fb159 InputSigType4174=Digital InputCue4175=fb160 InputSigType4175=Digital InputCue4176=fb161 InputSigType4176=Digital InputCue4177=fb162 InputSigType4177=Digital InputCue4178=fb163 InputSigType4178=Digital InputCue4179=fb164 InputSigType4179=Digital InputCue4180=fb165 InputSigType4180=Digital InputCue4181=fb166 InputSigType4181=Digital InputCue4182=fb167 InputSigType4182=Digital InputCue4183=fb168 InputSigType4183=Digital InputCue4184=fb169 InputSigType4184=Digital InputCue4185=fb170 InputSigType4185=Digital InputCue4186=fb171 InputSigType4186=Digital InputCue4187=fb172 InputSigType4187=Digital InputCue4188=fb173 InputSigType4188=Digital InputCue4189=fb174 InputSigType4189=Digital InputCue4190=fb175 InputSigType4190=Digital InputCue4191=fb176 InputSigType4191=Digital InputCue4192=fb177 InputSigType4192=Digital InputCue4193=fb178 InputSigType4193=Digital InputCue4194=fb179 InputSigType4194=Digital InputCue4195=fb180 InputSigType4195=Digital InputCue4196=fb181 InputSigType4196=Digital InputCue4197=fb182 InputSigType4197=Digital InputCue4198=fb183 InputSigType4198=Digital InputCue4199=fb184 InputSigType4199=Digital InputCue4200=fb185 InputSigType4200=Digital InputCue4201=fb186 InputSigType4201=Digital InputCue4202=fb187 InputSigType4202=Digital InputCue4203=fb188 InputSigType4203=Digital InputCue4204=fb189 InputSigType4204=Digital InputCue4205=fb190 InputSigType4205=Digital InputCue4206=fb191 InputSigType4206=Digital InputCue4207=fb192 InputSigType4207=Digital InputCue4208=fb193 InputSigType4208=Digital InputCue4209=fb194 InputSigType4209=Digital InputCue4210=fb195 InputSigType4210=Digital InputCue4211=fb196 InputSigType4211=Digital InputCue4212=fb197 InputSigType4212=Digital InputCue4213=fb198 InputSigType4213=Digital InputCue4214=fb199 InputSigType4214=Digital InputCue4215=fb200 InputSigType4215=Digital InputCue4216=fb201 InputSigType4216=Digital InputCue4217=fb202 InputSigType4217=Digital InputCue4218=fb203 InputSigType4218=Digital InputCue4219=fb204 InputSigType4219=Digital InputCue4220=fb205 InputSigType4220=Digital InputCue4221=fb206 InputSigType4221=Digital InputCue4222=fb207 InputSigType4222=Digital InputCue4223=fb208 InputSigType4223=Digital InputCue4224=fb209 InputSigType4224=Digital InputCue4225=fb210 InputSigType4225=Digital InputCue4226=fb211 InputSigType4226=Digital InputCue4227=fb212 InputSigType4227=Digital InputCue4228=fb213 InputSigType4228=Digital InputCue4229=fb214 InputSigType4229=Digital InputCue4230=fb215 InputSigType4230=Digital InputCue4231=fb216 InputSigType4231=Digital InputCue4232=fb217 InputSigType4232=Digital InputCue4233=fb218 InputSigType4233=Digital InputCue4234=fb219 InputSigType4234=Digital InputCue4235=fb220 InputSigType4235=Digital InputCue4236=fb221 InputSigType4236=Digital InputCue4237=fb222 InputSigType4237=Digital InputCue4238=fb223 InputSigType4238=Digital InputCue4239=fb224 InputSigType4239=Digital InputCue4240=fb225 InputSigType4240=Digital InputCue4241=fb226 InputSigType4241=Digital InputCue4242=fb227 InputSigType4242=Digital InputCue4243=fb228 InputSigType4243=Digital InputCue4244=fb229 InputSigType4244=Digital InputCue4245=fb230 InputSigType4245=Digital InputCue4246=fb231 InputSigType4246=Digital InputCue4247=fb232 InputSigType4247=Digital InputCue4248=fb233 InputSigType4248=Digital InputCue4249=fb234 InputSigType4249=Digital InputCue4250=fb235 InputSigType4250=Digital InputCue4251=fb236 InputSigType4251=Digital InputCue4252=fb237 InputSigType4252=Digital InputCue4253=fb238 InputSigType4253=Digital InputCue4254=fb239 InputSigType4254=Digital InputCue4255=fb240 InputSigType4255=Digital InputCue4256=fb241 InputSigType4256=Digital InputCue4257=fb242 InputSigType4257=Digital InputCue4258=fb243 InputSigType4258=Digital InputCue4259=fb244 InputSigType4259=Digital InputCue4260=fb245 InputSigType4260=Digital InputCue4261=fb246 InputSigType4261=Digital InputCue4262=fb247 InputSigType4262=Digital InputCue4263=fb248 InputSigType4263=Digital InputCue4264=fb249 InputSigType4264=Digital InputCue4265=fb250 InputSigType4265=Digital InputCue4266=fb251 InputSigType4266=Digital InputCue4267=fb252 InputSigType4267=Digital InputCue4268=fb253 InputSigType4268=Digital InputCue4269=fb254 InputSigType4269=Digital InputCue4270=fb255 InputSigType4270=Digital InputCue4271=fb256 InputSigType4271=Digital InputCue4272=fb257 InputSigType4272=Digital InputCue4273=fb258 InputSigType4273=Digital InputCue4274=fb259 InputSigType4274=Digital InputCue4275=fb260 InputSigType4275=Digital InputCue4276=fb261 InputSigType4276=Digital InputCue4277=fb262 InputSigType4277=Digital InputCue4278=fb263 InputSigType4278=Digital InputCue4279=fb264 InputSigType4279=Digital InputCue4280=fb265 InputSigType4280=Digital InputCue4281=fb266 InputSigType4281=Digital InputCue4282=fb267 InputSigType4282=Digital InputCue4283=fb268 InputSigType4283=Digital InputCue4284=fb269 InputSigType4284=Digital InputCue4285=fb270 InputSigType4285=Digital InputCue4286=fb271 InputSigType4286=Digital InputCue4287=fb272 InputSigType4287=Digital InputCue4288=fb273 InputSigType4288=Digital InputCue4289=fb274 InputSigType4289=Digital InputCue4290=fb275 InputSigType4290=Digital InputCue4291=fb276 InputSigType4291=Digital InputCue4292=fb277 InputSigType4292=Digital InputCue4293=fb278 InputSigType4293=Digital InputCue4294=fb279 InputSigType4294=Digital InputCue4295=fb280 InputSigType4295=Digital InputCue4296=fb281 InputSigType4296=Digital InputCue4297=fb282 InputSigType4297=Digital InputCue4298=fb283 InputSigType4298=Digital InputCue4299=fb284 InputSigType4299=Digital InputCue4300=fb285 InputSigType4300=Digital InputCue4301=fb286 InputSigType4301=Digital InputCue4302=fb287 InputSigType4302=Digital InputCue4303=fb288 InputSigType4303=Digital InputCue4304=fb289 InputSigType4304=Digital InputCue4305=fb290 InputSigType4305=Digital InputCue4306=fb291 InputSigType4306=Digital InputCue4307=fb292 InputSigType4307=Digital InputCue4308=fb293 InputSigType4308=Digital InputCue4309=fb294 InputSigType4309=Digital InputCue4310=fb295 InputSigType4310=Digital InputCue4311=fb296 InputSigType4311=Digital InputCue4312=fb297 InputSigType4312=Digital InputCue4313=fb298 InputSigType4313=Digital InputCue4314=fb299 InputSigType4314=Digital InputCue4315=fb300 InputSigType4315=Digital InputCue4316=[~EndGroup~]fb InputSigType4316=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED3~] OutputSigType42=Digital OutputCue43=[~UNUSED3~] OutputSigType43=Digital OutputCue44=[~UNUSED3~] OutputSigType44=Digital OutputCue45=[~UNUSED3~] OutputSigType45=Digital OutputCue46=[~UNUSED3~] OutputSigType46=Digital OutputCue47=[~UNUSED3~] OutputSigType47=Digital OutputCue48=[~UNUSED3~] OutputSigType48=Digital OutputCue49=[~UNUSED3~] OutputSigType49=Digital OutputCue50=[~UNUSED3~] OutputSigType50=Digital OutputCue51=[~UNUSED3~] OutputSigType51=Digital OutputCue52=[~UNUSED3~] OutputSigType52=Digital OutputCue53=[~UNUSED3~] OutputSigType53=Digital OutputCue54=[~UNUSED3~] OutputSigType54=Digital OutputCue55=[~UNUSED3~] OutputSigType55=Digital OutputCue56=[~UNUSED3~] OutputSigType56=Digital OutputCue57=[~UNUSED3~] OutputSigType57=Digital OutputCue58=[~UNUSED3~] OutputSigType58=Digital OutputCue59=[~UNUSED3~] OutputSigType59=Digital OutputCue60=[~UNUSED3~] OutputSigType60=Digital OutputCue61=[~UNUSED3~] OutputSigType61=Digital OutputCue62=[~UNUSED3~] OutputSigType62=Digital OutputCue63=[~UNUSED3~] OutputSigType63=Digital OutputCue64=[~UNUSED3~] OutputSigType64=Digital OutputCue65=[~UNUSED3~] OutputSigType65=Digital OutputCue66=[~UNUSED3~] OutputSigType66=Digital OutputCue67=[~UNUSED3~] OutputSigType67=Digital OutputCue68=[~UNUSED3~] OutputSigType68=Digital OutputCue69=[~UNUSED3~] OutputSigType69=Digital OutputCue70=[~UNUSED3~] OutputSigType70=Digital OutputCue71=[~UNUSED3~] OutputSigType71=Digital OutputCue72=[~UNUSED3~] OutputSigType72=Digital OutputCue73=[~UNUSED3~] OutputSigType73=Digital OutputCue74=[~UNUSED3~] OutputSigType74=Digital OutputCue75=[~UNUSED3~] OutputSigType75=Digital OutputCue76=[~UNUSED3~] OutputSigType76=Digital OutputCue77=[~UNUSED3~] OutputSigType77=Digital OutputCue78=[~UNUSED3~] OutputSigType78=Digital OutputCue79=[~UNUSED3~] OutputSigType79=Digital OutputCue80=[~UNUSED3~] OutputSigType80=Digital OutputCue81=[~UNUSED3~] OutputSigType81=Digital OutputCue82=[~UNUSED3~] OutputSigType82=Digital OutputCue83=[~UNUSED3~] OutputSigType83=Digital OutputCue84=[~UNUSED3~] OutputSigType84=Digital OutputCue85=[~UNUSED3~] OutputSigType85=Digital OutputCue86=[~UNUSED3~] OutputSigType86=Digital OutputCue87=[~UNUSED3~] OutputSigType87=Digital OutputCue88=[~UNUSED3~] OutputSigType88=Digital OutputCue89=[~UNUSED3~] OutputSigType89=Digital OutputCue90=[~UNUSED3~] OutputSigType90=Digital OutputCue91=[~UNUSED3~] OutputSigType91=Digital OutputCue92=[~UNUSED3~] OutputSigType92=Digital OutputCue93=[~UNUSED3~] OutputSigType93=Digital OutputCue94=[~UNUSED3~] OutputSigType94=Digital OutputCue95=[~UNUSED3~] OutputSigType95=Digital OutputCue96=[~UNUSED3~] OutputSigType96=Digital OutputCue97=[~UNUSED3~] OutputSigType97=Digital OutputCue98=[~UNUSED3~] OutputSigType98=Digital OutputCue99=[~UNUSED3~] OutputSigType99=Digital OutputCue100=[~UNUSED3~] OutputSigType100=Digital OutputCue101=[~UNUSED3~] OutputSigType101=Digital OutputCue102=[~UNUSED3~] OutputSigType102=Digital OutputCue103=[~UNUSED3~] OutputSigType103=Digital OutputCue104=[~UNUSED3~] OutputSigType104=Digital OutputCue105=[~UNUSED3~] OutputSigType105=Digital OutputCue106=[~UNUSED3~] OutputSigType106=Digital OutputCue107=[~UNUSED3~] OutputSigType107=Digital OutputCue108=[~UNUSED3~] OutputSigType108=Digital OutputCue109=[~UNUSED3~] OutputSigType109=Digital OutputCue110=[~UNUSED3~] OutputSigType110=Digital OutputCue111=[~UNUSED3~] OutputSigType111=Digital OutputCue112=[~UNUSED2~] OutputSigType112=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED3~] OutputSigType2044=Digital OutputCue2045=[~UNUSED3~] OutputSigType2045=Digital OutputCue2046=[~UNUSED3~] OutputSigType2046=Digital OutputCue2047=[~UNUSED3~] OutputSigType2047=Digital OutputCue2048=[~UNUSED3~] OutputSigType2048=Digital OutputCue2049=[~UNUSED3~] OutputSigType2049=Digital OutputCue2050=[~UNUSED3~] OutputSigType2050=Digital OutputCue2051=[~UNUSED3~] OutputSigType2051=Digital OutputCue2052=[~UNUSED3~] OutputSigType2052=Digital OutputCue2053=[~UNUSED3~] OutputSigType2053=Digital OutputCue2054=[~UNUSED3~] OutputSigType2054=Digital OutputCue2055=[~UNUSED3~] OutputSigType2055=Digital OutputCue2056=[~UNUSED3~] OutputSigType2056=Digital OutputCue2057=[~UNUSED3~] OutputSigType2057=Digital OutputCue2058=[~UNUSED3~] OutputSigType2058=Digital OutputCue2059=[~UNUSED3~] OutputSigType2059=Digital OutputCue2060=[~UNUSED3~] OutputSigType2060=Digital OutputCue2061=[~UNUSED3~] OutputSigType2061=Digital OutputCue2062=[~UNUSED3~] OutputSigType2062=Digital OutputCue2063=[~UNUSED3~] OutputSigType2063=Digital OutputCue2064=[~UNUSED3~] OutputSigType2064=Digital OutputCue2065=[~UNUSED3~] OutputSigType2065=Digital OutputCue2066=[~UNUSED3~] OutputSigType2066=Digital OutputCue2067=[~UNUSED3~] OutputSigType2067=Digital OutputCue2068=[~UNUSED3~] OutputSigType2068=Digital OutputCue2069=[~UNUSED3~] OutputSigType2069=Digital OutputCue2070=[~UNUSED3~] OutputSigType2070=Digital OutputCue2071=[~UNUSED3~] OutputSigType2071=Digital OutputCue2072=[~UNUSED3~] OutputSigType2072=Digital OutputCue2073=[~UNUSED3~] OutputSigType2073=Digital OutputCue2074=[~UNUSED3~] OutputSigType2074=Digital OutputCue2075=[~UNUSED3~] OutputSigType2075=Digital OutputCue2076=[~UNUSED3~] OutputSigType2076=Digital OutputCue2077=[~UNUSED3~] OutputSigType2077=Digital OutputCue2078=[~UNUSED3~] OutputSigType2078=Digital OutputCue2079=[~UNUSED3~] OutputSigType2079=Digital OutputCue2080=[~UNUSED3~] OutputSigType2080=Digital OutputCue2081=[~UNUSED3~] OutputSigType2081=Digital OutputCue2082=[~UNUSED3~] OutputSigType2082=Digital OutputCue2083=[~UNUSED3~] OutputSigType2083=Digital OutputCue2084=[~UNUSED3~] OutputSigType2084=Digital OutputCue2085=[~UNUSED3~] OutputSigType2085=Digital OutputCue2086=[~UNUSED3~] OutputSigType2086=Digital OutputCue2087=[~UNUSED3~] OutputSigType2087=Digital OutputCue2088=[~UNUSED3~] OutputSigType2088=Digital OutputCue2089=[~UNUSED3~] OutputSigType2089=Digital OutputCue2090=[~UNUSED3~] OutputSigType2090=Digital OutputCue2091=[~UNUSED3~] OutputSigType2091=Digital OutputCue2092=[~UNUSED3~] OutputSigType2092=Digital OutputCue2093=[~UNUSED3~] OutputSigType2093=Digital OutputCue2094=[~UNUSED3~] OutputSigType2094=Digital OutputCue2095=[~UNUSED3~] OutputSigType2095=Digital OutputCue2096=[~UNUSED3~] OutputSigType2096=Digital OutputCue2097=[~UNUSED3~] OutputSigType2097=Digital OutputCue2098=[~UNUSED3~] OutputSigType2098=Digital OutputCue2099=[~UNUSED3~] OutputSigType2099=Digital OutputCue2100=[~UNUSED3~] OutputSigType2100=Digital OutputCue2101=[~UNUSED3~] OutputSigType2101=Digital OutputCue2102=[~UNUSED3~] OutputSigType2102=Digital OutputCue2103=[~UNUSED3~] OutputSigType2103=Digital OutputCue2104=[~UNUSED3~] OutputSigType2104=Digital OutputCue2105=[~UNUSED3~] OutputSigType2105=Digital OutputCue2106=[~UNUSED3~] OutputSigType2106=Digital OutputCue2107=[~UNUSED3~] OutputSigType2107=Digital OutputCue2108=[~UNUSED3~] OutputSigType2108=Digital OutputCue2109=[~UNUSED3~] OutputSigType2109=Digital OutputCue2110=[~UNUSED3~] OutputSigType2110=Digital OutputCue2111=[~UNUSED3~] OutputSigType2111=Digital OutputCue2112=[~UNUSED3~] OutputSigType2112=Digital OutputCue2113=[~UNUSED3~] OutputSigType2113=Digital OutputCue2114=[~UNUSED2~] OutputSigType2114=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=press91 OutputSigType4106=Digital OutputCue4107=press92 OutputSigType4107=Digital OutputCue4108=press93 OutputSigType4108=Digital OutputCue4109=press94 OutputSigType4109=Digital OutputCue4110=press95 OutputSigType4110=Digital OutputCue4111=press96 OutputSigType4111=Digital OutputCue4112=press97 OutputSigType4112=Digital OutputCue4113=press98 OutputSigType4113=Digital OutputCue4114=press99 OutputSigType4114=Digital OutputCue4115=press100 OutputSigType4115=Digital OutputCue4116=press101 OutputSigType4116=Digital OutputCue4117=press102 OutputSigType4117=Digital OutputCue4118=press103 OutputSigType4118=Digital OutputCue4119=press104 OutputSigType4119=Digital OutputCue4120=press105 OutputSigType4120=Digital OutputCue4121=press106 OutputSigType4121=Digital OutputCue4122=press107 OutputSigType4122=Digital OutputCue4123=press108 OutputSigType4123=Digital OutputCue4124=press109 OutputSigType4124=Digital OutputCue4125=press110 OutputSigType4125=Digital OutputCue4126=press111 OutputSigType4126=Digital OutputCue4127=press112 OutputSigType4127=Digital OutputCue4128=press113 OutputSigType4128=Digital OutputCue4129=press114 OutputSigType4129=Digital OutputCue4130=press115 OutputSigType4130=Digital OutputCue4131=press116 OutputSigType4131=Digital OutputCue4132=press117 OutputSigType4132=Digital OutputCue4133=press118 OutputSigType4133=Digital OutputCue4134=press119 OutputSigType4134=Digital OutputCue4135=press120 OutputSigType4135=Digital OutputCue4136=press121 OutputSigType4136=Digital OutputCue4137=press122 OutputSigType4137=Digital OutputCue4138=press123 OutputSigType4138=Digital OutputCue4139=press124 OutputSigType4139=Digital OutputCue4140=press125 OutputSigType4140=Digital OutputCue4141=press126 OutputSigType4141=Digital OutputCue4142=press127 OutputSigType4142=Digital OutputCue4143=press128 OutputSigType4143=Digital OutputCue4144=press129 OutputSigType4144=Digital OutputCue4145=press130 OutputSigType4145=Digital OutputCue4146=press131 OutputSigType4146=Digital OutputCue4147=press132 OutputSigType4147=Digital OutputCue4148=press133 OutputSigType4148=Digital OutputCue4149=press134 OutputSigType4149=Digital OutputCue4150=press135 OutputSigType4150=Digital OutputCue4151=press136 OutputSigType4151=Digital OutputCue4152=press137 OutputSigType4152=Digital OutputCue4153=press138 OutputSigType4153=Digital OutputCue4154=press139 OutputSigType4154=Digital OutputCue4155=press140 OutputSigType4155=Digital OutputCue4156=press141 OutputSigType4156=Digital OutputCue4157=press142 OutputSigType4157=Digital OutputCue4158=press143 OutputSigType4158=Digital OutputCue4159=press144 OutputSigType4159=Digital OutputCue4160=press145 OutputSigType4160=Digital OutputCue4161=press146 OutputSigType4161=Digital OutputCue4162=press147 OutputSigType4162=Digital OutputCue4163=press148 OutputSigType4163=Digital OutputCue4164=press149 OutputSigType4164=Digital OutputCue4165=press150 OutputSigType4165=Digital OutputCue4166=press151 OutputSigType4166=Digital OutputCue4167=press152 OutputSigType4167=Digital OutputCue4168=press153 OutputSigType4168=Digital OutputCue4169=press154 OutputSigType4169=Digital OutputCue4170=press155 OutputSigType4170=Digital OutputCue4171=press156 OutputSigType4171=Digital OutputCue4172=press157 OutputSigType4172=Digital OutputCue4173=press158 OutputSigType4173=Digital OutputCue4174=press159 OutputSigType4174=Digital OutputCue4175=press160 OutputSigType4175=Digital OutputCue4176=press161 OutputSigType4176=Digital OutputCue4177=press162 OutputSigType4177=Digital OutputCue4178=press163 OutputSigType4178=Digital OutputCue4179=press164 OutputSigType4179=Digital OutputCue4180=press165 OutputSigType4180=Digital OutputCue4181=press166 OutputSigType4181=Digital OutputCue4182=press167 OutputSigType4182=Digital OutputCue4183=press168 OutputSigType4183=Digital OutputCue4184=press169 OutputSigType4184=Digital OutputCue4185=press170 OutputSigType4185=Digital OutputCue4186=press171 OutputSigType4186=Digital OutputCue4187=press172 OutputSigType4187=Digital OutputCue4188=press173 OutputSigType4188=Digital OutputCue4189=press174 OutputSigType4189=Digital OutputCue4190=press175 OutputSigType4190=Digital OutputCue4191=press176 OutputSigType4191=Digital OutputCue4192=press177 OutputSigType4192=Digital OutputCue4193=press178 OutputSigType4193=Digital OutputCue4194=press179 OutputSigType4194=Digital OutputCue4195=press180 OutputSigType4195=Digital OutputCue4196=press181 OutputSigType4196=Digital OutputCue4197=press182 OutputSigType4197=Digital OutputCue4198=press183 OutputSigType4198=Digital OutputCue4199=press184 OutputSigType4199=Digital OutputCue4200=press185 OutputSigType4200=Digital OutputCue4201=press186 OutputSigType4201=Digital OutputCue4202=press187 OutputSigType4202=Digital OutputCue4203=press188 OutputSigType4203=Digital OutputCue4204=press189 OutputSigType4204=Digital OutputCue4205=press190 OutputSigType4205=Digital OutputCue4206=press191 OutputSigType4206=Digital OutputCue4207=press192 OutputSigType4207=Digital OutputCue4208=press193 OutputSigType4208=Digital OutputCue4209=press194 OutputSigType4209=Digital OutputCue4210=press195 OutputSigType4210=Digital OutputCue4211=press196 OutputSigType4211=Digital OutputCue4212=press197 OutputSigType4212=Digital OutputCue4213=press198 OutputSigType4213=Digital OutputCue4214=press199 OutputSigType4214=Digital OutputCue4215=press200 OutputSigType4215=Digital OutputCue4216=press201 OutputSigType4216=Digital OutputCue4217=press202 OutputSigType4217=Digital OutputCue4218=press203 OutputSigType4218=Digital OutputCue4219=press204 OutputSigType4219=Digital OutputCue4220=press205 OutputSigType4220=Digital OutputCue4221=press206 OutputSigType4221=Digital OutputCue4222=press207 OutputSigType4222=Digital OutputCue4223=press208 OutputSigType4223=Digital OutputCue4224=press209 OutputSigType4224=Digital OutputCue4225=press210 OutputSigType4225=Digital OutputCue4226=press211 OutputSigType4226=Digital OutputCue4227=press212 OutputSigType4227=Digital OutputCue4228=press213 OutputSigType4228=Digital OutputCue4229=press214 OutputSigType4229=Digital OutputCue4230=press215 OutputSigType4230=Digital OutputCue4231=press216 OutputSigType4231=Digital OutputCue4232=press217 OutputSigType4232=Digital OutputCue4233=press218 OutputSigType4233=Digital OutputCue4234=press219 OutputSigType4234=Digital OutputCue4235=press220 OutputSigType4235=Digital OutputCue4236=press221 OutputSigType4236=Digital OutputCue4237=press222 OutputSigType4237=Digital OutputCue4238=press223 OutputSigType4238=Digital OutputCue4239=press224 OutputSigType4239=Digital OutputCue4240=press225 OutputSigType4240=Digital OutputCue4241=press226 OutputSigType4241=Digital OutputCue4242=press227 OutputSigType4242=Digital OutputCue4243=press228 OutputSigType4243=Digital OutputCue4244=press229 OutputSigType4244=Digital OutputCue4245=press230 OutputSigType4245=Digital OutputCue4246=press231 OutputSigType4246=Digital OutputCue4247=press232 OutputSigType4247=Digital OutputCue4248=press233 OutputSigType4248=Digital OutputCue4249=press234 OutputSigType4249=Digital OutputCue4250=press235 OutputSigType4250=Digital OutputCue4251=press236 OutputSigType4251=Digital OutputCue4252=press237 OutputSigType4252=Digital OutputCue4253=press238 OutputSigType4253=Digital OutputCue4254=press239 OutputSigType4254=Digital OutputCue4255=press240 OutputSigType4255=Digital OutputCue4256=press241 OutputSigType4256=Digital OutputCue4257=press242 OutputSigType4257=Digital OutputCue4258=press243 OutputSigType4258=Digital OutputCue4259=press244 OutputSigType4259=Digital OutputCue4260=press245 OutputSigType4260=Digital OutputCue4261=press246 OutputSigType4261=Digital OutputCue4262=press247 OutputSigType4262=Digital OutputCue4263=press248 OutputSigType4263=Digital OutputCue4264=press249 OutputSigType4264=Digital OutputCue4265=press250 OutputSigType4265=Digital OutputCue4266=press251 OutputSigType4266=Digital OutputCue4267=press252 OutputSigType4267=Digital OutputCue4268=press253 OutputSigType4268=Digital OutputCue4269=press254 OutputSigType4269=Digital OutputCue4270=press255 OutputSigType4270=Digital OutputCue4271=press256 OutputSigType4271=Digital OutputCue4272=press257 OutputSigType4272=Digital OutputCue4273=press258 OutputSigType4273=Digital OutputCue4274=press259 OutputSigType4274=Digital OutputCue4275=press260 OutputSigType4275=Digital OutputCue4276=press261 OutputSigType4276=Digital OutputCue4277=press262 OutputSigType4277=Digital OutputCue4278=press263 OutputSigType4278=Digital OutputCue4279=press264 OutputSigType4279=Digital OutputCue4280=press265 OutputSigType4280=Digital OutputCue4281=press266 OutputSigType4281=Digital OutputCue4282=press267 OutputSigType4282=Digital OutputCue4283=press268 OutputSigType4283=Digital OutputCue4284=press269 OutputSigType4284=Digital OutputCue4285=press270 OutputSigType4285=Digital OutputCue4286=press271 OutputSigType4286=Digital OutputCue4287=press272 OutputSigType4287=Digital OutputCue4288=press273 OutputSigType4288=Digital OutputCue4289=press274 OutputSigType4289=Digital OutputCue4290=press275 OutputSigType4290=Digital OutputCue4291=press276 OutputSigType4291=Digital OutputCue4292=press277 OutputSigType4292=Digital OutputCue4293=press278 OutputSigType4293=Digital OutputCue4294=press279 OutputSigType4294=Digital OutputCue4295=press280 OutputSigType4295=Digital OutputCue4296=press281 OutputSigType4296=Digital OutputCue4297=press282 OutputSigType4297=Digital OutputCue4298=press283 OutputSigType4298=Digital OutputCue4299=press284 OutputSigType4299=Digital OutputCue4300=press285 OutputSigType4300=Digital OutputCue4301=press286 OutputSigType4301=Digital OutputCue4302=press287 OutputSigType4302=Digital OutputCue4303=press288 OutputSigType4303=Digital OutputCue4304=press289 OutputSigType4304=Digital OutputCue4305=press290 OutputSigType4305=Digital OutputCue4306=press291 OutputSigType4306=Digital OutputCue4307=press292 OutputSigType4307=Digital OutputCue4308=press293 OutputSigType4308=Digital OutputCue4309=press294 OutputSigType4309=Digital OutputCue4310=press295 OutputSigType4310=Digital OutputCue4311=press296 OutputSigType4311=Digital OutputCue4312=press297 OutputSigType4312=Digital OutputCue4313=press298 OutputSigType4313=Digital OutputCue4314=press299 OutputSigType4314=Digital OutputCue4315=press300 OutputSigType4315=Digital OutputCue4316=[~EndGroup~]Press OutputSigType4316=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=text-o121 InputList3SigType132=Serial InputList3Cue133=text-o122 InputList3SigType133=Serial InputList3Cue134=text-o123 InputList3SigType134=Serial InputList3Cue135=text-o124 InputList3SigType135=Serial InputList3Cue136=text-o125 InputList3SigType136=Serial InputList3Cue137=text-o126 InputList3SigType137=Serial InputList3Cue138=text-o127 InputList3SigType138=Serial InputList3Cue139=text-o128 InputList3SigType139=Serial InputList3Cue140=text-o129 InputList3SigType140=Serial InputList3Cue141=text-o130 InputList3SigType141=Serial InputList3Cue142=text-o131 InputList3SigType142=Serial InputList3Cue143=text-o132 InputList3SigType143=Serial InputList3Cue144=text-o133 InputList3SigType144=Serial InputList3Cue145=text-o134 InputList3SigType145=Serial InputList3Cue146=text-o135 InputList3SigType146=Serial InputList3Cue147=text-o136 InputList3SigType147=Serial InputList3Cue148=text-o137 InputList3SigType148=Serial InputList3Cue149=text-o138 InputList3SigType149=Serial InputList3Cue150=text-o139 InputList3SigType150=Serial InputList3Cue151=text-o140 InputList3SigType151=Serial InputList3Cue152=text-o141 InputList3SigType152=Serial InputList3Cue153=text-o142 InputList3SigType153=Serial InputList3Cue154=text-o143 InputList3SigType154=Serial InputList3Cue155=text-o144 InputList3SigType155=Serial InputList3Cue156=text-o145 InputList3SigType156=Serial InputList3Cue157=text-o146 InputList3SigType157=Serial InputList3Cue158=text-o147 InputList3SigType158=Serial InputList3Cue159=text-o148 InputList3SigType159=Serial InputList3Cue160=text-o149 InputList3SigType160=Serial InputList3Cue161=text-o150 InputList3SigType161=Serial InputList3Cue162=text-o151 InputList3SigType162=Serial InputList3Cue163=text-o152 InputList3SigType163=Serial InputList3Cue164=text-o153 InputList3SigType164=Serial InputList3Cue165=text-o154 InputList3SigType165=Serial InputList3Cue166=text-o155 InputList3SigType166=Serial InputList3Cue167=text-o156 InputList3SigType167=Serial InputList3Cue168=text-o157 InputList3SigType168=Serial InputList3Cue169=text-o158 InputList3SigType169=Serial InputList3Cue170=text-o159 InputList3SigType170=Serial InputList3Cue171=text-o160 InputList3SigType171=Serial InputList3Cue172=text-o161 InputList3SigType172=Serial InputList3Cue173=text-o162 InputList3SigType173=Serial InputList3Cue174=text-o163 InputList3SigType174=Serial InputList3Cue175=text-o164 InputList3SigType175=Serial InputList3Cue176=text-o165 InputList3SigType176=Serial InputList3Cue177=text-o166 InputList3SigType177=Serial InputList3Cue178=text-o167 InputList3SigType178=Serial InputList3Cue179=text-o168 InputList3SigType179=Serial InputList3Cue180=text-o169 InputList3SigType180=Serial InputList3Cue181=text-o170 InputList3SigType181=Serial InputList3Cue182=text-o171 InputList3SigType182=Serial InputList3Cue183=text-o172 InputList3SigType183=Serial InputList3Cue184=text-o173 InputList3SigType184=Serial InputList3Cue185=text-o174 InputList3SigType185=Serial InputList3Cue186=text-o175 InputList3SigType186=Serial InputList3Cue187=text-o176 InputList3SigType187=Serial InputList3Cue188=text-o177 InputList3SigType188=Serial InputList3Cue189=text-o178 InputList3SigType189=Serial InputList3Cue190=text-o179 InputList3SigType190=Serial InputList3Cue191=text-o180 InputList3SigType191=Serial InputList3Cue192=text-o181 InputList3SigType192=Serial InputList3Cue193=text-o182 InputList3SigType193=Serial InputList3Cue194=text-o183 InputList3SigType194=Serial InputList3Cue195=text-o184 InputList3SigType195=Serial InputList3Cue196=text-o185 InputList3SigType196=Serial InputList3Cue197=text-o186 InputList3SigType197=Serial InputList3Cue198=text-o187 InputList3SigType198=Serial InputList3Cue199=text-o188 InputList3SigType199=Serial InputList3Cue200=text-o189 InputList3SigType200=Serial InputList3Cue201=text-o190 InputList3SigType201=Serial InputList3Cue202=text-o191 InputList3SigType202=Serial InputList3Cue203=text-o192 InputList3SigType203=Serial InputList3Cue204=text-o193 InputList3SigType204=Serial InputList3Cue205=text-o194 InputList3SigType205=Serial InputList3Cue206=text-o195 InputList3SigType206=Serial InputList3Cue207=text-o196 InputList3SigType207=Serial InputList3Cue208=text-o197 InputList3SigType208=Serial InputList3Cue209=text-o198 InputList3SigType209=Serial InputList3Cue210=text-o199 InputList3SigType210=Serial InputList3Cue211=text-o200 InputList3SigType211=Serial InputList3Cue212=text-o201 InputList3SigType212=Serial InputList3Cue213=text-o202 InputList3SigType213=Serial InputList3Cue214=text-o203 InputList3SigType214=Serial InputList3Cue215=text-o204 InputList3SigType215=Serial InputList3Cue216=text-o205 InputList3SigType216=Serial InputList3Cue217=text-o206 InputList3SigType217=Serial InputList3Cue218=text-o207 InputList3SigType218=Serial InputList3Cue219=text-o208 InputList3SigType219=Serial InputList3Cue220=text-o209 InputList3SigType220=Serial InputList3Cue221=text-o210 InputList3SigType221=Serial InputList3Cue222=text-o211 InputList3SigType222=Serial InputList3Cue223=text-o212 InputList3SigType223=Serial InputList3Cue224=text-o213 InputList3SigType224=Serial InputList3Cue225=text-o214 InputList3SigType225=Serial InputList3Cue226=text-o215 InputList3SigType226=Serial InputList3Cue227=text-o216 InputList3SigType227=Serial InputList3Cue228=text-o217 InputList3SigType228=Serial InputList3Cue229=text-o218 InputList3SigType229=Serial InputList3Cue230=text-o219 InputList3SigType230=Serial InputList3Cue231=text-o220 InputList3SigType231=Serial InputList3Cue232=text-o221 InputList3SigType232=Serial InputList3Cue233=text-o222 InputList3SigType233=Serial InputList3Cue234=text-o223 InputList3SigType234=Serial InputList3Cue235=text-o224 InputList3SigType235=Serial InputList3Cue236=text-o225 InputList3SigType236=Serial InputList3Cue237=text-o226 InputList3SigType237=Serial InputList3Cue238=text-o227 InputList3SigType238=Serial InputList3Cue239=text-o228 InputList3SigType239=Serial InputList3Cue240=text-o229 InputList3SigType240=Serial InputList3Cue241=text-o230 InputList3SigType241=Serial InputList3Cue242=text-o231 InputList3SigType242=Serial InputList3Cue243=text-o232 InputList3SigType243=Serial InputList3Cue244=text-o233 InputList3SigType244=Serial InputList3Cue245=text-o234 InputList3SigType245=Serial InputList3Cue246=text-o235 InputList3SigType246=Serial InputList3Cue247=text-o236 InputList3SigType247=Serial InputList3Cue248=text-o237 InputList3SigType248=Serial InputList3Cue249=text-o238 InputList3SigType249=Serial InputList3Cue250=text-o239 InputList3SigType250=Serial InputList3Cue251=text-o240 InputList3SigType251=Serial InputList3Cue252=text-o241 InputList3SigType252=Serial InputList3Cue253=text-o242 InputList3SigType253=Serial InputList3Cue254=text-o243 InputList3SigType254=Serial InputList3Cue255=text-o244 InputList3SigType255=Serial InputList3Cue256=text-o245 InputList3SigType256=Serial InputList3Cue257=text-o246 InputList3SigType257=Serial InputList3Cue258=text-o247 InputList3SigType258=Serial InputList3Cue259=text-o248 InputList3SigType259=Serial InputList3Cue260=text-o249 InputList3SigType260=Serial InputList3Cue261=text-o250 InputList3SigType261=Serial InputList3Cue262=text-o251 InputList3SigType262=Serial InputList3Cue263=text-o252 InputList3SigType263=Serial InputList3Cue264=text-o253 InputList3SigType264=Serial InputList3Cue265=text-o254 InputList3SigType265=Serial InputList3Cue266=text-o255 InputList3SigType266=Serial InputList3Cue267=text-o256 InputList3SigType267=Serial InputList3Cue268=text-o257 InputList3SigType268=Serial InputList3Cue269=text-o258 InputList3SigType269=Serial InputList3Cue270=text-o259 InputList3SigType270=Serial InputList3Cue271=text-o260 InputList3SigType271=Serial InputList3Cue272=text-o261 InputList3SigType272=Serial InputList3Cue273=text-o262 InputList3SigType273=Serial InputList3Cue274=text-o263 InputList3SigType274=Serial InputList3Cue275=text-o264 InputList3SigType275=Serial InputList3Cue276=text-o265 InputList3SigType276=Serial InputList3Cue277=text-o266 InputList3SigType277=Serial InputList3Cue278=text-o267 InputList3SigType278=Serial InputList3Cue279=text-o268 InputList3SigType279=Serial InputList3Cue280=text-o269 InputList3SigType280=Serial InputList3Cue281=text-o270 InputList3SigType281=Serial InputList3Cue282=text-o271 InputList3SigType282=Serial InputList3Cue283=text-o272 InputList3SigType283=Serial InputList3Cue284=text-o273 InputList3SigType284=Serial InputList3Cue285=text-o274 InputList3SigType285=Serial InputList3Cue286=text-o275 InputList3SigType286=Serial InputList3Cue287=text-o276 InputList3SigType287=Serial InputList3Cue288=text-o277 InputList3SigType288=Serial InputList3Cue289=text-o278 InputList3SigType289=Serial InputList3Cue290=text-o279 InputList3SigType290=Serial InputList3Cue291=text-o280 InputList3SigType291=Serial InputList3Cue292=text-o281 InputList3SigType292=Serial InputList3Cue293=text-o282 InputList3SigType293=Serial InputList3Cue294=text-o283 InputList3SigType294=Serial InputList3Cue295=text-o284 InputList3SigType295=Serial InputList3Cue296=text-o285 InputList3SigType296=Serial InputList3Cue297=text-o286 InputList3SigType297=Serial InputList3Cue298=text-o287 InputList3SigType298=Serial InputList3Cue299=text-o288 InputList3SigType299=Serial InputList3Cue300=text-o289 InputList3SigType300=Serial InputList3Cue301=text-o290 InputList3SigType301=Serial InputList3Cue302=text-o291 InputList3SigType302=Serial InputList3Cue303=text-o292 InputList3SigType303=Serial InputList3Cue304=text-o293 InputList3SigType304=Serial InputList3Cue305=text-o294 InputList3SigType305=Serial InputList3Cue306=text-o295 InputList3SigType306=Serial InputList3Cue307=text-o296 InputList3SigType307=Serial InputList3Cue308=text-o297 InputList3SigType308=Serial InputList3Cue309=text-o298 InputList3SigType309=Serial InputList3Cue310=text-o299 InputList3SigType310=Serial InputList3Cue311=text-o300 InputList3SigType311=Serial InputList3Cue312=text-o301 InputList3SigType312=Serial InputList3Cue313=text-o302 InputList3SigType313=Serial InputList3Cue314=text-o303 InputList3SigType314=Serial InputList3Cue315=text-o304 InputList3SigType315=Serial InputList3Cue316=text-o305 InputList3SigType316=Serial InputList3Cue317=text-o306 InputList3SigType317=Serial InputList3Cue318=text-o307 InputList3SigType318=Serial InputList3Cue319=text-o308 InputList3SigType319=Serial InputList3Cue320=text-o309 InputList3SigType320=Serial InputList3Cue321=text-o310 InputList3SigType321=Serial InputList3Cue322=text-o311 InputList3SigType322=Serial InputList3Cue323=text-o312 InputList3SigType323=Serial InputList3Cue324=text-o313 InputList3SigType324=Serial InputList3Cue325=text-o314 InputList3SigType325=Serial InputList3Cue326=text-o315 InputList3SigType326=Serial InputList3Cue327=text-o316 InputList3SigType327=Serial InputList3Cue328=text-o317 InputList3SigType328=Serial InputList3Cue329=text-o318 InputList3SigType329=Serial InputList3Cue330=text-o319 InputList3SigType330=Serial InputList3Cue331=text-o320 InputList3SigType331=Serial InputList3Cue332=text-o321 InputList3SigType332=Serial InputList3Cue333=text-o322 InputList3SigType333=Serial InputList3Cue334=text-o323 InputList3SigType334=Serial InputList3Cue335=text-o324 InputList3SigType335=Serial InputList3Cue336=text-o325 InputList3SigType336=Serial InputList3Cue337=text-o326 InputList3SigType337=Serial InputList3Cue338=text-o327 InputList3SigType338=Serial InputList3Cue339=text-o328 InputList3SigType339=Serial InputList3Cue340=text-o329 InputList3SigType340=Serial InputList3Cue341=text-o330 InputList3SigType341=Serial InputList3Cue342=text-o331 InputList3SigType342=Serial InputList3Cue343=text-o332 InputList3SigType343=Serial InputList3Cue344=text-o333 InputList3SigType344=Serial InputList3Cue345=text-o334 InputList3SigType345=Serial InputList3Cue346=text-o335 InputList3SigType346=Serial InputList3Cue347=text-o336 InputList3SigType347=Serial InputList3Cue348=text-o337 InputList3SigType348=Serial InputList3Cue349=text-o338 InputList3SigType349=Serial InputList3Cue350=text-o339 InputList3SigType350=Serial InputList3Cue351=text-o340 InputList3SigType351=Serial InputList3Cue352=text-o341 InputList3SigType352=Serial InputList3Cue353=text-o342 InputList3SigType353=Serial InputList3Cue354=text-o343 InputList3SigType354=Serial InputList3Cue355=text-o344 InputList3SigType355=Serial InputList3Cue356=text-o345 InputList3SigType356=Serial InputList3Cue357=text-o346 InputList3SigType357=Serial InputList3Cue358=text-o347 InputList3SigType358=Serial InputList3Cue359=text-o348 InputList3SigType359=Serial InputList3Cue360=text-o349 InputList3SigType360=Serial InputList3Cue361=text-o350 InputList3SigType361=Serial InputList3Cue362=text-o351 InputList3SigType362=Serial InputList3Cue363=text-o352 InputList3SigType363=Serial InputList3Cue364=text-o353 InputList3SigType364=Serial InputList3Cue365=text-o354 InputList3SigType365=Serial InputList3Cue366=text-o355 InputList3SigType366=Serial InputList3Cue367=text-o356 InputList3SigType367=Serial InputList3Cue368=text-o357 InputList3SigType368=Serial InputList3Cue369=text-o358 InputList3SigType369=Serial InputList3Cue370=text-o359 InputList3SigType370=Serial InputList3Cue371=text-o360 InputList3SigType371=Serial InputList3Cue372=text-o361 InputList3SigType372=Serial InputList3Cue373=text-o362 InputList3SigType373=Serial InputList3Cue374=text-o363 InputList3SigType374=Serial InputList3Cue375=text-o364 InputList3SigType375=Serial InputList3Cue376=text-o365 InputList3SigType376=Serial InputList3Cue377=text-o366 InputList3SigType377=Serial InputList3Cue378=text-o367 InputList3SigType378=Serial InputList3Cue379=text-o368 InputList3SigType379=Serial InputList3Cue380=text-o369 InputList3SigType380=Serial InputList3Cue381=text-o370 InputList3SigType381=Serial InputList3Cue382=text-o371 InputList3SigType382=Serial InputList3Cue383=text-o372 InputList3SigType383=Serial InputList3Cue384=text-o373 InputList3SigType384=Serial InputList3Cue385=text-o374 InputList3SigType385=Serial InputList3Cue386=text-o375 InputList3SigType386=Serial InputList3Cue387=text-o376 InputList3SigType387=Serial InputList3Cue388=text-o377 InputList3SigType388=Serial InputList3Cue389=text-o378 InputList3SigType389=Serial InputList3Cue390=text-o379 InputList3SigType390=Serial InputList3Cue391=text-o380 InputList3SigType391=Serial InputList3Cue392=text-o381 InputList3SigType392=Serial InputList3Cue393=text-o382 InputList3SigType393=Serial InputList3Cue394=text-o383 InputList3SigType394=Serial InputList3Cue395=text-o384 InputList3SigType395=Serial InputList3Cue396=text-o385 InputList3SigType396=Serial InputList3Cue397=text-o386 InputList3SigType397=Serial InputList3Cue398=text-o387 InputList3SigType398=Serial InputList3Cue399=text-o388 InputList3SigType399=Serial InputList3Cue400=text-o389 InputList3SigType400=Serial InputList3Cue401=text-o390 InputList3SigType401=Serial InputList3Cue402=text-o391 InputList3SigType402=Serial InputList3Cue403=text-o392 InputList3SigType403=Serial InputList3Cue404=text-o393 InputList3SigType404=Serial InputList3Cue405=text-o394 InputList3SigType405=Serial InputList3Cue406=text-o395 InputList3SigType406=Serial InputList3Cue407=text-o396 InputList3SigType407=Serial InputList3Cue408=text-o397 InputList3SigType408=Serial InputList3Cue409=text-o398 InputList3SigType409=Serial InputList3Cue410=text-o399 InputList3SigType410=Serial InputList3Cue411=text-o400 InputList3SigType411=Serial InputList3Cue412=[~EndGroup~]text-o InputList3SigType412=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=text-i121 OutputList3SigType132=Serial OutputList3Cue133=text-i122 OutputList3SigType133=Serial OutputList3Cue134=text-i123 OutputList3SigType134=Serial OutputList3Cue135=text-i124 OutputList3SigType135=Serial OutputList3Cue136=text-i125 OutputList3SigType136=Serial OutputList3Cue137=text-i126 OutputList3SigType137=Serial OutputList3Cue138=text-i127 OutputList3SigType138=Serial OutputList3Cue139=text-i128 OutputList3SigType139=Serial OutputList3Cue140=text-i129 OutputList3SigType140=Serial OutputList3Cue141=text-i130 OutputList3SigType141=Serial OutputList3Cue142=text-i131 OutputList3SigType142=Serial OutputList3Cue143=text-i132 OutputList3SigType143=Serial OutputList3Cue144=text-i133 OutputList3SigType144=Serial OutputList3Cue145=text-i134 OutputList3SigType145=Serial OutputList3Cue146=text-i135 OutputList3SigType146=Serial OutputList3Cue147=text-i136 OutputList3SigType147=Serial OutputList3Cue148=text-i137 OutputList3SigType148=Serial OutputList3Cue149=text-i138 OutputList3SigType149=Serial OutputList3Cue150=text-i139 OutputList3SigType150=Serial OutputList3Cue151=text-i140 OutputList3SigType151=Serial OutputList3Cue152=text-i141 OutputList3SigType152=Serial OutputList3Cue153=text-i142 OutputList3SigType153=Serial OutputList3Cue154=text-i143 OutputList3SigType154=Serial OutputList3Cue155=text-i144 OutputList3SigType155=Serial OutputList3Cue156=text-i145 OutputList3SigType156=Serial OutputList3Cue157=text-i146 OutputList3SigType157=Serial OutputList3Cue158=text-i147 OutputList3SigType158=Serial OutputList3Cue159=text-i148 OutputList3SigType159=Serial OutputList3Cue160=text-i149 OutputList3SigType160=Serial OutputList3Cue161=text-i150 OutputList3SigType161=Serial OutputList3Cue162=text-i151 OutputList3SigType162=Serial OutputList3Cue163=text-i152 OutputList3SigType163=Serial OutputList3Cue164=text-i153 OutputList3SigType164=Serial OutputList3Cue165=text-i154 OutputList3SigType165=Serial OutputList3Cue166=text-i155 OutputList3SigType166=Serial OutputList3Cue167=text-i156 OutputList3SigType167=Serial OutputList3Cue168=text-i157 OutputList3SigType168=Serial OutputList3Cue169=text-i158 OutputList3SigType169=Serial OutputList3Cue170=text-i159 OutputList3SigType170=Serial OutputList3Cue171=text-i160 OutputList3SigType171=Serial OutputList3Cue172=text-i161 OutputList3SigType172=Serial OutputList3Cue173=text-i162 OutputList3SigType173=Serial OutputList3Cue174=text-i163 OutputList3SigType174=Serial OutputList3Cue175=text-i164 OutputList3SigType175=Serial OutputList3Cue176=text-i165 OutputList3SigType176=Serial OutputList3Cue177=text-i166 OutputList3SigType177=Serial OutputList3Cue178=text-i167 OutputList3SigType178=Serial OutputList3Cue179=text-i168 OutputList3SigType179=Serial OutputList3Cue180=text-i169 OutputList3SigType180=Serial OutputList3Cue181=text-i170 OutputList3SigType181=Serial OutputList3Cue182=text-i171 OutputList3SigType182=Serial OutputList3Cue183=text-i172 OutputList3SigType183=Serial OutputList3Cue184=text-i173 OutputList3SigType184=Serial OutputList3Cue185=text-i174 OutputList3SigType185=Serial OutputList3Cue186=text-i175 OutputList3SigType186=Serial OutputList3Cue187=text-i176 OutputList3SigType187=Serial OutputList3Cue188=text-i177 OutputList3SigType188=Serial OutputList3Cue189=text-i178 OutputList3SigType189=Serial OutputList3Cue190=text-i179 OutputList3SigType190=Serial OutputList3Cue191=text-i180 OutputList3SigType191=Serial OutputList3Cue192=text-i181 OutputList3SigType192=Serial OutputList3Cue193=text-i182 OutputList3SigType193=Serial OutputList3Cue194=text-i183 OutputList3SigType194=Serial OutputList3Cue195=text-i184 OutputList3SigType195=Serial OutputList3Cue196=text-i185 OutputList3SigType196=Serial OutputList3Cue197=text-i186 OutputList3SigType197=Serial OutputList3Cue198=text-i187 OutputList3SigType198=Serial OutputList3Cue199=text-i188 OutputList3SigType199=Serial OutputList3Cue200=text-i189 OutputList3SigType200=Serial OutputList3Cue201=text-i190 OutputList3SigType201=Serial OutputList3Cue202=text-i191 OutputList3SigType202=Serial OutputList3Cue203=text-i192 OutputList3SigType203=Serial OutputList3Cue204=text-i193 OutputList3SigType204=Serial OutputList3Cue205=text-i194 OutputList3SigType205=Serial OutputList3Cue206=text-i195 OutputList3SigType206=Serial OutputList3Cue207=text-i196 OutputList3SigType207=Serial OutputList3Cue208=text-i197 OutputList3SigType208=Serial OutputList3Cue209=text-i198 OutputList3SigType209=Serial OutputList3Cue210=text-i199 OutputList3SigType210=Serial OutputList3Cue211=text-i200 OutputList3SigType211=Serial OutputList3Cue212=text-i201 OutputList3SigType212=Serial OutputList3Cue213=text-i202 OutputList3SigType213=Serial OutputList3Cue214=text-i203 OutputList3SigType214=Serial OutputList3Cue215=text-i204 OutputList3SigType215=Serial OutputList3Cue216=text-i205 OutputList3SigType216=Serial OutputList3Cue217=text-i206 OutputList3SigType217=Serial OutputList3Cue218=text-i207 OutputList3SigType218=Serial OutputList3Cue219=text-i208 OutputList3SigType219=Serial OutputList3Cue220=text-i209 OutputList3SigType220=Serial OutputList3Cue221=text-i210 OutputList3SigType221=Serial OutputList3Cue222=text-i211 OutputList3SigType222=Serial OutputList3Cue223=text-i212 OutputList3SigType223=Serial OutputList3Cue224=text-i213 OutputList3SigType224=Serial OutputList3Cue225=text-i214 OutputList3SigType225=Serial OutputList3Cue226=text-i215 OutputList3SigType226=Serial OutputList3Cue227=text-i216 OutputList3SigType227=Serial OutputList3Cue228=text-i217 OutputList3SigType228=Serial OutputList3Cue229=text-i218 OutputList3SigType229=Serial OutputList3Cue230=text-i219 OutputList3SigType230=Serial OutputList3Cue231=text-i220 OutputList3SigType231=Serial OutputList3Cue232=text-i221 OutputList3SigType232=Serial OutputList3Cue233=text-i222 OutputList3SigType233=Serial OutputList3Cue234=text-i223 OutputList3SigType234=Serial OutputList3Cue235=text-i224 OutputList3SigType235=Serial OutputList3Cue236=text-i225 OutputList3SigType236=Serial OutputList3Cue237=text-i226 OutputList3SigType237=Serial OutputList3Cue238=text-i227 OutputList3SigType238=Serial OutputList3Cue239=text-i228 OutputList3SigType239=Serial OutputList3Cue240=text-i229 OutputList3SigType240=Serial OutputList3Cue241=text-i230 OutputList3SigType241=Serial OutputList3Cue242=text-i231 OutputList3SigType242=Serial OutputList3Cue243=text-i232 OutputList3SigType243=Serial OutputList3Cue244=text-i233 OutputList3SigType244=Serial OutputList3Cue245=text-i234 OutputList3SigType245=Serial OutputList3Cue246=text-i235 OutputList3SigType246=Serial OutputList3Cue247=text-i236 OutputList3SigType247=Serial OutputList3Cue248=text-i237 OutputList3SigType248=Serial OutputList3Cue249=text-i238 OutputList3SigType249=Serial OutputList3Cue250=text-i239 OutputList3SigType250=Serial OutputList3Cue251=text-i240 OutputList3SigType251=Serial OutputList3Cue252=text-i241 OutputList3SigType252=Serial OutputList3Cue253=text-i242 OutputList3SigType253=Serial OutputList3Cue254=text-i243 OutputList3SigType254=Serial OutputList3Cue255=text-i244 OutputList3SigType255=Serial OutputList3Cue256=text-i245 OutputList3SigType256=Serial OutputList3Cue257=text-i246 OutputList3SigType257=Serial OutputList3Cue258=text-i247 OutputList3SigType258=Serial OutputList3Cue259=text-i248 OutputList3SigType259=Serial OutputList3Cue260=text-i249 OutputList3SigType260=Serial OutputList3Cue261=text-i250 OutputList3SigType261=Serial OutputList3Cue262=text-i251 OutputList3SigType262=Serial OutputList3Cue263=text-i252 OutputList3SigType263=Serial OutputList3Cue264=text-i253 OutputList3SigType264=Serial OutputList3Cue265=text-i254 OutputList3SigType265=Serial OutputList3Cue266=text-i255 OutputList3SigType266=Serial OutputList3Cue267=text-i256 OutputList3SigType267=Serial OutputList3Cue268=text-i257 OutputList3SigType268=Serial OutputList3Cue269=text-i258 OutputList3SigType269=Serial OutputList3Cue270=text-i259 OutputList3SigType270=Serial OutputList3Cue271=text-i260 OutputList3SigType271=Serial OutputList3Cue272=text-i261 OutputList3SigType272=Serial OutputList3Cue273=text-i262 OutputList3SigType273=Serial OutputList3Cue274=text-i263 OutputList3SigType274=Serial OutputList3Cue275=text-i264 OutputList3SigType275=Serial OutputList3Cue276=text-i265 OutputList3SigType276=Serial OutputList3Cue277=text-i266 OutputList3SigType277=Serial OutputList3Cue278=text-i267 OutputList3SigType278=Serial OutputList3Cue279=text-i268 OutputList3SigType279=Serial OutputList3Cue280=text-i269 OutputList3SigType280=Serial OutputList3Cue281=text-i270 OutputList3SigType281=Serial OutputList3Cue282=text-i271 OutputList3SigType282=Serial OutputList3Cue283=text-i272 OutputList3SigType283=Serial OutputList3Cue284=text-i273 OutputList3SigType284=Serial OutputList3Cue285=text-i274 OutputList3SigType285=Serial OutputList3Cue286=text-i275 OutputList3SigType286=Serial OutputList3Cue287=text-i276 OutputList3SigType287=Serial OutputList3Cue288=text-i277 OutputList3SigType288=Serial OutputList3Cue289=text-i278 OutputList3SigType289=Serial OutputList3Cue290=text-i279 OutputList3SigType290=Serial OutputList3Cue291=text-i280 OutputList3SigType291=Serial OutputList3Cue292=text-i281 OutputList3SigType292=Serial OutputList3Cue293=text-i282 OutputList3SigType293=Serial OutputList3Cue294=text-i283 OutputList3SigType294=Serial OutputList3Cue295=text-i284 OutputList3SigType295=Serial OutputList3Cue296=text-i285 OutputList3SigType296=Serial OutputList3Cue297=text-i286 OutputList3SigType297=Serial OutputList3Cue298=text-i287 OutputList3SigType298=Serial OutputList3Cue299=text-i288 OutputList3SigType299=Serial OutputList3Cue300=text-i289 OutputList3SigType300=Serial OutputList3Cue301=text-i290 OutputList3SigType301=Serial OutputList3Cue302=text-i291 OutputList3SigType302=Serial OutputList3Cue303=text-i292 OutputList3SigType303=Serial OutputList3Cue304=text-i293 OutputList3SigType304=Serial OutputList3Cue305=text-i294 OutputList3SigType305=Serial OutputList3Cue306=text-i295 OutputList3SigType306=Serial OutputList3Cue307=text-i296 OutputList3SigType307=Serial OutputList3Cue308=text-i297 OutputList3SigType308=Serial OutputList3Cue309=text-i298 OutputList3SigType309=Serial OutputList3Cue310=text-i299 OutputList3SigType310=Serial OutputList3Cue311=text-i300 OutputList3SigType311=Serial OutputList3Cue312=text-i301 OutputList3SigType312=Serial OutputList3Cue313=text-i302 OutputList3SigType313=Serial OutputList3Cue314=text-i303 OutputList3SigType314=Serial OutputList3Cue315=text-i304 OutputList3SigType315=Serial OutputList3Cue316=text-i305 OutputList3SigType316=Serial OutputList3Cue317=text-i306 OutputList3SigType317=Serial OutputList3Cue318=text-i307 OutputList3SigType318=Serial OutputList3Cue319=text-i308 OutputList3SigType319=Serial OutputList3Cue320=text-i309 OutputList3SigType320=Serial OutputList3Cue321=text-i310 OutputList3SigType321=Serial OutputList3Cue322=text-i311 OutputList3SigType322=Serial OutputList3Cue323=text-i312 OutputList3SigType323=Serial OutputList3Cue324=text-i313 OutputList3SigType324=Serial OutputList3Cue325=text-i314 OutputList3SigType325=Serial OutputList3Cue326=text-i315 OutputList3SigType326=Serial OutputList3Cue327=text-i316 OutputList3SigType327=Serial OutputList3Cue328=text-i317 OutputList3SigType328=Serial OutputList3Cue329=text-i318 OutputList3SigType329=Serial OutputList3Cue330=text-i319 OutputList3SigType330=Serial OutputList3Cue331=text-i320 OutputList3SigType331=Serial OutputList3Cue332=text-i321 OutputList3SigType332=Serial OutputList3Cue333=text-i322 OutputList3SigType333=Serial OutputList3Cue334=text-i323 OutputList3SigType334=Serial OutputList3Cue335=text-i324 OutputList3SigType335=Serial OutputList3Cue336=text-i325 OutputList3SigType336=Serial OutputList3Cue337=text-i326 OutputList3SigType337=Serial OutputList3Cue338=text-i327 OutputList3SigType338=Serial OutputList3Cue339=text-i328 OutputList3SigType339=Serial OutputList3Cue340=text-i329 OutputList3SigType340=Serial OutputList3Cue341=text-i330 OutputList3SigType341=Serial OutputList3Cue342=text-i331 OutputList3SigType342=Serial OutputList3Cue343=text-i332 OutputList3SigType343=Serial OutputList3Cue344=text-i333 OutputList3SigType344=Serial OutputList3Cue345=text-i334 OutputList3SigType345=Serial OutputList3Cue346=text-i335 OutputList3SigType346=Serial OutputList3Cue347=text-i336 OutputList3SigType347=Serial OutputList3Cue348=text-i337 OutputList3SigType348=Serial OutputList3Cue349=text-i338 OutputList3SigType349=Serial OutputList3Cue350=text-i339 OutputList3SigType350=Serial OutputList3Cue351=text-i340 OutputList3SigType351=Serial OutputList3Cue352=text-i341 OutputList3SigType352=Serial OutputList3Cue353=text-i342 OutputList3SigType353=Serial OutputList3Cue354=text-i343 OutputList3SigType354=Serial OutputList3Cue355=text-i344 OutputList3SigType355=Serial OutputList3Cue356=text-i345 OutputList3SigType356=Serial OutputList3Cue357=text-i346 OutputList3SigType357=Serial OutputList3Cue358=text-i347 OutputList3SigType358=Serial OutputList3Cue359=text-i348 OutputList3SigType359=Serial OutputList3Cue360=text-i349 OutputList3SigType360=Serial OutputList3Cue361=text-i350 OutputList3SigType361=Serial OutputList3Cue362=text-i351 OutputList3SigType362=Serial OutputList3Cue363=text-i352 OutputList3SigType363=Serial OutputList3Cue364=text-i353 OutputList3SigType364=Serial OutputList3Cue365=text-i354 OutputList3SigType365=Serial OutputList3Cue366=text-i355 OutputList3SigType366=Serial OutputList3Cue367=text-i356 OutputList3SigType367=Serial OutputList3Cue368=text-i357 OutputList3SigType368=Serial OutputList3Cue369=text-i358 OutputList3SigType369=Serial OutputList3Cue370=text-i359 OutputList3SigType370=Serial OutputList3Cue371=text-i360 OutputList3SigType371=Serial OutputList3Cue372=text-i361 OutputList3SigType372=Serial OutputList3Cue373=text-i362 OutputList3SigType373=Serial OutputList3Cue374=text-i363 OutputList3SigType374=Serial OutputList3Cue375=text-i364 OutputList3SigType375=Serial OutputList3Cue376=text-i365 OutputList3SigType376=Serial OutputList3Cue377=text-i366 OutputList3SigType377=Serial OutputList3Cue378=text-i367 OutputList3SigType378=Serial OutputList3Cue379=text-i368 OutputList3SigType379=Serial OutputList3Cue380=text-i369 OutputList3SigType380=Serial OutputList3Cue381=text-i370 OutputList3SigType381=Serial OutputList3Cue382=text-i371 OutputList3SigType382=Serial OutputList3Cue383=text-i372 OutputList3SigType383=Serial OutputList3Cue384=text-i373 OutputList3SigType384=Serial OutputList3Cue385=text-i374 OutputList3SigType385=Serial OutputList3Cue386=text-i375 OutputList3SigType386=Serial OutputList3Cue387=text-i376 OutputList3SigType387=Serial OutputList3Cue388=text-i377 OutputList3SigType388=Serial OutputList3Cue389=text-i378 OutputList3SigType389=Serial OutputList3Cue390=text-i379 OutputList3SigType390=Serial OutputList3Cue391=text-i380 OutputList3SigType391=Serial OutputList3Cue392=text-i381 OutputList3SigType392=Serial OutputList3Cue393=text-i382 OutputList3SigType393=Serial OutputList3Cue394=text-i383 OutputList3SigType394=Serial OutputList3Cue395=text-i384 OutputList3SigType395=Serial OutputList3Cue396=text-i385 OutputList3SigType396=Serial OutputList3Cue397=text-i386 OutputList3SigType397=Serial OutputList3Cue398=text-i387 OutputList3SigType398=Serial OutputList3Cue399=text-i388 OutputList3SigType399=Serial OutputList3Cue400=text-i389 OutputList3SigType400=Serial OutputList3Cue401=text-i390 OutputList3SigType401=Serial OutputList3Cue402=text-i391 OutputList3SigType402=Serial OutputList3Cue403=text-i392 OutputList3SigType403=Serial OutputList3Cue404=text-i393 OutputList3SigType404=Serial OutputList3Cue405=text-i394 OutputList3SigType405=Serial OutputList3Cue406=text-i395 OutputList3SigType406=Serial OutputList3Cue407=text-i396 OutputList3SigType407=Serial OutputList3Cue408=text-i397 OutputList3SigType408=Serial OutputList3Cue409=text-i398 OutputList3SigType409=Serial OutputList3Cue410=text-i399 OutputList3SigType410=Serial OutputList3Cue411=text-i400 OutputList3SigType411=Serial OutputList3Cue412=[~EndGroup~]text-i OutputList3SigType412=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=10 CedH=10 SmartObjId=10012d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=10 Tp=1 HD=TRUE DV=10012d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=10 Name=PepperDash Essentials iPad_[B.AV] Object - Presets_CATV Icon List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[B.AV] Object - DPad STB_STB DPad.ced Hint=STB DPad (Smart Object ID=10011) Code=11 SGControlType=DPad SGControlName=STB DPad GUID=F2340FAD-85E9-4E49-B46E-15E9B096F58B SmplCName=PepperDash Essentials iPad_[B.AV] Object - DPad STB_STB DPad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10015 ;Define the number of inputs, outputs and parameters MinVariableInputs=5 MaxVariableInputs=5 MinVariableOutputs=5 MaxVariableOutputs=5 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Up OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=Down OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Left OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=Right OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=OK OutputSigType5=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=11 CedH=11 SmartObjId=10011d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=11 Tp=1 HD=TRUE DV=10011d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=11 Name=PepperDash Essentials iPad_[B.AV] Object - DPad STB_STB DPad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced Hint=Tab Button Horizontal (Smart Object ID=10081) Code=12 SGControlType=Horizontal Tab Button SGControlName=Tab Button Horizontal GUID=198C97B0-9D0C-46C2-9557-27EA33C0BE9F SmplCName=PepperDash Essentials iPad_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced SMWRev=4.02.19 Expand=expand_random HelpID=10031 ;Define the number of inputs, outputs and parameters MinVariableInputs=4 MaxVariableInputs=4 MinVariableOutputs=4 MaxVariableOutputs=4 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Tab Button 1 Press OutputSigType1=Digital InputCue2=Tab Button 1 Select InputSigType2=Digital OutputCue2=[~UNUSED3~] OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Tab Button 2 Press OutputSigType3=Digital InputCue4=Tab Button 2 Select InputSigType4=Digital OutputCue4=[~UNUSED3~] OutputSigType4=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=12 CedH=12 SmartObjId=10081d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=12 Tp=1 HD=TRUE DV=10081d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=12 Name=PepperDash Essentials iPad_[B.AV] Object - Tab SetTopBox_Tab Button Horizontal.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[B.AV] Object - Dpad DVD_DVD DPad.ced Hint=DVD DPad (Smart Object ID=10411) Code=13 SGControlType=DPad SGControlName=DVD DPad GUID=D49BCF22-C770-4146-93E6-00867D885E1E SmplCName=PepperDash Essentials iPad_[B.AV] Object - Dpad DVD_DVD DPad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10015 ;Define the number of inputs, outputs and parameters MinVariableInputs=5 MaxVariableInputs=5 MinVariableOutputs=5 MaxVariableOutputs=5 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=Up OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=Down OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=Left OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=Right OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=OK OutputSigType5=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=13 CedH=13 SmartObjId=10411d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=13 Tp=1 HD=TRUE DV=10411d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=13 Name=PepperDash Essentials iPad_[B.AV] Object - Dpad DVD_DVD DPad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced Hint=CATV Keypad (Smart Object ID=10014) Code=14 SGControlType=Simple Keypad SGControlName=CATV Keypad GUID=5E33D4F4-5C5F-430C-879A-AE82529B3943 SmplCName=PepperDash Essentials iPad_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced SMWRev=4.02.19 Expand=expand_random HelpID=10061 ;Define the number of inputs, outputs and parameters MinVariableInputs=12 MaxVariableInputs=12 MinVariableOutputs=12 MaxVariableOutputs=12 NumFixedParams=1 MinVariableInputsList2=0 MaxVariableInputsList2=0 MinVariableOutputsList2=0 MaxVariableOutputsList2=0 MinVariableInputsList3=0 MaxVariableInputsList3=0 MinVariableOutputsList3=0 MaxVariableOutputsList3=0 ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital OutputCue1=1 OutputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital OutputCue2=2 OutputSigType2=Digital InputCue3=[~UNUSED3~] InputSigType3=Digital OutputCue3=3 OutputSigType3=Digital InputCue4=[~UNUSED3~] InputSigType4=Digital OutputCue4=4 OutputSigType4=Digital InputCue5=[~UNUSED3~] InputSigType5=Digital OutputCue5=5 OutputSigType5=Digital InputCue6=[~UNUSED3~] InputSigType6=Digital OutputCue6=6 OutputSigType6=Digital InputCue7=[~UNUSED3~] InputSigType7=Digital OutputCue7=7 OutputSigType7=Digital InputCue8=[~UNUSED3~] InputSigType8=Digital OutputCue8=8 OutputSigType8=Digital InputCue9=[~UNUSED3~] InputSigType9=Digital OutputCue9=9 OutputSigType9=Digital InputCue10=[~UNUSED3~] InputSigType10=Digital OutputCue10=0 OutputSigType10=Digital InputCue11=[~UNUSED3~] InputSigType11=Digital OutputCue11=Misc_1 OutputSigType11=Digital InputCue12=[~UNUSED3~] InputSigType12=Digital OutputCue12=Misc_2 OutputSigType12=Digital ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=14 CedH=14 SmartObjId=10014d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=14 Tp=1 HD=TRUE DV=10014d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=14 Name=PepperDash Essentials iPad_[B.AV] Source-Set Top Box Backer_CATV Keypad.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced Hint=CATV Icon List Vertical (Smart Object ID=3333) Code=15 SGControlType=Subpage Reference List Vertical SGControlName=CATV Icon List Vertical GUID=D6A79678-BAD2-4F6D-8104-A941FBA9432F SmplCName=PepperDash Essentials iPad_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4106 MaxVariableInputs=4106 MinVariableOutputs=4106 MaxVariableOutputs=4106 NumFixedParams=1 MinVariableInputsList2=3 MaxVariableInputsList2=3 MinVariableOutputsList2=3 MaxVariableOutputsList2=3 MinVariableInputsList3=132 MaxVariableInputsList3=132 MinVariableOutputsList3=132 MaxVariableOutputsList3=132 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=Item 21 Enable InputSigType32=Digital InputCue33=Item 22 Enable InputSigType33=Digital InputCue34=Item 23 Enable InputSigType34=Digital InputCue35=Item 24 Enable InputSigType35=Digital InputCue36=Item 25 Enable InputSigType36=Digital InputCue37=Item 26 Enable InputSigType37=Digital InputCue38=Item 27 Enable InputSigType38=Digital InputCue39=Item 28 Enable InputSigType39=Digital InputCue40=Item 29 Enable InputSigType40=Digital InputCue41=Item 30 Enable InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=Item 21 Visible InputSigType2034=Digital InputCue2035=Item 22 Visible InputSigType2035=Digital InputCue2036=Item 23 Visible InputSigType2036=Digital InputCue2037=Item 24 Visible InputSigType2037=Digital InputCue2038=Item 25 Visible InputSigType2038=Digital InputCue2039=Item 26 Visible InputSigType2039=Digital InputCue2040=Item 27 Visible InputSigType2040=Digital InputCue2041=Item 28 Visible InputSigType2041=Digital InputCue2042=Item 29 Visible InputSigType2042=Digital InputCue2043=Item 30 Visible InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=[~EndGroup~]fb InputSigType4106=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED3~] OutputSigType32=Digital OutputCue33=[~UNUSED3~] OutputSigType33=Digital OutputCue34=[~UNUSED3~] OutputSigType34=Digital OutputCue35=[~UNUSED3~] OutputSigType35=Digital OutputCue36=[~UNUSED3~] OutputSigType36=Digital OutputCue37=[~UNUSED3~] OutputSigType37=Digital OutputCue38=[~UNUSED3~] OutputSigType38=Digital OutputCue39=[~UNUSED3~] OutputSigType39=Digital OutputCue40=[~UNUSED3~] OutputSigType40=Digital OutputCue41=[~UNUSED3~] OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=[~EndGroup~]Press OutputSigType4106=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=text-o101 InputList3SigType112=Serial InputList3Cue113=text-o102 InputList3SigType113=Serial InputList3Cue114=text-o103 InputList3SigType114=Serial InputList3Cue115=text-o104 InputList3SigType115=Serial InputList3Cue116=text-o105 InputList3SigType116=Serial InputList3Cue117=text-o106 InputList3SigType117=Serial InputList3Cue118=text-o107 InputList3SigType118=Serial InputList3Cue119=text-o108 InputList3SigType119=Serial InputList3Cue120=text-o109 InputList3SigType120=Serial InputList3Cue121=text-o110 InputList3SigType121=Serial InputList3Cue122=text-o111 InputList3SigType122=Serial InputList3Cue123=text-o112 InputList3SigType123=Serial InputList3Cue124=text-o113 InputList3SigType124=Serial InputList3Cue125=text-o114 InputList3SigType125=Serial InputList3Cue126=text-o115 InputList3SigType126=Serial InputList3Cue127=text-o116 InputList3SigType127=Serial InputList3Cue128=text-o117 InputList3SigType128=Serial InputList3Cue129=text-o118 InputList3SigType129=Serial InputList3Cue130=text-o119 InputList3SigType130=Serial InputList3Cue131=text-o120 InputList3SigType131=Serial InputList3Cue132=[~EndGroup~]text-o InputList3SigType132=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=text-i101 OutputList3SigType112=Serial OutputList3Cue113=text-i102 OutputList3SigType113=Serial OutputList3Cue114=text-i103 OutputList3SigType114=Serial OutputList3Cue115=text-i104 OutputList3SigType115=Serial OutputList3Cue116=text-i105 OutputList3SigType116=Serial OutputList3Cue117=text-i106 OutputList3SigType117=Serial OutputList3Cue118=text-i107 OutputList3SigType118=Serial OutputList3Cue119=text-i108 OutputList3SigType119=Serial OutputList3Cue120=text-i109 OutputList3SigType120=Serial OutputList3Cue121=text-i110 OutputList3SigType121=Serial OutputList3Cue122=text-i111 OutputList3SigType122=Serial OutputList3Cue123=text-i112 OutputList3SigType123=Serial OutputList3Cue124=text-i113 OutputList3SigType124=Serial OutputList3Cue125=text-i114 OutputList3SigType125=Serial OutputList3Cue126=text-i115 OutputList3SigType126=Serial OutputList3Cue127=text-i116 OutputList3SigType127=Serial OutputList3Cue128=text-i117 OutputList3SigType128=Serial OutputList3Cue129=text-i118 OutputList3SigType129=Serial OutputList3Cue130=text-i119 OutputList3SigType130=Serial OutputList3Cue131=text-i120 OutputList3SigType131=Serial OutputList3Cue132=[~EndGroup~]text-i OutputList3SigType132=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=15 CedH=15 SmartObjId=3333d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=15 Tp=1 HD=TRUE DV=3333d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=15 Name=PepperDash Essentials iPad_[B.AV] Source-Set Top Box Backer_CATV Icon List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced Hint=Subpage Reference List Vertical_2 (Smart Object ID=1001) Code=16 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical_2 GUID=5F63F5C2-A987-4957-9243-C28805CE297E SmplCName=PepperDash Essentials iPad_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4116 MaxVariableInputs=4116 MinVariableOutputs=4116 MaxVariableOutputs=4116 NumFixedParams=1 MinVariableInputsList2=112 MaxVariableInputsList2=112 MinVariableOutputsList2=112 MaxVariableOutputsList2=112 MinVariableInputsList3=112 MaxVariableInputsList3=112 MinVariableOutputsList3=112 MaxVariableOutputsList3=112 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=Item 13 Enable InputSigType24=Digital InputCue25=Item 14 Enable InputSigType25=Digital InputCue26=Item 15 Enable InputSigType26=Digital InputCue27=Item 16 Enable InputSigType27=Digital InputCue28=Item 17 Enable InputSigType28=Digital InputCue29=Item 18 Enable InputSigType29=Digital InputCue30=Item 19 Enable InputSigType30=Digital InputCue31=Item 20 Enable InputSigType31=Digital InputCue32=[~UNUSED2~] InputSigType32=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=Item 13 Visible InputSigType2026=Digital InputCue2027=Item 14 Visible InputSigType2027=Digital InputCue2028=Item 15 Visible InputSigType2028=Digital InputCue2029=Item 16 Visible InputSigType2029=Digital InputCue2030=Item 17 Visible InputSigType2030=Digital InputCue2031=Item 18 Visible InputSigType2031=Digital InputCue2032=Item 19 Visible InputSigType2032=Digital InputCue2033=Item 20 Visible InputSigType2033=Digital InputCue2034=[~UNUSED2~] InputSigType2034=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=fb37 InputSigType4052=Digital InputCue4053=fb38 InputSigType4053=Digital InputCue4054=fb39 InputSigType4054=Digital InputCue4055=fb40 InputSigType4055=Digital InputCue4056=fb41 InputSigType4056=Digital InputCue4057=fb42 InputSigType4057=Digital InputCue4058=fb43 InputSigType4058=Digital InputCue4059=fb44 InputSigType4059=Digital InputCue4060=fb45 InputSigType4060=Digital InputCue4061=fb46 InputSigType4061=Digital InputCue4062=fb47 InputSigType4062=Digital InputCue4063=fb48 InputSigType4063=Digital InputCue4064=fb49 InputSigType4064=Digital InputCue4065=fb50 InputSigType4065=Digital InputCue4066=fb51 InputSigType4066=Digital InputCue4067=fb52 InputSigType4067=Digital InputCue4068=fb53 InputSigType4068=Digital InputCue4069=fb54 InputSigType4069=Digital InputCue4070=fb55 InputSigType4070=Digital InputCue4071=fb56 InputSigType4071=Digital InputCue4072=fb57 InputSigType4072=Digital InputCue4073=fb58 InputSigType4073=Digital InputCue4074=fb59 InputSigType4074=Digital InputCue4075=fb60 InputSigType4075=Digital InputCue4076=fb61 InputSigType4076=Digital InputCue4077=fb62 InputSigType4077=Digital InputCue4078=fb63 InputSigType4078=Digital InputCue4079=fb64 InputSigType4079=Digital InputCue4080=fb65 InputSigType4080=Digital InputCue4081=fb66 InputSigType4081=Digital InputCue4082=fb67 InputSigType4082=Digital InputCue4083=fb68 InputSigType4083=Digital InputCue4084=fb69 InputSigType4084=Digital InputCue4085=fb70 InputSigType4085=Digital InputCue4086=fb71 InputSigType4086=Digital InputCue4087=fb72 InputSigType4087=Digital InputCue4088=fb73 InputSigType4088=Digital InputCue4089=fb74 InputSigType4089=Digital InputCue4090=fb75 InputSigType4090=Digital InputCue4091=fb76 InputSigType4091=Digital InputCue4092=fb77 InputSigType4092=Digital InputCue4093=fb78 InputSigType4093=Digital InputCue4094=fb79 InputSigType4094=Digital InputCue4095=fb80 InputSigType4095=Digital InputCue4096=fb81 InputSigType4096=Digital InputCue4097=fb82 InputSigType4097=Digital InputCue4098=fb83 InputSigType4098=Digital InputCue4099=fb84 InputSigType4099=Digital InputCue4100=fb85 InputSigType4100=Digital InputCue4101=fb86 InputSigType4101=Digital InputCue4102=fb87 InputSigType4102=Digital InputCue4103=fb88 InputSigType4103=Digital InputCue4104=fb89 InputSigType4104=Digital InputCue4105=fb90 InputSigType4105=Digital InputCue4106=fb91 InputSigType4106=Digital InputCue4107=fb92 InputSigType4107=Digital InputCue4108=fb93 InputSigType4108=Digital InputCue4109=fb94 InputSigType4109=Digital InputCue4110=fb95 InputSigType4110=Digital InputCue4111=fb96 InputSigType4111=Digital InputCue4112=fb97 InputSigType4112=Digital InputCue4113=fb98 InputSigType4113=Digital InputCue4114=fb99 InputSigType4114=Digital InputCue4115=fb100 InputSigType4115=Digital InputCue4116=[~EndGroup~]fb InputSigType4116=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED3~] OutputSigType24=Digital OutputCue25=[~UNUSED3~] OutputSigType25=Digital OutputCue26=[~UNUSED3~] OutputSigType26=Digital OutputCue27=[~UNUSED3~] OutputSigType27=Digital OutputCue28=[~UNUSED3~] OutputSigType28=Digital OutputCue29=[~UNUSED3~] OutputSigType29=Digital OutputCue30=[~UNUSED3~] OutputSigType30=Digital OutputCue31=[~UNUSED3~] OutputSigType31=Digital OutputCue32=[~UNUSED2~] OutputSigType32=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED2~] OutputSigType2034=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=press37 OutputSigType4052=Digital OutputCue4053=press38 OutputSigType4053=Digital OutputCue4054=press39 OutputSigType4054=Digital OutputCue4055=press40 OutputSigType4055=Digital OutputCue4056=press41 OutputSigType4056=Digital OutputCue4057=press42 OutputSigType4057=Digital OutputCue4058=press43 OutputSigType4058=Digital OutputCue4059=press44 OutputSigType4059=Digital OutputCue4060=press45 OutputSigType4060=Digital OutputCue4061=press46 OutputSigType4061=Digital OutputCue4062=press47 OutputSigType4062=Digital OutputCue4063=press48 OutputSigType4063=Digital OutputCue4064=press49 OutputSigType4064=Digital OutputCue4065=press50 OutputSigType4065=Digital OutputCue4066=press51 OutputSigType4066=Digital OutputCue4067=press52 OutputSigType4067=Digital OutputCue4068=press53 OutputSigType4068=Digital OutputCue4069=press54 OutputSigType4069=Digital OutputCue4070=press55 OutputSigType4070=Digital OutputCue4071=press56 OutputSigType4071=Digital OutputCue4072=press57 OutputSigType4072=Digital OutputCue4073=press58 OutputSigType4073=Digital OutputCue4074=press59 OutputSigType4074=Digital OutputCue4075=press60 OutputSigType4075=Digital OutputCue4076=press61 OutputSigType4076=Digital OutputCue4077=press62 OutputSigType4077=Digital OutputCue4078=press63 OutputSigType4078=Digital OutputCue4079=press64 OutputSigType4079=Digital OutputCue4080=press65 OutputSigType4080=Digital OutputCue4081=press66 OutputSigType4081=Digital OutputCue4082=press67 OutputSigType4082=Digital OutputCue4083=press68 OutputSigType4083=Digital OutputCue4084=press69 OutputSigType4084=Digital OutputCue4085=press70 OutputSigType4085=Digital OutputCue4086=press71 OutputSigType4086=Digital OutputCue4087=press72 OutputSigType4087=Digital OutputCue4088=press73 OutputSigType4088=Digital OutputCue4089=press74 OutputSigType4089=Digital OutputCue4090=press75 OutputSigType4090=Digital OutputCue4091=press76 OutputSigType4091=Digital OutputCue4092=press77 OutputSigType4092=Digital OutputCue4093=press78 OutputSigType4093=Digital OutputCue4094=press79 OutputSigType4094=Digital OutputCue4095=press80 OutputSigType4095=Digital OutputCue4096=press81 OutputSigType4096=Digital OutputCue4097=press82 OutputSigType4097=Digital OutputCue4098=press83 OutputSigType4098=Digital OutputCue4099=press84 OutputSigType4099=Digital OutputCue4100=press85 OutputSigType4100=Digital OutputCue4101=press86 OutputSigType4101=Digital OutputCue4102=press87 OutputSigType4102=Digital OutputCue4103=press88 OutputSigType4103=Digital OutputCue4104=press89 OutputSigType4104=Digital OutputCue4105=press90 OutputSigType4105=Digital OutputCue4106=press91 OutputSigType4106=Digital OutputCue4107=press92 OutputSigType4107=Digital OutputCue4108=press93 OutputSigType4108=Digital OutputCue4109=press94 OutputSigType4109=Digital OutputCue4110=press95 OutputSigType4110=Digital OutputCue4111=press96 OutputSigType4111=Digital OutputCue4112=press97 OutputSigType4112=Digital OutputCue4113=press98 OutputSigType4113=Digital OutputCue4114=press99 OutputSigType4114=Digital OutputCue4115=press100 OutputSigType4115=Digital OutputCue4116=[~EndGroup~]Press OutputSigType4116=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=an_fb37 InputList2SigType48=Analog InputList2Cue49=an_fb38 InputList2SigType49=Analog InputList2Cue50=an_fb39 InputList2SigType50=Analog InputList2Cue51=an_fb40 InputList2SigType51=Analog InputList2Cue52=an_fb41 InputList2SigType52=Analog InputList2Cue53=an_fb42 InputList2SigType53=Analog InputList2Cue54=an_fb43 InputList2SigType54=Analog InputList2Cue55=an_fb44 InputList2SigType55=Analog InputList2Cue56=an_fb45 InputList2SigType56=Analog InputList2Cue57=an_fb46 InputList2SigType57=Analog InputList2Cue58=an_fb47 InputList2SigType58=Analog InputList2Cue59=an_fb48 InputList2SigType59=Analog InputList2Cue60=an_fb49 InputList2SigType60=Analog InputList2Cue61=an_fb50 InputList2SigType61=Analog InputList2Cue62=an_fb51 InputList2SigType62=Analog InputList2Cue63=an_fb52 InputList2SigType63=Analog InputList2Cue64=an_fb53 InputList2SigType64=Analog InputList2Cue65=an_fb54 InputList2SigType65=Analog InputList2Cue66=an_fb55 InputList2SigType66=Analog InputList2Cue67=an_fb56 InputList2SigType67=Analog InputList2Cue68=an_fb57 InputList2SigType68=Analog InputList2Cue69=an_fb58 InputList2SigType69=Analog InputList2Cue70=an_fb59 InputList2SigType70=Analog InputList2Cue71=an_fb60 InputList2SigType71=Analog InputList2Cue72=an_fb61 InputList2SigType72=Analog InputList2Cue73=an_fb62 InputList2SigType73=Analog InputList2Cue74=an_fb63 InputList2SigType74=Analog InputList2Cue75=an_fb64 InputList2SigType75=Analog InputList2Cue76=an_fb65 InputList2SigType76=Analog InputList2Cue77=an_fb66 InputList2SigType77=Analog InputList2Cue78=an_fb67 InputList2SigType78=Analog InputList2Cue79=an_fb68 InputList2SigType79=Analog InputList2Cue80=an_fb69 InputList2SigType80=Analog InputList2Cue81=an_fb70 InputList2SigType81=Analog InputList2Cue82=an_fb71 InputList2SigType82=Analog InputList2Cue83=an_fb72 InputList2SigType83=Analog InputList2Cue84=an_fb73 InputList2SigType84=Analog InputList2Cue85=an_fb74 InputList2SigType85=Analog InputList2Cue86=an_fb75 InputList2SigType86=Analog InputList2Cue87=an_fb76 InputList2SigType87=Analog InputList2Cue88=an_fb77 InputList2SigType88=Analog InputList2Cue89=an_fb78 InputList2SigType89=Analog InputList2Cue90=an_fb79 InputList2SigType90=Analog InputList2Cue91=an_fb80 InputList2SigType91=Analog InputList2Cue92=an_fb81 InputList2SigType92=Analog InputList2Cue93=an_fb82 InputList2SigType93=Analog InputList2Cue94=an_fb83 InputList2SigType94=Analog InputList2Cue95=an_fb84 InputList2SigType95=Analog InputList2Cue96=an_fb85 InputList2SigType96=Analog InputList2Cue97=an_fb86 InputList2SigType97=Analog InputList2Cue98=an_fb87 InputList2SigType98=Analog InputList2Cue99=an_fb88 InputList2SigType99=Analog InputList2Cue100=an_fb89 InputList2SigType100=Analog InputList2Cue101=an_fb90 InputList2SigType101=Analog InputList2Cue102=an_fb91 InputList2SigType102=Analog InputList2Cue103=an_fb92 InputList2SigType103=Analog InputList2Cue104=an_fb93 InputList2SigType104=Analog InputList2Cue105=an_fb94 InputList2SigType105=Analog InputList2Cue106=an_fb95 InputList2SigType106=Analog InputList2Cue107=an_fb96 InputList2SigType107=Analog InputList2Cue108=an_fb97 InputList2SigType108=Analog InputList2Cue109=an_fb98 InputList2SigType109=Analog InputList2Cue110=an_fb99 InputList2SigType110=Analog InputList2Cue111=an_fb100 InputList2SigType111=Analog InputList2Cue112=[~EndGroup~]an_fb InputList2SigType112=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=an_act37 OutputList2SigType48=Analog OutputList2Cue49=an_act38 OutputList2SigType49=Analog OutputList2Cue50=an_act39 OutputList2SigType50=Analog OutputList2Cue51=an_act40 OutputList2SigType51=Analog OutputList2Cue52=an_act41 OutputList2SigType52=Analog OutputList2Cue53=an_act42 OutputList2SigType53=Analog OutputList2Cue54=an_act43 OutputList2SigType54=Analog OutputList2Cue55=an_act44 OutputList2SigType55=Analog OutputList2Cue56=an_act45 OutputList2SigType56=Analog OutputList2Cue57=an_act46 OutputList2SigType57=Analog OutputList2Cue58=an_act47 OutputList2SigType58=Analog OutputList2Cue59=an_act48 OutputList2SigType59=Analog OutputList2Cue60=an_act49 OutputList2SigType60=Analog OutputList2Cue61=an_act50 OutputList2SigType61=Analog OutputList2Cue62=an_act51 OutputList2SigType62=Analog OutputList2Cue63=an_act52 OutputList2SigType63=Analog OutputList2Cue64=an_act53 OutputList2SigType64=Analog OutputList2Cue65=an_act54 OutputList2SigType65=Analog OutputList2Cue66=an_act55 OutputList2SigType66=Analog OutputList2Cue67=an_act56 OutputList2SigType67=Analog OutputList2Cue68=an_act57 OutputList2SigType68=Analog OutputList2Cue69=an_act58 OutputList2SigType69=Analog OutputList2Cue70=an_act59 OutputList2SigType70=Analog OutputList2Cue71=an_act60 OutputList2SigType71=Analog OutputList2Cue72=an_act61 OutputList2SigType72=Analog OutputList2Cue73=an_act62 OutputList2SigType73=Analog OutputList2Cue74=an_act63 OutputList2SigType74=Analog OutputList2Cue75=an_act64 OutputList2SigType75=Analog OutputList2Cue76=an_act65 OutputList2SigType76=Analog OutputList2Cue77=an_act66 OutputList2SigType77=Analog OutputList2Cue78=an_act67 OutputList2SigType78=Analog OutputList2Cue79=an_act68 OutputList2SigType79=Analog OutputList2Cue80=an_act69 OutputList2SigType80=Analog OutputList2Cue81=an_act70 OutputList2SigType81=Analog OutputList2Cue82=an_act71 OutputList2SigType82=Analog OutputList2Cue83=an_act72 OutputList2SigType83=Analog OutputList2Cue84=an_act73 OutputList2SigType84=Analog OutputList2Cue85=an_act74 OutputList2SigType85=Analog OutputList2Cue86=an_act75 OutputList2SigType86=Analog OutputList2Cue87=an_act76 OutputList2SigType87=Analog OutputList2Cue88=an_act77 OutputList2SigType88=Analog OutputList2Cue89=an_act78 OutputList2SigType89=Analog OutputList2Cue90=an_act79 OutputList2SigType90=Analog OutputList2Cue91=an_act80 OutputList2SigType91=Analog OutputList2Cue92=an_act81 OutputList2SigType92=Analog OutputList2Cue93=an_act82 OutputList2SigType93=Analog OutputList2Cue94=an_act83 OutputList2SigType94=Analog OutputList2Cue95=an_act84 OutputList2SigType95=Analog OutputList2Cue96=an_act85 OutputList2SigType96=Analog OutputList2Cue97=an_act86 OutputList2SigType97=Analog OutputList2Cue98=an_act87 OutputList2SigType98=Analog OutputList2Cue99=an_act88 OutputList2SigType99=Analog OutputList2Cue100=an_act89 OutputList2SigType100=Analog OutputList2Cue101=an_act90 OutputList2SigType101=Analog OutputList2Cue102=an_act91 OutputList2SigType102=Analog OutputList2Cue103=an_act92 OutputList2SigType103=Analog OutputList2Cue104=an_act93 OutputList2SigType104=Analog OutputList2Cue105=an_act94 OutputList2SigType105=Analog OutputList2Cue106=an_act95 OutputList2SigType106=Analog OutputList2Cue107=an_act96 OutputList2SigType107=Analog OutputList2Cue108=an_act97 OutputList2SigType108=Analog OutputList2Cue109=an_act98 OutputList2SigType109=Analog OutputList2Cue110=an_act99 OutputList2SigType110=Analog OutputList2Cue111=an_act100 OutputList2SigType111=Analog OutputList2Cue112=[~EndGroup~]an_act OutputList2SigType112=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=text-o61 InputList3SigType72=Serial InputList3Cue73=text-o62 InputList3SigType73=Serial InputList3Cue74=text-o63 InputList3SigType74=Serial InputList3Cue75=text-o64 InputList3SigType75=Serial InputList3Cue76=text-o65 InputList3SigType76=Serial InputList3Cue77=text-o66 InputList3SigType77=Serial InputList3Cue78=text-o67 InputList3SigType78=Serial InputList3Cue79=text-o68 InputList3SigType79=Serial InputList3Cue80=text-o69 InputList3SigType80=Serial InputList3Cue81=text-o70 InputList3SigType81=Serial InputList3Cue82=text-o71 InputList3SigType82=Serial InputList3Cue83=text-o72 InputList3SigType83=Serial InputList3Cue84=text-o73 InputList3SigType84=Serial InputList3Cue85=text-o74 InputList3SigType85=Serial InputList3Cue86=text-o75 InputList3SigType86=Serial InputList3Cue87=text-o76 InputList3SigType87=Serial InputList3Cue88=text-o77 InputList3SigType88=Serial InputList3Cue89=text-o78 InputList3SigType89=Serial InputList3Cue90=text-o79 InputList3SigType90=Serial InputList3Cue91=text-o80 InputList3SigType91=Serial InputList3Cue92=text-o81 InputList3SigType92=Serial InputList3Cue93=text-o82 InputList3SigType93=Serial InputList3Cue94=text-o83 InputList3SigType94=Serial InputList3Cue95=text-o84 InputList3SigType95=Serial InputList3Cue96=text-o85 InputList3SigType96=Serial InputList3Cue97=text-o86 InputList3SigType97=Serial InputList3Cue98=text-o87 InputList3SigType98=Serial InputList3Cue99=text-o88 InputList3SigType99=Serial InputList3Cue100=text-o89 InputList3SigType100=Serial InputList3Cue101=text-o90 InputList3SigType101=Serial InputList3Cue102=text-o91 InputList3SigType102=Serial InputList3Cue103=text-o92 InputList3SigType103=Serial InputList3Cue104=text-o93 InputList3SigType104=Serial InputList3Cue105=text-o94 InputList3SigType105=Serial InputList3Cue106=text-o95 InputList3SigType106=Serial InputList3Cue107=text-o96 InputList3SigType107=Serial InputList3Cue108=text-o97 InputList3SigType108=Serial InputList3Cue109=text-o98 InputList3SigType109=Serial InputList3Cue110=text-o99 InputList3SigType110=Serial InputList3Cue111=text-o100 InputList3SigType111=Serial InputList3Cue112=[~EndGroup~]text-o InputList3SigType112=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=text-i61 OutputList3SigType72=Serial OutputList3Cue73=text-i62 OutputList3SigType73=Serial OutputList3Cue74=text-i63 OutputList3SigType74=Serial OutputList3Cue75=text-i64 OutputList3SigType75=Serial OutputList3Cue76=text-i65 OutputList3SigType76=Serial OutputList3Cue77=text-i66 OutputList3SigType77=Serial OutputList3Cue78=text-i67 OutputList3SigType78=Serial OutputList3Cue79=text-i68 OutputList3SigType79=Serial OutputList3Cue80=text-i69 OutputList3SigType80=Serial OutputList3Cue81=text-i70 OutputList3SigType81=Serial OutputList3Cue82=text-i71 OutputList3SigType82=Serial OutputList3Cue83=text-i72 OutputList3SigType83=Serial OutputList3Cue84=text-i73 OutputList3SigType84=Serial OutputList3Cue85=text-i74 OutputList3SigType85=Serial OutputList3Cue86=text-i75 OutputList3SigType86=Serial OutputList3Cue87=text-i76 OutputList3SigType87=Serial OutputList3Cue88=text-i77 OutputList3SigType88=Serial OutputList3Cue89=text-i78 OutputList3SigType89=Serial OutputList3Cue90=text-i79 OutputList3SigType90=Serial OutputList3Cue91=text-i80 OutputList3SigType91=Serial OutputList3Cue92=text-i81 OutputList3SigType92=Serial OutputList3Cue93=text-i82 OutputList3SigType93=Serial OutputList3Cue94=text-i83 OutputList3SigType94=Serial OutputList3Cue95=text-i84 OutputList3SigType95=Serial OutputList3Cue96=text-i85 OutputList3SigType96=Serial OutputList3Cue97=text-i86 OutputList3SigType97=Serial OutputList3Cue98=text-i87 OutputList3SigType98=Serial OutputList3Cue99=text-i88 OutputList3SigType99=Serial OutputList3Cue100=text-i89 OutputList3SigType100=Serial OutputList3Cue101=text-i90 OutputList3SigType101=Serial OutputList3Cue102=text-i91 OutputList3SigType102=Serial OutputList3Cue103=text-i92 OutputList3SigType103=Serial OutputList3Cue104=text-i93 OutputList3SigType104=Serial OutputList3Cue105=text-i94 OutputList3SigType105=Serial OutputList3Cue106=text-i95 OutputList3SigType106=Serial OutputList3Cue107=text-i96 OutputList3SigType107=Serial OutputList3Cue108=text-i97 OutputList3SigType108=Serial OutputList3Cue109=text-i98 OutputList3SigType109=Serial OutputList3Cue110=text-i99 OutputList3SigType110=Serial OutputList3Cue111=text-i100 OutputList3SigType111=Serial OutputList3Cue112=[~EndGroup~]text-i OutputList3SigType112=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=16 CedH=16 SmartObjId=1001d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=16 Tp=1 HD=TRUE DV=1001d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=16 Name=PepperDash Essentials iPad_[Z.Dialogs] Call List_Subpage Reference List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced Hint=Dynamic Button List Vertical (Smart Object ID=3901) Code=17 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical GUID=15B95903-FB30-472E-9D10-82A9C3A9D7C7 SmplCName=PepperDash Essentials iPad_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=[~UNUSED2~] InputSigType22=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=[~UNUSED2~] InputSigType2024=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=[~UNUSED2~] InputSigType4026=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=[~UNUSED2~] OutputSigType22=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED2~] OutputSigType2024=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED2~] OutputSigType4026=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=[~UNUSED2~] InputList2SigType22=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED2~] OutputList2SigType22=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=[~UNUSED2~] InputList3SigType22=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=[~UNUSED2~] InputList3SigType2024=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED2~] OutputList3SigType22=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED2~] OutputList3SigType2024=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=17 CedH=17 SmartObjId=3901d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=17 Tp=1 HD=TRUE DV=3901d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=17 Name=PepperDash Essentials iPad_[E.Technician Controls] Menu_Dynamic Button List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced Hint=Subpage Reference List Vertical (Smart Object ID=15023) Code=18 SGControlType=Subpage Reference List Vertical SGControlName=Subpage Reference List Vertical GUID=EC6E6B35-F033-4F14-9465-FEEBE20455CC SmplCName=PepperDash Essentials iPad_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced SMWRev=4.02.20 Expand=expand_random HelpID=10125 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=4052 MaxVariableInputs=4052 MinVariableOutputs=4052 MaxVariableOutputs=4052 NumFixedParams=1 MinVariableInputsList2=48 MaxVariableInputsList2=48 MinVariableOutputsList2=48 MaxVariableOutputsList2=48 MinVariableInputsList3=72 MaxVariableInputsList3=72 MinVariableOutputsList3=72 MaxVariableOutputsList3=72 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=[~UNUSED3~] InputSigType1=Digital InputCue2=[~UNUSED2~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Enable InputSigType11=Digital InputCue12=Item 1 Enable InputSigType12=Digital InputCue13=Item 2 Enable InputSigType13=Digital InputCue14=Item 3 Enable InputSigType14=Digital InputCue15=Item 4 Enable InputSigType15=Digital InputCue16=Item 5 Enable InputSigType16=Digital InputCue17=Item 6 Enable InputSigType17=Digital InputCue18=Item 7 Enable InputSigType18=Digital InputCue19=Item 8 Enable InputSigType19=Digital InputCue20=Item 9 Enable InputSigType20=Digital InputCue21=Item 10 Enable InputSigType21=Digital InputCue22=Item 11 Enable InputSigType22=Digital InputCue23=Item 12 Enable InputSigType23=Digital InputCue24=[~UNUSED2~] InputSigType24=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Enable InputSigType2012=Digital InputCue2013=[~BeginGroup~]Visible InputSigType2013=Digital InputCue2014=Item 1 Visible InputSigType2014=Digital InputCue2015=Item 2 Visible InputSigType2015=Digital InputCue2016=Item 3 Visible InputSigType2016=Digital InputCue2017=Item 4 Visible InputSigType2017=Digital InputCue2018=Item 5 Visible InputSigType2018=Digital InputCue2019=Item 6 Visible InputSigType2019=Digital InputCue2020=Item 7 Visible InputSigType2020=Digital InputCue2021=Item 8 Visible InputSigType2021=Digital InputCue2022=Item 9 Visible InputSigType2022=Digital InputCue2023=Item 10 Visible InputSigType2023=Digital InputCue2024=Item 11 Visible InputSigType2024=Digital InputCue2025=Item 12 Visible InputSigType2025=Digital InputCue2026=[~UNUSED2~] InputSigType2026=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Visible InputSigType4014=Digital InputCue4015=[~BeginGroup~]fb InputSigType4015=Digital InputCue4016=fb1 InputSigType4016=Digital InputCue4017=fb2 InputSigType4017=Digital InputCue4018=fb3 InputSigType4018=Digital InputCue4019=fb4 InputSigType4019=Digital InputCue4020=fb5 InputSigType4020=Digital InputCue4021=fb6 InputSigType4021=Digital InputCue4022=fb7 InputSigType4022=Digital InputCue4023=fb8 InputSigType4023=Digital InputCue4024=fb9 InputSigType4024=Digital InputCue4025=fb10 InputSigType4025=Digital InputCue4026=fb11 InputSigType4026=Digital InputCue4027=fb12 InputSigType4027=Digital InputCue4028=fb13 InputSigType4028=Digital InputCue4029=fb14 InputSigType4029=Digital InputCue4030=fb15 InputSigType4030=Digital InputCue4031=fb16 InputSigType4031=Digital InputCue4032=fb17 InputSigType4032=Digital InputCue4033=fb18 InputSigType4033=Digital InputCue4034=fb19 InputSigType4034=Digital InputCue4035=fb20 InputSigType4035=Digital InputCue4036=fb21 InputSigType4036=Digital InputCue4037=fb22 InputSigType4037=Digital InputCue4038=fb23 InputSigType4038=Digital InputCue4039=fb24 InputSigType4039=Digital InputCue4040=fb25 InputSigType4040=Digital InputCue4041=fb26 InputSigType4041=Digital InputCue4042=fb27 InputSigType4042=Digital InputCue4043=fb28 InputSigType4043=Digital InputCue4044=fb29 InputSigType4044=Digital InputCue4045=fb30 InputSigType4045=Digital InputCue4046=fb31 InputSigType4046=Digital InputCue4047=fb32 InputSigType4047=Digital InputCue4048=fb33 InputSigType4048=Digital InputCue4049=fb34 InputSigType4049=Digital InputCue4050=fb35 InputSigType4050=Digital InputCue4051=fb36 InputSigType4051=Digital InputCue4052=[~EndGroup~]fb InputSigType4052=Digital OutputCue1=Is Moving OutputSigType1=Digital OutputCue2=[~UNUSED2~] OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Enable OutputSigType11=Digital OutputCue12=[~UNUSED3~] OutputSigType12=Digital OutputCue13=[~UNUSED3~] OutputSigType13=Digital OutputCue14=[~UNUSED3~] OutputSigType14=Digital OutputCue15=[~UNUSED3~] OutputSigType15=Digital OutputCue16=[~UNUSED3~] OutputSigType16=Digital OutputCue17=[~UNUSED3~] OutputSigType17=Digital OutputCue18=[~UNUSED3~] OutputSigType18=Digital OutputCue19=[~UNUSED3~] OutputSigType19=Digital OutputCue20=[~UNUSED3~] OutputSigType20=Digital OutputCue21=[~UNUSED3~] OutputSigType21=Digital OutputCue22=[~UNUSED3~] OutputSigType22=Digital OutputCue23=[~UNUSED3~] OutputSigType23=Digital OutputCue24=[~UNUSED2~] OutputSigType24=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Enable OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Visible OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED2~] OutputSigType2026=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Visible OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Press OutputSigType4015=Digital OutputCue4016=press1 OutputSigType4016=Digital OutputCue4017=press2 OutputSigType4017=Digital OutputCue4018=press3 OutputSigType4018=Digital OutputCue4019=press4 OutputSigType4019=Digital OutputCue4020=press5 OutputSigType4020=Digital OutputCue4021=press6 OutputSigType4021=Digital OutputCue4022=press7 OutputSigType4022=Digital OutputCue4023=press8 OutputSigType4023=Digital OutputCue4024=press9 OutputSigType4024=Digital OutputCue4025=press10 OutputSigType4025=Digital OutputCue4026=press11 OutputSigType4026=Digital OutputCue4027=press12 OutputSigType4027=Digital OutputCue4028=press13 OutputSigType4028=Digital OutputCue4029=press14 OutputSigType4029=Digital OutputCue4030=press15 OutputSigType4030=Digital OutputCue4031=press16 OutputSigType4031=Digital OutputCue4032=press17 OutputSigType4032=Digital OutputCue4033=press18 OutputSigType4033=Digital OutputCue4034=press19 OutputSigType4034=Digital OutputCue4035=press20 OutputSigType4035=Digital OutputCue4036=press21 OutputSigType4036=Digital OutputCue4037=press22 OutputSigType4037=Digital OutputCue4038=press23 OutputSigType4038=Digital OutputCue4039=press24 OutputSigType4039=Digital OutputCue4040=press25 OutputSigType4040=Digital OutputCue4041=press26 OutputSigType4041=Digital OutputCue4042=press27 OutputSigType4042=Digital OutputCue4043=press28 OutputSigType4043=Digital OutputCue4044=press29 OutputSigType4044=Digital OutputCue4045=press30 OutputSigType4045=Digital OutputCue4046=press31 OutputSigType4046=Digital OutputCue4047=press32 OutputSigType4047=Digital OutputCue4048=press33 OutputSigType4048=Digital OutputCue4049=press34 OutputSigType4049=Digital OutputCue4050=press35 OutputSigType4050=Digital OutputCue4051=press36 OutputSigType4051=Digital OutputCue4052=[~EndGroup~]Press OutputSigType4052=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=Scroll To Item InputList2SigType2=Analog InputList2Cue3=Set Number of Items InputList2SigType3=Analog InputList2Cue4=[~UNUSED2~] InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]an_fb InputList2SigType11=Analog InputList2Cue12=an_fb1 InputList2SigType12=Analog InputList2Cue13=an_fb2 InputList2SigType13=Analog InputList2Cue14=an_fb3 InputList2SigType14=Analog InputList2Cue15=an_fb4 InputList2SigType15=Analog InputList2Cue16=an_fb5 InputList2SigType16=Analog InputList2Cue17=an_fb6 InputList2SigType17=Analog InputList2Cue18=an_fb7 InputList2SigType18=Analog InputList2Cue19=an_fb8 InputList2SigType19=Analog InputList2Cue20=an_fb9 InputList2SigType20=Analog InputList2Cue21=an_fb10 InputList2SigType21=Analog InputList2Cue22=an_fb11 InputList2SigType22=Analog InputList2Cue23=an_fb12 InputList2SigType23=Analog InputList2Cue24=an_fb13 InputList2SigType24=Analog InputList2Cue25=an_fb14 InputList2SigType25=Analog InputList2Cue26=an_fb15 InputList2SigType26=Analog InputList2Cue27=an_fb16 InputList2SigType27=Analog InputList2Cue28=an_fb17 InputList2SigType28=Analog InputList2Cue29=an_fb18 InputList2SigType29=Analog InputList2Cue30=an_fb19 InputList2SigType30=Analog InputList2Cue31=an_fb20 InputList2SigType31=Analog InputList2Cue32=an_fb21 InputList2SigType32=Analog InputList2Cue33=an_fb22 InputList2SigType33=Analog InputList2Cue34=an_fb23 InputList2SigType34=Analog InputList2Cue35=an_fb24 InputList2SigType35=Analog InputList2Cue36=an_fb25 InputList2SigType36=Analog InputList2Cue37=an_fb26 InputList2SigType37=Analog InputList2Cue38=an_fb27 InputList2SigType38=Analog InputList2Cue39=an_fb28 InputList2SigType39=Analog InputList2Cue40=an_fb29 InputList2SigType40=Analog InputList2Cue41=an_fb30 InputList2SigType41=Analog InputList2Cue42=an_fb31 InputList2SigType42=Analog InputList2Cue43=an_fb32 InputList2SigType43=Analog InputList2Cue44=an_fb33 InputList2SigType44=Analog InputList2Cue45=an_fb34 InputList2SigType45=Analog InputList2Cue46=an_fb35 InputList2SigType46=Analog InputList2Cue47=an_fb36 InputList2SigType47=Analog InputList2Cue48=[~EndGroup~]an_fb InputList2SigType48=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=[~UNUSED3~] OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED2~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]an_act OutputList2SigType11=Analog OutputList2Cue12=an_act1 OutputList2SigType12=Analog OutputList2Cue13=an_act2 OutputList2SigType13=Analog OutputList2Cue14=an_act3 OutputList2SigType14=Analog OutputList2Cue15=an_act4 OutputList2SigType15=Analog OutputList2Cue16=an_act5 OutputList2SigType16=Analog OutputList2Cue17=an_act6 OutputList2SigType17=Analog OutputList2Cue18=an_act7 OutputList2SigType18=Analog OutputList2Cue19=an_act8 OutputList2SigType19=Analog OutputList2Cue20=an_act9 OutputList2SigType20=Analog OutputList2Cue21=an_act10 OutputList2SigType21=Analog OutputList2Cue22=an_act11 OutputList2SigType22=Analog OutputList2Cue23=an_act12 OutputList2SigType23=Analog OutputList2Cue24=an_act13 OutputList2SigType24=Analog OutputList2Cue25=an_act14 OutputList2SigType25=Analog OutputList2Cue26=an_act15 OutputList2SigType26=Analog OutputList2Cue27=an_act16 OutputList2SigType27=Analog OutputList2Cue28=an_act17 OutputList2SigType28=Analog OutputList2Cue29=an_act18 OutputList2SigType29=Analog OutputList2Cue30=an_act19 OutputList2SigType30=Analog OutputList2Cue31=an_act20 OutputList2SigType31=Analog OutputList2Cue32=an_act21 OutputList2SigType32=Analog OutputList2Cue33=an_act22 OutputList2SigType33=Analog OutputList2Cue34=an_act23 OutputList2SigType34=Analog OutputList2Cue35=an_act24 OutputList2SigType35=Analog OutputList2Cue36=an_act25 OutputList2SigType36=Analog OutputList2Cue37=an_act26 OutputList2SigType37=Analog OutputList2Cue38=an_act27 OutputList2SigType38=Analog OutputList2Cue39=an_act28 OutputList2SigType39=Analog OutputList2Cue40=an_act29 OutputList2SigType40=Analog OutputList2Cue41=an_act30 OutputList2SigType41=Analog OutputList2Cue42=an_act31 OutputList2SigType42=Analog OutputList2Cue43=an_act32 OutputList2SigType43=Analog OutputList2Cue44=an_act33 OutputList2SigType44=Analog OutputList2Cue45=an_act34 OutputList2SigType45=Analog OutputList2Cue46=an_act35 OutputList2SigType46=Analog OutputList2Cue47=an_act36 OutputList2SigType47=Analog OutputList2Cue48=[~EndGroup~]an_act OutputList2SigType48=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]text-o InputList3SigType11=Serial InputList3Cue12=text-o1 InputList3SigType12=Serial InputList3Cue13=text-o2 InputList3SigType13=Serial InputList3Cue14=text-o3 InputList3SigType14=Serial InputList3Cue15=text-o4 InputList3SigType15=Serial InputList3Cue16=text-o5 InputList3SigType16=Serial InputList3Cue17=text-o6 InputList3SigType17=Serial InputList3Cue18=text-o7 InputList3SigType18=Serial InputList3Cue19=text-o8 InputList3SigType19=Serial InputList3Cue20=text-o9 InputList3SigType20=Serial InputList3Cue21=text-o10 InputList3SigType21=Serial InputList3Cue22=text-o11 InputList3SigType22=Serial InputList3Cue23=text-o12 InputList3SigType23=Serial InputList3Cue24=text-o13 InputList3SigType24=Serial InputList3Cue25=text-o14 InputList3SigType25=Serial InputList3Cue26=text-o15 InputList3SigType26=Serial InputList3Cue27=text-o16 InputList3SigType27=Serial InputList3Cue28=text-o17 InputList3SigType28=Serial InputList3Cue29=text-o18 InputList3SigType29=Serial InputList3Cue30=text-o19 InputList3SigType30=Serial InputList3Cue31=text-o20 InputList3SigType31=Serial InputList3Cue32=text-o21 InputList3SigType32=Serial InputList3Cue33=text-o22 InputList3SigType33=Serial InputList3Cue34=text-o23 InputList3SigType34=Serial InputList3Cue35=text-o24 InputList3SigType35=Serial InputList3Cue36=text-o25 InputList3SigType36=Serial InputList3Cue37=text-o26 InputList3SigType37=Serial InputList3Cue38=text-o27 InputList3SigType38=Serial InputList3Cue39=text-o28 InputList3SigType39=Serial InputList3Cue40=text-o29 InputList3SigType40=Serial InputList3Cue41=text-o30 InputList3SigType41=Serial InputList3Cue42=text-o31 InputList3SigType42=Serial InputList3Cue43=text-o32 InputList3SigType43=Serial InputList3Cue44=text-o33 InputList3SigType44=Serial InputList3Cue45=text-o34 InputList3SigType45=Serial InputList3Cue46=text-o35 InputList3SigType46=Serial InputList3Cue47=text-o36 InputList3SigType47=Serial InputList3Cue48=text-o37 InputList3SigType48=Serial InputList3Cue49=text-o38 InputList3SigType49=Serial InputList3Cue50=text-o39 InputList3SigType50=Serial InputList3Cue51=text-o40 InputList3SigType51=Serial InputList3Cue52=text-o41 InputList3SigType52=Serial InputList3Cue53=text-o42 InputList3SigType53=Serial InputList3Cue54=text-o43 InputList3SigType54=Serial InputList3Cue55=text-o44 InputList3SigType55=Serial InputList3Cue56=text-o45 InputList3SigType56=Serial InputList3Cue57=text-o46 InputList3SigType57=Serial InputList3Cue58=text-o47 InputList3SigType58=Serial InputList3Cue59=text-o48 InputList3SigType59=Serial InputList3Cue60=text-o49 InputList3SigType60=Serial InputList3Cue61=text-o50 InputList3SigType61=Serial InputList3Cue62=text-o51 InputList3SigType62=Serial InputList3Cue63=text-o52 InputList3SigType63=Serial InputList3Cue64=text-o53 InputList3SigType64=Serial InputList3Cue65=text-o54 InputList3SigType65=Serial InputList3Cue66=text-o55 InputList3SigType66=Serial InputList3Cue67=text-o56 InputList3SigType67=Serial InputList3Cue68=text-o57 InputList3SigType68=Serial InputList3Cue69=text-o58 InputList3SigType69=Serial InputList3Cue70=text-o59 InputList3SigType70=Serial InputList3Cue71=text-o60 InputList3SigType71=Serial InputList3Cue72=[~EndGroup~]text-o InputList3SigType72=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]text-i OutputList3SigType11=Serial OutputList3Cue12=text-i1 OutputList3SigType12=Serial OutputList3Cue13=text-i2 OutputList3SigType13=Serial OutputList3Cue14=text-i3 OutputList3SigType14=Serial OutputList3Cue15=text-i4 OutputList3SigType15=Serial OutputList3Cue16=text-i5 OutputList3SigType16=Serial OutputList3Cue17=text-i6 OutputList3SigType17=Serial OutputList3Cue18=text-i7 OutputList3SigType18=Serial OutputList3Cue19=text-i8 OutputList3SigType19=Serial OutputList3Cue20=text-i9 OutputList3SigType20=Serial OutputList3Cue21=text-i10 OutputList3SigType21=Serial OutputList3Cue22=text-i11 OutputList3SigType22=Serial OutputList3Cue23=text-i12 OutputList3SigType23=Serial OutputList3Cue24=text-i13 OutputList3SigType24=Serial OutputList3Cue25=text-i14 OutputList3SigType25=Serial OutputList3Cue26=text-i15 OutputList3SigType26=Serial OutputList3Cue27=text-i16 OutputList3SigType27=Serial OutputList3Cue28=text-i17 OutputList3SigType28=Serial OutputList3Cue29=text-i18 OutputList3SigType29=Serial OutputList3Cue30=text-i19 OutputList3SigType30=Serial OutputList3Cue31=text-i20 OutputList3SigType31=Serial OutputList3Cue32=text-i21 OutputList3SigType32=Serial OutputList3Cue33=text-i22 OutputList3SigType33=Serial OutputList3Cue34=text-i23 OutputList3SigType34=Serial OutputList3Cue35=text-i24 OutputList3SigType35=Serial OutputList3Cue36=text-i25 OutputList3SigType36=Serial OutputList3Cue37=text-i26 OutputList3SigType37=Serial OutputList3Cue38=text-i27 OutputList3SigType38=Serial OutputList3Cue39=text-i28 OutputList3SigType39=Serial OutputList3Cue40=text-i29 OutputList3SigType40=Serial OutputList3Cue41=text-i30 OutputList3SigType41=Serial OutputList3Cue42=text-i31 OutputList3SigType42=Serial OutputList3Cue43=text-i32 OutputList3SigType43=Serial OutputList3Cue44=text-i33 OutputList3SigType44=Serial OutputList3Cue45=text-i34 OutputList3SigType45=Serial OutputList3Cue46=text-i35 OutputList3SigType46=Serial OutputList3Cue47=text-i36 OutputList3SigType47=Serial OutputList3Cue48=text-i37 OutputList3SigType48=Serial OutputList3Cue49=text-i38 OutputList3SigType49=Serial OutputList3Cue50=text-i39 OutputList3SigType50=Serial OutputList3Cue51=text-i40 OutputList3SigType51=Serial OutputList3Cue52=text-i41 OutputList3SigType52=Serial OutputList3Cue53=text-i42 OutputList3SigType53=Serial OutputList3Cue54=text-i43 OutputList3SigType54=Serial OutputList3Cue55=text-i44 OutputList3SigType55=Serial OutputList3Cue56=text-i45 OutputList3SigType56=Serial OutputList3Cue57=text-i46 OutputList3SigType57=Serial OutputList3Cue58=text-i47 OutputList3SigType58=Serial OutputList3Cue59=text-i48 OutputList3SigType59=Serial OutputList3Cue60=text-i49 OutputList3SigType60=Serial OutputList3Cue61=text-i50 OutputList3SigType61=Serial OutputList3Cue62=text-i51 OutputList3SigType62=Serial OutputList3Cue63=text-i52 OutputList3SigType63=Serial OutputList3Cue64=text-i53 OutputList3SigType64=Serial OutputList3Cue65=text-i54 OutputList3SigType65=Serial OutputList3Cue66=text-i55 OutputList3SigType66=Serial OutputList3Cue67=text-i56 OutputList3SigType67=Serial OutputList3Cue68=text-i57 OutputList3SigType68=Serial OutputList3Cue69=text-i58 OutputList3SigType69=Serial OutputList3Cue70=text-i59 OutputList3SigType70=Serial OutputList3Cue71=text-i60 OutputList3SigType71=Serial OutputList3Cue72=[~EndGroup~]text-i OutputList3SigType72=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=18 CedH=18 SmartObjId=15023d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=18 Tp=1 HD=TRUE DV=15023d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=18 Name=PepperDash Essentials iPad_[Z.Dialogs] Schedule List_Subpage Reference List Vertical.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ;================================================================================ [ ObjTp=Symbol Name=PepperDash Essentials iPad_[D.VC] Recents_Dynamic Button List Vertical_2.ced Hint=Dynamic Button List Vertical_2 (Smart Object ID=1203) Code=19 SGControlType=Dynamic Button List Vertical SGControlName=Dynamic Button List Vertical_2 GUID=2C4B55E4-42AC-486D-BC6E-C7DD7D24C974 SmplCName=PepperDash Essentials iPad_[D.VC] Recents_Dynamic Button List Vertical_2.ced SMWRev=4.02.20 Expand=expand_random HelpID=10112 Render=8 ;Define the number of inputs, outputs and parameters MinVariableInputs=6016 MaxVariableInputs=6016 MinVariableOutputs=6016 MaxVariableOutputs=6016 NumFixedParams=1 MinVariableInputsList2=2012 MaxVariableInputsList2=2012 MinVariableOutputsList2=2012 MaxVariableOutputsList2=2012 MinVariableInputsList3=4014 MaxVariableInputsList3=4014 MinVariableOutputsList3=4014 MaxVariableOutputsList3=4014 InputSigType1=Digital OutputSigType1=Digital InputList2SigType1=Analog OutputList2SigType1=Analog InputList3SigType1=Serial OutputList3SigType1=Serial ;Define the cues, and signal types each input, output and parameter. InputCue1=Disable Redraw InputSigType1=Digital InputCue2=[~UNUSED3~] InputSigType2=Digital InputCue3=[~UNUSED2~] InputSigType3=Digital InputCue4=[~UNUSED2~] InputSigType4=Digital InputCue5=[~UNUSED2~] InputSigType5=Digital InputCue6=[~UNUSED2~] InputSigType6=Digital InputCue7=[~UNUSED2~] InputSigType7=Digital InputCue8=[~UNUSED2~] InputSigType8=Digital InputCue9=[~UNUSED2~] InputSigType9=Digital InputCue10=[~UNUSED2~] InputSigType10=Digital InputCue11=[~BeginGroup~]Press InputSigType11=Digital InputCue12=Item 1 Selected InputSigType12=Digital InputCue13=Item 2 Selected InputSigType13=Digital InputCue14=Item 3 Selected InputSigType14=Digital InputCue15=Item 4 Selected InputSigType15=Digital InputCue16=Item 5 Selected InputSigType16=Digital InputCue17=Item 6 Selected InputSigType17=Digital InputCue18=Item 7 Selected InputSigType18=Digital InputCue19=Item 8 Selected InputSigType19=Digital InputCue20=Item 9 Selected InputSigType20=Digital InputCue21=Item 10 Selected InputSigType21=Digital InputCue22=Item 11 Selected InputSigType22=Digital InputCue23=Item 12 Selected InputSigType23=Digital InputCue24=Item 13 Selected InputSigType24=Digital InputCue25=Item 14 Selected InputSigType25=Digital InputCue26=Item 15 Selected InputSigType26=Digital InputCue27=Item 16 Selected InputSigType27=Digital InputCue28=Item 17 Selected InputSigType28=Digital InputCue29=Item 18 Selected InputSigType29=Digital InputCue30=Item 19 Selected InputSigType30=Digital InputCue31=Item 20 Selected InputSigType31=Digital InputCue32=Item 21 Selected InputSigType32=Digital InputCue33=Item 22 Selected InputSigType33=Digital InputCue34=Item 23 Selected InputSigType34=Digital InputCue35=Item 24 Selected InputSigType35=Digital InputCue36=Item 25 Selected InputSigType36=Digital InputCue37=Item 26 Selected InputSigType37=Digital InputCue38=Item 27 Selected InputSigType38=Digital InputCue39=Item 28 Selected InputSigType39=Digital InputCue40=Item 29 Selected InputSigType40=Digital InputCue41=Item 30 Selected InputSigType41=Digital InputCue42=[~UNUSED2~] InputSigType42=Digital|Analog|Serial|String InputCue2012=[~EndGroup~]Press InputSigType2012=Digital InputCue2013=[~BeginGroup~]Enable InputSigType2013=Digital InputCue2014=Item 1 Enabled InputSigType2014=Digital InputCue2015=Item 2 Enabled InputSigType2015=Digital InputCue2016=Item 3 Enabled InputSigType2016=Digital InputCue2017=Item 4 Enabled InputSigType2017=Digital InputCue2018=Item 5 Enabled InputSigType2018=Digital InputCue2019=Item 6 Enabled InputSigType2019=Digital InputCue2020=Item 7 Enabled InputSigType2020=Digital InputCue2021=Item 8 Enabled InputSigType2021=Digital InputCue2022=Item 9 Enabled InputSigType2022=Digital InputCue2023=Item 10 Enabled InputSigType2023=Digital InputCue2024=Item 11 Enabled InputSigType2024=Digital InputCue2025=Item 12 Enabled InputSigType2025=Digital InputCue2026=Item 13 Enabled InputSigType2026=Digital InputCue2027=Item 14 Enabled InputSigType2027=Digital InputCue2028=Item 15 Enabled InputSigType2028=Digital InputCue2029=Item 16 Enabled InputSigType2029=Digital InputCue2030=Item 17 Enabled InputSigType2030=Digital InputCue2031=Item 18 Enabled InputSigType2031=Digital InputCue2032=Item 19 Enabled InputSigType2032=Digital InputCue2033=Item 20 Enabled InputSigType2033=Digital InputCue2034=Item 21 Enabled InputSigType2034=Digital InputCue2035=Item 22 Enabled InputSigType2035=Digital InputCue2036=Item 23 Enabled InputSigType2036=Digital InputCue2037=Item 24 Enabled InputSigType2037=Digital InputCue2038=Item 25 Enabled InputSigType2038=Digital InputCue2039=Item 26 Enabled InputSigType2039=Digital InputCue2040=Item 27 Enabled InputSigType2040=Digital InputCue2041=Item 28 Enabled InputSigType2041=Digital InputCue2042=Item 29 Enabled InputSigType2042=Digital InputCue2043=Item 30 Enabled InputSigType2043=Digital InputCue2044=[~UNUSED2~] InputSigType2044=Digital|Analog|Serial|String InputCue4014=[~EndGroup~]Enable InputSigType4014=Digital InputCue4015=[~BeginGroup~]Visible InputSigType4015=Digital InputCue4016=Item 1 Visible InputSigType4016=Digital InputCue4017=Item 2 Visible InputSigType4017=Digital InputCue4018=Item 3 Visible InputSigType4018=Digital InputCue4019=Item 4 Visible InputSigType4019=Digital InputCue4020=Item 5 Visible InputSigType4020=Digital InputCue4021=Item 6 Visible InputSigType4021=Digital InputCue4022=Item 7 Visible InputSigType4022=Digital InputCue4023=Item 8 Visible InputSigType4023=Digital InputCue4024=Item 9 Visible InputSigType4024=Digital InputCue4025=Item 10 Visible InputSigType4025=Digital InputCue4026=Item 11 Visible InputSigType4026=Digital InputCue4027=Item 12 Visible InputSigType4027=Digital InputCue4028=Item 13 Visible InputSigType4028=Digital InputCue4029=Item 14 Visible InputSigType4029=Digital InputCue4030=Item 15 Visible InputSigType4030=Digital InputCue4031=Item 16 Visible InputSigType4031=Digital InputCue4032=Item 17 Visible InputSigType4032=Digital InputCue4033=Item 18 Visible InputSigType4033=Digital InputCue4034=Item 19 Visible InputSigType4034=Digital InputCue4035=Item 20 Visible InputSigType4035=Digital InputCue4036=Item 21 Visible InputSigType4036=Digital InputCue4037=Item 22 Visible InputSigType4037=Digital InputCue4038=Item 23 Visible InputSigType4038=Digital InputCue4039=Item 24 Visible InputSigType4039=Digital InputCue4040=Item 25 Visible InputSigType4040=Digital InputCue4041=Item 26 Visible InputSigType4041=Digital InputCue4042=Item 27 Visible InputSigType4042=Digital InputCue4043=Item 28 Visible InputSigType4043=Digital InputCue4044=Item 29 Visible InputSigType4044=Digital InputCue4045=Item 30 Visible InputSigType4045=Digital InputCue4046=[~UNUSED2~] InputSigType4046=Digital|Analog|Serial|String InputCue6016=[~EndGroup~]Visible InputSigType6016=Digital OutputCue1=[~UNUSED3~] OutputSigType1=Digital OutputCue2=Is Moving OutputSigType2=Digital OutputCue3=[~UNUSED2~] OutputSigType3=Digital OutputCue4=[~UNUSED2~] OutputSigType4=Digital OutputCue5=[~UNUSED2~] OutputSigType5=Digital OutputCue6=[~UNUSED2~] OutputSigType6=Digital OutputCue7=[~UNUSED2~] OutputSigType7=Digital OutputCue8=[~UNUSED2~] OutputSigType8=Digital OutputCue9=[~UNUSED2~] OutputSigType9=Digital OutputCue10=[~UNUSED2~] OutputSigType10=Digital OutputCue11=[~BeginGroup~]Press OutputSigType11=Digital OutputCue12=Item 1 Pressed OutputSigType12=Digital OutputCue13=Item 2 Pressed OutputSigType13=Digital OutputCue14=Item 3 Pressed OutputSigType14=Digital OutputCue15=Item 4 Pressed OutputSigType15=Digital OutputCue16=Item 5 Pressed OutputSigType16=Digital OutputCue17=Item 6 Pressed OutputSigType17=Digital OutputCue18=Item 7 Pressed OutputSigType18=Digital OutputCue19=Item 8 Pressed OutputSigType19=Digital OutputCue20=Item 9 Pressed OutputSigType20=Digital OutputCue21=Item 10 Pressed OutputSigType21=Digital OutputCue22=Item 11 Pressed OutputSigType22=Digital OutputCue23=Item 12 Pressed OutputSigType23=Digital OutputCue24=Item 13 Pressed OutputSigType24=Digital OutputCue25=Item 14 Pressed OutputSigType25=Digital OutputCue26=Item 15 Pressed OutputSigType26=Digital OutputCue27=Item 16 Pressed OutputSigType27=Digital OutputCue28=Item 17 Pressed OutputSigType28=Digital OutputCue29=Item 18 Pressed OutputSigType29=Digital OutputCue30=Item 19 Pressed OutputSigType30=Digital OutputCue31=Item 20 Pressed OutputSigType31=Digital OutputCue32=Item 21 Pressed OutputSigType32=Digital OutputCue33=Item 22 Pressed OutputSigType33=Digital OutputCue34=Item 23 Pressed OutputSigType34=Digital OutputCue35=Item 24 Pressed OutputSigType35=Digital OutputCue36=Item 25 Pressed OutputSigType36=Digital OutputCue37=Item 26 Pressed OutputSigType37=Digital OutputCue38=Item 27 Pressed OutputSigType38=Digital OutputCue39=Item 28 Pressed OutputSigType39=Digital OutputCue40=Item 29 Pressed OutputSigType40=Digital OutputCue41=Item 30 Pressed OutputSigType41=Digital OutputCue42=[~UNUSED2~] OutputSigType42=Digital|Analog|Serial|String OutputCue2012=[~EndGroup~]Press OutputSigType2012=Digital OutputCue2013=[~BeginGroup~]Enable OutputSigType2013=Digital OutputCue2014=[~UNUSED3~] OutputSigType2014=Digital OutputCue2015=[~UNUSED3~] OutputSigType2015=Digital OutputCue2016=[~UNUSED3~] OutputSigType2016=Digital OutputCue2017=[~UNUSED3~] OutputSigType2017=Digital OutputCue2018=[~UNUSED3~] OutputSigType2018=Digital OutputCue2019=[~UNUSED3~] OutputSigType2019=Digital OutputCue2020=[~UNUSED3~] OutputSigType2020=Digital OutputCue2021=[~UNUSED3~] OutputSigType2021=Digital OutputCue2022=[~UNUSED3~] OutputSigType2022=Digital OutputCue2023=[~UNUSED3~] OutputSigType2023=Digital OutputCue2024=[~UNUSED3~] OutputSigType2024=Digital OutputCue2025=[~UNUSED3~] OutputSigType2025=Digital OutputCue2026=[~UNUSED3~] OutputSigType2026=Digital OutputCue2027=[~UNUSED3~] OutputSigType2027=Digital OutputCue2028=[~UNUSED3~] OutputSigType2028=Digital OutputCue2029=[~UNUSED3~] OutputSigType2029=Digital OutputCue2030=[~UNUSED3~] OutputSigType2030=Digital OutputCue2031=[~UNUSED3~] OutputSigType2031=Digital OutputCue2032=[~UNUSED3~] OutputSigType2032=Digital OutputCue2033=[~UNUSED3~] OutputSigType2033=Digital OutputCue2034=[~UNUSED3~] OutputSigType2034=Digital OutputCue2035=[~UNUSED3~] OutputSigType2035=Digital OutputCue2036=[~UNUSED3~] OutputSigType2036=Digital OutputCue2037=[~UNUSED3~] OutputSigType2037=Digital OutputCue2038=[~UNUSED3~] OutputSigType2038=Digital OutputCue2039=[~UNUSED3~] OutputSigType2039=Digital OutputCue2040=[~UNUSED3~] OutputSigType2040=Digital OutputCue2041=[~UNUSED3~] OutputSigType2041=Digital OutputCue2042=[~UNUSED3~] OutputSigType2042=Digital OutputCue2043=[~UNUSED3~] OutputSigType2043=Digital OutputCue2044=[~UNUSED2~] OutputSigType2044=Digital|Analog|Serial|String OutputCue4014=[~EndGroup~]Enable OutputSigType4014=Digital OutputCue4015=[~BeginGroup~]Visible OutputSigType4015=Digital OutputCue4016=[~UNUSED3~] OutputSigType4016=Digital OutputCue4017=[~UNUSED3~] OutputSigType4017=Digital OutputCue4018=[~UNUSED3~] OutputSigType4018=Digital OutputCue4019=[~UNUSED3~] OutputSigType4019=Digital OutputCue4020=[~UNUSED3~] OutputSigType4020=Digital OutputCue4021=[~UNUSED3~] OutputSigType4021=Digital OutputCue4022=[~UNUSED3~] OutputSigType4022=Digital OutputCue4023=[~UNUSED3~] OutputSigType4023=Digital OutputCue4024=[~UNUSED3~] OutputSigType4024=Digital OutputCue4025=[~UNUSED3~] OutputSigType4025=Digital OutputCue4026=[~UNUSED3~] OutputSigType4026=Digital OutputCue4027=[~UNUSED3~] OutputSigType4027=Digital OutputCue4028=[~UNUSED3~] OutputSigType4028=Digital OutputCue4029=[~UNUSED3~] OutputSigType4029=Digital OutputCue4030=[~UNUSED3~] OutputSigType4030=Digital OutputCue4031=[~UNUSED3~] OutputSigType4031=Digital OutputCue4032=[~UNUSED3~] OutputSigType4032=Digital OutputCue4033=[~UNUSED3~] OutputSigType4033=Digital OutputCue4034=[~UNUSED3~] OutputSigType4034=Digital OutputCue4035=[~UNUSED3~] OutputSigType4035=Digital OutputCue4036=[~UNUSED3~] OutputSigType4036=Digital OutputCue4037=[~UNUSED3~] OutputSigType4037=Digital OutputCue4038=[~UNUSED3~] OutputSigType4038=Digital OutputCue4039=[~UNUSED3~] OutputSigType4039=Digital OutputCue4040=[~UNUSED3~] OutputSigType4040=Digital OutputCue4041=[~UNUSED3~] OutputSigType4041=Digital OutputCue4042=[~UNUSED3~] OutputSigType4042=Digital OutputCue4043=[~UNUSED3~] OutputSigType4043=Digital OutputCue4044=[~UNUSED3~] OutputSigType4044=Digital OutputCue4045=[~UNUSED3~] OutputSigType4045=Digital OutputCue4046=[~UNUSED2~] OutputSigType4046=Digital|Analog|Serial|String OutputCue6016=[~EndGroup~]Visible OutputSigType6016=Digital InputList2Cue1=[~UNUSED3~] InputList2SigType1=Analog InputList2Cue2=[~UNUSED3~] InputList2SigType2=Analog InputList2Cue3=Scroll To Item InputList2SigType3=Analog InputList2Cue4=Set Number of Items InputList2SigType4=Analog InputList2Cue5=[~UNUSED2~] InputList2SigType5=Analog InputList2Cue6=[~UNUSED2~] InputList2SigType6=Analog InputList2Cue7=[~UNUSED2~] InputList2SigType7=Analog InputList2Cue8=[~UNUSED2~] InputList2SigType8=Analog InputList2Cue9=[~UNUSED2~] InputList2SigType9=Analog InputList2Cue10=[~UNUSED2~] InputList2SigType10=Analog InputList2Cue11=[~BeginGroup~]Item Icons InputList2SigType11=Analog InputList2Cue12=Set Item 1 Icon Analog InputList2SigType12=Analog InputList2Cue13=Set Item 2 Icon Analog InputList2SigType13=Analog InputList2Cue14=Set Item 3 Icon Analog InputList2SigType14=Analog InputList2Cue15=Set Item 4 Icon Analog InputList2SigType15=Analog InputList2Cue16=Set Item 5 Icon Analog InputList2SigType16=Analog InputList2Cue17=Set Item 6 Icon Analog InputList2SigType17=Analog InputList2Cue18=Set Item 7 Icon Analog InputList2SigType18=Analog InputList2Cue19=Set Item 8 Icon Analog InputList2SigType19=Analog InputList2Cue20=Set Item 9 Icon Analog InputList2SigType20=Analog InputList2Cue21=Set Item 10 Icon Analog InputList2SigType21=Analog InputList2Cue22=Set Item 11 Icon Analog InputList2SigType22=Analog InputList2Cue23=Set Item 12 Icon Analog InputList2SigType23=Analog InputList2Cue24=Set Item 13 Icon Analog InputList2SigType24=Analog InputList2Cue25=Set Item 14 Icon Analog InputList2SigType25=Analog InputList2Cue26=Set Item 15 Icon Analog InputList2SigType26=Analog InputList2Cue27=Set Item 16 Icon Analog InputList2SigType27=Analog InputList2Cue28=Set Item 17 Icon Analog InputList2SigType28=Analog InputList2Cue29=Set Item 18 Icon Analog InputList2SigType29=Analog InputList2Cue30=Set Item 19 Icon Analog InputList2SigType30=Analog InputList2Cue31=Set Item 20 Icon Analog InputList2SigType31=Analog InputList2Cue32=Set Item 21 Icon Analog InputList2SigType32=Analog InputList2Cue33=Set Item 22 Icon Analog InputList2SigType33=Analog InputList2Cue34=Set Item 23 Icon Analog InputList2SigType34=Analog InputList2Cue35=Set Item 24 Icon Analog InputList2SigType35=Analog InputList2Cue36=Set Item 25 Icon Analog InputList2SigType36=Analog InputList2Cue37=Set Item 26 Icon Analog InputList2SigType37=Analog InputList2Cue38=Set Item 27 Icon Analog InputList2SigType38=Analog InputList2Cue39=Set Item 28 Icon Analog InputList2SigType39=Analog InputList2Cue40=Set Item 29 Icon Analog InputList2SigType40=Analog InputList2Cue41=Set Item 30 Icon Analog InputList2SigType41=Analog InputList2Cue42=[~UNUSED2~] InputList2SigType42=Digital|Analog|Serial|String InputList2Cue2012=[~EndGroup~]Item Icons InputList2SigType2012=Analog OutputList2Cue1=Item Clicked OutputList2SigType1=Analog OutputList2Cue2=Item Held OutputList2SigType2=Analog OutputList2Cue3=[~UNUSED3~] OutputList2SigType3=Analog OutputList2Cue4=[~UNUSED3~] OutputList2SigType4=Analog OutputList2Cue5=[~UNUSED2~] OutputList2SigType5=Analog OutputList2Cue6=[~UNUSED2~] OutputList2SigType6=Analog OutputList2Cue7=[~UNUSED2~] OutputList2SigType7=Analog OutputList2Cue8=[~UNUSED2~] OutputList2SigType8=Analog OutputList2Cue9=[~UNUSED2~] OutputList2SigType9=Analog OutputList2Cue10=[~UNUSED2~] OutputList2SigType10=Analog OutputList2Cue11=[~BeginGroup~]Item Icons OutputList2SigType11=Analog OutputList2Cue12=[~UNUSED3~] OutputList2SigType12=Analog OutputList2Cue13=[~UNUSED3~] OutputList2SigType13=Analog OutputList2Cue14=[~UNUSED3~] OutputList2SigType14=Analog OutputList2Cue15=[~UNUSED3~] OutputList2SigType15=Analog OutputList2Cue16=[~UNUSED3~] OutputList2SigType16=Analog OutputList2Cue17=[~UNUSED3~] OutputList2SigType17=Analog OutputList2Cue18=[~UNUSED3~] OutputList2SigType18=Analog OutputList2Cue19=[~UNUSED3~] OutputList2SigType19=Analog OutputList2Cue20=[~UNUSED3~] OutputList2SigType20=Analog OutputList2Cue21=[~UNUSED3~] OutputList2SigType21=Analog OutputList2Cue22=[~UNUSED3~] OutputList2SigType22=Analog OutputList2Cue23=[~UNUSED3~] OutputList2SigType23=Analog OutputList2Cue24=[~UNUSED3~] OutputList2SigType24=Analog OutputList2Cue25=[~UNUSED3~] OutputList2SigType25=Analog OutputList2Cue26=[~UNUSED3~] OutputList2SigType26=Analog OutputList2Cue27=[~UNUSED3~] OutputList2SigType27=Analog OutputList2Cue28=[~UNUSED3~] OutputList2SigType28=Analog OutputList2Cue29=[~UNUSED3~] OutputList2SigType29=Analog OutputList2Cue30=[~UNUSED3~] OutputList2SigType30=Analog OutputList2Cue31=[~UNUSED3~] OutputList2SigType31=Analog OutputList2Cue32=[~UNUSED3~] OutputList2SigType32=Analog OutputList2Cue33=[~UNUSED3~] OutputList2SigType33=Analog OutputList2Cue34=[~UNUSED3~] OutputList2SigType34=Analog OutputList2Cue35=[~UNUSED3~] OutputList2SigType35=Analog OutputList2Cue36=[~UNUSED3~] OutputList2SigType36=Analog OutputList2Cue37=[~UNUSED3~] OutputList2SigType37=Analog OutputList2Cue38=[~UNUSED3~] OutputList2SigType38=Analog OutputList2Cue39=[~UNUSED3~] OutputList2SigType39=Analog OutputList2Cue40=[~UNUSED3~] OutputList2SigType40=Analog OutputList2Cue41=[~UNUSED3~] OutputList2SigType41=Analog OutputList2Cue42=[~UNUSED2~] OutputList2SigType42=Digital|Analog|Serial|String OutputList2Cue2012=[~EndGroup~]Item Icons OutputList2SigType2012=Analog InputList3Cue1=[~UNUSED2~] InputList3SigType1=Serial InputList3Cue2=[~UNUSED2~] InputList3SigType2=Serial InputList3Cue3=[~UNUSED2~] InputList3SigType3=Serial InputList3Cue4=[~UNUSED2~] InputList3SigType4=Serial InputList3Cue5=[~UNUSED2~] InputList3SigType5=Serial InputList3Cue6=[~UNUSED2~] InputList3SigType6=Serial InputList3Cue7=[~UNUSED2~] InputList3SigType7=Serial InputList3Cue8=[~UNUSED2~] InputList3SigType8=Serial InputList3Cue9=[~UNUSED2~] InputList3SigType9=Serial InputList3Cue10=[~UNUSED2~] InputList3SigType10=Serial InputList3Cue11=[~BeginGroup~]Item Texts InputList3SigType11=Serial InputList3Cue12=Set Item 1 Text InputList3SigType12=Serial InputList3Cue13=Set Item 2 Text InputList3SigType13=Serial InputList3Cue14=Set Item 3 Text InputList3SigType14=Serial InputList3Cue15=Set Item 4 Text InputList3SigType15=Serial InputList3Cue16=Set Item 5 Text InputList3SigType16=Serial InputList3Cue17=Set Item 6 Text InputList3SigType17=Serial InputList3Cue18=Set Item 7 Text InputList3SigType18=Serial InputList3Cue19=Set Item 8 Text InputList3SigType19=Serial InputList3Cue20=Set Item 9 Text InputList3SigType20=Serial InputList3Cue21=Set Item 10 Text InputList3SigType21=Serial InputList3Cue22=Set Item 11 Text InputList3SigType22=Serial InputList3Cue23=Set Item 12 Text InputList3SigType23=Serial InputList3Cue24=Set Item 13 Text InputList3SigType24=Serial InputList3Cue25=Set Item 14 Text InputList3SigType25=Serial InputList3Cue26=Set Item 15 Text InputList3SigType26=Serial InputList3Cue27=Set Item 16 Text InputList3SigType27=Serial InputList3Cue28=Set Item 17 Text InputList3SigType28=Serial InputList3Cue29=Set Item 18 Text InputList3SigType29=Serial InputList3Cue30=Set Item 19 Text InputList3SigType30=Serial InputList3Cue31=Set Item 20 Text InputList3SigType31=Serial InputList3Cue32=Set Item 21 Text InputList3SigType32=Serial InputList3Cue33=Set Item 22 Text InputList3SigType33=Serial InputList3Cue34=Set Item 23 Text InputList3SigType34=Serial InputList3Cue35=Set Item 24 Text InputList3SigType35=Serial InputList3Cue36=Set Item 25 Text InputList3SigType36=Serial InputList3Cue37=Set Item 26 Text InputList3SigType37=Serial InputList3Cue38=Set Item 27 Text InputList3SigType38=Serial InputList3Cue39=Set Item 28 Text InputList3SigType39=Serial InputList3Cue40=Set Item 29 Text InputList3SigType40=Serial InputList3Cue41=Set Item 30 Text InputList3SigType41=Serial InputList3Cue42=[~UNUSED2~] InputList3SigType42=Digital|Analog|Serial|String InputList3Cue2012=[~EndGroup~]Item Texts InputList3SigType2012=Serial InputList3Cue2013=[~BeginGroup~]Item Icons InputList3SigType2013=Serial InputList3Cue2014=Set Item 1 Icon Serial InputList3SigType2014=Serial InputList3Cue2015=Set Item 2 Icon Serial InputList3SigType2015=Serial InputList3Cue2016=Set Item 3 Icon Serial InputList3SigType2016=Serial InputList3Cue2017=Set Item 4 Icon Serial InputList3SigType2017=Serial InputList3Cue2018=Set Item 5 Icon Serial InputList3SigType2018=Serial InputList3Cue2019=Set Item 6 Icon Serial InputList3SigType2019=Serial InputList3Cue2020=Set Item 7 Icon Serial InputList3SigType2020=Serial InputList3Cue2021=Set Item 8 Icon Serial InputList3SigType2021=Serial InputList3Cue2022=Set Item 9 Icon Serial InputList3SigType2022=Serial InputList3Cue2023=Set Item 10 Icon Serial InputList3SigType2023=Serial InputList3Cue2024=Set Item 11 Icon Serial InputList3SigType2024=Serial InputList3Cue2025=Set Item 12 Icon Serial InputList3SigType2025=Serial InputList3Cue2026=Set Item 13 Icon Serial InputList3SigType2026=Serial InputList3Cue2027=Set Item 14 Icon Serial InputList3SigType2027=Serial InputList3Cue2028=Set Item 15 Icon Serial InputList3SigType2028=Serial InputList3Cue2029=Set Item 16 Icon Serial InputList3SigType2029=Serial InputList3Cue2030=Set Item 17 Icon Serial InputList3SigType2030=Serial InputList3Cue2031=Set Item 18 Icon Serial InputList3SigType2031=Serial InputList3Cue2032=Set Item 19 Icon Serial InputList3SigType2032=Serial InputList3Cue2033=Set Item 20 Icon Serial InputList3SigType2033=Serial InputList3Cue2034=Set Item 21 Icon Serial InputList3SigType2034=Serial InputList3Cue2035=Set Item 22 Icon Serial InputList3SigType2035=Serial InputList3Cue2036=Set Item 23 Icon Serial InputList3SigType2036=Serial InputList3Cue2037=Set Item 24 Icon Serial InputList3SigType2037=Serial InputList3Cue2038=Set Item 25 Icon Serial InputList3SigType2038=Serial InputList3Cue2039=Set Item 26 Icon Serial InputList3SigType2039=Serial InputList3Cue2040=Set Item 27 Icon Serial InputList3SigType2040=Serial InputList3Cue2041=Set Item 28 Icon Serial InputList3SigType2041=Serial InputList3Cue2042=Set Item 29 Icon Serial InputList3SigType2042=Serial InputList3Cue2043=Set Item 30 Icon Serial InputList3SigType2043=Serial InputList3Cue2044=[~UNUSED2~] InputList3SigType2044=Digital|Analog|Serial|String InputList3Cue4014=[~EndGroup~]Item Icons InputList3SigType4014=Serial OutputList3Cue1=[~UNUSED2~] OutputList3SigType1=Serial OutputList3Cue2=[~UNUSED2~] OutputList3SigType2=Serial OutputList3Cue3=[~UNUSED2~] OutputList3SigType3=Serial OutputList3Cue4=[~UNUSED2~] OutputList3SigType4=Serial OutputList3Cue5=[~UNUSED2~] OutputList3SigType5=Serial OutputList3Cue6=[~UNUSED2~] OutputList3SigType6=Serial OutputList3Cue7=[~UNUSED2~] OutputList3SigType7=Serial OutputList3Cue8=[~UNUSED2~] OutputList3SigType8=Serial OutputList3Cue9=[~UNUSED2~] OutputList3SigType9=Serial OutputList3Cue10=[~UNUSED2~] OutputList3SigType10=Serial OutputList3Cue11=[~BeginGroup~]Item Texts OutputList3SigType11=Serial OutputList3Cue12=[~UNUSED3~] OutputList3SigType12=Serial OutputList3Cue13=[~UNUSED3~] OutputList3SigType13=Serial OutputList3Cue14=[~UNUSED3~] OutputList3SigType14=Serial OutputList3Cue15=[~UNUSED3~] OutputList3SigType15=Serial OutputList3Cue16=[~UNUSED3~] OutputList3SigType16=Serial OutputList3Cue17=[~UNUSED3~] OutputList3SigType17=Serial OutputList3Cue18=[~UNUSED3~] OutputList3SigType18=Serial OutputList3Cue19=[~UNUSED3~] OutputList3SigType19=Serial OutputList3Cue20=[~UNUSED3~] OutputList3SigType20=Serial OutputList3Cue21=[~UNUSED3~] OutputList3SigType21=Serial OutputList3Cue22=[~UNUSED3~] OutputList3SigType22=Serial OutputList3Cue23=[~UNUSED3~] OutputList3SigType23=Serial OutputList3Cue24=[~UNUSED3~] OutputList3SigType24=Serial OutputList3Cue25=[~UNUSED3~] OutputList3SigType25=Serial OutputList3Cue26=[~UNUSED3~] OutputList3SigType26=Serial OutputList3Cue27=[~UNUSED3~] OutputList3SigType27=Serial OutputList3Cue28=[~UNUSED3~] OutputList3SigType28=Serial OutputList3Cue29=[~UNUSED3~] OutputList3SigType29=Serial OutputList3Cue30=[~UNUSED3~] OutputList3SigType30=Serial OutputList3Cue31=[~UNUSED3~] OutputList3SigType31=Serial OutputList3Cue32=[~UNUSED3~] OutputList3SigType32=Serial OutputList3Cue33=[~UNUSED3~] OutputList3SigType33=Serial OutputList3Cue34=[~UNUSED3~] OutputList3SigType34=Serial OutputList3Cue35=[~UNUSED3~] OutputList3SigType35=Serial OutputList3Cue36=[~UNUSED3~] OutputList3SigType36=Serial OutputList3Cue37=[~UNUSED3~] OutputList3SigType37=Serial OutputList3Cue38=[~UNUSED3~] OutputList3SigType38=Serial OutputList3Cue39=[~UNUSED3~] OutputList3SigType39=Serial OutputList3Cue40=[~UNUSED3~] OutputList3SigType40=Serial OutputList3Cue41=[~UNUSED3~] OutputList3SigType41=Serial OutputList3Cue42=[~UNUSED2~] OutputList3SigType42=Digital|Analog|Serial|String OutputList3Cue2012=[~EndGroup~]Item Texts OutputList3SigType2012=Serial OutputList3Cue2013=[~BeginGroup~]Item Icons OutputList3SigType2013=Serial OutputList3Cue2014=[~UNUSED3~] OutputList3SigType2014=Serial OutputList3Cue2015=[~UNUSED3~] OutputList3SigType2015=Serial OutputList3Cue2016=[~UNUSED3~] OutputList3SigType2016=Serial OutputList3Cue2017=[~UNUSED3~] OutputList3SigType2017=Serial OutputList3Cue2018=[~UNUSED3~] OutputList3SigType2018=Serial OutputList3Cue2019=[~UNUSED3~] OutputList3SigType2019=Serial OutputList3Cue2020=[~UNUSED3~] OutputList3SigType2020=Serial OutputList3Cue2021=[~UNUSED3~] OutputList3SigType2021=Serial OutputList3Cue2022=[~UNUSED3~] OutputList3SigType2022=Serial OutputList3Cue2023=[~UNUSED3~] OutputList3SigType2023=Serial OutputList3Cue2024=[~UNUSED3~] OutputList3SigType2024=Serial OutputList3Cue2025=[~UNUSED3~] OutputList3SigType2025=Serial OutputList3Cue2026=[~UNUSED3~] OutputList3SigType2026=Serial OutputList3Cue2027=[~UNUSED3~] OutputList3SigType2027=Serial OutputList3Cue2028=[~UNUSED3~] OutputList3SigType2028=Serial OutputList3Cue2029=[~UNUSED3~] OutputList3SigType2029=Serial OutputList3Cue2030=[~UNUSED3~] OutputList3SigType2030=Serial OutputList3Cue2031=[~UNUSED3~] OutputList3SigType2031=Serial OutputList3Cue2032=[~UNUSED3~] OutputList3SigType2032=Serial OutputList3Cue2033=[~UNUSED3~] OutputList3SigType2033=Serial OutputList3Cue2034=[~UNUSED3~] OutputList3SigType2034=Serial OutputList3Cue2035=[~UNUSED3~] OutputList3SigType2035=Serial OutputList3Cue2036=[~UNUSED3~] OutputList3SigType2036=Serial OutputList3Cue2037=[~UNUSED3~] OutputList3SigType2037=Serial OutputList3Cue2038=[~UNUSED3~] OutputList3SigType2038=Serial OutputList3Cue2039=[~UNUSED3~] OutputList3SigType2039=Serial OutputList3Cue2040=[~UNUSED3~] OutputList3SigType2040=Serial OutputList3Cue2041=[~UNUSED3~] OutputList3SigType2041=Serial OutputList3Cue2042=[~UNUSED3~] OutputList3SigType2042=Serial OutputList3Cue2043=[~UNUSED3~] OutputList3SigType2043=Serial OutputList3Cue2044=[~UNUSED2~] OutputList3SigType2044=Digital|Analog|Serial|String OutputList3Cue4014=[~EndGroup~]Item Icons OutputList3SigType4014=Serial ParamCue1=SmartObjectId ParamSigType1=Constant MPp=1 Pp1=19 CedH=19 SmartObjId=1203d ] ; Parameter Properties for Smart Object ID [ ObjTp=Dp H=19 Tp=1 HD=TRUE DV=1203d NF=1 DNF=1 EncFmt=0 DVLF=1 Sgn=0 ] ; Smart Objects Definition section [ ObjTp=CED H=19 Name=PepperDash Essentials iPad_[D.VC] Recents_Dynamic Button List Vertical_2.ced ;Cedver is the version of the Smart Graphics control, not the CED file format. ;If the control definition changes, increment this. CedVer=1 ] ================================================ FILE: src/PepperDash.Essentials/app.config ================================================  ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs ================================================  using System; using System.Collections.Generic; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.EthernetCommunication; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core.Bridges { /// /// Base class for bridge API variants /// [Obsolete("Will be removed in v3.0.0")] public abstract class BridgeApi : EssentialsDevice { /// /// Constructor /// /// Device key protected BridgeApi(string key) : base(key) { } /// /// Constructor /// /// /// protected BridgeApi(string key, string name) : base(key, name) { } } /// /// Class to link devices and rooms to an EISC Instance /// public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor { /// /// Gets the PropertiesConfig /// public EiscApiPropertiesConfig PropertiesConfig { get; private set; } /// /// Gets the JoinMaps dictionary /// public Dictionary JoinMaps { get; private set; } /// /// Gets the EISC instance /// public BasicTriList Eisc { get; private set; } /// /// Constructor /// /// Device configuration /// EISC instance public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) : base(dc.Key, dc.Name) { JoinMaps = new Dictionary(); PropertiesConfig = dc.Properties.ToObject(); Eisc = eisc; Eisc.SigChange += Eisc_SigChange; CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000); AddPostActivationAction(LinkDevices); AddPostActivationAction(LinkRooms); AddPostActivationAction(RegisterEisc); } /// /// CustomActivate method /// public override bool CustomActivate() { CommunicationMonitor.Start(); return base.CustomActivate(); } /// /// Deactivate method /// public override bool Deactivate() { CommunicationMonitor.Stop(); return base.Deactivate(); } private void LinkDevices() { Debug.LogMessage(LogEventLevel.Debug, this, "Linking Devices..."); if (PropertiesConfig.Devices == null) { this.LogDebug("No devices linked to this bridge"); return; } foreach (var d in PropertiesConfig.Devices) { var device = DeviceManager.GetDeviceForKey(d.DeviceKey); if (device == null) { continue; } Debug.LogMessage(LogEventLevel.Debug, this, "Linking Device: '{0}'", device.Key); if (device is IBridgeAdvanced bridge) { bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this); continue; } this.LogWarning("{deviceKey} is not compatible with this bridge type. Please update the device.", device.Key); } } private void RegisterEisc() { if (Eisc.Registered) { return; } var registerResult = Eisc.Register(); if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success) { this.LogVerbose("Registration result: {registerResult}", registerResult); return; } this.LogDebug("EISC registration successful"); } /// /// Link rooms to this EISC. Rooms MUST implement IBridgeAdvanced /// public void LinkRooms() { this.LogDebug("Linking Rooms..."); if (PropertiesConfig.Rooms == null) { this.LogDebug("No rooms linked to this bridge."); return; } foreach (var room in PropertiesConfig.Rooms) { if (!(DeviceManager.GetDeviceForKey(room.RoomKey) is IBridgeAdvanced rm)) { this.LogDebug("Room {roomKey} does not implement IBridgeAdvanced. Skipping...", room.RoomKey); continue; } rm.LinkToApi(Eisc, room.JoinStart, room.JoinMapKey, this); } } /// /// Adds a join map /// /// The key of the device to add the join map for /// The join map to add public void AddJoinMap(string deviceKey, JoinMapBaseAdvanced joinMap) { if (!JoinMaps.ContainsKey(deviceKey)) { JoinMaps.Add(deviceKey, joinMap); } else { this.LogWarning("Unable to add join map with key '{deviceKey}'. Key already exists in JoinMaps dictionary", deviceKey); } } /// /// PrintJoinMaps method /// public virtual void PrintJoinMaps() { CrestronConsole.ConsoleCommandResponse("Join Maps for EISC IPID: {0}\r\n", Eisc.ID.ToString("X")); foreach (var joinMap in JoinMaps) { CrestronConsole.ConsoleCommandResponse("Join map for device '{0}':", joinMap.Key); joinMap.Value.PrintJoinMapInfo(); } } /// /// MarkdownForBridge method /// public virtual void MarkdownForBridge(string bridgeKey) { this.LogInformation("Writing Joinmaps to files for EISC IPID: {eiscId}", Eisc.ID.ToString("X")); foreach (var joinMap in JoinMaps) { this.LogInformation("Generating markdown for device '{deviceKey}':", joinMap.Key); joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey); } } /// /// Prints the join map for a device by key /// /// The key of the device to print the join map for public void PrintJoinMapForDevice(string deviceKey) { var joinMap = JoinMaps[deviceKey]; if (joinMap == null) { this.LogInformation("Unable to find joinMap for device with key: '{deviceKey}'", deviceKey); return; } this.LogInformation("Join map for device '{deviceKey}' on EISC '{eiscKey}':", deviceKey, Key); joinMap.PrintJoinMapInfo(); } /// /// Prints the join map for a device by key in Markdown format /// /// The key of the device to print the join map for /// The key of the bridge to use for the Markdown output public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey) { var joinMap = JoinMaps[deviceKey]; if (joinMap == null) { this.LogInformation("Unable to find joinMap for device with key: '{deviceKey}'", deviceKey); return; } this.LogInformation("Join map for device '{deviceKey}' on EISC '{eiscKey}':", deviceKey, Key); joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey); } /// /// Used for debugging to trigger an action based on a join number and type /// /// The join number to execute the action for /// The type of join (digital, analog, serial) /// The state to pass to the action public void ExecuteJoinAction(uint join, string type, object state) { try { switch (type.ToLower()) { case "digital": { if (Eisc.BooleanOutput[join].UserObject is Action userObject) { this.LogVerbose("Executing Boolean Action"); userObject(Convert.ToBoolean(state)); } else this.LogVerbose("User Object is null. Nothing to Execute"); break; } case "analog": { if (Eisc.UShortOutput[join].UserObject is Action userObject) { this.LogVerbose("Executing Analog Action"); userObject(Convert.ToUInt16(state)); } else this.LogVerbose("User Object is null. Nothing to Execute"); break; } case "serial": { if (Eisc.StringOutput[join].UserObject is Action userObject) { this.LogVerbose("Executing Serial Action"); userObject(Convert.ToString(state)); } else this.LogVerbose("User Object is null. Nothing to Execute"); break; } default: { this.LogVerbose("Unknown join type. Use digital/serial/analog"); break; } } } catch (Exception e) { this.LogError("ExecuteJoinAction error: {message}", e.Message); this.LogDebug(e, "Stack Trace: "); } } /// /// Handle incoming sig changes /// /// BasicTriList device that triggered the event /// Event arguments containing the signal information protected void Eisc_SigChange(object currentDevice, SigEventArgs args) { try { this.LogVerbose("EiscApiAdvanced change: {type} {number}={value}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); var userObject = args.Sig.UserObject; if (userObject == null) return; if (userObject is Action) { this.LogDebug("Executing Boolean Action"); (userObject as Action)(args.Sig.BoolValue); } else if (userObject is Action) { this.LogDebug("Executing Analog Action"); (userObject as Action)(args.Sig.UShortValue); } else if (userObject is Action) { this.LogDebug("Executing Serial Action"); (userObject as Action)(args.Sig.StringValue); } } catch (Exception e) { this.LogError("Eisc_SigChange handler error: {message}", e.Message); this.LogDebug(e, "Stack Trace: "); } } #region Implementation of ICommunicationMonitor /// /// Gets or sets the CommunicationMonitor /// public StatusMonitorBase CommunicationMonitor { get; private set; } #endregion } /// /// Represents a EiscApiPropertiesConfig /// public class EiscApiPropertiesConfig { /// /// Gets or sets the Control /// [JsonProperty("control")] public EssentialsControlPropertiesConfig Control { get; set; } /// /// Gets or sets the Devices /// [JsonProperty("devices")] public List Devices { get; set; } /// /// Gets or sets the Rooms /// [JsonProperty("rooms")] public List Rooms { get; set; } /// /// Represents a ApiDevicePropertiesConfig /// public class ApiDevicePropertiesConfig { /// /// Gets or sets the DeviceKey /// [JsonProperty("deviceKey")] public string DeviceKey { get; set; } /// /// Gets or sets the JoinStart /// [JsonProperty("joinStart")] public uint JoinStart { get; set; } /// /// Gets or sets the JoinMapKey /// [JsonProperty("joinMapKey")] public string JoinMapKey { get; set; } } /// /// Represents a ApiRoomPropertiesConfig /// public class ApiRoomPropertiesConfig { /// /// Gets or sets the RoomKey /// [JsonProperty("roomKey")] public string RoomKey { get; set; } /// /// Gets or sets the JoinStart /// [JsonProperty("joinStart")] public uint JoinStart { get; set; } /// /// Gets or sets the JoinMapKey /// [JsonProperty("joinMapKey")] public string JoinMapKey { get; set; } } } /// /// Factory class for EiscApiAdvanced devices /// /// /// Supported types: /// eiscapiadv - Create a standard EISC client over TCP/IP /// eiscapiadvanced - Create a standard EISC client over TCP/IP /// eiscapiadvancedserver - Create an EISC server /// eiscapiadvancedclient - Create an EISC client /// vceiscapiadv - Create a VC-4 EISC client /// vceiscapiadvanced - Create a VC-4 EISC client /// eiscapiadvudp - Create a standard EISC client over UDP /// eiscapiadvancedudp - Create a standard EISC client over UDP /// public class EiscApiAdvancedFactory : EssentialsDeviceFactory { /// /// Constructor /// public EiscApiAdvancedFactory() { TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced", "eiscapiadvudp", "eiscapiadvancedudp" }; } /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogDebug("Attempting to create new EiscApiAdvanced Device"); var controlProperties = CommFactory.GetControlPropertiesConfig(dc); BasicTriList eisc; switch (dc.Type.ToLower()) { case "eiscapiadvudp": case "eiscapiadvancedudp": { eisc = new EthernetIntersystemCommunications(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem); break; } case "eiscapiadv": case "eiscapiadvanced": { eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem); break; } case "eiscapiadvancedserver": { eisc = new EISCServer(controlProperties.IpIdInt, Global.ControlSystem); break; } case "eiscapiadvancedclient": { eisc = new EISCClient(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem); break; } case "vceiscapiadv": case "vceiscapiadvanced": { if (string.IsNullOrEmpty(controlProperties.RoomId)) { Debug.LogInformation("Unable to build VC-4 EISC Client for device {deviceKey}. Room ID is missing or empty", dc.Key); eisc = null; break; } eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, controlProperties.RoomId, Global.ControlSystem); break; } default: eisc = null; break; } if (eisc == null) { return null; } return new EiscApiAdvanced(dc, eisc); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/BridgeHelper.cs ================================================ using PepperDash.Core; using Serilog.Events; //using PepperDash.Essentials.Devices.Common.Cameras; namespace PepperDash.Essentials.Core.Bridges { /// /// Helper methods for bridges /// public static class BridgeHelper { /// /// PrintJoinMp method /// /// target bridgekey to print join map for public static void PrintJoinMap(string command) { var targets = command.Split(' '); var bridgeKey = targets[0].Trim(); if (!(DeviceManager.GetDeviceForKey(bridgeKey) is EiscApiAdvanced bridge)) { Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey); return; } if (targets.Length > 1) { var deviceKey = targets[1].Trim(); if (string.IsNullOrEmpty(deviceKey)) return; bridge.PrintJoinMapForDevice(deviceKey); } else { bridge.PrintJoinMaps(); } } /// /// JoinmapMarkdown method /// public static void JoinmapMarkdown(string command) { var targets = command.Split(' '); var bridgeKey = targets[0].Trim(); var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced; if (bridge == null) { Debug.LogMessage(LogEventLevel.Information, "Unable to find advanced bridge with key: '{0}'", bridgeKey); return; } if (targets.Length > 1) { var deviceKey = targets[1].Trim(); if (string.IsNullOrEmpty(deviceKey)) return; bridge.MarkdownJoinMapForDevice(deviceKey, bridgeKey); } else { bridge.MarkdownForBridge(bridgeKey); } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/IBridge.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core.Bridges { /// /// Defines the contract for IBridgeAdvanced /// public interface IBridgeAdvanced { /// /// Links the bridge to the API using the provided trilist, join start, join map key, and bridge. /// /// The trilist to link to. /// The starting join number. /// The key for the join map. /// The EISC API bridge. void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/AirMediaControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a AirMediaControllerJoinMap /// public class AirMediaControllerJoinMap : JoinMapBaseAdvanced { /// /// Air Media Online status /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Air Media In Sharing Session status /// [JoinName("IsInSession")] public JoinDataComplete IsInSession = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media In Sharing Session", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Air Media Has HDMI Video Sync status /// [JoinName("HdmiVideoSync")] public JoinDataComplete HdmiVideoSync = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Has HDMI Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Air Media Automatic Input Routing Enable(d) /// [JoinName("AutomaticInputRoutingEnabled")] public JoinDataComplete AutomaticInputRoutingEnabled = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Automatic Input Routing Enable(d)", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Air Media Video Route Select / Feedback /// [JoinName("VideoOut")] public JoinDataComplete VideoOut = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Video Route Select / Feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Air Media Error Status Feedback /// [JoinName("ErrorFB")] public JoinDataComplete ErrorFB = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Error Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Air Media Number of Users Connected Feedback /// [JoinName("NumberOfUsersConnectedFB")] public JoinDataComplete NumberOfUsersConnectedFB = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Number of Users Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Air Media Login Code Set / Get /// [JoinName("LoginCode")] public JoinDataComplete LoginCode = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Login Code Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Air Media Device Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Device Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Air Media IP Address Feedback /// [JoinName("ConnectionAddressFB")] public JoinDataComplete ConnectionAddressFB = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media IP Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Air Media Hostname Feedback /// [JoinName("HostnameFB")] public JoinDataComplete HostnameFB = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Hostname", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Air Media Serial Number Feedback /// [JoinName("SerialNumberFeedback")] public JoinDataComplete SerialNumberFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Air Media Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public AirMediaControllerJoinMap(uint joinStart) : this(joinStart, typeof(AirMediaControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected AirMediaControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){} } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/AppleTvJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a AppleTvJoinMap /// public class AppleTvJoinMap : JoinMapBaseAdvanced { /// /// AppleTv Nav Up /// [JoinName("UpArrow")] public JoinDataComplete UpArrow = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "AppleTv Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// AppleTv Nav Down /// [JoinName("DnArrow")] public JoinDataComplete DnArrow = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "AppleTv Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// AppleTv Nav Left /// [JoinName("LeftArrow")] public JoinDataComplete LeftArrow = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "AppleTv Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// AppleTv Nav Right /// [JoinName("RightArrow")] public JoinDataComplete RightArrow = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "AppleTv Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// AppleTv Menu /// [JoinName("Menu")] public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "AppleTv Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// AppleTv Select /// [JoinName("Select")] public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "AppleTv Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// AppleTv Play/Pause /// [JoinName("PlayPause")] public JoinDataComplete PlayPause = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "AppleTv Play/Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public AppleTvJoinMap(uint joinStart) : base(joinStart, typeof(AppleTvJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map public AppleTvJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/C2nRthsControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a C2nRthsControllerJoinMap /// public class C2nRthsControllerJoinMap : JoinMapBaseAdvanced { /// /// C2nRthsController Online status /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Temp Sensor Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Temperature Format (C/F) /// [JoinName("TemperatureFormat")] public JoinDataComplete TemperatureFormat = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Temp Sensor Unit Format", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Temperature Sensor Feedbacks /// [JoinName("Temperature")] public JoinDataComplete Temperature = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Temp Sensor Temperature Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Humidity Sensor Feedbacks /// [JoinName("Humidity")] public JoinDataComplete Humidity = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Temp Sensor Humidity Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Temp Sensor Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Temp Sensor Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public C2nRthsControllerJoinMap(uint joinStart) : this(joinStart, typeof(C2nRthsControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected C2nRthsControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/CameraControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a CameraControllerJoinMap /// public class CameraControllerJoinMap : JoinMapBaseAdvanced { /// /// Tilt Up /// [JoinName("TiltUp")] public JoinDataComplete TiltUp = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Tilt Down /// [JoinName("TiltDown")] public JoinDataComplete TiltDown = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Tilt Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Pan Left /// [JoinName("PanLeft")] public JoinDataComplete PanLeft = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Pan Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Pan Right /// [JoinName("PanRight")] public JoinDataComplete PanRight = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Pan Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Zoom In /// [JoinName("ZoomIn")] public JoinDataComplete ZoomIn = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Zoom In", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Zoom Out /// [JoinName("ZoomOut")] public JoinDataComplete ZoomOut = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Zoom Out", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Is Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Power On /// [JoinName("PowerOn")] public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Power Off /// [JoinName("PowerOff")] public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Number Of Presets /// [JoinName("NumberOfPresets")] public JoinDataComplete NumberOfPresets = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Tells Essentials the number of defined presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// Preset Recall Start /// [JoinName("PresetRecallStart")] public JoinDataComplete PresetRecallStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Recall Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Preset Label Start /// [JoinName("PresetLabelStart")] public JoinDataComplete PresetLabelStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Label Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); /// /// Preset Save Start /// [JoinName("PresetSaveStart")] public JoinDataComplete PresetSaveStart = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 20 }, new JoinMetadata { Description = "Preset Save Start", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Mode Auto /// [JoinName("CameraModeAuto")] public JoinDataComplete CameraModeAuto = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Auto", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Mode Manual /// [JoinName("CameraModeManual")] public JoinDataComplete CameraModeManual = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Manual", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Mode Off /// [JoinName("CameraModeOff")] public JoinDataComplete CameraModeOff = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Supports Camera Mode Manual /// [JoinName("SupportsCameraModeAuto")] public JoinDataComplete SupportsCameraModeAuto = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Camera Mode Auto", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Supports Camera Mode Off /// [JoinName("SupportsCameraModeOff")] public JoinDataComplete SupportsCameraModeOff = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Camera Mode Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Supports Presets /// [JoinName("SupportsPresets")] public JoinDataComplete SupportsPresets = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public CameraControllerJoinMap(uint joinStart) : this(joinStart, typeof(CameraControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected CameraControllerJoinMap(uint joinStart, Type type) : base(joinStart, type){} } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a CenOdtOccupancySensorBaseJoinMap /// public class CenOdtOccupancySensorBaseJoinMap : JoinMapBaseAdvanced { #region Digitals /// /// Online /// [JoinName("Online")] public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Force Occupied /// [JoinName("ForceOccupied")] public JoinDataComplete ForceOccupied = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Force Occupied", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Force Vacant /// [JoinName("ForceVacant")] public JoinDataComplete ForceVacant = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Force Vacant", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Enable Raw States /// [JoinName("EnableRawStates")] public JoinDataComplete EnableRawStates = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Raw States", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Disable Raw States /// [JoinName("RoomOccupiedFeedback")] public JoinDataComplete RoomOccupiedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Room Occupied Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Grace Occupancy Detected Feedback /// [JoinName("GraceOccupancyDetectedFeedback")] public JoinDataComplete GraceOccupancyDetectedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Grace Occupancy Detected Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Room Vacant Feedback /// [JoinName("RoomVacantFeedback")] public JoinDataComplete RoomVacantFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Room Vacant Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Raw Occupancy Feedback /// [JoinName("RawOccupancyFeedback")] public JoinDataComplete RawOccupancyFeedback = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Raw Occupancy Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Raw Occupancy Pir Feedback /// [JoinName("RawOccupancyPirFeedback")] public JoinDataComplete RawOccupancyPirFeedback = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Raw Occupancy Pir Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Raw Occupancy Us Feedback /// [JoinName("RawOccupancyUsFeedback")] public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Raw Occupancy Us Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Identity Mode On /// [JoinName("IdentityModeOn")] public JoinDataComplete IdentityMode = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Identity Mode", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Identity Mode Off /// [JoinName("IdentityModeFeedback")] public JoinDataComplete IdentityModeFeedback = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Identity Mode Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Enable Led Flash /// [JoinName("EnableLedFlash")] public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Led Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Disable Led Flash /// [JoinName("DisableLedFlash")] public JoinDataComplete DisableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Disable Led Flash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Enable Short Timeout /// [JoinName("EnableShortTimeout")] public JoinDataComplete EnableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Short Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Disable Short Timeout /// [JoinName("DisableShortTimeout")] public JoinDataComplete DisableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "Disable Short Timeout", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Or When Vacated /// [JoinName("OrWhenVacated")] public JoinDataComplete OrWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "Or When Vacated", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// And When Vacated /// [JoinName("AndWhenVacated")] public JoinDataComplete AndWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, new JoinMetadata { Description = "AndWhenVacated", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Enable Us A /// [JoinName("EnableUsA")] public JoinDataComplete EnableUsA = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Us A", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Disable Us A /// [JoinName("DisableUsA")] public JoinDataComplete DisableUsA = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, new JoinMetadata { Description = "Disable Us A", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Enable Us B /// [JoinName("EnableUsB")] public JoinDataComplete EnableUsB = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Us B", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Disable Us B /// [JoinName("DisableUsB")] public JoinDataComplete DisableUsB = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, new JoinMetadata { Description = "Disable Us B", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Enable Pir /// [JoinName("EnablePir")] public JoinDataComplete EnablePir = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Pir", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Disable Pir /// [JoinName("DisablePir")] public JoinDataComplete DisablePir = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "Disable Pir", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Increment Us In Occupied State /// [JoinName("IncrementUsInOccupiedState")] public JoinDataComplete IncrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, new JoinMetadata { Description = "Increment Us In OccupiedState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Decrement Us In Occupied State /// [JoinName("DecrementUsInOccupiedState")] public JoinDataComplete DecrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "Dencrement Us In Occupied State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Increment Us In Vacant State /// [JoinName("IncrementUsInVacantState")] public JoinDataComplete IncrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, new JoinMetadata { Description = "Increment Us In VacantState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Decrement Us In Vacant State /// [JoinName("DecrementUsInVacantState")] public JoinDataComplete DecrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, new JoinMetadata { Description = "Decrement Us In VacantState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Increment Pir In Occupied State /// [JoinName("IncrementPirInOccupiedState")] public JoinDataComplete IncrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, new JoinMetadata { Description = "Increment Pir In Occupied State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Decrement Pir In Occupied State /// [JoinName("DecrementPirInOccupiedState")] public JoinDataComplete DecrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, new JoinMetadata { Description = "Decrement Pir In OccupiedState", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Increment Pir In Vacant State /// [JoinName("IncrementPirInVacantState")] public JoinDataComplete IncrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, new JoinMetadata { Description = "Increment Pir In Vacant State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Decrement Pir In Vacant State /// [JoinName("DecrementPirInVacantState")] public JoinDataComplete DecrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, new JoinMetadata { Description = "Decrement Pir In Vacant State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); #endregion #region Analog /// /// Timeout /// [JoinName("Timeout")] public JoinDataComplete Timeout = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Timeout Local Feedback /// [JoinName("TimeoutLocalFeedback")] public JoinDataComplete TimeoutLocalFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Timeout Local Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Internal PhotoSensor Value /// [JoinName("InternalPhotoSensorValue")] public JoinDataComplete InternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Internal PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// External PhotoSensor Value /// [JoinName("UsSensitivityInOccupiedState")] public JoinDataComplete UsSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Us Sensitivity In Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Us Sensitivity In Vacant State /// [JoinName("UsSensitivityInVacantState")] public JoinDataComplete UsSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Us Sensitivity In Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Pir Sensitivity In Occupied State /// [JoinName("PirSensitivityInOccupiedState")] public JoinDataComplete PirSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Pir Sensitivity In Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Pir Sensitivity In Vacant State /// [JoinName("PirSensitivityInVacantState")] public JoinDataComplete PirSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Pir Sensitivity In Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); #endregion #region Serial /// /// Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); #endregion /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public CenOdtOccupancySensorBaseJoinMap(uint joinStart) : this(joinStart, typeof(CenOdtOccupancySensorBaseJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected CenOdtOccupancySensorBaseJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/DisplayControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a DisplayControllerJoinMap /// public class DisplayControllerJoinMap : JoinMapBaseAdvanced { /// /// Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Power Off /// [JoinName("PowerOff")] public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Power On /// [JoinName("PowerOn")] public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Is Two Way Display /// [JoinName("IsTwoWayDisplay")] public JoinDataComplete IsTwoWayDisplay = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Is Two Way Display", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Up /// [JoinName("VolumeUp")] public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Level /// [JoinName("VolumeLevel")] public JoinDataComplete VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Level", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Volume Down /// [JoinName("VolumeDown")] public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Mute /// [JoinName("VolumeMute")] public JoinDataComplete VolumeMute = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Mute", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Mute On /// [JoinName("VolumeMuteOn")] public JoinDataComplete VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Mute On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Mute Off /// [JoinName("VolumeMuteOff")] public JoinDataComplete VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Mute Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Input Select Offset /// [JoinName("InputSelectOffset")] public JoinDataComplete InputSelectOffset = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, new JoinMetadata { Description = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Input Names Offset /// [JoinName("InputNamesOffset")] public JoinDataComplete InputNamesOffset = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, new JoinMetadata { Description = "Input Names Offset", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Input Select /// [JoinName("InputSelect")] public JoinDataComplete InputSelect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Input Select", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Button Visibility Offset /// [JoinName("ButtonVisibilityOffset")] public JoinDataComplete ButtonVisibilityOffset = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 10 }, new JoinMetadata { Description = "Button Visibility Offset", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalSerial }); /// /// Is Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata { Description = "Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public DisplayControllerJoinMap(uint joinStart) : this(joinStart, typeof(DisplayControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected DisplayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmBladeChassisControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a DmBladeChassisControllerJoinMap /// public class DmBladeChassisControllerJoinMap : JoinMapBaseAdvanced { /// /// DM Blade Chassis Online status /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "DM Blade Chassis Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Blade Input Video Sync /// [JoinName("VideoSyncStatus")] public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Blade Chassis Input Endpoint Online /// [JoinName("InputEndpointOnline")] public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Blade Chassis Output Endpoint Online /// [JoinName("OutputEndpointOnline")] public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Blade Chassis Tx Advanced Is Present /// [JoinName("TxAdvancedIsPresent")] public JoinDataComplete TxAdvancedIsPresent = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Tx Advanced Is Present", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Blade Chassis Rx Advanced Is Present /// [JoinName("OutputVideo")] public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Output Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Blade Chassis Input HDCP Support State /// [JoinName("HdcpSupportState")] public JoinDataComplete HdcpSupportState = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Input HDCP Support State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// DM Blade Chassis Input HDCP Support Capability /// [JoinName("HdcpSupportCapability")] public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Blade Chassis Input Names /// [JoinName("InputNames")] public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Blade Chassis Output Names /// [JoinName("OutputNames")] public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Blade Chassis Video Output Currently Routed Video Input Name /// [JoinName("OutputCurrentVideoInputNames")] public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Blade Chassis Input Current Resolution /// [JoinName("InputCurrentResolution")] public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 128 }, new JoinMetadata { Description = "DM Blade Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public DmBladeChassisControllerJoinMap(uint joinStart) : this(joinStart, typeof(DmBladeChassisControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected DmBladeChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmChassisControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a DmChassisControllerJoinMap /// public class DmChassisControllerJoinMap : JoinMapBaseAdvanced { /// /// DM Chassis enable audio breakaway routing /// [JoinName("EnableAudioBreakaway")] public JoinDataComplete EnableAudioBreakaway = new JoinDataComplete( new JoinData {JoinNumber = 4, JoinSpan = 1}, new JoinMetadata { Description = "DM Chassis enable audio breakaway routing", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis enable USB breakaway routing /// [JoinName("EnableUsbBreakaway")] public JoinDataComplete EnableUsbBreakaway = new JoinDataComplete( new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "DM Chassis enable USB breakaway routing", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "DM Chassis Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis SystemId Get/Set/Trigger /// [JoinName("SystemId")] public JoinDataComplete SystemId = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata { Description = "DM Chassis SystemId Get/Set/Trigger/", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalAnalog }); /// /// DM Chassis Online status /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "DM Chassis Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Input Video Sync /// [JoinName("VideoSyncStatus")] public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, new JoinMetadata { Description = "DM Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Input Endpoint Online /// [JoinName("InputEndpointOnline")] public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Output Endpoint Online /// [JoinName("OutputEndpointOnline")] public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Tx Advanced Is Present /// [JoinName("TxAdvancedIsPresent")] public JoinDataComplete TxAdvancedIsPresent = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Tx Advanced Is Present", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Rx Advanced Is Present /// [JoinName("OutputDisabledByHdcp")] public JoinDataComplete OutputDisabledByHdcp = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Disabled by HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Output Set / Get /// [JoinName("OutputVideo")] public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Video Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Output Audio Set / Get /// [JoinName("OutputAudio")] public JoinDataComplete OutputAudio = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Audio Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Input Set / Get /// [JoinName("OutputUsb")] public JoinDataComplete OutputUsb = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output USB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Input Set / Get /// [JoinName("InputUsb")] public JoinDataComplete InputUsb = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input Usb Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Input HDCP Support State /// [JoinName("HdcpSupportState")] public JoinDataComplete HdcpSupportState = new JoinDataComplete(new JoinData { JoinNumber = 1001, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input HDCP Support State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Input HDCP Support Capability /// [JoinName("HdcpSupportCapability")] public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Stream Input Start (1), Stop (2), Pause (3) with Feedback /// [JoinName("InputStreamCardState")] public JoinDataComplete InputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1501, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Stream Input Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Stream Output Start (1), Stop (2), Pause (3) with Feedback /// [JoinName("OutputStreamCardState")] public JoinDataComplete OutputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1601, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Stream Output Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis No Route Name /// [JoinName("NoRouteName")] public JoinDataComplete NoRouteName = new JoinDataComplete(new JoinData { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Input Names /// [JoinName("InputNames")] public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Output Names /// [JoinName("OutputNames")] public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Video Input Names /// [JoinName("InputVideoNames")] public JoinDataComplete InputVideoNames = new JoinDataComplete(new JoinData {JoinNumber = 501, JoinSpan = 200}, new JoinMetadata { Description = "DM Chassis Video Input Names", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Audio Input Names /// [JoinName("InputAudioNames")] public JoinDataComplete InputAudioNames = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 200 }, new JoinMetadata { Description = "DM Chassis Audio Input Names", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Video Output Names /// [JoinName("OutputVideoNames")] public JoinDataComplete OutputVideoNames = new JoinDataComplete(new JoinData { JoinNumber = 901, JoinSpan = 200 }, new JoinMetadata { Description = "DM Chassis Video Output Names", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Audio Output Names /// [JoinName("OutputAudioNames")] public JoinDataComplete OutputAudioNames = new JoinDataComplete(new JoinData { JoinNumber = 1101, JoinSpan = 200 }, new JoinMetadata { Description = "DM Chassis Audio Output Names", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Video Output Currently Routed Video Input Name /// [JoinName("OutputCurrentVideoInputNames")] public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Audio Output Currently Routed Audio Input Name /// [JoinName("OutputCurrentAudioInputNames")] public JoinDataComplete OutputCurrentAudioInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2201, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Audio Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Input Current Resolution /// [JoinName("InputCurrentResolution")] public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public DmChassisControllerJoinMap(uint joinStart) : this(joinStart, typeof(DmChassisControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected DmChassisControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmRmcControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a DmRmcControllerJoinMap /// public class DmRmcControllerJoinMap : JoinMapBaseAdvanced { /// /// DM RMC Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM RMC Mute Video /// [JoinName("VideoMuteOn")] public JoinDataComplete VideoMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC Mute Video", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// DM RMC UnMute Video /// [JoinName("VideoMuteOff")] public JoinDataComplete VideoMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC UnMute Video", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// DM RMC Mute Video Toggle /// [JoinName("VideoMuteToggle")] public JoinDataComplete VideoMuteToggle = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC Mute Video Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DM RMC Current Output Resolution /// [JoinName("CurrentOutputResolution")] public JoinDataComplete CurrentOutputResolution = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC Current Output Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM RMC EDID Manufacturer /// [JoinName("EdidManufacturer")] public JoinDataComplete EdidManufacturer = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC EDID Manufacturer", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM RMC EDID Name /// [JoinName("EdidName")] public JoinDataComplete EdidName = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC EDID Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM RMC EDID Preferred Timing /// [JoinName("EdidPrefferedTiming")] public JoinDataComplete EdidPrefferedTiming = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC EDID Preferred Timing", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM RMC EDID Serial Number /// [JoinName("EdidSerialNumber")] public JoinDataComplete EdidSerialNumber = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC EDID Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM RMC Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM RMC Audio Video Source Set / Get /// [JoinName("AudioVideoSource")] public JoinDataComplete AudioVideoSource = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC Audio Video Source Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM RMC HDCP Support Capability /// [JoinName("HdcpSupportCapability")] public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC HDCP Support Capability", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// DM RMC Port 1 (DM) HDCP State Set / Get /// [JoinName("Port1HdcpState")] public JoinDataComplete Port1HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC Port 1 (DM) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM RMC Port 2 (HDMI) HDCP State Set / Get /// [JoinName("Port2HdcpState")] public JoinDataComplete Port2HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC Port 2 (HDMI) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM RMC HDMI Input Sync /// [JoinName("HdmiInputSync")] public JoinDataComplete HdmiInputSync = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "DM RMC HDMI Input Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM RMC Number of Input Ports that support HDCP /// [JoinName("HdcpInputPortCount")] public JoinDataComplete HdcpInputPortCount = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Number of Input Ports that support HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public DmRmcControllerJoinMap(uint joinStart) : this(joinStart, typeof(DmRmcControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected DmRmcControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmTxControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a DmTxControllerJoinMap /// public class DmTxControllerJoinMap : JoinMapBaseAdvanced { /// /// DM TX Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM TX Video Sync /// [JoinName("VideoSyncStatus")] public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM TX Enable Free Run Set / Get /// [JoinName("FreeRunEnabled")] public JoinDataComplete FreeRunEnabled = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Enable Free Run Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Input 1 Video Sync Status /// [JoinName("Input1VideoSyncStatus")] public JoinDataComplete Input1VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Input 1 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Input 2 Video Sync Status /// [JoinName("Input2VideoSyncStatus")] public JoinDataComplete Input2VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Input 2 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Input 3 Video Sync Status /// [JoinName("Input3VideoSyncStatus")] public JoinDataComplete Input3VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Input 3 Video Sync Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM TX Current Input Resolution /// [JoinName("CurrentInputResolution")] public JoinDataComplete CurrentInputResolution = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Current Input Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM TX Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM TX Video Input Set / Get /// [JoinName("VideoInput")] public JoinDataComplete VideoInput = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Video Input Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM TX Audio Input Set / Get /// [JoinName("AudioInput")] public JoinDataComplete AudioInput = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Audio Input Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM TX HDCP Support Capability /// [JoinName("HdcpSupportCapability")] public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX HDCP Support Capability", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// DM TX Port 1 HDCP State Set / Get /// [JoinName("Port1HdcpState")] public JoinDataComplete Port1HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Port 1 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM TX Port 2 HDCP State Set / Get /// [JoinName("Port2HdcpState")] public JoinDataComplete Port2HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Port 2 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM TX VGA Brightness /// [JoinName("VgaBrightness")] public JoinDataComplete VgaBrightness = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX VGA Brightness", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM TX VGA Contrast /// [JoinName("VgaContrast")] public JoinDataComplete VgaContrast = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM TX Port 3 HDCP State Set / Get /// [JoinName("Port3HdcpState")] public JoinDataComplete Port3HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "DM TX Port 3 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM TX Number of Input Ports that support HDCP /// [JoinName("HdcpInputPortCount")] public JoinDataComplete HdcpInputPortCount = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "Number of Input Ports that support HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public DmTxControllerJoinMap(uint joinStart) : this(joinStart, typeof(DmTxControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected DmTxControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsAudioOutputControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a DmpsAudioOutputControllerJoinMap /// public class DmpsAudioOutputControllerJoinMap : JoinMapBaseAdvanced { /// /// Master Volume Level Signed dB Set / Get /// [JoinName("MasterVolumeLevel")] public JoinDataComplete MasterVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Master Volume 16bit Scaled Set / Get /// [JoinName("MasterVolumeLevelScaled")] public JoinDataComplete MasterVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Mixer Preset Recall Set /// [JoinName("MixerPresetRecall")] public JoinDataComplete MixerPresetRecall = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Mixer Preset Recall Set", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// Mixer Eq Preset Recall Set /// [JoinName("MixerEqPresetRecall")] public JoinDataComplete MixerEqPresetRecall = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Mixer Eq Preset Recall Set", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// Master Volume Mute On Set / Get /// [JoinName("MasterVolumeMuteOn")] public JoinDataComplete MasterVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Master Volume Mute Off Set / Get /// [JoinName("MasterVolumeMuteOff")] public JoinDataComplete MasterVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Master Volume Level Up /// [JoinName("MasterVolumeUp")] public JoinDataComplete MasterVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Master Volume Level Down /// [JoinName("MasterVolumeDown")] public JoinDataComplete MasterVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Master Volume Scaled Send Enable/Disable /// [JoinName("MasterVolumeLevelScaledSend")] public JoinDataComplete MasterVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Source Volume Signed dB Set / Get /// [JoinName("SourceVolumeLevel")] public JoinDataComplete SourceVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Source Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Source Volume 16bit Scaled Set / Get /// [JoinName("SourceVolumeLevelScaled")] public JoinDataComplete SourceVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Source Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Source Volume Mute On Set / Get /// [JoinName("SourceVolumeMuteOn")] public JoinDataComplete SourceVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Source Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Source Volume Mute Off Set / Get /// [JoinName("SourceVolumeMuteOff")] public JoinDataComplete SourceVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Source Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Source Volume Level Up /// [JoinName("SourceVolumeUp")] public JoinDataComplete SourceVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "Source Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Source Volume Level Down /// [JoinName("SourceVolumeDown")] public JoinDataComplete SourceVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "Source Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Source Volume Scaled Send Enable/Disable /// [JoinName("SourceVolumeLevelScaledSend")] public JoinDataComplete SourceVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "Source Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec1 Volume Signed dB Set / Get /// [JoinName("Codec1VolumeLevel")] public JoinDataComplete Codec1VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "Codec1 Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Codec1 Volume 16bit Scaled Set / Get /// [JoinName("Codec1VolumeLevelScaled")] public JoinDataComplete Codec1VolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "Codec1 Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Codec1 Volume Mute On Set / Get /// [JoinName("Codec1VolumeMuteOn")] public JoinDataComplete Codec1VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "Codec1 Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec1 Volume Mute Off Set / Get /// [JoinName("Codec1VolumeMuteOff")] public JoinDataComplete Codec1VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "Codec1 Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec1 Volume Level Up /// [JoinName("Codec1VolumeUp")] public JoinDataComplete Codec1VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, new JoinMetadata { Description = "Codec1 Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec1 Volume Level Down /// [JoinName("Codec1VolumeDown")] public JoinDataComplete Codec1VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "Codec1 Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec1 Volume Scaled Send Enable/Disable /// [JoinName("Codec1VolumeLevelScaledSend")] public JoinDataComplete Codec1VolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, new JoinMetadata { Description = "Codec1 Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec2 Volume Signed dB Set / Get /// [JoinName("Codec2VolumeLevel")] public JoinDataComplete Codec2VolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata { Description = "Codec2 Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Codec2 Volume 16bit Scaled Set / Get /// [JoinName("Codec2VolumeLevelScaled")] public JoinDataComplete Codec2VolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, new JoinMetadata { Description = "Codec2 Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Codec2 Volume Mute On Set / Get /// [JoinName("Codec2VolumeMuteOn")] public JoinDataComplete Codec2VolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata { Description = "Codec2 Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec2 Volume Mute Off Set / Get /// [JoinName("Codec2VolumeMuteOff")] public JoinDataComplete Codec2VolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, new JoinMetadata { Description = "Codec2 Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec2 Volume Level Up /// [JoinName("Codec2VolumeUp")] public JoinDataComplete Codec2VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, new JoinMetadata { Description = "Codec2 Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec2 Volume Level Down /// [JoinName("Codec2VolumeDown")] public JoinDataComplete Codec2VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, new JoinMetadata { Description = "Codec2 Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Codec2 Volume Scaled Send Enable/Disable /// [JoinName("Codec2VolumeLevelScaledSend")] public JoinDataComplete Codec2VolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, new JoinMetadata { Description = "Codec2 Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// MicsMaster Volume Signed dB Set / Get /// [JoinName("MicsMasterVolumeLevel")] public JoinDataComplete MicsMasterVolumeLevel = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "MicsMaster Volume Signed dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// MicsMaster Volume 16bit Scaled Set / Get /// [JoinName("MicsMasterVolumeLevelScaled")] public JoinDataComplete MicsMasterVolumeLevelScaled = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "MicsMaster Volume 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// MicsMaster Volume Mute On Set / Get /// [JoinName("MicsMasterVolumeMuteOn")] public JoinDataComplete MicsMasterVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "MicsMaster Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// MicsMaster Volume Mute Off Set / Get /// [JoinName("MicsMasterVolumeMuteOff")] public JoinDataComplete MicsMasterVolumeMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "MicsMaster Volume Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// MicsMaster Volume Level Up /// [JoinName("MicsMasterVolumeUp")] public JoinDataComplete MicsMasterVolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, new JoinMetadata { Description = "MicsMaster Volume Level Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// MicsMaster Volume Level Down /// [JoinName("MicsMasterVolumeDown")] public JoinDataComplete MicsMasterVolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 44, JoinSpan = 1 }, new JoinMetadata { Description = "MicsMaster Volume Level Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// MicsMaster Volume Scaled Send Enable/Disable /// [JoinName("MicsMasterVolumeLevelScaledSend")] public JoinDataComplete MicsMasterVolumeLevelScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 45, JoinSpan = 1 }, new JoinMetadata { Description = "Mics Master Volume Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public DmpsAudioOutputControllerJoinMap(uint joinStart) : this(joinStart, typeof(DmpsAudioOutputControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected DmpsAudioOutputControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsMicrophoneControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a DmpsMicrophoneControllerJoinMap /// public class DmpsMicrophoneControllerJoinMap : JoinMapBaseAdvanced { /// /// Mic Gain dB Set / Get /// [JoinName("MicGain")] public JoinDataComplete MicGain = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Gain dB Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Mic Gain 16bit Scaled Set / Get /// [JoinName("MicGainScaled")] public JoinDataComplete MicGainScaled = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Gain 16bit Scaled Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Mic Mute On Set / Get /// [JoinName("MicMuteOn")] public JoinDataComplete MicMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Mic Mute Off Set / Get /// [JoinName("MicMuteOff")] public JoinDataComplete MicMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Mute Off Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Mic Gain Scaled Send Enable/Disable /// [JoinName("MicGainScaledSend")] public JoinDataComplete MicGainScaledSend = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Gain Scaled Send Enable/Disable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Mic Name Get /// [JoinName("MicName")] public JoinDataComplete MicName = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Name Get", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public DmpsMicrophoneControllerJoinMap(uint joinStart) : this(joinStart, typeof(DmpsMicrophoneControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected DmpsMicrophoneControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/DmpsRoutingControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a DmpsRoutingControllerJoinMap /// public class DmpsRoutingControllerJoinMap : JoinMapBaseAdvanced { /// /// DMPS Enable Audio and Video Routing /// [JoinName("EnableRouting")] public JoinDataComplete EnableRouting = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "DMPS Enable Audio and Video Routing", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DMPS Disable Audio and Video Routing /// [JoinName("SystemPowerOn")] public JoinDataComplete SystemPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "DMPS System Power On Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// DMPS Disable Audio and Video Routing /// [JoinName("SystemPowerOff")] public JoinDataComplete SystemPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "DMPS System Power Off Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// DMPS Front Panel Lock On Get/Set /// [JoinName("FrontPanelLockOn")] public JoinDataComplete FrontPanelLockOn = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "DMPS Front Panel Lock On Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// DMPS Front Panel Lock Off Get/Set /// [JoinName("FrontPanelLockOff")] public JoinDataComplete FrontPanelLockOff = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "DMPS Front Panel Lock Off Get/Set", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// DM Input Video Sync /// [JoinName("VideoSyncStatus")] public JoinDataComplete VideoSyncStatus = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, new JoinMetadata { Description = "DM Input Video Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Input Endpoint Online /// [JoinName("InputEndpointOnline")] public JoinDataComplete InputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Output Endpoint Online /// [JoinName("OutputEndpointOnline")] public JoinDataComplete OutputEndpointOnline = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Endpoint Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DM Chassis Input Video Set / Get /// [JoinName("OutputVideo")] public JoinDataComplete OutputVideo = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Video Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Input Audio Set / Get /// [JoinName("OutputAudio")] public JoinDataComplete OutputAudio = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Audio Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// DM Chassis Input Name /// [JoinName("InputNames")] public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Output Name /// [JoinName("OutputNames")] public JoinDataComplete OutputNames = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Video Input Name /// [JoinName("InputVideoNames")] public JoinDataComplete InputVideoNames = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Audio Input Name /// [JoinName("InputAudioNames")] public JoinDataComplete InputAudioNames = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 32 }, new JoinMetadata { Description = "Audio Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Video Output Name /// [JoinName("OutputVideoNames")] public JoinDataComplete OutputVideoNames = new JoinDataComplete(new JoinData { JoinNumber = 901, JoinSpan = 32 }, new JoinMetadata { Description = "Video Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Audio Output Name /// [JoinName("OutputAudioNames")] public JoinDataComplete OutputAudioNames = new JoinDataComplete(new JoinData { JoinNumber = 1101, JoinSpan = 32 }, new JoinMetadata { Description = "Audio Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Video Output Currently Routed Video Input Name /// [JoinName("OutputCurrentVideoInputNames")] public JoinDataComplete OutputCurrentVideoInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2001, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Video Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Audio Output Currently Routed Video Input Name /// [JoinName("OutputCurrentAudioInputNames")] public JoinDataComplete OutputCurrentAudioInputNames = new JoinDataComplete(new JoinData { JoinNumber = 2201, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Audio Output Currently Routed Video Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// DM Chassis Input Current Resolution /// [JoinName("InputCurrentResolution")] public JoinDataComplete InputCurrentResolution = new JoinDataComplete(new JoinData { JoinNumber = 2401, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input Current Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public DmpsRoutingControllerJoinMap(uint joinStart) : this(joinStart, typeof(DmpsRoutingControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected DmpsRoutingControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericIrControllerJoinMap.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Bridges.JoinMaps { /// /// Represents a GenericIrControllerJoinMap /// public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced { /// /// PLAY /// [JoinName("PLAY")] public JoinDataComplete Play = new JoinDataComplete( new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "PLAY", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STOP /// [JoinName("STOP")] public JoinDataComplete Stop = new JoinDataComplete( new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "STOP", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// PAUSE /// [JoinName("PAUSE")] public JoinDataComplete Pause = new JoinDataComplete( new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "PAUSE", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// FSCAN /// [JoinName("FSCAN")] public JoinDataComplete ForwardScan = new JoinDataComplete( new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "FSCAN", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// RSCAN /// [JoinName("RSCAN")] public JoinDataComplete ReverseScan = new JoinDataComplete( new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "RSCAN", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// F_SKIP /// [JoinName("F_SKIP")] public JoinDataComplete ForwardSkip = new JoinDataComplete( new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "F_SKIP", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// R_SKIP /// [JoinName("R_SKIP")] public JoinDataComplete ReverseSkip = new JoinDataComplete( new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "R_SKIP", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// RECORD /// [JoinName("RECORD")] public JoinDataComplete Record = new JoinDataComplete( new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "RECORD", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// POWER /// [JoinName("POWER")] public JoinDataComplete Power = new JoinDataComplete( new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "POWER", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 0 /// [JoinName("0")] public JoinDataComplete Kp0 = new JoinDataComplete( new JoinData { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata { Description = "0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 1 /// [JoinName("1")] public JoinDataComplete Kp1 = new JoinDataComplete( new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 2 /// [JoinName("2")] public JoinDataComplete Kp2 = new JoinDataComplete( new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 3 /// [JoinName("3")] public JoinDataComplete Kp3 = new JoinDataComplete( new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 4 /// [JoinName("4")] public JoinDataComplete Kp4 = new JoinDataComplete( new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 5 /// [JoinName("5")] public JoinDataComplete Kp5 = new JoinDataComplete( new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 6 /// [JoinName("6")] public JoinDataComplete Kp6 = new JoinDataComplete( new JoinData { JoinNumber = 16, JoinSpan = 1 }, new JoinMetadata { Description = "6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 7 /// [JoinName("7")] public JoinDataComplete Kp7 = new JoinDataComplete( new JoinData { JoinNumber = 17, JoinSpan = 1 }, new JoinMetadata { Description = "7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 8 /// [JoinName("8")] public JoinDataComplete Kp8 = new JoinDataComplete( new JoinData { JoinNumber = 18, JoinSpan = 1 }, new JoinMetadata { Description = "8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// 9 /// [JoinName("9")] public JoinDataComplete Kp9 = new JoinDataComplete( new JoinData { JoinNumber = 19, JoinSpan = 1 }, new JoinMetadata { Description = "9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); // [JoinName("+10")] // public JoinDataComplete Kp9 = new JoinDataComplete( // new JoinData // { // JoinNumber = 20, // JoinSpan = 1 // }, // new JoinMetadata // { // Description = "+10", // JoinCapabilities = eJoinCapabilities.FromSIMPL, // JoinType = eJoinType.Digital // }); /// /// ENTER /// [JoinName("ENTER")] public JoinDataComplete Enter = new JoinDataComplete( new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "ENTER", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// CH+ /// [JoinName("CH+")] public JoinDataComplete ChannelUp = new JoinDataComplete( new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "CH+", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// CH- /// [JoinName("CH-")] public JoinDataComplete ChannelDown = new JoinDataComplete( new JoinData { JoinNumber = 23, JoinSpan = 1 }, new JoinMetadata { Description = "CH-", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// * /// [JoinName("*")] public JoinDataComplete KpStar = new JoinDataComplete( new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "*", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// # /// [JoinName("#")] public JoinDataComplete KpPound = new JoinDataComplete( new JoinData { JoinNumber = 25, JoinSpan = 1 }, new JoinMetadata { Description = "#", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); // [JoinName(".")] // public JoinDataComplete KpPound = new JoinDataComplete( // new JoinData // { // JoinNumber = 26, // JoinSpan = 1 // }, // new JoinMetadata // { // Description = ".", // JoinCapabilities = eJoinCapabilities.FromSIMPL, // JoinType = eJoinType.Digital // }); /// /// POWER_ON /// [JoinName("POWER_ON")] public JoinDataComplete PowerOn = new JoinDataComplete( new JoinData { JoinNumber = 27, JoinSpan = 1 }, new JoinMetadata { Description = "POWER_ON", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// POWER_OFF /// [JoinName("POWER_OFF")] public JoinDataComplete PowerOff = new JoinDataComplete( new JoinData { JoinNumber = 28, JoinSpan = 1 }, new JoinMetadata { Description = "POWER_OFF", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// PLAY_PAUSE /// [JoinName("PLAY_PAUSE")] public JoinDataComplete PlayPause = new JoinDataComplete( new JoinData { JoinNumber = 29, JoinSpan = 1 }, new JoinMetadata { Description = "PLAY_PAUSE", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// LAST /// [JoinName("LAST")] public JoinDataComplete Last = new JoinDataComplete( new JoinData { JoinNumber = 30, JoinSpan = 1 }, new JoinMetadata { Description = "LAST", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// HOME /// [JoinName("HOME")] public JoinDataComplete Home = new JoinDataComplete( new JoinData { JoinNumber = 40, JoinSpan = 1 }, new JoinMetadata { Description = "HOME", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// BACK /// [JoinName("BACK")] public JoinDataComplete Back = new JoinDataComplete( new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "BACK", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// GUIDE /// [JoinName("GUIDE")] public JoinDataComplete Guide = new JoinDataComplete( new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "GUIDE", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// INFO /// [JoinName("INFO")] public JoinDataComplete Info = new JoinDataComplete( new JoinData { JoinNumber = 43, JoinSpan = 1 }, new JoinMetadata { Description = "INFO", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// MENU /// [JoinName("MENU")] public JoinDataComplete Menu = new JoinDataComplete( new JoinData { JoinNumber = 44, JoinSpan = 1 }, new JoinMetadata { Description = "MENU", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// UP_ARROW /// [JoinName("UP_ARROW")] public JoinDataComplete DpadUp = new JoinDataComplete( new JoinData { JoinNumber = 45, JoinSpan = 1 }, new JoinMetadata { Description = "UP_ARROW", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DN_ARROW /// [JoinName("DN_ARROW")] public JoinDataComplete DpadDown = new JoinDataComplete( new JoinData { JoinNumber = 46, JoinSpan = 1 }, new JoinMetadata { Description = "DN_ARROW", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// LEFT_ARROW /// [JoinName("LEFT_ARROW")] public JoinDataComplete DpadLeft = new JoinDataComplete( new JoinData { JoinNumber = 47, JoinSpan = 1 }, new JoinMetadata { Description = "LEFT_ARROW", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// RIGHT_ARROW /// [JoinName("RIGHT_ARROW")] public JoinDataComplete DpadRight = new JoinDataComplete( new JoinData { JoinNumber = 48, JoinSpan = 1 }, new JoinMetadata { Description = "RIGHT_ARROW", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// SELECT /// [JoinName("SELECT")] public JoinDataComplete DpadSelect = new JoinDataComplete( new JoinData { JoinNumber = 49, JoinSpan = 1 }, new JoinMetadata { Description = "SELECT", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// OPTIONS /// [JoinName("OPTIONS")] public JoinDataComplete Options = new JoinDataComplete( new JoinData { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata { Description = "OPTIONS", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// RETURN /// [JoinName("RETURN")] public JoinDataComplete Return = new JoinDataComplete( new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "RETURN", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DVR /// [JoinName("DVR")] public JoinDataComplete Dvr = new JoinDataComplete( new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "DVR", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// ON_DEMAND /// [JoinName("ON_DEMAND")] public JoinDataComplete OnDemand = new JoinDataComplete( new JoinData { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata { Description = "ON_DEMAND", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// PAGE_UP /// [JoinName("PAGE_UP")] public JoinDataComplete PageUp = new JoinDataComplete( new JoinData { JoinNumber = 54, JoinSpan = 1 }, new JoinMetadata { Description = "PAGE_UP", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// PAGE_DOWN /// [JoinName("PAGE_DOWN")] public JoinDataComplete PageDown = new JoinDataComplete( new JoinData { JoinNumber = 55, JoinSpan = 1 }, new JoinMetadata { Description = "PAGE_DOWN", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// F_SRCH /// [JoinName("F_SRCH")] public JoinDataComplete ForwardSearch = new JoinDataComplete( new JoinData { JoinNumber = 56, JoinSpan = 1 }, new JoinMetadata { Description = "F_SRCH", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// R_SRCH /// [JoinName("R_SRCH")] public JoinDataComplete ReverseSearch = new JoinDataComplete( new JoinData { JoinNumber = 57, JoinSpan = 1 }, new JoinMetadata { Description = "R_SRCH", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// TRACK+ /// [JoinName("TRACK+")] public JoinDataComplete TrackPlus = new JoinDataComplete( new JoinData { JoinNumber = 58, JoinSpan = 1 }, new JoinMetadata { Description = "TRACK+", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// TRACK- /// [JoinName("TRACK-")] public JoinDataComplete TrackMinus = new JoinDataComplete( new JoinData { JoinNumber = 59, JoinSpan = 1 }, new JoinMetadata { Description = "TRACK-", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// A /// [JoinName("A")] public JoinDataComplete KpA = new JoinDataComplete( new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "A", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// B /// [JoinName("B")] public JoinDataComplete KpB = new JoinDataComplete( new JoinData { JoinNumber = 62, JoinSpan = 1 }, new JoinMetadata { Description = "B", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// C /// [JoinName("C")] public JoinDataComplete KpC = new JoinDataComplete( new JoinData { JoinNumber = 63, JoinSpan = 1 }, new JoinMetadata { Description = "C", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// D /// [JoinName("D")] public JoinDataComplete KpD = new JoinDataComplete( new JoinData { JoinNumber = 64, JoinSpan = 1 }, new JoinMetadata { Description = "D", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// RED /// [JoinName("RED")] public JoinDataComplete KpRed = new JoinDataComplete( new JoinData { JoinNumber = 65, JoinSpan = 1 }, new JoinMetadata { Description = "RED", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// GREEN /// [JoinName("GREEN")] public JoinDataComplete KpGreen = new JoinDataComplete( new JoinData { JoinNumber = 66, JoinSpan = 1 }, new JoinMetadata { Description = "GREEN", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// YELLOW /// [JoinName("YELLOW")] public JoinDataComplete KpYellow = new JoinDataComplete( new JoinData { JoinNumber = 67, JoinSpan = 1 }, new JoinMetadata { Description = "YELLOW", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// BLUE /// [JoinName("BLUE")] public JoinDataComplete KpBlue = new JoinDataComplete( new JoinData { JoinNumber = 68, JoinSpan = 1 }, new JoinMetadata { Description = "BLUE", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor /// /// Join this join map will start at public GenericIrControllerJoinMap(uint joinStart) : base(joinStart, typeof(GenericIrControllerJoinMap)) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericLightingJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a GenericLightingJoinMap /// public class GenericLightingJoinMap : JoinMapBaseAdvanced { /// /// Lighting Controller Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Lighting Controller Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Select Scene By Index /// [JoinName("SelectScene")] public JoinDataComplete SelectScene = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Lighting Controller Select Scene By Index", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Select Scene Direct /// [JoinName("SelectSceneDirect")] public JoinDataComplete SelectSceneDirect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 10 }, new JoinMetadata { Description = "Lighting Controller Select Scene", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalSerial }); /// /// Button Visibility /// [JoinName("ButtonVisibility")] public JoinDataComplete ButtonVisibility = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 10 }, new JoinMetadata { Description = "Lighting Controller Button Visibility", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Set Integration Id /// [JoinName("IntegrationIdSet")] public JoinDataComplete IntegrationIdSet = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Lighting Controller Set Integration Id", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public GenericLightingJoinMap(uint joinStart) : this(joinStart, typeof(GenericLightingJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected GenericLightingJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/GenericRelayControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a GenericRelayControllerJoinMap /// public class GenericRelayControllerJoinMap : JoinMapBaseAdvanced { /// /// Device Relay State Set / Get /// [JoinName("Relay")] public JoinDataComplete Relay = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Device Relay State Set / Get", 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 GenericRelayControllerJoinMap(uint joinStart) : this(joinStart, typeof(GenericRelayControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected GenericRelayControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsOccupancySensorBaseJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a GlsOccupancySensorBaseJoinMap /// public class GlsOccupancySensorBaseJoinMap : JoinMapBaseAdvanced { /// /// Occ Sensor Is Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Set to Occupied /// [JoinName("ForceOccupied")] public JoinDataComplete ForceOccupied = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Set to Occupied", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Set to Vacant /// [JoinName("ForceVacant")] public JoinDataComplete ForceVacant = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Set to Vacant", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Enable Raw /// [JoinName("EnableRawStates")] public JoinDataComplete EnableRawStates = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Enable Raw", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Disable Raw /// [JoinName("RoomOccupiedFeedback")] public JoinDataComplete RoomOccupiedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Room Is Occupied", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Grace Occupancy Detected /// [JoinName("GraceOccupancyDetectedFeedback")] public JoinDataComplete GraceOccupancyDetectedFeedback = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Grace Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Room Is Vacant /// [JoinName("RoomVacantFeedback")] public JoinDataComplete RoomVacantFeedback = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Room Is Vacant", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Raw Occupancy Detected /// [JoinName("RawOccupancyFeedback")] public JoinDataComplete RawOccupancyFeedback = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Raw Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Raw PIR Occupancy Detected /// [JoinName("RawOccupancyPirFeedback")] public JoinDataComplete RawOccupancyPirFeedback = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Raw PIR Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Raw US Occupancy Detected /// [JoinName("RawOccupancyUsFeedback")] public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Raw US Occupancy Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Enable LED Flash /// [JoinName("EnableLedFlash")] public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Enable LED Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Disable LED Flash /// [JoinName("DisableLedFlash")] public JoinDataComplete DisableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Disable LED Flash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Enable Short Timeout /// [JoinName("EnableShortTimeout")] public JoinDataComplete EnableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Enable Short Timeout", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Disable Short Timeout /// [JoinName("DisableShortTimeout")] public JoinDataComplete DisableShortTimeout = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Disable Short Timeout", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Set To Vacant when Either Sensor is Vacant /// [JoinName("OrWhenVacated")] public JoinDataComplete OrWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Set To Vacant when Either Sensor is Vacant", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Set To Vacant when Both Sensors are Vacant /// [JoinName("AndWhenVacated")] public JoinDataComplete AndWhenVacated = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Set To Vacant when Both Sensors are Vacant", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Enable Ultrasonic Sensor A /// [JoinName("EnableUsA")] public JoinDataComplete EnableUsA = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Enable Ultrasonic Sensor A", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Disable Ultrasonic Sensor A /// [JoinName("DisableUsA")] public JoinDataComplete DisableUsA = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Disable Ultrasonic Sensor A", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Enable Ultrasonic Sensor B /// [JoinName("EnableUsB")] public JoinDataComplete EnableUsB = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Enable Ultrasonic Sensor B", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Disable Ultrasonic Sensor B /// [JoinName("DisableUsB")] public JoinDataComplete DisableUsB = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Disable Ultrasonic Sensor B", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Enable IR Sensor /// [JoinName("EnablePir")] public JoinDataComplete EnablePir = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Enable IR Sensor", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Disable IR Sensor /// [JoinName("DisablePir")] public JoinDataComplete DisablePir = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Disable IR Sensor", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Increment US Occupied State Sensitivity /// [JoinName("IncrementUsInOccupiedState")] public JoinDataComplete IncrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Increment US Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Decrement US Occupied State Sensitivity /// [JoinName("DecrementUsInOccupiedState")] public JoinDataComplete DecrementUsInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Decrement US Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Increment US Vacant State Sensitivity /// [JoinName("IncrementUsInVacantState")] public JoinDataComplete IncrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Increment US Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Decrement US Vacant State Sensitivity /// [JoinName("DecrementUsInVacantState")] public JoinDataComplete DecrementUsInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Decrement US Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Increment IR Occupied State Sensitivity /// [JoinName("IncrementPirInOccupiedState")] public JoinDataComplete IncrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Increment IR Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Decrement IR Occupied State Sensitivity /// [JoinName("DecrementPirInOccupiedState")] public JoinDataComplete DecrementPirInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Decrement IR Occupied State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Increment IR Vacant State Sensitivity /// [JoinName("IncrementPirInVacantState")] public JoinDataComplete IncrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Increment IR Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Decrement IR Vacant State Sensitivity /// [JoinName("DecrementPirInVacantState")] public JoinDataComplete DecrementPirInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Decrement IR Vacant State Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Occ Sensor Timeout Value /// [JoinName("Timeout")] public JoinDataComplete Timeout = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Timeout Value", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Occ Sensor Local Timeout Value /// [JoinName("TimeoutLocalFeedback")] public JoinDataComplete TimeoutLocalFeedback = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Local Timeout Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Occ Sensor Internal PhotoSensor Value /// [JoinName("InternalPhotoSensorValue")] public JoinDataComplete InternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Internal PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Occ Sensor External PhotoSensor Value /// [JoinName("ExternalPhotoSensorValue")] public JoinDataComplete ExternalPhotoSensorValue = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor External PhotoSensor Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Occ Sensor Ultrasonic Sensitivity in Occupied State /// [JoinName("UsSensitivityInOccupiedState")] public JoinDataComplete UsSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Ultrasonic Sensitivity in Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Occ Sensor Ultrasonic Sensitivity in Vacant State /// [JoinName("UsSensitivityInVacantState")] public JoinDataComplete UsSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Ultrasonic Sensitivity in Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Occ Sensor PIR Sensitivity in Occupied State /// [JoinName("PirSensitivityInOccupiedState")] public JoinDataComplete PirSensitivityInOccupiedState = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor PIR Sensitivity in Occupied State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Occ Sensor PIR Sensitivity in Vacant State /// [JoinName("PirSensitivityInVacantState")] public JoinDataComplete PirSensitivityInVacantState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor PIR Sensitivity in Vacant State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Occ Sensor Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Occ Sensor Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public GlsOccupancySensorBaseJoinMap(uint joinStart) : this(joinStart, typeof(GlsOccupancySensorBaseJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected GlsOccupancySensorBaseJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs ================================================ using System; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Bridges.JoinMaps { /// /// Represents a GlsPartitionSensorJoinMap /// public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced { #region Digital /// /// Sensor Is Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete( new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Sensor Is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Sensor Enable /// [JoinName("Enable")] public JoinDataComplete Enable = new JoinDataComplete( new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Sensor Enable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Sensor Partition Sensed /// [JoinName("PartitionSensed")] public JoinDataComplete PartitionSensed = new JoinDataComplete( new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Sensor Partition Sensed", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Sensor Partition Not Sensed /// [JoinName("PartitionNotSensed")] public JoinDataComplete PartitionNotSensed = new JoinDataComplete( new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Sensor Partition Not Sensed", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Sensor Increase Sensitivity /// [JoinName("IncreaseSensitivity")] public JoinDataComplete IncreaseSensitivity = new JoinDataComplete( new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Sensor Increase Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Sensor Decrease Sensitivity /// [JoinName("DecreaseSensitivity")] public JoinDataComplete DecreaseSensitivity = new JoinDataComplete( new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Sensor Decrease Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); #endregion #region Analog /// /// Sensor Sensitivity /// [JoinName("Sensitivity")] public JoinDataComplete Sensitivity = new JoinDataComplete( new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Sensor Sensitivity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); #endregion #region Serial /// /// Sensor Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete( new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Sensor Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); #endregion /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public GlsPartitionSensorJoinMap(uint joinStart) : this(joinStart, typeof(GlsPartitionSensorJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected GlsPartitionSensorJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdNxM4kEControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a HdMdNxM4kEControllerJoinMap /// public class HdMdNxM4kEControllerJoinMap : JoinMapBaseAdvanced { /// /// Device Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Device Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Enable Automatic Routing on 4x1 Switchers /// [JoinName("EnableAutoRoute")] public JoinDataComplete EnableAutoRoute = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Automatic Routing on 4x1 Switchers", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Device Input Name /// [JoinName("InputName")] public JoinDataComplete InputName = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, new JoinMetadata { Description = "Device Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Device Input Sync /// [JoinName("InputSync")] public JoinDataComplete InputSync = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, new JoinMetadata { Description = "Device Input Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Device Output Name /// [JoinName("OutputName")] public JoinDataComplete OutputName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 2 }, new JoinMetadata { Description = "Device Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Device Output Route Set/Get /// [JoinName("OutputRoute")] public JoinDataComplete OutputRoute = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 2 }, new JoinMetadata { Description = "Device Output Route Set/Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Device Output Route Name /// [JoinName("OutputRoutedName")] public JoinDataComplete OutputRoutedName = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 2 }, new JoinMetadata { Description = "Device Output Route Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Device Enable Input Hdcp /// [JoinName("EnableInputHdcp")] public JoinDataComplete EnableInputHdcp = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 8 }, new JoinMetadata { Description = "Device Enable Input Hdcp", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Device Disable Input Hdcp /// [JoinName("DisableInputHdcp")] public JoinDataComplete DisableInputHdcp = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 8 }, new JoinMetadata { Description = "Device Disnable Input Hdcp", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Device Online Status /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, new JoinMetadata { Description = "Device Onlne", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public HdMdNxM4kEControllerJoinMap(uint joinStart) : this(joinStart, typeof(HdMdNxM4kEControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected HdMdNxM4kEControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdMdxxxCEControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a HdMdxxxCEControllerJoinMap /// public class HdMdxxxCEControllerJoinMap : JoinMapBaseAdvanced { /// /// Device Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Device Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Remote End Detected /// [JoinName("RemoteEndDetected")] public JoinDataComplete RemoteEndDetected = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Device Remote End Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Auto Route On /// [JoinName("AutoRouteOn")] public JoinDataComplete AutoRouteOn = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Device Auto Route On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Auto Route Off /// [JoinName("AutoRouteOff")] public JoinDataComplete AutoRouteOff = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Device Auto Route Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Priority Routing On /// [JoinName("PriorityRoutingOn")] public JoinDataComplete PriorityRoutingOn = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Device Priority Routing On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Priority Routing Off /// [JoinName("PriorityRoutingOff")] public JoinDataComplete PriorityRoutingOff = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Device Priority Routing Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Input On Screen Display Enabled /// [JoinName("InputOnScreenDisplayEnabled")] public JoinDataComplete InputOnScreenDisplayEnabled = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Device Input OSD Enabled", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Input On Screen Display Disabled /// [JoinName("InputOnScreenDisplayDisabled")] public JoinDataComplete InputOnScreenDisplayDisabled = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Device Input OSD Disabled", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Sync Detected /// [JoinName("SyncDetected")] public JoinDataComplete SyncDetected = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 5 }, new JoinMetadata { Description = "Device Sync Detected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Video Source /// [JoinName("VideoSource")] public JoinDataComplete VideoSource = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 5 }, new JoinMetadata { Description = "Device Video Source Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Source Count /// [JoinName("SourceCount")] public JoinDataComplete SourceCount = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 5 }, new JoinMetadata { Description = "Device Video Source Count", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Source Names /// [JoinName("SourceNames")] public JoinDataComplete SourceNames = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 5 }, new JoinMetadata { Description = "Device Video Source Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public HdMdxxxCEControllerJoinMap(uint joinStart) : this(joinStart, typeof(HdMdxxxCEControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected HdMdxxxCEControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/HdPsXxxControllerJoinMap.cs ================================================ using System; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a HdPsXxxControllerJoinMap /// public class HdPsXxxControllerJoinMap : JoinMapBaseAdvanced { #region Digital /// /// Enable Automatic Routing on Xx1 Switchers /// [JoinName("EnableAutoRoute")] public JoinDataComplete EnableAutoRoute = new JoinDataComplete( new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Automatic Routing on Xx1 Switchers", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Device Input Sync /// [JoinName("InputSync")] public JoinDataComplete InputSync = new JoinDataComplete( new JoinData { JoinNumber = 2, JoinSpan = 8 }, new JoinMetadata { Description = "Device Input Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Device Enable Input Hdcp /// [JoinName("EnableInputHdcp")] public JoinDataComplete EnableInputHdcp = new JoinDataComplete( new JoinData { JoinNumber = 11, JoinSpan = 8 }, new JoinMetadata { Description = "Device Enable Input Hdcp", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Device Disnable Input Hdcp /// [JoinName("DisableInputHdcp")] public JoinDataComplete DisableInputHdcp = new JoinDataComplete( new JoinData { JoinNumber = 21, JoinSpan = 8 }, new JoinMetadata { Description = "Device Disnable Input Hdcp", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Device Onlne /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete( new JoinData { JoinNumber = 30, JoinSpan = 1 }, new JoinMetadata { Description = "Device Onlne", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); #endregion #region Analog /// /// Device Input Route Set/Get /// [JoinName("OutputRoute")] public JoinDataComplete OutputRoute = new JoinDataComplete( new JoinData { JoinNumber = 11, JoinSpan = 2 }, new JoinMetadata { Description = "Device Output Route Set/Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); #endregion #region Serial /// /// Device Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete( new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Device Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Device Input Name /// [JoinName("InputName")] public JoinDataComplete InputName = new JoinDataComplete( new JoinData { JoinNumber = 2, JoinSpan = 8 }, new JoinMetadata { Description = "Device Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Device Output Name /// [JoinName("OutputName")] public JoinDataComplete OutputName = new JoinDataComplete( new JoinData { JoinNumber = 11, JoinSpan = 2 }, new JoinMetadata { Description = "Device Output Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Device Output Route Name /// [JoinName("OutputRoutedName")] public JoinDataComplete OutputRoutedName = new JoinDataComplete( new JoinData { JoinNumber = 16, JoinSpan = 2 }, new JoinMetadata { Description = "Device Output Route Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); #endregion /// /// Constructor to use when instantiating this join map without inheriting from it /// /// Join this join map will start at public HdPsXxxControllerJoinMap(uint joinStart) : this(joinStart, typeof(HdPsXxxControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected HdPsXxxControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/Hrxxx0WirelessRemoteControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a Hrxxx0WirelessRemoteControllerJoinMap /// public class Hrxxx0WirelessRemoteControllerJoinMap : JoinMapBaseAdvanced { /// /// Power /// [JoinName("Power")] public JoinDataComplete Power = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Power", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Menu /// [JoinName("Menu")] public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Menu", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Guide /// [JoinName("Guide")] public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Guide", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Info /// [JoinName("Info")] public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Info", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// VolumeUp /// [JoinName("VolumeUp")] public JoinDataComplete VolumeUp = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "VolumeUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// VolumeDown /// [JoinName("VolumeDown")] public JoinDataComplete VolumeDown = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "VolumeDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DialPadUp /// [JoinName("DialPadUp")] public JoinDataComplete DialPadUp = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "DialPadUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DialPadDown /// [JoinName("DialPadDown")] public JoinDataComplete DialPadDown = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "DialPadDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DialPadLeft /// [JoinName("DialPadLeft")] public JoinDataComplete DialPadLeft = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "DialPadLeft", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DialPadRight /// [JoinName("DialPadRight")] public JoinDataComplete DialPadRight = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata { Description = "DialPadRight", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// DialPadSelect /// [JoinName("DialPadSelect")] public JoinDataComplete DialPadSelect = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "DialPadSelect", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// ChannelUp /// [JoinName("ChannelUp")] public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "ChannelUp", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// ChannelDown /// [JoinName("ChannelDown")] public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "ChannelDown", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Mute /// [JoinName("Mute")] public JoinDataComplete Mute = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "Mute", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Exit /// [JoinName("Exit")] public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "Exit", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Last /// [JoinName("Last")] public JoinDataComplete Last = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, new JoinMetadata { Description = "Last", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Play /// [JoinName("Play")] public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, new JoinMetadata { Description = "Play", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Pause /// [JoinName("Pause")] public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, new JoinMetadata { Description = "Pause", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Rewind /// [JoinName("Rewind")] public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, new JoinMetadata { Description = "Rewind", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// FastForward /// [JoinName("FastForward")] public JoinDataComplete FastForward = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, new JoinMetadata { Description = "FastForward", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// PreviousTrack /// [JoinName("PreviousTrack")] public JoinDataComplete PreviousTrack = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "PreviousTrack", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// NextTrack /// [JoinName("NextTrack")] public JoinDataComplete NextTrack = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "NextTrack", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Stop /// [JoinName("Stop")] public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, new JoinMetadata { Description = "Stop", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Record /// [JoinName("Record")] public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "Record", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Dvr /// [JoinName("Dvr")] public JoinDataComplete Dvr = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, new JoinMetadata { Description = "Dvr", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad1 /// [JoinName("Keypad1")] public JoinDataComplete Keypad1 = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad2Abc /// [JoinName("Keypad2Abc")] public JoinDataComplete Keypad2 = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad2Abc", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad3Def /// [JoinName("Keypad3Def")] public JoinDataComplete Keypad3Def = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad3Def", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad4Ghi /// [JoinName("Keypad4Ghi")] public JoinDataComplete Keypad4Ghi = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad4Ghi", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad5Jkl /// [JoinName("Keypad5Jkl")] public JoinDataComplete Keypad5Jkl = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad5Jkl", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad6Mno /// [JoinName("Keypad6Mno")] public JoinDataComplete Keypad6Mno = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad6Mno", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad7Pqrs /// [JoinName("Keypad7Pqrs")] public JoinDataComplete Keypad7Pqrs = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad7Pqrs", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad8Tuv /// [JoinName("Keypad8Tuv")] public JoinDataComplete Keypad8Tuv = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad8Tuv", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad9Wxyz /// [JoinName("Keypad9Wxyz")] public JoinDataComplete Keypad9Wxyz = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad9Wxyz", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad0 /// [JoinName("Keypad0")] public JoinDataComplete Keypad0 = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad0", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Clear /// [JoinName("Clear")] public JoinDataComplete Clear = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, new JoinMetadata { Description = "Clear", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Enter /// [JoinName("Enter")] public JoinDataComplete Enter = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, new JoinMetadata { Description = "Enter", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Red /// [JoinName("Red")] public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, new JoinMetadata { Description = "Red", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Green /// [JoinName("Green")] public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, new JoinMetadata { Description = "Green", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Yellow /// [JoinName("Yellow")] public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, new JoinMetadata { Description = "Yellow", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Blue /// [JoinName("Blue")] public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "Blue", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom1 /// [JoinName("Custom1")] public JoinDataComplete Custom1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "Custom1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom2 /// [JoinName("Custom2")] public JoinDataComplete Custom2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, new JoinMetadata { Description = "Custom2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom3 /// [JoinName("Custom3")] public JoinDataComplete Custom3 = new JoinDataComplete(new JoinData { JoinNumber = 44, JoinSpan = 1 }, new JoinMetadata { Description = "Custom3", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom4 /// [JoinName("Custom4")] public JoinDataComplete Custom4 = new JoinDataComplete(new JoinData { JoinNumber = 45, JoinSpan = 1 }, new JoinMetadata { Description = "Custom4", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom5 /// [JoinName("Custom5")] public JoinDataComplete Custom5 = new JoinDataComplete(new JoinData { JoinNumber = 46, JoinSpan = 1 }, new JoinMetadata { Description = "Custom5", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom6 /// [JoinName("Custom6")] public JoinDataComplete Custom6 = new JoinDataComplete(new JoinData { JoinNumber = 47, JoinSpan = 1 }, new JoinMetadata { Description = "Custom6", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom7 /// [JoinName("Custom7")] public JoinDataComplete Custom7 = new JoinDataComplete(new JoinData { JoinNumber = 48, JoinSpan = 1 }, new JoinMetadata { Description = "Custom7", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom8 /// [JoinName("Custom8")] public JoinDataComplete Custom8 = new JoinDataComplete(new JoinData { JoinNumber = 49, JoinSpan = 1 }, new JoinMetadata { Description = "Custom8", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Custom9 /// [JoinName("Custom9")] public JoinDataComplete Custom9 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata { Description = "Custom9", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Fav /// [JoinName("Fav")] public JoinDataComplete Fav = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "Fav", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Home /// [JoinName("Home")] public JoinDataComplete Home = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "Home", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// BatteryLow /// [JoinName("BatteryLow")] public JoinDataComplete BatteryLow = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata { Description = "BatteryLow", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// BatteryCritical /// [JoinName("BatteryCritical")] public JoinDataComplete BatteryCritical = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1 }, new JoinMetadata { Description = "BatteryCritical", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// BatteryVoltage /// [JoinName("BatteryVoltage")] public JoinDataComplete BatteryVoltage = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "BatteryVoltage", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public Hrxxx0WirelessRemoteControllerJoinMap(uint joinStart) : this(joinStart, typeof(Hrxxx0WirelessRemoteControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected Hrxxx0WirelessRemoteControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/IAnalogInputJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a IAnalogInputJoinMap /// public class IAnalogInputJoinMap : JoinMapBaseAdvanced { /// /// Input Value /// [JoinName("InputValue")] public JoinDataComplete InputValue = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Input Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Minimum Change /// [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) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/IBasicCommunicationJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a IBasicCommunicationJoinMap /// public class IBasicCommunicationJoinMap : JoinMapBaseAdvanced { /// /// Text Received From Remote Device /// [JoinName("TextReceived")] public JoinDataComplete TextReceived = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Text Received From Remote Device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Text Sent To Remote Device /// [JoinName("SendText")] public JoinDataComplete SendText = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Text Sent To Remote Device", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); /// /// Set Port Config /// [JoinName("SetPortConfig")] public JoinDataComplete SetPortConfig = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Set Port Config", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); /// /// Connect /// [JoinName("Connect")] public JoinDataComplete Connect = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Connect", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Disconnect /// [JoinName("Connected")] public JoinDataComplete Connected = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Connected", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Status /// [JoinName("Status")] public JoinDataComplete Status = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public IBasicCommunicationJoinMap(uint joinStart) : this(joinStart, typeof(IBasicCommunicationJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected IBasicCommunicationJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalInputJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a IDigitalInputJoinMap /// public class IDigitalInputJoinMap : JoinMapBaseAdvanced { /// /// Input State /// [JoinName("InputState")] public JoinDataComplete InputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Input State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public IDigitalInputJoinMap(uint joinStart) : this(joinStart, typeof(IDigitalInputJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected IDigitalInputJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/IDigitalOutputJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a IDigitalOutputJoinMap /// public class IDigitalOutputJoinMap : JoinMapBaseAdvanced { /// /// Output State /// [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) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/IRBlurayBaseJoinMap.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core.Bridges { /// /// Join map for IRBlurayBase devices /// public class IRBlurayBaseJoinMap : JoinMapBaseAdvanced { /// /// Power On /// [JoinName("PowerOn")] public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Power On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Power Off /// [JoinName("PowerOff")] public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Power Toggle /// [JoinName("PowerToggle")] public JoinDataComplete PowerToggle = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Power Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Nav Up /// [JoinName("Up")] public JoinDataComplete Up = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Nav Down /// [JoinName("Down")] public JoinDataComplete Down = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Nav Left /// [JoinName("Left")] public JoinDataComplete Left = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Nav Right /// [JoinName("Right")] public JoinDataComplete Right = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Select /// [JoinName("Select")] public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Menu /// [JoinName("Menu")] public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Exit /// [JoinName("Exit")] public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata { Description = "Exit", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 0 /// [JoinName("Digit0")] public JoinDataComplete Digit0 = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 1 /// [JoinName("Digit1")] public JoinDataComplete Digit1 = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 2 /// [JoinName("Digit2")] public JoinDataComplete Digit2 = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 3 /// [JoinName("Digit3")] public JoinDataComplete Digit3 = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 4 /// [JoinName("Digit4")] public JoinDataComplete Digit4 = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 5 /// [JoinName("Digit5")] public JoinDataComplete Digit5 = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 6 /// [JoinName("Digit6")] public JoinDataComplete Digit6 = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 7 /// [JoinName("Digit7")] public JoinDataComplete Digit7 = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 8 /// [JoinName("Digit8")] public JoinDataComplete Digit8 = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Digit 9 /// [JoinName("Digit9")] public JoinDataComplete Digit9 = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, new JoinMetadata { Description = "Digit 9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad Clear /// [JoinName("KeypadClear")] public JoinDataComplete KeypadClear = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad Clear", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad Enter /// [JoinName("KeypadEnter")] public JoinDataComplete KeypadEnter = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad Enter", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Channel Up /// [JoinName("ChannelUp")] public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, new JoinMetadata { Description = "STB Channel Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Channel Down /// [JoinName("ChannelDown")] public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "STB Channel Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Last Channel /// [JoinName("LastChannel")] public JoinDataComplete LastChannel = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, new JoinMetadata { Description = "Last Channel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Guide /// [JoinName("Guide")] public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, new JoinMetadata { Description = "Guide", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Info /// [JoinName("Info")] public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, new JoinMetadata { Description = "Info", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Red /// [JoinName("Red")] public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, new JoinMetadata { Description = "Red", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Green /// [JoinName("Green")] public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, new JoinMetadata { Description = "Green", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Yellow /// [JoinName("Yellow")] public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, new JoinMetadata { Description = "Yellow", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Blue /// [JoinName("Blue")] public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata { Description = "Blue", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Play /// [JoinName("Play")] public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, new JoinMetadata { Description = "Play", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Pause /// [JoinName("Pause")] public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, new JoinMetadata { Description = "Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Stop /// [JoinName("Stop")] public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, new JoinMetadata { Description = "Stop", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Fast Forward /// [JoinName("FFwd")] public JoinDataComplete FFwd = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, new JoinMetadata { Description = "FFwd", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Rewind /// [JoinName("Rewind")] public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, new JoinMetadata { Description = "Rewind", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Chapter Plus /// [JoinName("ChapPlus")] public JoinDataComplete ChapPlus = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, new JoinMetadata { Description = "Chapter Plus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Chapter Minus /// [JoinName("ChapMinus")] public JoinDataComplete ChapMinus = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, new JoinMetadata { Description = "Chapter Minus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Replay /// [JoinName("Replay")] public JoinDataComplete Replay = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, new JoinMetadata { Description = "Replay", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Record /// [JoinName("Record")] public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "Record", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Has Keypad Accessory Button 1 /// [JoinName("HasKeypadAccessoryButton1")] public JoinDataComplete HasKeypadAccessoryButton1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "Has Keypad Accessory Button 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Has Keypad Accessory Button 2 /// [JoinName("HasKeypadAccessoryButton2")] public JoinDataComplete HasKeypadAccessoryButton2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, new JoinMetadata { Description = "Has Keypad Accessory Button 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad Accessory Button 1 Press /// [JoinName("KeypadAccessoryButton1Press")] public JoinDataComplete KeypadAccessoryButton1Press = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 2 }, new JoinMetadata { Description = "Keypad Accessory Button 1 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad Accessory Button 2 Press /// [JoinName("KeypadAccessoryButton2Press")] public JoinDataComplete KeypadAccessoryButton2Press = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 2 }, new JoinMetadata { Description = "Keypad Accessory Button 2 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Keypad Accessory Button 1 Label /// [JoinName("KeypadAccessoryButton1Label")] public JoinDataComplete KeypadAccessoryButton1Label = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Keypad Accessory Button 2 Label /// [JoinName("KeypadAccessoryButton2Label")] public JoinDataComplete KeypadAccessoryButton2Label = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, new JoinMetadata { Description = "Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public IRBlurayBaseJoinMap(uint joinStart) : this(joinStart, typeof(IRBlurayBaseJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected IRBlurayBaseJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/PduJoinMapBase.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a PduJoinMapBase /// public class PduJoinMapBase : JoinMapBaseAdvanced { /// /// PDU Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "PDU Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// PDU Online Status /// [JoinName("Online")] public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Number of Controlled Outlets /// [JoinName("OutletCount")] public JoinDataComplete OutletCount = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Number of COntrolled Outlets", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Outlet Name /// [JoinName("OutletName")] public JoinDataComplete OutletName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Outlet Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Outlet Enabled Status /// [JoinName("OutletEnabled")] public JoinDataComplete OutletEnabled = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Outlet Enabled", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Outlet Power State /// [JoinName("OutletPowerCycle")] public JoinDataComplete OutletPowerCycle = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Outlet Power Cycle", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Outlet Power On /// [JoinName("OutletPowerOn")] public JoinDataComplete OutletPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "Outlet Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Outlet Power Off /// [JoinName("OutletPowerOff")] public JoinDataComplete OutletPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "Outlet Power Off", 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 PduJoinMapBase(uint joinStart) :base(joinStart, typeof(PduJoinMapBase)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map public PduJoinMapBase(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/SetTopBoxControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a SetTopBoxControllerJoinMap /// public class SetTopBoxControllerJoinMap : JoinMapBaseAdvanced { /// /// STB Power On /// [JoinName("PowerOn")] public JoinDataComplete PowerOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "STB Power On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Power Off /// [JoinName("PowerOff")] public JoinDataComplete PowerOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "STB Power Off", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Power Toggle /// [JoinName("PowerToggle")] public JoinDataComplete PowerToggle = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "STB Power Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Has DPad /// [JoinName("HasDpad")] public JoinDataComplete HasDpad = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "STB Has DPad", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// STB Nav Up /// [JoinName("Up")] public JoinDataComplete Up = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "STB Nav Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Nav Down /// [JoinName("Down")] public JoinDataComplete Down = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "STB Nav Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Nav Left /// [JoinName("Left")] public JoinDataComplete Left = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "STB Nav Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Nav Right /// [JoinName("Right")] public JoinDataComplete Right = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "STB Nav Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Select /// [JoinName("Select")] public JoinDataComplete Select = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "STB Select", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Menu /// [JoinName("Menu")] public JoinDataComplete Menu = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "STB Menu", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Exit /// [JoinName("Exit")] public JoinDataComplete Exit = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata { Description = "STB Exit", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Has Numeric /// [JoinName("HasNumeric")] public JoinDataComplete HasNumeric = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "STB Has Numeric", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 0 /// [JoinName("Digit0")] public JoinDataComplete Digit0 = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 1 /// [JoinName("Digit1")] public JoinDataComplete Digit1 = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 2 /// [JoinName("Digit2")] public JoinDataComplete Digit2 = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 3 /// [JoinName("Digit3")] public JoinDataComplete Digit3 = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 4 /// [JoinName("Digit4")] public JoinDataComplete Digit4 = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 5 /// [JoinName("Digit5")] public JoinDataComplete Digit5 = new JoinDataComplete(new JoinData { JoinNumber = 16, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 6 /// [JoinName("Digit6")] public JoinDataComplete Digit6 = new JoinDataComplete(new JoinData { JoinNumber = 17, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 7 /// [JoinName("Digit7")] public JoinDataComplete Digit7 = new JoinDataComplete(new JoinData { JoinNumber = 18, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 8 /// [JoinName("Digit8")] public JoinDataComplete Digit8 = new JoinDataComplete(new JoinData { JoinNumber = 19, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Digit 9 /// [JoinName("Digit9")] public JoinDataComplete Digit9 = new JoinDataComplete(new JoinData { JoinNumber = 20, JoinSpan = 1 }, new JoinMetadata { Description = "STB Digit 9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Dash /// [JoinName("Dash")] public JoinDataComplete Dash = new JoinDataComplete(new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "STB Dash", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Keypad Enter /// [JoinName("KeypadEnter")] public JoinDataComplete KeypadEnter = new JoinDataComplete(new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "STB Keypad Enter", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Channel Up /// [JoinName("ChannelUp")] public JoinDataComplete ChannelUp = new JoinDataComplete(new JoinData { JoinNumber = 23, JoinSpan = 1 }, new JoinMetadata { Description = "STB Channel Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Channel Down /// [JoinName("ChannelDown")] public JoinDataComplete ChannelDown = new JoinDataComplete(new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "STB Channel Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Last Channel /// [JoinName("LastChannel")] public JoinDataComplete LastChannel = new JoinDataComplete(new JoinData { JoinNumber = 25, JoinSpan = 1 }, new JoinMetadata { Description = "STB Last Channel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Guide /// [JoinName("Guide")] public JoinDataComplete Guide = new JoinDataComplete(new JoinData { JoinNumber = 26, JoinSpan = 1 }, new JoinMetadata { Description = "STB Guide", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Info /// [JoinName("Info")] public JoinDataComplete Info = new JoinDataComplete(new JoinData { JoinNumber = 27, JoinSpan = 1 }, new JoinMetadata { Description = "STB Info", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Red /// [JoinName("Red")] public JoinDataComplete Red = new JoinDataComplete(new JoinData { JoinNumber = 28, JoinSpan = 1 }, new JoinMetadata { Description = "STB Red", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Green /// [JoinName("Green")] public JoinDataComplete Green = new JoinDataComplete(new JoinData { JoinNumber = 29, JoinSpan = 1 }, new JoinMetadata { Description = "STB Green", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Yellow /// [JoinName("Yellow")] public JoinDataComplete Yellow = new JoinDataComplete(new JoinData { JoinNumber = 30, JoinSpan = 1 }, new JoinMetadata { Description = "STB Yellow", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Blue /// [JoinName("Blue")] public JoinDataComplete Blue = new JoinDataComplete(new JoinData { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata { Description = "STB Blue", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Has DVR /// [JoinName("HasDvr")] public JoinDataComplete HasDvr = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, new JoinMetadata { Description = "STB Has DVR", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// STB Dvr List /// [JoinName("DvrList")] public JoinDataComplete DvrList = new JoinDataComplete(new JoinData { JoinNumber = 32, JoinSpan = 1 }, new JoinMetadata { Description = "STB DvrList", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Play /// [JoinName("Play")] public JoinDataComplete Play = new JoinDataComplete(new JoinData { JoinNumber = 33, JoinSpan = 1 }, new JoinMetadata { Description = "STB Play", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Pause /// [JoinName("Pause")] public JoinDataComplete Pause = new JoinDataComplete(new JoinData { JoinNumber = 34, JoinSpan = 1 }, new JoinMetadata { Description = "STB Pause", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Stop /// [JoinName("Stop")] public JoinDataComplete Stop = new JoinDataComplete(new JoinData { JoinNumber = 35, JoinSpan = 1 }, new JoinMetadata { Description = "STB Stop", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB FFwd /// [JoinName("FFwd")] public JoinDataComplete FFwd = new JoinDataComplete(new JoinData { JoinNumber = 36, JoinSpan = 1 }, new JoinMetadata { Description = "STB FFwd", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Rewind /// [JoinName("Rewind")] public JoinDataComplete Rewind = new JoinDataComplete(new JoinData { JoinNumber = 37, JoinSpan = 1 }, new JoinMetadata { Description = "STB Rewind", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Chapter Plus /// [JoinName("ChapPlus")] public JoinDataComplete ChapPlus = new JoinDataComplete(new JoinData { JoinNumber = 38, JoinSpan = 1 }, new JoinMetadata { Description = "STB Chapter Plus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Chapter Minus /// [JoinName("ChapMinus")] public JoinDataComplete ChapMinus = new JoinDataComplete(new JoinData { JoinNumber = 39, JoinSpan = 1 }, new JoinMetadata { Description = "STB Chapter Minus", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Replay /// [JoinName("Replay")] public JoinDataComplete Replay = new JoinDataComplete(new JoinData { JoinNumber = 40, JoinSpan = 1 }, new JoinMetadata { Description = "STB Replay", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Record /// [JoinName("Record")] public JoinDataComplete Record = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "STB Record", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Has Keypad Accessory Button 1 /// [JoinName("HasKeypadAccessoryButton1")] public JoinDataComplete HasKeypadAccessoryButton1 = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "STB Has Keypad Accessory Button 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// STB Has Keypad Accessory Button 2 /// [JoinName("HasKeypadAccessoryButton2")] public JoinDataComplete HasKeypadAccessoryButton2 = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, new JoinMetadata { Description = "STB Has Keypad Accessory Button 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// STB Keypad Accessory Button 1 Press /// [JoinName("KeypadAccessoryButton1Press")] public JoinDataComplete KeypadAccessoryButton1Press = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 2 }, new JoinMetadata { Description = "STB Keypad Accessory Button 1 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Keypad Accessory Button 2 Press /// [JoinName("KeypadAccessoryButton2Press")] public JoinDataComplete KeypadAccessoryButton2Press = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 2 }, new JoinMetadata { Description = "STB Keypad Accessory Button 2 Press", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "STB Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// STB Keypad Accessory Button 1 Label /// [JoinName("KeypadAccessoryButton1Label")] public JoinDataComplete KeypadAccessoryButton1Label = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "STB Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// STB Keypad Accessory Button 2 Label /// [JoinName("KeypadAccessoryButton2Label")] public JoinDataComplete KeypadAccessoryButton2Label = new JoinDataComplete(new JoinData { JoinNumber = 43, JoinSpan = 1 }, new JoinMetadata { Description = "STB Keypad Accessory Button 1 Label", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// STB Load Presets /// [JoinName("LoadPresets")] public JoinDataComplete LoadPresets = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata { Description = "STB Load Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// STB Has Presets /// [JoinName("HasPresets")] public JoinDataComplete HasPresets = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata { Description = "STB Load Presets", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public SetTopBoxControllerJoinMap(uint joinStart) : this(joinStart, typeof(SetTopBoxControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected SetTopBoxControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/StatusSignControllerJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a StatusSignControllerJoinMap /// public class StatusSignControllerJoinMap : JoinMapBaseAdvanced { /// /// Status Sign Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Status Sign Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Status Sign Name /// [JoinName("Name")] public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Status Sign Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Red LED Control /// [JoinName("RedControl")] public JoinDataComplete RedControl = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Status Red LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Red LED Intensity /// [JoinName("RedLed")] public JoinDataComplete RedLed = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Status Red LED Intensity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Green LED Control /// [JoinName("GreenControl")] public JoinDataComplete GreenControl = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Status Green LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Green LED Intensity /// [JoinName("GreenLed")] public JoinDataComplete GreenLed = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Status Green LED Intensity", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Blue LED Control /// [JoinName("BlueControl")] public JoinDataComplete BlueControl = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Status Blue LED Enable / Disable", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Blue LED Intensity /// [JoinName("BlueLed")] public JoinDataComplete BlueLed = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Status Blue LED Intensity", 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 StatusSignControllerJoinMap(uint joinStart) : this(joinStart, typeof(StatusSignControllerJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected StatusSignControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/SystemMonitorJoinMap.cs ================================================ using System; namespace PepperDash.Essentials.Core.Bridges { /// /// Represents a SystemMonitorJoinMap /// public class SystemMonitorJoinMap : JoinMapBaseAdvanced { /// /// Processor Timezone /// [JoinName("TimeZone")] public JoinDataComplete TimeZone = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Timezone", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Processor Timezone Name /// [JoinName("TimeZoneName")] public JoinDataComplete TimeZoneName = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Timezone Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor OS Version /// [JoinName("IOControllerVersion")] public JoinDataComplete IOControllerVersion = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Processor IO Controller Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor SNMP App Version /// [JoinName("SnmpAppVersion")] public JoinDataComplete SnmpAppVersion = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Processor SNMP App Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor BACNet App Version /// [JoinName("BACnetAppVersion")] public JoinDataComplete BACnetAppVersion = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata { Description = "Processor BACNet App Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Controller Version /// [JoinName("ControllerVersion")] public JoinDataComplete ControllerVersion = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Controller Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Serial Number /// [JoinName("SerialNumber")] public JoinDataComplete SerialNumber = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Serial Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Model /// [JoinName("Model")] public JoinDataComplete Model = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Model", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Uptime /// [JoinName("Uptime")] public JoinDataComplete Uptime = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Uptime", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Last Boot Time /// [JoinName("LastBoot")] public JoinDataComplete LastBoot = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Last Boot", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Program Offset Join /// [JoinName("ProgramOffsetJoin")] public JoinDataComplete ProgramOffsetJoin = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 5 }, new JoinMetadata { Description = "All Program Data is offset between slots by 5 - First Joins Start at 11", JoinCapabilities = eJoinCapabilities.None, JoinType = eJoinType.None }); /// /// Processor Program Start /// [JoinName("ProgramStart")] public JoinDataComplete ProgramStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program Start / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Processor Program Stop /// [JoinName("ProgramStop")] public JoinDataComplete ProgramStop = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program Stop / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Processor Program Register /// [JoinName("ProgramRegister")] public JoinDataComplete ProgramRegister = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program Register / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Processor Program Unregister /// [JoinName("ProgramUnregister")] public JoinDataComplete ProgramUnregister = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program UnRegister / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Processor Program Name /// [JoinName("ProgramName")] public JoinDataComplete ProgramName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Program Version /// [JoinName("ProgramCompiledTime")] public JoinDataComplete ProgramCompiledTime = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program Compile Time", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Program Crestron Database Version /// [JoinName("ProgramCrestronDatabaseVersion")] public JoinDataComplete ProgramCrestronDatabaseVersion = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program Database Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Program Environment Version /// [JoinName("ProgramEnvironmentVersion")] public JoinDataComplete ProgramEnvironmentVersion = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program Environment Version", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Program Aggregate Info /// [JoinName("AggregatedProgramInfo")] public JoinDataComplete AggregatedProgramInfo = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Program Aggregate Info Json", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Ethernet Offset Join /// [JoinName("EthernetOffsetJoin")] public JoinDataComplete EthernetOffsetJoin = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "All Ethernet Data is offset between Nics by 5 - First Joins Start at 76", JoinCapabilities = eJoinCapabilities.None, JoinType = eJoinType.None }); /// /// Processor Ethernet Hostname /// [JoinName("HostName")] public JoinDataComplete HostName = new JoinDataComplete(new JoinData { JoinNumber = 76, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Hostname", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Current Ip Address /// [JoinName("CurrentIpAddress")] public JoinDataComplete CurrentIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 77, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Current Ip Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Current Subnet Mask /// [JoinName("CurrentSubnetMask")] public JoinDataComplete CurrentSubnetMask = new JoinDataComplete(new JoinData { JoinNumber = 78, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Current Subnet Mask", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Current Default Gateway /// [JoinName("CurrentDefaultGateway")] public JoinDataComplete CurrentDefaultGateway = new JoinDataComplete(new JoinData { JoinNumber = 79, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Current Default Gateway", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Static Ip Address /// [JoinName("StaticIpAddress")] public JoinDataComplete StaticIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 80, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Static Ip Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Static Subnet Mask /// [JoinName("StaticSubnetMask")] public JoinDataComplete StaticSubnetMask = new JoinDataComplete(new JoinData { JoinNumber = 81, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Static Subnet Mask", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Static Default Gateway /// [JoinName("StaticDefaultGateway")] public JoinDataComplete StaticDefaultGateway = new JoinDataComplete(new JoinData { JoinNumber = 82, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Static Default Gateway", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Domain /// [JoinName("Domain")] public JoinDataComplete Domain = new JoinDataComplete(new JoinData { JoinNumber = 83, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Domain", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Dns Server /// [JoinName("DnsServer")] public JoinDataComplete DnsServer = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Dns Server", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Mac Address /// [JoinName("MacAddress")] public JoinDataComplete MacAddress = new JoinDataComplete(new JoinData { JoinNumber = 85, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Mac Address", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Ethernet Dhcp Status /// [JoinName("DhcpStatus")] public JoinDataComplete DhcpStatus = new JoinDataComplete(new JoinData { JoinNumber = 86, JoinSpan = 1 }, new JoinMetadata { Description = "Processor Ethernet Dhcp Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Processor Reboot /// [JoinName("ProcessorRebot")] public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Reboot processor", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Is Appliance Fb /// [JoinName("IsAppliance")] public JoinDataComplete IsAppliance = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Is appliance Fb", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Is Server Fb /// [JoinName("IsServer")] public JoinDataComplete IsServer = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Is server Fb", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Program Reset /// [JoinName("ProgramReset")] public JoinDataComplete ProgramReset = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "Resets the program", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public SystemMonitorJoinMap(uint joinStart) : this(joinStart, typeof(SystemMonitorJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map protected SystemMonitorJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs ================================================ using System; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Bridges.JoinMaps { /// /// Represents a VideoCodecControllerJoinMap /// public class VideoCodecControllerJoinMap : JoinMapBaseAdvanced { #region Digital /// /// Device is Online /// [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete( new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Device is Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// If High, will send DTMF tones to the call set by SelectCall analog. If low sends DTMF tones to last connected call. /// [JoinName("SendDtmfToSpecificCallIndex")] public JoinDataComplete SendDtmfToSpecificCallIndex = new JoinDataComplete( new JoinData { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata { Description = "If High, will send DTMF tones to the call set by SelectCall analog. If low sends DTMF tones to last connected call.", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 1 /// [JoinName("Dtmf1")] public JoinDataComplete Dtmf1 = new JoinDataComplete( new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 1", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 2 /// [JoinName("Dtmf2")] public JoinDataComplete Dtmf2 = new JoinDataComplete( new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 2", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 3 /// [JoinName("Dtmf3")] public JoinDataComplete Dtmf3 = new JoinDataComplete( new JoinData { JoinNumber = 13, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 3", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 4 /// [JoinName("Dtmf4")] public JoinDataComplete Dtmf4 = new JoinDataComplete( new JoinData { JoinNumber = 14, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 4", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 5 /// [JoinName("Dtmf5")] public JoinDataComplete Dtmf5 = new JoinDataComplete( new JoinData { JoinNumber = 15, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 5", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 6 /// [JoinName("Dtmf6")] public JoinDataComplete Dtmf6 = new JoinDataComplete( new JoinData { JoinNumber = 16, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 6", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 7 /// [JoinName("Dtmf7")] public JoinDataComplete Dtmf7 = new JoinDataComplete( new JoinData { JoinNumber = 17, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 7", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 8 /// [JoinName("Dtmf8")] public JoinDataComplete Dtmf8 = new JoinDataComplete( new JoinData { JoinNumber = 18, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 9 /// [JoinName("Dtmf9")] public JoinDataComplete Dtmf9 = new JoinDataComplete( new JoinData { JoinNumber = 19, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 9", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF 0 /// [JoinName("Dtmf0")] public JoinDataComplete Dtmf0 = new JoinDataComplete( new JoinData { JoinNumber = 20, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF 0", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF * /// [JoinName("DtmfStar")] public JoinDataComplete DtmfStar = new JoinDataComplete( new JoinData { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF *", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// DTMF # /// [JoinName("DtmfPound")] public JoinDataComplete DtmfPound = new JoinDataComplete( new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "DTMF #", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// End All Calls /// [JoinName("EndAllCalls")] public JoinDataComplete EndAllCalls = new JoinDataComplete( new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "End All Calls", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Current Hook State /// [JoinName("HookState")] public JoinDataComplete HookState = new JoinDataComplete( new JoinData { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata { Description = "Current Hook State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Speed Dial /// [JoinName("SpeedDialStart")] public JoinDataComplete SpeedDialStart = new JoinDataComplete( new JoinData { JoinNumber = 41, JoinSpan = 4 }, new JoinMetadata { Description = "Speed Dial", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Incoming Call /// [JoinName("IncomingCall")] public JoinDataComplete IncomingCall = new JoinDataComplete( new JoinData { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata { Description = "Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Answer Incoming Call /// [JoinName("IncomingAnswer")] public JoinDataComplete IncomingAnswer = new JoinDataComplete( new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "Answer Incoming Call", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Reject Incoming Call /// [JoinName("IncomingReject")] public JoinDataComplete IncomingReject = new JoinDataComplete( new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "Reject Incoming Call", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Manual Dial /// [JoinName("ManualDial")] public JoinDataComplete ManualDial = new JoinDataComplete( new JoinData { JoinNumber = 71, JoinSpan = 1 }, new JoinMetadata { Description = "Dial manual string specified by CurrentDialString serial join", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Dial Phone /// [JoinName("DialPhone")] public JoinDataComplete DialPhone = new JoinDataComplete( new JoinData { JoinNumber = 72, JoinSpan = 1 }, new JoinMetadata { Description = "Dial Phone", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Phone Hook State /// [JoinName("PhoneHookState")] public JoinDataComplete PhoneHookState = new JoinDataComplete( new JoinData { JoinNumber = 72, JoinSpan = 1 }, new JoinMetadata { Description = "Dial Phone", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Hang Up Phone /// [JoinName("HangUpPhone")] public JoinDataComplete HangUpPhone = new JoinDataComplete( new JoinData { JoinNumber = 73, JoinSpan = 1 }, new JoinMetadata { Description = "Hang Up Phone", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// End Call /// [JoinName("EndCallStart")] public JoinDataComplete EndCallStart = new JoinDataComplete( new JoinData { JoinNumber = 81, JoinSpan = 8 }, new JoinMetadata { Description = "End a specific call by call index. ", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Join All Calls /// [JoinName("JoinAllCalls")] public JoinDataComplete JoinAllCalls = new JoinDataComplete( new JoinData { JoinNumber = 90, JoinSpan = 1 }, new JoinMetadata { Description = "Join all calls", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Join Call /// [JoinName("JoinCallStart")] public JoinDataComplete JoinCallStart = new JoinDataComplete( new JoinData { JoinNumber = 91, JoinSpan = 8 }, new JoinMetadata { Description = "Join a specific call by call index. ", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Search Busy /// [JoinName("DirectorySearchBusy")] public JoinDataComplete DirectorySearchBusy = new JoinDataComplete( new JoinData { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata { Description = "Directory Search Busy FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Selected Entry Is Contact /// [JoinName("DirectoryEntryIsContact")] public JoinDataComplete DirectoryEntryIsContact = new JoinDataComplete( new JoinData { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata { Description = "Directory Selected Entry Is Contact FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Line Selected /// [JoinName("DirectoryLineSelected")] public JoinDataComplete DirectoryLineSelected = new JoinDataComplete( new JoinData { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata { Description = "Directory Line Selected FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Is Root /// [JoinName("DirectoryIsRoot")] public JoinDataComplete DirectoryIsRoot = new JoinDataComplete( new JoinData { JoinNumber = 102, JoinSpan = 1 }, new JoinMetadata { Description = "Directory is on Root FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Has Changed /// [JoinName("DirectoryHasChanged")] public JoinDataComplete DirectoryHasChanged = new JoinDataComplete( new JoinData { JoinNumber = 103, JoinSpan = 1 }, new JoinMetadata { Description = "Directory has changed FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Go to Root /// [JoinName("DirectoryRoot")] public JoinDataComplete DirectoryRoot = new JoinDataComplete( new JoinData { JoinNumber = 104, JoinSpan = 1 }, new JoinMetadata { Description = "Go to Directory Root", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Go Back One Level /// [JoinName("DirectoryFolderBack")] public JoinDataComplete DirectoryFolderBack = new JoinDataComplete( new JoinData { JoinNumber = 105, JoinSpan = 1 }, new JoinMetadata { Description = "Go back one directory level", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Dial Selected Line /// [JoinName("DirectoryDialSelectedLine")] public JoinDataComplete DirectoryDialSelectedLine = new JoinDataComplete( new JoinData { JoinNumber = 106, JoinSpan = 1 }, new JoinMetadata { Description = "Dial selected directory line", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Disable Auto Dial Selected Line /// [JoinName("DirectoryDisableAutoDialSelectedLine")] public JoinDataComplete DirectoryDisableAutoDialSelectedLine = new JoinDataComplete( new JoinData { JoinNumber = 107, JoinSpan = 1 }, new JoinMetadata { Description = "Set high to disable automatic dialing of a contact when selected", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Dial Selected Contact Method /// [JoinName("DirectoryDialSelectedContactMethod")] public JoinDataComplete DirectoryDialSelectedContactMethod = new JoinDataComplete( new JoinData { JoinNumber = 108, JoinSpan = 1 }, new JoinMetadata { Description = "Pulse to dial the selected contact method", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Directory Clear Selected /// [JoinName("DirectoryClearSelected")] public JoinDataComplete DirectoryClearSelected = new JoinDataComplete( new JoinData { JoinNumber = 110, JoinSpan = 1 }, new JoinMetadata { Description = "Clear Selected Entry and String from Search", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Tilt Up /// [JoinName("CameraTiltUp")] public JoinDataComplete CameraTiltUp = new JoinDataComplete( new JoinData { JoinNumber = 111, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Tilt Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Tilt Down /// [JoinName("CameraTiltDown")] public JoinDataComplete CameraTiltDown = new JoinDataComplete( new JoinData { JoinNumber = 112, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Tilt Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Pan Left /// [JoinName("CameraPanLeft")] public JoinDataComplete CameraPanLeft = new JoinDataComplete( new JoinData { JoinNumber = 113, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Pan Left", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Pan Right /// [JoinName("CameraPanRight")] public JoinDataComplete CameraPanRight = new JoinDataComplete( new JoinData { JoinNumber = 114, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Pan Right", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Zoom In /// [JoinName("CameraZoomIn")] public JoinDataComplete CameraZoomIn = new JoinDataComplete( new JoinData { JoinNumber = 115, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Zoom In", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Zoom Out /// [JoinName("CameraZoomOut")] public JoinDataComplete CameraZoomOut = new JoinDataComplete( new JoinData { JoinNumber = 116, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Zoom Out", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Focus Near /// [JoinName("CameraFocusNear")] public JoinDataComplete CameraFocusNear = new JoinDataComplete( new JoinData { JoinNumber = 117, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Focus Near", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Focus Far /// [JoinName("CameraFocusFar")] public JoinDataComplete CameraFocusFar = new JoinDataComplete( new JoinData { JoinNumber = 118, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Focus Far", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Auto Focus /// [JoinName("CameraFocusAuto")] public JoinDataComplete CameraFocusAuto = new JoinDataComplete( new JoinData { JoinNumber = 119, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Auto Focus Trigger", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Preset Save /// [JoinName("CameraPresetSave")] public JoinDataComplete CameraPresetSave = new JoinDataComplete( new JoinData { JoinNumber = 121, JoinSpan = 1 }, new JoinMetadata { Description = "Pulse to save selected preset spcified by CameraPresetSelect analog join. FB will pulse for 3s when preset saved.", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Preset Recall /// [JoinName("CameraModeAuto")] public JoinDataComplete CameraModeAuto = new JoinDataComplete( new JoinData { JoinNumber = 131, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Auto. Enables camera auto tracking mode, with feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Mode Manual /// [JoinName("CameraModeManual")] public JoinDataComplete CameraModeManual = new JoinDataComplete( new JoinData { JoinNumber = 132, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Manual. Disables camera auto tracking mode, with feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Mode Off /// [JoinName("CameraModeOff")] public JoinDataComplete CameraModeOff = new JoinDataComplete( new JoinData { JoinNumber = 133, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Mode Off. Disables camera video, with feedback. Works like video mute.", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Self View /// [JoinName("CameraSelfView")] public JoinDataComplete CameraSelfView = new JoinDataComplete( new JoinData { JoinNumber = 141, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Self View Toggle/FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Layout /// [JoinName("CameraLayout")] public JoinDataComplete CameraLayout = new JoinDataComplete( new JoinData { JoinNumber = 142, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Layout Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Supports Auto Mode /// [JoinName("CameraSupportsAutoMode")] public JoinDataComplete CameraSupportsAutoMode = new JoinDataComplete( new JoinData { JoinNumber = 143, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Supports Auto Mode FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Camera Supports Off Mode /// [JoinName("CameraSupportsOffMode")] public JoinDataComplete CameraSupportsOffMode = new JoinDataComplete( new JoinData { JoinNumber = 144, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Supports Off Mode FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Update Meetings /// [JoinName("UpdateMeetings")] public JoinDataComplete UpdateMeetings = new JoinDataComplete( new JoinData { JoinNumber = 160, JoinSpan = 1 }, new JoinMetadata { Description = "Update Meetings", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Dial Meeting Start /// [JoinName("DialMeetingStart")] public JoinDataComplete DialMeetingStart = new JoinDataComplete( new JoinData { JoinNumber = 161, JoinSpan = 10 }, new JoinMetadata { Description = "Join meeting", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Mic Mute On /// [JoinName("MicMuteOn")] public JoinDataComplete MicMuteOn = new JoinDataComplete( new JoinData { JoinNumber = 171, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Mute On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Mic Mute Off /// [JoinName("MicMuteOff")] public JoinDataComplete MicMuteOff = new JoinDataComplete( new JoinData { JoinNumber = 172, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Mute Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Mic Mute Toggle /// [JoinName("MicMuteToggle")] public JoinDataComplete MicMuteToggle = new JoinDataComplete( new JoinData { JoinNumber = 173, JoinSpan = 1 }, new JoinMetadata { Description = "Mic Mute Toggle", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Up /// [JoinName("VolumeUp")] public JoinDataComplete VolumeUp = new JoinDataComplete( new JoinData { JoinNumber = 174, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Up", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Down /// [JoinName("VolumeDown")] public JoinDataComplete VolumeDown = new JoinDataComplete( new JoinData { JoinNumber = 175, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Down", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Mute On /// [JoinName("VolumeMuteOn")] public JoinDataComplete VolumeMuteOn = new JoinDataComplete( new JoinData { JoinNumber = 176, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Mute On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Mute Off /// [JoinName("VolumeMuteOff")] public JoinDataComplete VolumeMuteOff = new JoinDataComplete( new JoinData { JoinNumber = 177, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Mute Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Volume Mute Toggle /// [JoinName("VolumeMuteToggle")] public JoinDataComplete VolumeMuteToggle = new JoinDataComplete( new JoinData { JoinNumber = 178, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Mute Toggle", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Remove Selected Recent Call Item /// [JoinName("RemoveSelectedRecentCallItem")] public JoinDataComplete RemoveSelectedRecentCallItem = new JoinDataComplete( new JoinData { JoinNumber = 181, JoinSpan = 1 }, new JoinMetadata { Description = "Pulse to remove the selected recent call item specified by the SelectRecentCallItem analog join", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Dial Selected Recent Call Item /// [JoinName("DialSelectedRecentCallItem")] public JoinDataComplete DialSelectedRecentCallItem = new JoinDataComplete( new JoinData { JoinNumber = 182, JoinSpan = 1 }, new JoinMetadata { Description = "Pulse to dial the selected recent call item specified by the SelectRecentCallItem analog join", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Source Share Start /// [JoinName("SourceShareStart")] public JoinDataComplete SourceShareStart = new JoinDataComplete( new JoinData { JoinNumber = 201, JoinSpan = 1 }, new JoinMetadata { Description = "Start Sharing & Feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Source Share End /// [JoinName("SourceShareEnd")] public JoinDataComplete SourceShareEnd = new JoinDataComplete( new JoinData { JoinNumber = 202, JoinSpan = 1 }, new JoinMetadata { Description = "Stop Sharing & Feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); /// /// Source Share Auto Start /// [JoinName("AutoShareWhileInCall")] public JoinDataComplete SourceShareAutoStart = new JoinDataComplete( new JoinData { JoinNumber = 203, JoinSpan = 1 }, new JoinMetadata { Description = "When high, will autostart sharing when a call is joined", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Recieving Content /// [JoinName("RecievingContent")] public JoinDataComplete RecievingContent = new JoinDataComplete( new JoinData { JoinNumber = 204, JoinSpan = 1 }, new JoinMetadata { Description = "Recieving content from the far end", JoinType = eJoinType.Digital, JoinCapabilities = eJoinCapabilities.ToSIMPL }); /// /// Selfview Position /// [JoinName("SelfviewPosition")] public JoinDataComplete SelfviewPosition = new JoinDataComplete( new JoinData { JoinNumber = 211, JoinSpan = 1 }, new JoinMetadata { Description = "Toggles selfview position", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Hold All Calls /// [JoinName("HoldAllCalls")] public JoinDataComplete HoldAllCalls = new JoinDataComplete( new JoinData { JoinNumber = 220, JoinSpan = 1 }, new JoinMetadata { Description = "Holds all calls", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Hold Call at Index /// [JoinName("HoldCallsStart")] public JoinDataComplete HoldCallsStart = new JoinDataComplete( new JoinData { JoinNumber = 221, JoinSpan = 8 }, new JoinMetadata { Description = "Holds Call at specified index. FB reported on Call Status XSIG", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Resume All Calls /// [JoinName("ResumeCallsStart")] public JoinDataComplete ResumeCallsStart = new JoinDataComplete( new JoinData { JoinNumber = 231, JoinSpan = 8 }, new JoinMetadata { Description = "Resume Call at specified index", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); /// /// Multi Site Option Is Enabled /// [JoinName("MultiSiteOptionIsEnabled")] public JoinDataComplete MultiSiteOptionIsEnabled = new JoinDataComplete( new JoinData { JoinNumber = 301, JoinSpan = 1 }, new JoinMetadata { Description = "Multi site option is enabled FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Auto Answer Enabled /// [JoinName("AutoAnswerEnabled")] public JoinDataComplete AutoAnswerEnabled = new JoinDataComplete( new JoinData { JoinNumber = 302, JoinSpan = 1 }, new JoinMetadata { Description = "Auto Answer is enabled FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Participant Audio Mute Toggle /// [JoinName("ParticipantAudioMuteToggleStart")] public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete( new JoinData { JoinNumber = 501, JoinSpan = 50 }, new JoinMetadata { Description = "Toggles the participant's audio mute status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Participant Video Mute Toggle /// [JoinName("ParticipantVideoMuteToggleStart")] public JoinDataComplete ParticipantVideoMuteToggleStart = new JoinDataComplete( new JoinData { JoinNumber = 801, JoinSpan = 50 }, new JoinMetadata { Description = "Toggles the participant's video mute status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Participant Pin Toggle /// [JoinName("ParticipantPinToggleStart")] public JoinDataComplete ParticipantPinToggleStart = new JoinDataComplete( new JoinData { JoinNumber = 1101, JoinSpan = 50 }, new JoinMetadata { Description = "Toggles the participant's pin status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); #endregion #region Analog // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set /// /// Meetings To Display /// [JoinName("MeetingsToDisplay")] public JoinDataComplete MeetingsToDisplay = new JoinDataComplete( new JoinData { JoinNumber = 40, JoinSpan = 1 }, new JoinMetadata { Description = "Set/FB the number of meetings to display via the bridge xsig; default: 3 meetings.", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Select Call /// [JoinName("SelectCall")] public JoinDataComplete SelectCall = new JoinDataComplete( new JoinData { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata { Description = "Sets the selected Call for DTMF commands. Valid values 1-8", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// Connected Call Count /// [JoinName("ConnectedCallCount")] public JoinDataComplete ConnectedCallCount = new JoinDataComplete( new JoinData { JoinNumber = 25, JoinSpan = 1 }, new JoinMetadata { Description = "Reports the number of currently connected calls", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Minutes Before Meeting Start /// [JoinName("MinutesBeforeMeetingStart")] public JoinDataComplete MinutesBeforeMeetingStart = new JoinDataComplete( new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "Minutes before meeting start that a meeting is joinable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// Camera Number Select /// [JoinName("CameraNumberSelect")] public JoinDataComplete CameraNumberSelect = new JoinDataComplete( new JoinData { JoinNumber = 60, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Number Select/FB. 1 based index. Valid range is 1 to the value reported by CameraCount.", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Camera Count /// [JoinName("CameraCount")] public JoinDataComplete CameraCount = new JoinDataComplete( new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "Reports the number of cameras", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Directory Row Count /// [JoinName("DirectoryRowCount")] public JoinDataComplete DirectoryRowCount = new JoinDataComplete( new JoinData { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata { Description = "Directory Row Count FB", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Directory Select Row /// [JoinName("DirectorySelectRow")] public JoinDataComplete DirectorySelectRow = new JoinDataComplete( new JoinData { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata { Description = "Directory Select Row and Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// Selected Contact Method Count /// [JoinName("SelectedContactMethodCount")] public JoinDataComplete SelectedContactMethodCount = new JoinDataComplete( new JoinData { JoinNumber = 102, JoinSpan = 1 }, new JoinMetadata { Description = "Reports the number of contact methods for the selected contact", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// Select Contact Method /// [JoinName("SelectContactMethod")] public JoinDataComplete SelectContactMethod = new JoinDataComplete( new JoinData { JoinNumber = 103, JoinSpan = 1 }, new JoinMetadata { Description = "Selects a contact method by index", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); /// /// Directory Select Row Feedback /// [JoinName("DirectorySelectRowFeedback")] public JoinDataComplete DirectorySelectRowFeedback = new JoinDataComplete( new JoinData { JoinNumber = 104, JoinSpan = 1 }, new JoinMetadata { Description = "Directory Select Row and Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Camera Preset Select /// [JoinName("CameraPresetSelect")] public JoinDataComplete CameraPresetSelect = new JoinDataComplete( new JoinData { JoinNumber = 121, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Preset Select", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Far End Preset Select /// [JoinName("FarEndPresetSelect")] public JoinDataComplete FarEndPresetSelect = new JoinDataComplete( new JoinData { JoinNumber = 122, JoinSpan = 1 }, new JoinMetadata { Description = "Far End Preset Preset Select", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Participant Count /// [JoinName("ParticipantCount")] public JoinDataComplete ParticipantCount = new JoinDataComplete( new JoinData { JoinNumber = 151, JoinSpan = 1 }, new JoinMetadata { Description = "Current Participant Count", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Meeting Count /// [JoinName("Meeting Count Fb")] public JoinDataComplete MeetingCount = new JoinDataComplete( new JoinData { JoinNumber = 161, JoinSpan = 1 }, new JoinMetadata { Description = "Meeting Count", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Volume Level /// [JoinName("VolumeLevel")] public JoinDataComplete VolumeLevel = new JoinDataComplete( new JoinData { JoinNumber = 174, JoinSpan = 1 }, new JoinMetadata { Description = "Volume Level", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Select Recent Call Item /// [JoinName("SelectRecentCallItem")] public JoinDataComplete SelectRecentCallItem = new JoinDataComplete( new JoinData { JoinNumber = 180, JoinSpan = 1 }, new JoinMetadata { Description = "Select/FB for Recent Call Item. Valid values 1 - 10", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog }); /// /// Recent Call Occurrence Type /// [JoinName("RecentCallOccurrenceType")] public JoinDataComplete RecentCallOccurrenceType = new JoinDataComplete( new JoinData { JoinNumber = 181, JoinSpan = 10 }, new JoinMetadata { Description = "Recent Call Occurrence Type. [0-3] 0 = Unknown, 1 = Placed, 2 = Received, 3 = NoAnswer", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); /// /// Recent Call Count /// [JoinName("RecentCallCount")] public JoinDataComplete RecentCallCount = new JoinDataComplete( new JoinData { JoinNumber = 191, JoinSpan = 1 }, new JoinMetadata { Description = "Recent Call Count", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); #endregion #region Serials /// /// Current Dial String /// [JoinName("CurrentDialString")] public JoinDataComplete CurrentDialString = new JoinDataComplete( new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Value to dial when ManualDial digital join is pulsed", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Phone Dial String /// [JoinName("PhoneDialString")] public JoinDataComplete PhoneDialString = new JoinDataComplete( new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Phone Dial String", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); /// /// Current Call Data /// [JoinName("CurrentCallData")] public JoinDataComplete CurrentCallData = new JoinDataComplete( new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Current Call Data - XSIG", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Call Direction /// [JoinName("CallDirection")] public JoinDataComplete CallDirection = new JoinDataComplete( new JoinData { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata { Description = "Current Call Direction", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Incoming Call Name /// [JoinName("IncomingCallName")] public JoinDataComplete IncomingCallName = new JoinDataComplete( new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "Incoming Call Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Incoming Call Number /// [JoinName("IncomingCallNumber")] public JoinDataComplete IncomingCallNumber = new JoinDataComplete( new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "Incoming Call Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Directory Search String /// [JoinName("DirectorySearchString")] public JoinDataComplete DirectorySearchString = new JoinDataComplete( new JoinData { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata { Description = "Directory Search String", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); /// /// Directory Entries /// [JoinName("DirectoryEntries")] public JoinDataComplete DirectoryEntries = new JoinDataComplete( new JoinData { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata { Description = "Directory Entries - XSig, 255 entries", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Schedule Data /// [JoinName("Schedule")] public JoinDataComplete Schedule = new JoinDataComplete( new JoinData { JoinNumber = 102, JoinSpan = 1 }, new JoinMetadata { Description = "Schedule Data - XSIG", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Contact Methods /// [JoinName("ContactMethods")] public JoinDataComplete ContactMethods = new JoinDataComplete( new JoinData { JoinNumber = 103, JoinSpan = 1 }, new JoinMetadata { Description = "Contact Methods - XSig, 10 entries", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Camera Preset Names /// [JoinName("CameraPresetNames")] public JoinDataComplete CameraPresetNames = new JoinDataComplete( new JoinData { JoinNumber = 121, JoinSpan = 1 }, new JoinMetadata { Description = "Camera Preset Names - XSIG, max of 15", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Current Layout String /// [JoinName("CurrentLayoutStringFb")] public JoinDataComplete CurrentLayoutStringFb = new JoinDataComplete( new JoinData { JoinNumber = 141, JoinSpan = 1 }, new JoinMetadata { Description = "Current Layout Fb", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Available Layouts XSig /// [JoinName("AvailableLayoutsFb")] public JoinDataComplete AvailableLayoutsFb = new JoinDataComplete( new JoinData { JoinNumber = 142, JoinSpan = 1 }, new JoinMetadata { Description = "xSig of all available layouts", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Select Layout /// [JoinName("SelectLayout")] public JoinDataComplete SelectLayout = new JoinDataComplete( new JoinData { JoinNumber = 142, JoinSpan = 1 }, new JoinMetadata { Description = "Select Layout by string", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); /// /// Current Participants XSig /// [JoinName("CurrentParticipants")] public JoinDataComplete CurrentParticipants = new JoinDataComplete( new JoinData { JoinNumber = 151, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Participants XSig", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Camera Names XSig /// [JoinName("CameraNamesFb")] public JoinDataComplete CameraNamesFb = new JoinDataComplete( new JoinData { JoinNumber = 161, JoinSpan = 10 }, new JoinMetadata { Description = "Camera Name Fb", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Selected Recent Call Name /// [JoinName("SelectedRecentCallName")] public JoinDataComplete SelectedRecentCallName = new JoinDataComplete( new JoinData { JoinNumber = 171, JoinSpan = 1 }, new JoinMetadata { Description = "Selected Recent Call Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Selected Recent Call Number /// [JoinName("SelectedRecentCallNumber")] public JoinDataComplete SelectedRecentCallNumber = new JoinDataComplete( new JoinData { JoinNumber = 172, JoinSpan = 1 }, new JoinMetadata { Description = "Selected Recent Call Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Recent Call Names /// [JoinName("RecentCallNamesStart")] public JoinDataComplete RecentCallNamesStart = new JoinDataComplete( new JoinData { JoinNumber = 181, JoinSpan = 10 }, new JoinMetadata { Description = "Recent Call Names", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Recent Call Numbers /// [JoinName("RecentCallTimesStart")] public JoinDataComplete RecentCallTimesStart = new JoinDataComplete( new JoinData { JoinNumber = 191, JoinSpan = 10 }, new JoinMetadata { Description = "Recent Calls Times", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Current Source /// [JoinName("CurrentSource")] public JoinDataComplete CurrentSource = new JoinDataComplete( new JoinData { JoinNumber = 201, JoinSpan = 1 }, new JoinMetadata { Description = "Current Source", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Selfview Position Feedback /// [JoinName("SelfviewPositionFb")] public JoinDataComplete SelfviewPositionFb = new JoinDataComplete( new JoinData { JoinNumber = 211, JoinSpan = 1 }, new JoinMetadata { Description = "advance selfview position", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Device IP Address /// [JoinName("DeviceIpAddresss")] public JoinDataComplete DeviceIpAddresss = new JoinDataComplete( new JoinData { JoinNumber = 301, JoinSpan = 1 }, new JoinMetadata { Description = "IP Address of device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// SIP Phone Number /// [JoinName("SipPhoneNumber")] public JoinDataComplete SipPhoneNumber = new JoinDataComplete( new JoinData { JoinNumber = 302, JoinSpan = 1 }, new JoinMetadata { Description = "SIP phone number of device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// E164 Alias /// [JoinName("E164Alias")] public JoinDataComplete E164Alias = new JoinDataComplete( new JoinData { JoinNumber = 303, JoinSpan = 1 }, new JoinMetadata { Description = "E164 alias of device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// H323 ID /// [JoinName("H323Id")] public JoinDataComplete H323Id = new JoinDataComplete( new JoinData { JoinNumber = 304, JoinSpan = 1 }, new JoinMetadata { Description = "H323 ID of device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// SIP URI /// [JoinName("SipUri")] public JoinDataComplete SipUri = new JoinDataComplete( new JoinData { JoinNumber = 305, JoinSpan = 1 }, new JoinMetadata { Description = "SIP URI of device", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Selected Directory Entry Name /// [JoinName("DirectoryEntrySelectedName")] public JoinDataComplete DirectoryEntrySelectedName = new JoinDataComplete( new JoinData { JoinNumber = 356, JoinSpan = 1 }, new JoinMetadata { Description = "Selected Directory Entry Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Selected Directory Entry Number /// [JoinName("DirectoryEntrySelectedNumber")] public JoinDataComplete DirectoryEntrySelectedNumber = new JoinDataComplete( new JoinData { JoinNumber = 357, JoinSpan = 1 }, new JoinMetadata { Description = "Selected Directory Entry Number", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); /// /// Selected Directory Folder Name /// [JoinName("DirectorySelectedFolderName")] public JoinDataComplete DirectorySelectedFolderName = new JoinDataComplete( new JoinData { JoinNumber = 358, JoinSpan = 1 }, new JoinMetadata { Description = "Selected Directory Folder Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); #endregion /// /// Constructor for the VideoCodecControllerJoinMap class. /// /// Join this join map will start at public VideoCodecControllerJoinMap(uint joinStart) : base(joinStart, typeof(VideoCodecControllerJoinMap)) { } /// /// /// /// Join this join map will start at /// Type of the child join map public VideoCodecControllerJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DM; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Represents a CecPortController /// public class CecPortController : Device, IBasicCommunicationWithStreamDebugging { /// /// Gets or sets the StreamDebugging /// public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// Event raised when bytes are received /// public event EventHandler BytesReceived; /// /// Event raised when text is received /// public event EventHandler TextReceived; /// /// Gets or sets the IsConnected /// public bool IsConnected { get { return true; } } ICec Port; /// /// Constructor /// /// key of the device /// post activation function for the device /// configuration for the device public CecPortController(string key, Func postActivationFunc, EssentialsControlPropertiesConfig config) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); AddPostActivationAction(() => { Port = postActivationFunc(config); Port.StreamCec.CecChange += StreamCec_CecChange; }); } /// /// Constructor /// /// key of the device /// CEC port public CecPortController(string key, ICec port) : base(key) { Port = port; Port.StreamCec.CecChange += new CecChangeEventHandler(StreamCec_CecChange); } void StreamCec_CecChange(Cec cecDevice, CecEventArgs args) { if (args.EventId == CecEventIds.CecMessageReceivedEventId) OnDataReceived(cecDevice.Received.StringValue); else if (args.EventId == CecEventIds.ErrorFeedbackEventId) if (cecDevice.ErrorFeedback.BoolValue) Debug.LogMessage(LogEventLevel.Verbose, this, "CEC NAK Error"); } void OnDataReceived(string s) { var bytesHandler = BytesReceived; if (bytesHandler != null) { var bytes = Encoding.GetEncoding(28591).GetBytes(s); this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); } var textHandler = TextReceived; if (textHandler != null) { this.PrintReceivedText(s); textHandler(this, new GenericCommMethodReceiveTextArgs(s)); } } #region IBasicCommunication Members /// /// SendText method /// public void SendText(string text) { if (Port == null) return; this.PrintSentText(text); Port.StreamCec.Send.StringValue = text; } /// /// SendBytes method /// public void SendBytes(byte[] bytes) { if (Port == null) return; var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); this.PrintSentBytes(bytes); Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); Port.StreamCec.Send.StringValue = text; } /// /// Connect method /// public void Connect() { } /// /// Disconnect method /// public void Disconnect() { } #endregion /// /// /// /// /// /// SimulateReceive method /// public void SimulateReceive(string s) { // split out hex chars and build string var split = Regex.Split(s, @"(\\[Xx][0-9a-fA-F][0-9a-fA-F])"); StringBuilder b = new StringBuilder(); foreach (var t in split) { if (t.StartsWith(@"\") && t.Length == 4) b.Append((char)(Convert.ToByte(t.Substring(2, 2), 16))); else b.Append(t); } OnDataReceived(b.ToString()); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs ================================================ using System; using System.Text; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.GeneralIO; using PepperDash.Core; using PepperDash.Core.Logging; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Represents a ComPortController /// public class ComPortController : Device, IBasicCommunicationWithStreamDebugging { /// /// Gets or sets the StreamDebugging /// public CommunicationStreamDebugging StreamDebugging { get; private set; } /// /// Event fired when bytes are received /// public event EventHandler BytesReceived; /// /// Event fired when text is received /// public event EventHandler TextReceived; /// /// Gets or sets the IsConnected /// public bool IsConnected { get { return true; } } ComPort Port; ComPort.ComPortSpec Spec; /// /// Constructor /// /// /// /// /// public ComPortController(string key, Func postActivationFunc, ComPort.ComPortSpec spec, EssentialsControlPropertiesConfig config) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); Spec = spec; AddPostActivationAction(() => { Port = postActivationFunc(config); RegisterAndConfigureComPort(); }); } /// /// Constructor /// /// Device key /// COM port instance /// COM port specification public ComPortController(string key, ComPort port, ComPort.ComPortSpec spec) : base(key) { if (port == null) { Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Invalid com port, continuing but comms will not function"); return; } Port = port; Spec = spec; //IsConnected = new BoolFeedback(CommonBoolCue.IsConnected, () => true); RegisterAndConfigureComPort(); } private void RegisterAndConfigureComPort() { if (Port == null) { this.LogInformation($"Configured {Port.Parent.GetType().Name}-comport-{Port.ID} for {Key} does not exist."); return; } if (Port.Parent is CrestronControlSystem || Port.Parent is CenIoCom102) { var result = Port.Register(); if (result != eDeviceRegistrationUnRegistrationResponse.Success) { this.LogError($"Cannot register {Key} using {Port.Parent.GetType().Name}-comport-{Port.ID} (result == {result})"); return; } this.LogInformation($"Successfully registered {Key} using {Port.Parent.GetType().Name}-comport-{Port.ID} (result == {result})"); } var specResult = Port.SetComPortSpec(Spec); if (specResult != 0) { this.LogError($"Cannot set comspec for {Key} using {Port.Parent.GetType().Name}-comport-{Port.ID} (result == {specResult})"); return; } this.LogInformation($"Successfully set comspec for {Key} using {Port.Parent.GetType().Name}-comport-{Port.ID} (result == {specResult})"); Port.SerialDataReceived += Port_SerialDataReceived; } /// /// Destructor /// ~ComPortController() { Port.SerialDataReceived -= Port_SerialDataReceived; } void Port_SerialDataReceived(ComPort ReceivingComPort, ComPortSerialDataEventArgs args) { OnDataReceived(args.SerialData); } void OnDataReceived(string s) { var eventSubscribed = false; var bytesHandler = BytesReceived; if (bytesHandler != null) { var bytes = Encoding.GetEncoding(28591).GetBytes(s); this.PrintReceivedBytes(bytes); bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); eventSubscribed = true; } var textHandler = TextReceived; if (textHandler != null) { this.PrintReceivedText(s); textHandler(this, new GenericCommMethodReceiveTextArgs(s)); eventSubscribed = true; } if (!eventSubscribed) Debug.LogMessage(LogEventLevel.Warning, this, "Received data but no handler is registered"); } /// /// Deactivate method /// /// public override bool Deactivate() { return Port.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success; } #region IBasicCommunication Members /// /// SendText method /// public void SendText(string text) { if (Port == null) return; this.PrintSentText(text); Port.Send(text); } /// /// SendBytes method /// public void SendBytes(byte[] bytes) { if (Port == null) return; var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); this.PrintSentBytes(bytes); Port.Send(text); } /// /// Connect method /// public void Connect() { } /// /// Disconnect method /// public void Disconnect() { } #endregion /// /// /// /// /// /// SimulateReceive method /// public void SimulateReceive(string s) { // split out hex chars and build string var split = Regex.Split(s, @"(\\[Xx][0-9a-fA-F][0-9a-fA-F])"); StringBuilder b = new StringBuilder(); foreach (var t in split) { if (t.StartsWith(@"\") && t.Length == 4) b.Append((char)(Convert.ToByte(t.Substring(2, 2), 16))); else b.Append(t); } OnDataReceived(b.ToString()); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/ComSpecJsonConverter.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// This converter creates a proper ComPort.ComPortSpec struct from more-friendly JSON values. It uses /// ComSpecPropsJsonConverter to finish the individual properties. /// public class ComSpecJsonConverter : JsonConverter { /// /// ReadJson method /// /// reader to use /// type of the object being read /// existing value of the object being read /// serializer to use /// deserialized object public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (objectType == typeof(ComPort.ComPortSpec?)) { var newSer = new JsonSerializer(); newSer.Converters.Add(new ComSpecPropsJsonConverter()); newSer.ObjectCreationHandling = ObjectCreationHandling.Replace; return newSer.Deserialize(reader); } return null; } /// /// CanConvert method /// /// public override bool CanConvert(Type objectType) { return objectType == typeof(ComPort.ComPortSpec?); } /// /// Gets or sets the CanRead /// public override bool CanRead { get { return true; } } /// /// Gets or sets the CanWrite /// /// public override bool CanWrite { get { return false; } } /// /// WriteJson method /// /// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } /// /// Represents a ComSpecPropsJsonConverter /// public class ComSpecPropsJsonConverter : JsonConverter { /// public override bool CanConvert(Type objectType) { return objectType == typeof(ComPort.eComBaudRates) || objectType == typeof(ComPort.eComDataBits) || objectType == typeof(ComPort.eComParityType) || objectType == typeof(ComPort.eComHardwareHandshakeType) || objectType == typeof(ComPort.eComSoftwareHandshakeType) || objectType == typeof(ComPort.eComProtocolType) || objectType == typeof(ComPort.eComStopBits); } /// /// Gets or sets the CanRead /// /// public override bool CanRead { get { return true; } } /// /// ReadJson method /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { //Debug.LogMessage(LogEventLevel.Verbose, "ReadJson type: " + objectType.Name); if (objectType == typeof(ComPort.eComBaudRates)) return Enum.Parse(typeof(ComPort.eComBaudRates), "ComspecBaudRate" + reader.Value, false); else if (objectType == typeof(ComPort.eComDataBits)) return Enum.Parse(typeof(ComPort.eComDataBits), "ComspecDataBits" + reader.Value, true); else if (objectType == typeof(ComPort.eComHardwareHandshakeType)) return Enum.Parse(typeof(ComPort.eComHardwareHandshakeType), "ComspecHardwareHandshake" + reader.Value, true); else if (objectType == typeof(ComPort.eComParityType)) return Enum.Parse(typeof(ComPort.eComParityType), "ComspecParity" + reader.Value, true); else if (objectType == typeof(ComPort.eComProtocolType)) return Enum.Parse(typeof(ComPort.eComProtocolType), "ComspecProtocol" + reader.Value, true); else if (objectType == typeof(ComPort.eComSoftwareHandshakeType)) return Enum.Parse(typeof(ComPort.eComSoftwareHandshakeType), "ComspecSoftwareHandshake" + reader.Value, true); else if (objectType == typeof(ComPort.eComStopBits)) return Enum.Parse(typeof(ComPort.eComStopBits), "ComspecStopBits" + reader.Value, true); return null; } /// /// WriteJson method /// /// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/CommBridge.cs ================================================ using System; using System.Collections.Generic; using System.Text; using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; namespace PepperDash.Essentials.Core { /// /// Implements IBasicCommunication and sends all communication through an EISC /// [Description("Generic communication wrapper class for any IBasicCommunication type")] public class CommBridge : EssentialsBridgeableDevice, IBasicCommunication { private EiscApiAdvanced eisc; private IBasicCommunicationJoinMap joinMap; /// /// Event triggered when text is received through the communication bridge. /// public event EventHandler TextReceived; /// /// Event triggered when bytes are received through the communication bridge. /// public event EventHandler BytesReceived; /// /// Indicates whether the communication bridge is currently connected. /// public bool IsConnected { get; private set; } /// /// Initializes a new instance of the class. /// /// The unique key for the communication bridge. /// The display name for the communication bridge. public CommBridge(string key, string name) : base(key, name) { } /// /// Sends a byte array through the communication bridge. /// /// The byte array to send. public void SendBytes(byte[] bytes) { if (eisc == null) { this.LogWarning("EISC is null, cannot send bytes."); return; } eisc.Eisc.SetString(joinMap.SendText.JoinNumber, Encoding.ASCII.GetString(bytes, 0, bytes.Length)); } /// /// Sends a text string through the communication bridge. /// /// The text string to send. public void SendText(string text) { if (eisc == null) { this.LogWarning("EISC is null, cannot send text."); return; } eisc.Eisc.SetString(joinMap.SendText.JoinNumber, text); } /// /// Initiates a connection through the communication bridge. /// public void Connect() { if (eisc == null) { this.LogWarning("EISC is null, cannot connect."); return; } eisc.Eisc.SetBool(joinMap.Connect.JoinNumber, true); } /// /// Terminates the connection through the communication bridge. /// public void Disconnect() { if (eisc == null) { this.LogWarning("EISC is null, cannot disconnect."); return; } eisc.Eisc.SetBool(joinMap.Connect.JoinNumber, false); } /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { joinMap = new IBasicCommunicationJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } this.LogDebug("Linking to Trilist '{0}'", trilist.ID.ToString("X")); eisc = bridge; trilist.SetBoolSigAction(joinMap.Connected.JoinNumber, (b) => IsConnected = b); trilist.SetStringSigAction(joinMap.TextReceived.JoinNumber, (s) => { TextReceived?.Invoke(this, new GenericCommMethodReceiveTextArgs(s)); BytesReceived?.Invoke(this, new GenericCommMethodReceiveBytesArgs(Encoding.ASCII.GetBytes(s))); }); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs ================================================  using System; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DM; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// /// public class CommFactory { /// /// GetControlPropertiesConfig method /// /// The Device config object /// EssentialsControlPropertiesConfig object public static EssentialsControlPropertiesConfig GetControlPropertiesConfig(DeviceConfig deviceConfig) { try { return JsonConvert.DeserializeObject (deviceConfig.Properties["control"].ToString()); //Debug.LogMessage(LogEventLevel.Verbose, "Control TEST: {0}", JsonConvert.SerializeObject(controlConfig)); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "ERROR: [{0}] Control properties deserialize failed:\r{1}", deviceConfig.Key, e); return null; } } /// /// Returns a comm method of either com port, TCP, SSH, and puts this into the DeviceManager /// /// The Device config object /// /// CreateCommForDevice method /// public static IBasicCommunication CreateCommForDevice(DeviceConfig deviceConfig) { EssentialsControlPropertiesConfig controlConfig = GetControlPropertiesConfig(deviceConfig); if (controlConfig == null) return null; IBasicCommunication comm = null; try { var c = controlConfig.TcpSshProperties; switch (controlConfig.Method) { case eControlMethod.Com: comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams.Value, controlConfig); break; case eControlMethod.ComBridge: comm = new CommBridge(deviceConfig.Key + "-simpl", deviceConfig.Name + " Simpl"); break; case eControlMethod.Cec: comm = new CecPortController(deviceConfig.Key + "-cec", GetCecPort, controlConfig); break; case eControlMethod.IR: break; case eControlMethod.Ssh: { var ssh = new GenericSshClient(deviceConfig.Key + "-ssh", c.Address, c.Port, c.Username, c.Password) { AutoReconnect = c.AutoReconnect, DisableEcho = c.DisableSshEcho }; if (ssh.AutoReconnect) ssh.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs; comm = ssh; break; } case eControlMethod.Tcpip: { var tcp = new GenericTcpIpClient(deviceConfig.Key + "-tcp", c.Address, c.Port, c.BufferSize) { AutoReconnect = c.AutoReconnect }; if (tcp.AutoReconnect) tcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs; comm = tcp; break; } case eControlMethod.Udp: { var udp = new GenericUdpServer(deviceConfig.Key + "-udp", c.Address, c.Port, c.BufferSize); comm = udp; break; } case eControlMethod.UdpClient: { var udpClient = new GenericUdpClient(deviceConfig.Key + "-udpClient", c.Address, c.Port, c.BufferSize) { AutoReconnect = c.AutoReconnect }; if (udpClient.AutoReconnect) udpClient.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs; comm = udpClient; break; } case eControlMethod.Telnet: break; case eControlMethod.SecureTcpIp: { var secureTcp = new GenericSecureTcpIpClient(deviceConfig.Key + "-secureTcp", c.Address, c.Port, c.BufferSize) { AutoReconnect = c.AutoReconnect }; if (secureTcp.AutoReconnect) secureTcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs; comm = secureTcp; break; } default: break; } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Cannot create communication from JSON:\r{0}\r\rException:\r{1}", deviceConfig.Properties.ToString(), e); } // put it in the device manager if it's the right flavor if (comm is Device comDev) DeviceManager.AddDevice(comDev); return comm; } /// /// GetComPort method /// public static ComPort GetComPort(EssentialsControlPropertiesConfig config) { var comPar = config.ComParams; var dev = GetIComPortsDeviceFromManagedDevice(config.ControlPortDevKey); if (dev != null && config.ControlPortNumber <= dev.NumberOfComPorts) return dev.ComPorts[config.ControlPortNumber.Value]; Debug.LogMessage(LogEventLevel.Information, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber); return null; } /// /// Gets an ICec port from a RoutingInput or RoutingOutput on a device /// /// /// /// /// GetCecPort method /// public static ICec GetCecPort(ControlPropertiesConfig config) { try { var dev = DeviceManager.GetDeviceForKey(config.ControlPortDevKey); Debug.LogMessage(LogEventLevel.Information, "GetCecPort: device '{0}' {1}", config.ControlPortDevKey, dev == null ? "is not valid, failed to get cec port" : "found in device manager, attempting to get cec port"); if (dev == null) return null; if (String.IsNullOrEmpty(config.ControlPortName)) { Debug.LogMessage(LogEventLevel.Information, "GetCecPort: '{0}' - Configuration missing 'ControlPortName'", config.ControlPortDevKey); return null; } var inputsOutputs = dev as IRoutingInputsOutputs; if (inputsOutputs == null) { Debug.LogMessage(LogEventLevel.Information, "GetCecPort: Device '{0}' does not support IRoutingInputsOutputs, failed to get CEC port called '{1}'", config.ControlPortDevKey, config.ControlPortName); return null; } var inputPort = inputsOutputs.InputPorts[config.ControlPortName]; if (inputPort != null && inputPort.Port is ICec) return inputPort.Port as ICec; var outputPort = inputsOutputs.OutputPorts[config.ControlPortName]; if (outputPort != null && outputPort.Port is ICec) return outputPort.Port as ICec; } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Debug, "GetCecPort Exception Message: {0}", ex.Message); Debug.LogMessage(LogEventLevel.Verbose, "GetCecPort Exception StackTrace: {0}", ex.StackTrace); if (ex.InnerException != null) Debug.LogMessage(LogEventLevel.Information, "GetCecPort Exception InnerException: {0}", ex.InnerException); } Debug.LogMessage(LogEventLevel.Information, "GetCecPort: Device '{0}' does not have a CEC port called '{1}'", config.ControlPortDevKey, config.ControlPortName); return null; } /// /// Helper to grab the IComPorts device for this PortDeviceKey. Key "controlSystem" will /// return the ControlSystem object from the Global class. /// /// IComPorts device or null if the device is not found or does not implement IComPorts /// /// GetIComPortsDeviceFromManagedDevice method /// public static IComPorts GetIComPortsDeviceFromManagedDevice(string ComPortDevKey) { if ((ComPortDevKey.Equals("controlSystem", System.StringComparison.OrdinalIgnoreCase) || ComPortDevKey.Equals("processor", System.StringComparison.OrdinalIgnoreCase)) && Global.ControlSystem is IComPorts) return Global.ControlSystem; else { var dev = DeviceManager.GetDeviceForKey(ComPortDevKey) as IComPorts; if (dev == null) Debug.LogMessage(LogEventLevel.Information, "ComPortConfig: Cannot find com port device '{0}'", ComPortDevKey); return dev; } } } /// /// Represents a EssentialsControlPropertiesConfig /// public class EssentialsControlPropertiesConfig : ControlPropertiesConfig { /// /// Gets or sets the ComParams /// [JsonProperty("comParams", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(ComSpecJsonConverter))] public ComPort.ComPortSpec? ComParams { get; set; } /// /// Gets or sets the CresnetId /// [JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)] public string CresnetId { get; set; } /// /// Attempts to provide uint conversion of string CresnetId /// [JsonIgnore] public uint CresnetIdInt { get { try { return Convert.ToUInt32(CresnetId, 16); } catch (Exception) { throw new FormatException(string.Format("ERROR:Unable to convert Cresnet ID: {0} to hex. Error:\n{1}", CresnetId)); } } } /// /// Gets or sets the InfinetId /// [JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)] public string InfinetId { get; set; } /// /// Attepmts to provide uiont conversion of string InifinetId /// [JsonIgnore] public uint InfinetIdInt { get { try { return Convert.ToUInt32(InfinetId, 16); } catch (Exception) { throw new FormatException(string.Format("ERROR:Unable to conver Infinet ID: {0} to hex. Error:\n{1}", InfinetId)); } } } } /// /// Represents a IrControlSpec /// public class IrControlSpec { /// /// Gets or sets the PortDeviceKey /// public string PortDeviceKey { get; set; } /// /// Gets or sets the PortNumber /// public uint PortNumber { get; set; } /// /// Gets or sets the File /// public string File { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/CommunicationExtras.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// /// public interface IComPortsDevice { /// /// Gets the Device /// IComPorts Device { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/ConsoleCommMockDevice.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Represents a ConsoleCommMockDevice /// public class ConsoleCommMockDevice : EssentialsDevice, ICommunicationMonitor { /// /// Gets or sets the Communication /// public IBasicCommunication Communication { get; private set; } /// /// Gets or sets the PortGather /// public CommunicationGather PortGather { get; private set; } /// /// Gets or sets the CommunicationMonitor /// public StatusMonitorBase CommunicationMonitor { get; private set; } /// /// Gets or sets the LineEnding /// public string LineEnding { get; set; } /// /// Gets or sets the ShowHexResponse /// public bool ShowHexResponse { get; set; } /// /// Initializes a new instance of the ConsoleCommMockDevice class. /// /// The key of the device. /// The name of the device. /// The properties configuration for the device. /// The communication method for the device. public ConsoleCommMockDevice(string key, string name, ConsoleCommMockDevicePropertiesConfig props, IBasicCommunication comm) :base(key, name) { Communication = comm; PortGather = new CommunicationGather(Communication, '\x0d'); //PortGather.LineReceived += this.Port_LineReceived; CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties); LineEnding = props.LineEnding; } /// /// CustomActivate method /// /// public override bool CustomActivate() { Communication.Connect(); CommunicationMonitor.StatusChange += (o, a) => { Debug.LogMessage(LogEventLevel.Verbose, 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 SendLine(string s) { //if (Debug.Level == 2) // Debug.LogMessage(LogEventLevel.Verbose, this, " Send '{0}'", ComTextHelper.GetEscapedText(s)); Communication.SendText(s + LineEnding); } } /// /// Represents a ConsoleCommMockDevicePropertiesConfig /// public class ConsoleCommMockDevicePropertiesConfig { /// /// Gets or sets the LineEnding /// public string LineEnding { get; set; } /// /// Gets or sets the CommunicationMonitorProperties /// public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } /// /// Initializes a new instance of the ConsoleCommMockDevicePropertiesConfig class. /// public ConsoleCommMockDevicePropertiesConfig() { LineEnding = "\x0a"; } } /// /// Represents a ConsoleCommMockDeviceFactory /// public class ConsoleCommMockDeviceFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the ConsoleCommMockDeviceFactory class. /// public ConsoleCommMockDeviceFactory() { TypeNames = new List() { "commmock" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Comm Mock Device"); var comm = CommFactory.CreateCommForDevice(dc); var props = Newtonsoft.Json.JsonConvert.DeserializeObject( dc.Properties.ToString()); return new ConsoleCommMockDevice(dc.Key, dc.Name, props, comm); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/GenericComm.cs ================================================  using System; using System.Collections.Generic; using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Serves as a generic wrapper class for all styles of IBasicCommuncation ports /// [Description("Generic communication wrapper class for any IBasicCommunication type")] public class GenericComm : ReconfigurableBridgableDevice { EssentialsControlPropertiesConfig PropertiesConfig; /// /// Gets the CommPort /// public IBasicCommunication CommPort { get; private set; } /// /// Constructor /// /// the config of the device public GenericComm(DeviceConfig config) : base(config) { PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); var commPort = CommFactory.CreateCommForDevice(config); //Fixing decision to require '-comPorts' in declaration for DGE in order to get a device with comports included if (commPort == null) { config.Key = config.Key + "-comPorts"; commPort = CommFactory.CreateCommForDevice(config); } CommPort = commPort; } /// /// BuildDevice method /// public static IKeyed BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); return new GenericComm(dc); } /// /// SetPortConfig method /// public void SetPortConfig(string portConfig) { // TODO: Deserialize new EssentialsControlPropertiesConfig and handle as necessary try { PropertiesConfig = JsonConvert.DeserializeObject (portConfig); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, this, "Error deserializing port config: {0}", e); } } /// /// CustomSetConfig method /// /// the new device configuration protected override void CustomSetConfig(DeviceConfig config) { PropertiesConfig = CommFactory.GetControlPropertiesConfig(config); ConfigWriter.UpdateDeviceConfig(config); } /// /// LinkToApi method /// /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new IBasicCommunicationJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } if (CommPort == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. CommPort is null", Key); return; } Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); // this is a permanent event handler. This cannot be -= from event CommPort.TextReceived += (s, a) => { trilist.SetString(joinMap.TextReceived.JoinNumber, a.Text); }; trilist.SetStringSigAction(joinMap.SendText.JoinNumber, s => CommPort.SendText(s)); trilist.SetStringSigAction(joinMap.SetPortConfig.JoinNumber, SetPortConfig); var sComm = CommPort as ISocketStatus; if (sComm == null) return; sComm.ConnectionChange += (s, a) => { trilist.SetUshort(joinMap.Status.JoinNumber, (ushort)(a.Client.ClientStatus)); trilist.SetBool(joinMap.Connected.JoinNumber, a.Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED); }; trilist.SetBoolSigAction(joinMap.Connect.JoinNumber, b => { if (b) { sComm.Connect(); } else { sComm.Disconnect(); } }); } } /// /// Represents a GenericCommFactory /// public class GenericCommFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the GenericCommFactory class. /// public GenericCommFactory() { TypeNames = new List() { "genericComm" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); return new GenericComm(dc); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/GenericHttpClient.cs ================================================ using Crestron.SimplSharp.Net.Http; using PepperDash.Core; using System; namespace PepperDash.Essentials.Core { /// /// Represents a GenericHttpClient /// [Obsolete("Please use the builtin HttpClient class instead: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines")] public class GenericHttpClient : Device, IBasicCommunication { private readonly HttpClient Client; /// /// Event raised when response is received /// public event EventHandler ResponseRecived; /// /// Constructor /// /// key of the device /// name of the device /// hostname for the HTTP client public GenericHttpClient(string key, string name, string hostname) : base(key, name) { Client = new HttpClient { HostName = hostname }; } /// /// SendText method /// /// the path to send the request to public void SendText(string path) { HttpClientRequest request = new HttpClientRequest(); string url = string.Format("http://{0}/{1}", Client.HostName, path); request.Url = new UrlParser(url); HttpClient.DISPATCHASYNC_ERROR error = Client.DispatchAsyncEx(request, Response, request); } /// /// SendText method /// /// format for the items /// items to format public void SendText(string format, params object[] items) { HttpClientRequest request = new HttpClientRequest(); string url = string.Format("http://{0}/{1}", Client.HostName, string.Format(format, items)); request.Url = new UrlParser(url); HttpClient.DISPATCHASYNC_ERROR error = Client.DispatchAsyncEx(request, Response, request); } /// /// SendTextNoResponse method /// /// format for the items /// items to format public void SendTextNoResponse(string format, params object[] items) { HttpClientRequest request = new HttpClientRequest(); string url = string.Format("http://{0}/{1}", Client.HostName, string.Format(format, items)); request.Url = new UrlParser(url); Client.Dispatch(request); } /// /// Response method /// /// response received from the HTTP client /// error status of the HTTP callback /// original HTTP client request private void Response(HttpClientResponse response, HTTP_CALLBACK_ERROR error, object request) { if (error == HTTP_CALLBACK_ERROR.COMPLETED) { var responseReceived = response; if (responseReceived.ContentString.Length > 0) { ResponseRecived?.Invoke(this, new GenericHttpClientEventArgs(responseReceived.ContentString, (request as HttpClientRequest).Url.ToString(), error)); } } } #region IBasicCommunication Members /// /// SendBytes method /// /// bytes to send public void SendBytes(byte[] bytes) { throw new NotImplementedException(); } #endregion #region ICommunicationReceiver Members /// /// BytesReceived event /// public event EventHandler BytesReceived; /// /// Connect method /// public void Connect() { throw new NotImplementedException(); } /// /// Disconnect method /// public void Disconnect() { throw new NotImplementedException(); } /// /// IsConnected property /// public bool IsConnected { get { return true; } } /// /// TextReceived event /// public event EventHandler TextReceived; #endregion } /// /// Represents a GenericHttpClientEventArgs /// public class GenericHttpClientEventArgs : EventArgs { /// /// Gets or sets the ResponseText /// public string ResponseText { get; private set; } /// /// Gets or sets the RequestPath /// public string RequestPath { get; private set; } /// /// Gets or sets the Error /// public HTTP_CALLBACK_ERROR Error { get; set; } /// /// Constructor /// /// response text /// request path /// error status public GenericHttpClientEventArgs(string response, string request, HTTP_CALLBACK_ERROR error) { ResponseText = response; RequestPath = request; Error = error; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs ================================================  using System; using System.Collections.Generic; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Helper class for IR port operations /// public static class IRPortHelper { /// /// Gets the IrDriverPathPrefix /// public static string IrDriverPathPrefix { get { return Global.FilePathPrefix + "IR" + Global.DirectorySeparator; } } /// /// Finds either the ControlSystem or a device controller that contains IR ports and /// returns a port from the hardware device /// /// JSON token containing properties /// IrPortConfig object. The port and or filename will be empty/null /// if valid values don't exist on config public static IrOutPortConfig GetIrPort(JToken propsToken) { var control = propsToken["control"]; if (control == null) return null; if (control["method"].Value() != "ir") { Debug.LogMessage(LogEventLevel.Information, "IRPortHelper called with non-IR properties"); return null; } var port = new IrOutPortConfig(); var portDevKey = control.Value("controlPortDevKey"); var portNum = control.Value("controlPortNumber"); if (portDevKey == null || portNum == 0) { Debug.LogMessage(LogEventLevel.Debug, "WARNING: Properties is missing port device or port number"); return port; } IIROutputPorts irDev = null; if (portDevKey.Equals("controlSystem", StringComparison.OrdinalIgnoreCase) || portDevKey.Equals("processor", StringComparison.OrdinalIgnoreCase)) irDev = Global.ControlSystem; else irDev = DeviceManager.GetDeviceForKey(portDevKey) as IIROutputPorts; if (irDev == null) { Debug.LogMessage(LogEventLevel.Debug, "[Config] Error, device with IR ports '{0}' not found", portDevKey); return port; } if (portNum <= irDev.NumberOfIROutputPorts) // success! { var file = IrDriverPathPrefix + control["irFile"].Value(); port.Port = irDev.IROutputPorts[portNum]; port.FileName = file; return port; // new IrOutPortConfig { Port = irDev.IROutputPorts[portNum], FileName = file }; } else { Debug.LogMessage(LogEventLevel.Debug, "[Config] Error, device '{0}' IR port {1} out of range", portDevKey, portNum); return port; } } /// /// GetIrOutputPort method /// /// DeviceConfig to get the IR port for /// IROutputPort or null if not found public static IROutputPort GetIrOutputPort(DeviceConfig dc) { var irControllerKey = dc.Key + "-ir"; if (dc.Properties == null) { Debug.LogMessage(LogEventLevel.Information, "[{0}] WARNING: Device config does not include properties. IR will not function.", dc.Key); return null; } var control = dc.Properties["control"]; if (control == null) { Debug.LogMessage(LogEventLevel.Information, "WARNING: Device config does not include control properties. IR will not function for {0}", dc.Key); return null; } var portDevKey = control.Value("controlPortDevKey"); var portNum = control.Value("controlPortNumber"); IIROutputPorts irDev = null; if (portDevKey == null) { Debug.LogMessage(LogEventLevel.Information, "WARNING: control properties is missing ir device for {0}", dc.Key); return null; } if (portNum == 0) { Debug.LogMessage(LogEventLevel.Information, "WARNING: control properties is missing ir port number for {0}", dc.Key); return null; } if (portDevKey.Equals("controlSystem", StringComparison.OrdinalIgnoreCase) || portDevKey.Equals("processor", StringComparison.OrdinalIgnoreCase)) irDev = Global.ControlSystem; else irDev = DeviceManager.GetDeviceForKey(portDevKey) as IIROutputPorts; if (irDev == null) { Debug.LogMessage(LogEventLevel.Information, "WARNING: device with IR ports '{0}' not found", portDevKey); return null; } if (portNum > irDev.NumberOfIROutputPorts) { Debug.LogMessage(LogEventLevel.Information, "WARNING: device '{0}' IR port {1} out of range", portDevKey, portNum); return null; } var port = irDev.IROutputPorts[portNum]; return port; } /// /// GetIrOutputPortController method /// /// DeviceConfig to create the IrOutputPortController for /// IrOutputPortController object public static IrOutputPortController GetIrOutputPortController(DeviceConfig config) { Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Ir Port Controller"); if (config == null) { return null; } var postActivationFunc = new Func (GetIrOutputPort); var irDevice = new IrOutputPortController(config.Key + "-ir", postActivationFunc, config); return irDevice; } /* /// /// GetIrOutputPortController method /// public static IrOutputPortController GetIrOutputPortController(DeviceConfig devConf) { var irControllerKey = devConf.Key + "-ir"; if (devConf.Properties == null) { Debug.LogMessage(LogEventLevel.Information, "[{0}] WARNING: Device config does not include properties. IR will not function.", devConf.Key); return new IrOutputPortController(irControllerKey, null, ""); } var control = devConf.Properties["control"]; if (control == null) { var c = new IrOutputPortController(irControllerKey, null, ""); Debug.LogMessage(LogEventLevel.Information, c, "WARNING: Device config does not include control properties. IR will not function"); return c; } var portDevKey = control.Value("controlPortDevKey"); var portNum = control.Value("controlPortNumber"); IIROutputPorts irDev = null; if (portDevKey == null) { var c = new IrOutputPortController(irControllerKey, null, ""); Debug.LogMessage(LogEventLevel.Information, c, "WARNING: control properties is missing ir device"); return c; } if (portNum == 0) { var c = new IrOutputPortController(irControllerKey, null, ""); Debug.LogMessage(LogEventLevel.Information, c, "WARNING: control properties is missing ir port number"); return c; } if (portDevKey.Equals("controlSystem", StringComparison.OrdinalIgnoreCase) || portDevKey.Equals("processor", StringComparison.OrdinalIgnoreCase)) irDev = Global.ControlSystem; else irDev = DeviceManager.GetDeviceForKey(portDevKey) as IIROutputPorts; if (irDev == null) { var c = new IrOutputPortController(irControllerKey, null, ""); Debug.LogMessage(LogEventLevel.Information, c, "WARNING: device with IR ports '{0}' not found", portDevKey); return c; } if (portNum <= irDev.NumberOfIROutputPorts) // success! return new IrOutputPortController(irControllerKey, irDev.IROutputPorts[portNum], IrDriverPathPrefix + control["irFile"].Value()); else { var c = new IrOutputPortController(irControllerKey, null, ""); Debug.LogMessage(LogEventLevel.Information, c, "WARNING: device '{0}' IR port {1} out of range", portDevKey, portNum); return c; } }*/ } /// /// Represents a IrOutPortConfig /// public class IrOutPortConfig { /// /// Gets or sets the Port /// [JsonProperty("port")] public IROutputPort Port { get; set; } /// /// Gets or sets the FileName /// [JsonProperty("fileName")] public string FileName { get; set; } /// /// Gets or sets a value indicating whether to use bridge join map /// [JsonProperty("useBridgeJoinMap")] public bool UseBridgeJoinMap { get; set; } /// /// Constructor /// public IrOutPortConfig() { FileName = ""; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/AudioControlPointListItem.cs ================================================ using Crestron.SimplSharpPro; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.Config { /// /// Represents a AudioControlPointListItem /// public class AudioControlPointListItem { /// /// Level controls for this audio control point /// [JsonProperty("levelControls")] public Dictionary LevelControls { get; set; } = new Dictionary(); /// /// Presets for this audio control point /// [JsonProperty("presets")] public Dictionary Presets { get; set; } = new Dictionary(); } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/BaseStreamingDeviceProperties.cs ================================================ using System; using Newtonsoft.Json; namespace PepperDash.Essentials.Core.Config { /// /// Represents the base properties for a streaming device. /// public class BaseStreamingDeviceProperties { /// /// The multicast video address for the streaming device. /// [JsonProperty("multicastVideoAddress", NullValueHandling = NullValueHandling.Ignore)] public string MulticastVideoAddress { get; set; } /// /// The multicast audio address for the streaming device. /// [JsonProperty("multicastAudioAddress", NullValueHandling = NullValueHandling.Ignore)] public string MulticastAudioAddress { get; set; } /// /// The URL for the streaming device's media stream. /// [JsonProperty("streamUrl", NullValueHandling = NullValueHandling.Ignore)] public string StreamUrl { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/BasicConfig.cs ================================================  using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.Devices; namespace PepperDash.Essentials.Core.Config { /// /// Override this and splice on specific room type behavior, as well as other properties /// public class BasicConfig { /// /// Gets or sets the Info /// [JsonProperty("info")] public InfoConfig Info { get; set; } /// /// Gets or sets the Devices /// [JsonProperty("devices")] public List Devices { get; set; } /// /// Gets or sets the SourceLists /// [JsonProperty("sourceLists")] public Dictionary> SourceLists { get; set; } /// /// Gets or sets the DestinationLists /// [JsonProperty("destinationLists")] public Dictionary> DestinationLists { get; set; } /// /// Gets or sets the AudioControlPointLists /// [JsonProperty("audioControlPointLists")] public Dictionary AudioControlPointLists { get; set; } /// /// Gets or sets the CameraLists /// [JsonProperty("cameraLists")] public Dictionary> CameraLists { get; set; } /// /// Gets or sets the TieLines /// [JsonProperty("tieLines")] public List TieLines { get; set; } /// /// Gets or sets the JoinMaps /// [JsonProperty("joinMaps")] public Dictionary JoinMaps { get; set; } /// /// BasicConfig Constructor /// public BasicConfig() { Info = new InfoConfig(); Devices = new List(); SourceLists = new Dictionary>(); DestinationLists = new Dictionary>(); AudioControlPointLists = new Dictionary(); CameraLists = new Dictionary>(); TieLines = new List(); JoinMaps = new Dictionary(); } /// /// Checks SourceLists for a given list and returns it if found. Otherwise, returns null /// public Dictionary GetSourceListForKey(string key) { if (SourceLists == null || string.IsNullOrEmpty(key) || !SourceLists.ContainsKey(key)) return null; return SourceLists[key]; } /// /// Retrieves a DestinationListItem based on the key /// /// key of the list to retrieve /// DestinationList if the key exists, null otherwise public Dictionary GetDestinationListForKey(string key) { if (DestinationLists == null || string.IsNullOrEmpty(key) || !DestinationLists.ContainsKey(key)) { return null; } return DestinationLists[key]; } /// /// Retrieves a AudioControlPointList based on the key /// /// key of the list to retrieve /// AudioControlPointList if the key exists, null otherwise /// /// GetAudioControlPointListForKey method /// public AudioControlPointListItem GetAudioControlPointListForKey(string key) { if (AudioControlPointLists == null || string.IsNullOrEmpty(key) || !AudioControlPointLists.ContainsKey(key)) return null; return AudioControlPointLists[key]; } /// /// Checks CameraLists for a given list and returns it if found. Otherwise, returns null /// /// Key of desired camera list public Dictionary GetCameraListForKey(string key) { if (CameraLists == null || string.IsNullOrEmpty(key) || !CameraLists.ContainsKey(key)) return null; return CameraLists[key]; } /// /// Checks Devices for an item with a Key that matches and returns it if found. Otherwise, retunes null /// /// Key of desired device public DeviceConfig GetDeviceForKey(string key) { if (string.IsNullOrEmpty(key)) return null; var deviceConfig = Devices.FirstOrDefault(d => d.Key.Equals(key)); if (deviceConfig != null) return deviceConfig; else { return null; } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/ConfigPropertiesHelpers.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; using Newtonsoft.Json.Linq; namespace PepperDash.Essentials.Core.Config { /// /// Represents a ConfigPropertiesHelpers /// public class ConfigPropertiesHelpers { /// /// GetHasAudio method /// public static bool GetHasAudio(DeviceConfig deviceConfig) { return deviceConfig.Properties.Value("hasAudio"); } /// /// Returns the value of properties.hasControls, or false if not defined /// public static bool GetHasControls(DeviceConfig deviceConfig) { return deviceConfig.Properties.Value("hasControls"); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/DeviceConfig.cs ================================================  using System; using System.Collections.Generic; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Config { /// /// Represents a DeviceConfig /// public class DeviceConfig { /// /// Gets or sets the Key /// [JsonProperty("key")] public string Key { get; set; } /// /// Gets or sets the Uid /// [JsonProperty("uid")] public int Uid { get; set; } /// /// Gets or sets the Name /// [JsonProperty("name")] public string Name { get; set; } /// /// Gets or sets the Group /// [JsonProperty("group")] public string Group { get; set; } /// /// Gets or sets the Type /// [JsonProperty("type")] public string Type { get; set; } /// /// Gets or sets the Properties /// [JsonProperty("properties")] [JsonConverter(typeof(DevicePropertiesConverter))] public JToken Properties { get; set; } /// /// Constructor /// /// device config public DeviceConfig(DeviceConfig dc) { Key = dc.Key; Uid = dc.Uid; Name = dc.Name; Group = dc.Group; Type = dc.Type; Properties = JToken.Parse(dc.Properties.ToString()); //Properties = JToken.FromObject(dc.Properties); } /// /// Default Constructor /// public DeviceConfig() { } } /// /// Represents a DevicePropertiesConverter /// public class DevicePropertiesConverter : JsonConverter { /// /// CanConvert method /// public override bool CanConvert(Type objectType) { return objectType == typeof(JToken); } /// /// ReadJson method /// /// reader to use /// type of object being read /// existing value for the object /// serializer to use /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return JToken.ReadFrom(reader); } /// public override bool CanWrite { get { return false; } } /// /// WriteJson method /// /// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException("SOD OFF HOSER"); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/Essentials/ConfigReader.cs ================================================  using System; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core.Config { /// /// Loads the ConfigObject from the file /// public class ConfigReader { /// /// Local Config Present Message /// public const string LocalConfigPresent = @" *************************************************** ************* Using Local config file ************* ***************************************************"; /// /// The loaded config object /// public static EssentialsConfig ConfigObject { get; private set; } /// /// LoadConfig2 method /// public static bool LoadConfig2() { Debug.LogMessage(LogEventLevel.Information, "Loading unmerged system/template portal configuration file."); try { // Check for local config file first var filePath = Global.FilePathPrefix + ConfigWriter.LocalConfigFolder + Global.DirectorySeparator + Global.ConfigFileName; bool localConfigFound = false; Debug.LogMessage(LogEventLevel.Information, "Attempting to load Local config file: '{0}'", filePath); // Check for local config directory first var configFiles = GetConfigFiles(filePath); if (configFiles != null) { if (configFiles.Length > 1) { Debug.LogMessage(LogEventLevel.Information, "****Error: Multiple Local Configuration files present. Please ensure only a single file exists and reset program.****"); return false; } if(configFiles.Length == 1) { localConfigFound = true; } } else { Debug.LogMessage(LogEventLevel.Information, "Local Configuration file not present.", filePath); } // Check for Portal Config if(!localConfigFound) { filePath = Global.FilePathPrefix + Global.ConfigFileName; Debug.LogMessage(LogEventLevel.Information, "Attempting to load Portal config file: '{0}'", filePath); configFiles = GetConfigFiles(filePath); if (configFiles != null) { Debug.LogMessage(LogEventLevel.Verbose, "{0} config files found matching pattern", configFiles.Length); if (configFiles.Length > 1) { Debug.LogMessage(LogEventLevel.Information, "****Error: Multiple Portal Configuration files present. Please ensure only a single file exists and reset program.****"); return false; } else if (configFiles.Length == 1) { Debug.LogMessage(LogEventLevel.Information, "Found Portal config file: '{0}'", filePath); } else { Debug.LogMessage(LogEventLevel.Information, "No config file found."); return false; } } else { Debug.LogMessage(LogEventLevel.Information, "ERROR: Portal Configuration file not present. Please load file and reset program."); return false; } } // Get the actual file path filePath = configFiles[0].FullName; // Generate debug statement if using a local file. if (localConfigFound) { GetLocalFileMessage(filePath); } // Read the file using (StreamReader fs = new StreamReader(filePath)) { Debug.LogMessage(LogEventLevel.Information, "Loading config file: '{0}'", filePath); if (localConfigFound) { ConfigObject = JObject.Parse(fs.ReadToEnd()).ToObject(); Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded Local Config"); return true; } else { var parsedConfig = JObject.Parse(fs.ReadToEnd()); // Check if it's a v2 config (check for "version" node) // this means it's already merged by the Portal API // from the v2 config tool var isV2Config = parsedConfig["versions"] != null; if (isV2Config) { Debug.LogMessage(LogEventLevel.Information, "Config file is a v2 format, no merge necessary."); ConfigObject = parsedConfig.ToObject(); Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded v2 Config"); return true; } // Extract SystemUrl and TemplateUrl into final config output ConfigObject = PortalConfigReader.MergeConfigs(parsedConfig).ToObject(); if (parsedConfig["system_url"] != null) { ConfigObject.SystemUrl = parsedConfig["system_url"].Value(); } if (parsedConfig["template_url"] != null) { ConfigObject.TemplateUrl = parsedConfig["template_url"].Value(); } } Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded Merged Config"); return true; } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "ERROR: Config load failed: \r{0}", e); return false; } } /// /// Returns all the files from the directory specified. /// /// path to the directory /// config files public static FileInfo[] GetConfigFiles(string filePath) { // Get the directory var dir = Path.GetDirectoryName(filePath); if (Directory.Exists(dir)) { Debug.LogMessage(LogEventLevel.Debug, "Searching in Directory '{0}'", dir); // Get the directory info var dirInfo = new DirectoryInfo(dir); // Get the file name var fileName = Path.GetFileName(filePath); Debug.LogMessage(LogEventLevel.Debug, "For Config Files matching: '{0}'", fileName); // Get the files that match from the directory return dirInfo.GetFiles(fileName); } else { Debug.LogMessage(LogEventLevel.Information, "Directory not found: ", dir); return null; } } /// /// Returns the group for a given device key in config /// /// Key of the device /// Group name if the device is found, null otherwise public static string GetGroupForDeviceKey(string key) { var dev = ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); return dev == null ? null : dev.Group; } private static void GetLocalFileMessage(string filePath) { var filePathLength = filePath.Length + 2; var debugStringWidth = filePathLength + 12; if (debugStringWidth < 51) { debugStringWidth = 51; } var qualifier = (filePathLength % 2 != 0) ? " Using Local Config File " : " Using Local Config File "; var bookend1 = (debugStringWidth - qualifier.Length) / 2; var bookend2 = (debugStringWidth - filePathLength) / 2; var newDebugString = new StringBuilder() .Append(CrestronEnvironment.NewLine) // Line 1 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) // Line 2 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) // Line 3 .Append(new string('*', 2)) .Append(new string(' ', debugStringWidth - 4)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) // Line 4 .Append(new string('*', 2)) .Append(new string(' ', bookend1 - 2)) .Append(qualifier) .Append(new string(' ', bookend1 - 2)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) // Line 5 .Append(new string('*', 2)) .Append(new string(' ', bookend2 - 2)) .Append(" " + filePath + " ") .Append(new string(' ', bookend2 - 2)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) // Line 6 .Append(new string('*', 2)) .Append(new string(' ', debugStringWidth - 4)) .Append(new string('*', 2)) .Append(CrestronEnvironment.NewLine) // Line 7 .Append(new string('*', debugStringWidth)) .Append(CrestronEnvironment.NewLine) // Line 8 .Append(new string('*', debugStringWidth)); Debug.LogMessage(LogEventLevel.Verbose, "Found Local config file: '{0}'", filePath); Debug.LogMessage(LogEventLevel.Information, newDebugString.ToString()); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/Essentials/ConfigUpdater.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharpPro.Diagnostics; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core.Config { /// /// ConfigUpdater class /// [Obsolete("ConfigUpdater is no longer supported and will be removed in a future release.")] public static class ConfigUpdater { /// /// ConfigStatusChanged event /// public static event EventHandler ConfigStatusChanged; /// /// GetConfigFromServer method /// /// URL of the config server public static void GetConfigFromServer(string url) { Debug.LogMessage(LogEventLevel.Information, "Attempting to get new config from '{0}'", url); // HTTP GET var req = new HttpClientRequest(); try { req.RequestType = RequestType.Get; req.Url.Parse(url); new HttpClient().DispatchAsync(req, (r, e) => { if (e == HTTP_CALLBACK_ERROR.COMPLETED) { if (r.Code == 200) { var newConfig = r.ContentString; OnStatusUpdate(eUpdateStatus.ConfigFileReceived); ArchiveExistingPortalConfigs(); CheckForLocalConfigAndDelete(); WriteConfigToFile(newConfig); RestartProgram(); } else { Debug.LogMessage(LogEventLevel.Information, "Config Update Process Stopped. Failed to get config file from server: {0}", r.Code); OnStatusUpdate(eUpdateStatus.UpdateFailed); } } else Debug.LogMessage(LogEventLevel.Information, "Request for config from Server Failed: {0}", e); }); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, "Error Getting Config from Server: {0}", e); } } static void OnStatusUpdate(eUpdateStatus status) { var handler = ConfigStatusChanged; if (handler != null) { handler(typeof(ConfigUpdater), new ConfigStatusEventArgs(status)); } } static void WriteConfigToFile(string configData) { var filePath = Global.FilePathPrefix + "configurationFile-updated.json"; try { var config = JObject.Parse(configData).ToObject(); ConfigWriter.WriteFile(filePath, configData); OnStatusUpdate(eUpdateStatus.WritingConfigFile); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, "Error parsing new config: {0}", e); OnStatusUpdate(eUpdateStatus.UpdateFailed); } } /// /// Checks for any existing portal config files and archives them /// static void ArchiveExistingPortalConfigs() { var filePath = Global.FilePathPrefix + Global.ConfigFileName; var configFiles = ConfigReader.GetConfigFiles(filePath); if (configFiles != null) { Debug.LogMessage(LogEventLevel.Information, "Existing config files found. Moving to Archive folder."); OnStatusUpdate(eUpdateStatus.ArchivingConfigs); MoveFilesToArchiveFolder(configFiles); } else { Debug.LogMessage(LogEventLevel.Information, "No Existing config files found in '{0}'. Nothing to archive", filePath); } } /// /// Checks for presence of archive folder and if found deletes contents. /// Moves any config files to the archive folder and adds a .bak suffix /// /// static void MoveFilesToArchiveFolder(FileInfo[] files) { string archiveDirectoryPath = Global.FilePathPrefix + "archive"; if (!Directory.Exists(archiveDirectoryPath)) { // Directory does not exist, create it Directory.Create(archiveDirectoryPath); } else { // Directory exists, first clear any contents var archivedConfigFiles = ConfigReader.GetConfigFiles(archiveDirectoryPath + Global.DirectorySeparator + Global.ConfigFileName + ".bak"); if (archivedConfigFiles != null && archivedConfigFiles.Length > 0) { Debug.LogMessage(LogEventLevel.Information, "{0} Existing files found in archive folder. Deleting.", archivedConfigFiles.Length); for (int i = 0; i < archivedConfigFiles.Length; i++) { var file = archivedConfigFiles[i]; Debug.LogMessage(LogEventLevel.Information, "Deleting archived file: '{0}'", file.FullName); file.Delete(); } } } // Move any files from the program folder to the archive folder foreach (var file in files) { Debug.LogMessage(LogEventLevel.Information, "Moving config file '{0}' to archive folder", file.FullName); // Moves the file and appends the .bak extension var fileDest = archiveDirectoryPath + "/" + file.Name + ".bak"; if (!File.Exists(fileDest)) { file.MoveTo(fileDest); } else Debug.LogMessage(LogEventLevel.Information, "Cannot move file to archive folder. Existing file already exists with same name: '{0}'", fileDest); } } /// /// Checks for LocalConfig folder in file system and deletes if found /// static void CheckForLocalConfigAndDelete() { var folderPath = Global.FilePathPrefix + ConfigWriter.LocalConfigFolder; if (Directory.Exists(folderPath)) { OnStatusUpdate(eUpdateStatus.DeletingLocalConfig); Directory.Delete(folderPath); Debug.LogMessage(LogEventLevel.Information, "Local Config Found in '{0}'. Deleting.", folderPath); } } /// /// Connects to the processor via SSH and restarts the program /// static void RestartProgram() { Debug.LogMessage(LogEventLevel.Information, "Attempting to Reset Program"); OnStatusUpdate(eUpdateStatus.RestartingProgram); string response = string.Empty; CrestronConsole.SendControlSystemCommand(string.Format("progreset -p:{0}", InitialParametersClass.ApplicationNumber), ref response); Debug.LogMessage(LogEventLevel.Debug, "Console Response: {0}", response); } } /// /// Enumeration of eUpdateStatus values /// public enum eUpdateStatus { /// /// UpdateStarted status /// UpdateStarted, /// /// ConfigFileReceived status /// ConfigFileReceived, /// /// ArchivingConfigs status /// ArchivingConfigs, /// /// DeletingLocalConfig status /// DeletingLocalConfig, /// /// WritingConfigFile status /// WritingConfigFile, /// /// RestartingProgram status /// RestartingProgram, /// /// UpdateSucceeded status /// UpdateSucceeded, /// /// UpdateFailed status /// UpdateFailed } /// /// Represents a ConfigStatusEventArgs /// public class ConfigStatusEventArgs : EventArgs { /// /// Gets or sets the UpdateStatus /// public eUpdateStatus UpdateStatus { get; private set; } /// /// ConfigStatusEventArgs Constructor /// /// public ConfigStatusEventArgs(eUpdateStatus status) { UpdateStatus = status; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/Essentials/ConfigWriter.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core.Config { /// /// Responsible for updating config at runtime, and writing the updates out to a local file /// public class ConfigWriter { /// /// LocalConfigFolder constant /// public const string LocalConfigFolder = "LocalConfig"; /// /// WriteTimeout constant /// public const long WriteTimeout = 30000; /// /// WriteTimer variable /// public static CTimer WriteTimer; static CCriticalSection fileLock = new CCriticalSection(); /// /// Updates the config properties of a device /// /// The key of the device to update /// The new properties for the device /// True if the update was successful, otherwise false public static bool UpdateDeviceProperties(string deviceKey, JToken properties) { bool success = false; // Get the current device config var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(deviceKey)); if (deviceConfig != null) { // Replace the current properties JToken with the new one passed into this method deviceConfig.Properties = properties; Debug.LogMessage(LogEventLevel.Debug, "Updated properties of device: '{0}'", deviceKey); success = true; } ResetTimer(); return success; } /// /// UpdateDeviceConfig method /// /// The new device config /// True if the update was successful, otherwise false public static bool UpdateDeviceConfig(DeviceConfig config) { bool success = false; var deviceConfigIndex = ConfigReader.ConfigObject.Devices.FindIndex(d => d.Key.Equals(config.Key)); if (deviceConfigIndex >= 0) { ConfigReader.ConfigObject.Devices[deviceConfigIndex] = config; Debug.LogMessage(LogEventLevel.Debug, "Updated config of device: '{0}'", config.Key); success = true; } ResetTimer(); return success; } /// /// UpdateRoomConfig method /// /// The new room config /// True if the update was successful, otherwise false public static bool UpdateRoomConfig(DeviceConfig config) { bool success = false; var roomConfigIndex = ConfigReader.ConfigObject.Rooms.FindIndex(d => d.Key.Equals(config.Key)); if (roomConfigIndex >= 0) { ConfigReader.ConfigObject.Rooms[roomConfigIndex] = config; Debug.LogMessage(LogEventLevel.Debug, "Updated room of device: '{0}'", config.Key); success = true; } ResetTimer(); return success; } /// /// Resets (or starts) the write timer /// static void ResetTimer() { if (WriteTimer == null) WriteTimer = new CTimer(WriteConfigFile, WriteTimeout); WriteTimer.Reset(WriteTimeout); Debug.LogMessage(LogEventLevel.Debug, "Config File write timer has been reset."); } /// /// Writes the current config to a file in the LocalConfig subfolder /// private static void WriteConfigFile(object o) { var filePath = Global.FilePathPrefix + LocalConfigFolder + Global.DirectorySeparator + "configurationFile.json"; var configData = JsonConvert.SerializeObject(ConfigReader.ConfigObject); WriteFile(filePath, configData); } /// /// Writes the current config data to a file /// /// The file path to write to /// The config data to write public static void WriteFile(string filePath, string configData) { if (WriteTimer != null) WriteTimer.Stop(); Debug.LogMessage(LogEventLevel.Information, "Writing Configuration to file"); Debug.LogMessage(LogEventLevel.Information, "Attempting to write config file: '{0}'", filePath); try { if (fileLock.TryEnter()) { using (StreamWriter sw = new StreamWriter(filePath)) { sw.Write(configData); sw.Flush(); } } else { Debug.LogMessage(LogEventLevel.Information, "Unable to enter FileLock"); } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Error: Config write failed: \r{0}", e); } finally { if (fileLock != null && !fileLock.Disposed) fileLock.Leave(); } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/Essentials/EssentialsConfig.cs ================================================  using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; using PepperDash.Core; namespace PepperDash.Essentials.Core.Config { /// /// Loads the ConfigObject from the file /// public class EssentialsConfig : BasicConfig { /// /// Gets or sets the SystemUrl /// [JsonProperty("system_url")] public string SystemUrl { get; set; } /// /// Gets or sets the TemplateUrl /// [JsonProperty("template_url")] public string TemplateUrl { get; set; } /// /// Gets the SystemUuid extracted from the SystemUrl /// [JsonProperty("systemUuid")] public string SystemUuid { get { string uuid; if (string.IsNullOrEmpty(SystemUrl)) { uuid = "missing url"; } else if (SystemUrl.Contains("#")) { var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*"); uuid = result.Groups[1].Value; } else if (SystemUrl.Contains("detail")) { var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/detail\/(.*)\/.*"); uuid = result.Groups[1].Value; } else { var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/.*"); uuid = result.Groups[1].Value; } return uuid; } } /// /// Gets the TemplateUuid extracted from the TemplateUrl /// [JsonProperty("templateUuid")] public string TemplateUuid { get { string uuid; if (string.IsNullOrEmpty(TemplateUrl)) { uuid = "missing template url"; } else if (TemplateUrl.Contains("#")) { var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/templates\/(.*)\/#.*"); uuid = result.Groups[1].Value; } else if (TemplateUrl.Contains("detail")) { var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/detail\/(.*)\/system-template-versions\/detail\/(.*)\/.*"); uuid = result.Groups[2].Value; } else { var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/(.*)\/system-template-versions\/(.*)\/.*"); uuid = result.Groups[2].Value; } return uuid; } } /// /// Gets or sets the Rooms /// [JsonProperty("rooms")] public List Rooms { get; set; } /// /// Gets or sets the Versions /// public VersionData Versions { get; set; } /// /// Initializes a new instance of the class. /// public EssentialsConfig() : base() { Rooms = new List(); } } /// /// Represents version data for Essentials and its packages /// public class VersionData { /// /// Gets or sets the Essentials version /// [JsonProperty("essentials")] public NugetVersion Essentials { get; set; } /// /// Gets or sets the list of Packages /// [JsonProperty("packages")] public List Packages { get; set; } /// /// Initializes a new instance of the class. /// public VersionData() { Packages = new List(); } } /// /// Represents a NugetVersion /// public class NugetVersion { /// /// Gets or sets the Version /// [JsonProperty("version")] public string Version { get; set; } /// /// Gets or sets the PackageId /// [JsonProperty("packageId")] public string PackageId { get; set; } } /// /// Represents a SystemTemplateConfigs /// public class SystemTemplateConfigs { /// /// Gets or sets the System /// public EssentialsConfig System { get; set; } /// /// Gets or sets the Template /// public EssentialsConfig Template { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/ILoadConfig.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core { /// /// Defines the contract for ILoadConfig /// public interface ILoadConfig { /// /// GoWithLoad method /// void GoWithLoad(); } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/InfoConfig.cs ================================================  using Crestron.SimplSharp; using Newtonsoft.Json; using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core.Config { /// /// Represents the info section of a Config file /// public class InfoConfig { /// /// Gets or sets the Name /// [JsonProperty("name")] public string Name { get; set; } /// /// Gets or sets the Date /// [JsonProperty("date")] public DateTime Date { get; set; } /// /// Gets or sets the Type /// [JsonProperty("type")] public string Type { get; set; } /// /// Gets or sets the Version /// [JsonProperty("version")] public string Version { get; set; } /// /// Gets or sets the RuntimeInfo /// [JsonProperty("runtimeInfo")] public RuntimeInfo RuntimeInfo { get; set; } /// /// Gets or sets the Comment /// [JsonProperty("comment")] public string Comment { get; set; } /// /// Gets or sets the HostName /// [JsonProperty("hostname")] public string HostName { get; set; } /// /// Gets or sets the AppNumber /// [JsonProperty("appNumber")] public uint AppNumber { get; set; } /// /// InfoConfig Constructor /// public InfoConfig() { Name = ""; Date = DateTime.Now; Type = ""; Version = ""; Comment = ""; HostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); AppNumber = InitialParametersClass.ApplicationNumber; RuntimeInfo = new RuntimeInfo(); } } /// /// Represents a RuntimeInfo /// public class RuntimeInfo { /// /// The name of the running application /// [JsonProperty("appName")] public string AppName {get; set;} //{ // get // { // return Assembly.GetExecutingAssembly().GetName().Name; // } //} /// /// The Assembly version of the running application /// [JsonProperty("assemblyVersion")] public string AssemblyVersion {get; set;} //{ // get // { // var version = Assembly.GetExecutingAssembly().GetName().Version; // return string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); // } //} /// , /// The OS Version of the processor (Firmware Version) /// [JsonProperty("osVersion")] public string OsVersion {get; set;} //{ // get // { // return Crestron.SimplSharp.CrestronEnvironment.OSVersion.Firmware; // } //} /// /// The information gathered by the processor at runtime about it's NICs and their IP addresses. /// [JsonProperty("ipInfo")] public Dictionary IpInfo { get { return Global.EthernetAdapterInfoCollection; } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Config/SourceDevicePropertiesConfigBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core.Config { /// /// Represents a SourceDevicePropertiesConfigBase /// public class SourceDevicePropertiesConfigBase { /// /// Gets or sets the DisableSharing /// public bool DisableSharing { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs ================================================ using System; using System.Linq; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Core.JsonStandardObjects; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Abstract base class for Crestron GenericBase devices /// public abstract class CrestronGenericBaseDevice : EssentialsDevice, IOnline, IHasFeedback, ICommunicationMonitor, IUsageTracking { /// /// Gets or sets the Hardware /// protected GenericBase Hardware; /// /// Gets or sets the Feedbacks /// public FeedbackCollection Feedbacks { get; private set; } /// /// Gets or sets the IsOnline /// public BoolFeedback IsOnline { get; private set; } /// /// Gets or sets the IsRegistered /// public BoolFeedback IsRegistered { get; private set; } /// /// Gets or sets the IpConnectionsText /// public StringFeedback IpConnectionsText { get; private set; } /// /// Gets or sets the PreventRegistration /// public bool PreventRegistration { get; protected set; } /// /// Constructor /// /// key of the device /// name of the device /// hardware instance protected CrestronGenericBaseDevice(string key, string name, GenericBase hardware) : base(key, name) { Feedbacks = new FeedbackCollection(); Hardware = hardware; IsOnline = new BoolFeedback("IsOnlineFeedback", () => Hardware.IsOnline); IsRegistered = new BoolFeedback("IsRegistered", () => Hardware.Registered); IpConnectionsText = new StringFeedback("IpConnectionsText", () => Hardware.ConnectedIpList != null ? string.Join(",", Hardware.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray()) : string.Empty); AddToFeedbackList(IsOnline, IpConnectionsText); CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000); } /// /// Constructor without hardware instance /// /// key of the device /// name of the device protected CrestronGenericBaseDevice(string key, string name) : base(key, name) { Feedbacks = new FeedbackCollection(); } /// /// Registers the Crestron GenericBase hardware instance /// /// hardware instance protected void RegisterCrestronGenericBase(GenericBase hardware) { Hardware = hardware; IsOnline = new BoolFeedback("IsOnlineFeedback", () => Hardware.IsOnline); IsRegistered = new BoolFeedback("IsRegistered", () => Hardware.Registered); IpConnectionsText = new StringFeedback("IpConnectionsText", () => Hardware.ConnectedIpList != null ? string.Join(",", Hardware.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray()) : string.Empty); AddToFeedbackList(IsOnline, IpConnectionsText); CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000); } /// /// CustomActivate method /// /// public override bool CustomActivate() { Debug.LogMessage(LogEventLevel.Information, this, "Activating"); if (!PreventRegistration) { //Debug.LogMessage(LogEventLevel.Debug, this, " Does not require registration. Skipping"); if (Hardware.Registerable && !Hardware.Registered) { var response = Hardware.RegisterWithLogging(Key); if (response != eDeviceRegistrationUnRegistrationResponse.Success) { //Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Crestron device: {0}", response); return false; } } IsRegistered.FireUpdate(); } else { AddPostActivationAction(() => { if (Hardware.Registerable && !Hardware.Registered) { var response = Hardware.RegisterWithLogging(Key); } IsRegistered.FireUpdate(); }); } foreach (var f in Feedbacks) { f.FireUpdate(); } Hardware.OnlineStatusChange += Hardware_OnlineStatusChange; CommunicationMonitor.Start(); return base.CustomActivate(); } /// /// This disconnects events and unregisters the base hardware device. /// /// true if successful, otherwise false public override bool Deactivate() { CommunicationMonitor.Stop(); Hardware.OnlineStatusChange -= Hardware_OnlineStatusChange; var success = Hardware.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success; IsRegistered.FireUpdate(); return success; } /// /// Adds feedback(s) to the list /// /// feedback(s) to be added to the list public void AddToFeedbackList(params Feedback[] newFbs) { foreach (var f in newFbs) { if (f == null) continue; if (!Feedbacks.Contains(f)) { Feedbacks.Add(f); } } } void Hardware_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) { Debug.LogMessage(LogEventLevel.Verbose, this, "OnlineStatusChange Event. Online = {0}", args.DeviceOnLine); if (!Hardware.Registered) { return; // protects in cases where device has been unregistered and feedbacks would attempt to access null sigs. } foreach (var feedback in Feedbacks) { if (feedback != null) feedback.FireUpdate(); } } #region IStatusMonitor Members /// /// Gets or sets the CommunicationMonitor /// public StatusMonitorBase CommunicationMonitor { get; private set; } #endregion #region IUsageTracking Members /// /// Gets or sets the UsageTracker /// public UsageTracking UsageTracker { get; set; } #endregion } /// /// Abstract base class for Crestron GenericBase devices that are bridgeable /// public abstract class CrestronGenericBridgeableBaseDevice : CrestronGenericBaseDevice, IBridgeAdvanced { /// /// Constructor /// /// key of the device /// name of the device /// hardware instance protected CrestronGenericBridgeableBaseDevice(string key, string name, GenericBase hardware) : base(key, name, hardware) { } /// /// Constructor without hardware instance /// /// key of the device /// name of the device protected CrestronGenericBridgeableBaseDevice(string key, string name) : base(key, name) { } /// /// Links to API /// /// the trilist /// the starting join number /// the join map key /// the bridge instance public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } //*********************************************************************************** /// /// Represents a CrestronGenericBaseDeviceEventIds /// public class CrestronGenericBaseDeviceEventIds { /// /// IsOnline event ID /// public const uint IsOnline = 1; /// /// IpConnectionsText event ID /// public const uint IpConnectionsText =2; } /// /// Adds logging to Register() failure /// public static class GenericBaseExtensions { /// /// RegisterWithLogging method /// /// the GenericBase device /// the device key public static eDeviceRegistrationUnRegistrationResponse RegisterWithLogging(this GenericBase device, string key) { var result = device.Register(); Debug.LogMessage(LogEventLevel.Information, "Register device result: '{0}', type '{1}', result {2}", key, device, result); //if (result != eDeviceRegistrationUnRegistrationResponse.Success) //{ // Debug.LogMessage(LogEventLevel.Information, "Cannot register device '{0}': {1}", key, result); //} return result; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Crestron/CrestronGenericBaseDevice.cs.orig ================================================ 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; namespace PepperDash.Essentials.Core { /// /// A bridge class to cover the basic features of GenericBase hardware /// public class CrestronGenericBaseDevice : Device, IOnline, IHasFeedback, ICommunicationMonitor, IUsageTracking { public virtual GenericBase Hardware { get; protected set; } public BoolFeedback IsOnline { get; private set; } public BoolFeedback IsRegistered { get; private set; } public StringFeedback IpConnectionsText { get; private set; } public CrestronGenericBaseDevice(string key, string name, GenericBase hardware) : base(key, name) { Hardware = hardware; IsOnline = new BoolFeedback(CommonBoolCue.IsOnlineFeedback, () => Hardware.IsOnline); IsRegistered = new BoolFeedback(new Cue("IsRegistered", 0, eCueType.Bool), () => Hardware.Registered); IpConnectionsText = new StringFeedback(CommonStringCue.IpConnectionsText, () => string.Join(",", Hardware.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray())); CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000); } /// /// Make sure that overriding classes call this! /// Registers the Crestron device, connects up to the base events, starts communication monitor /// public override bool CustomActivate() { Debug.LogMessage(LogEventLevel.Information, this, "Activating"); var response = Hardware.RegisterWithLogging(Key); if (response != eDeviceRegistrationUnRegistrationResponse.Success) { <<<<<<< HEAD Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Crestron device: {0}", response); return false; } ======= Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Crestron device: {0}", response); return false; } >>>>>>> origin/feature/ecs-342-neil Hardware.OnlineStatusChange += new OnlineStatusChangeEventHandler(Hardware_OnlineStatusChange); CommunicationMonitor.Start(); return true; } /// /// This disconnects events and unregisters the base hardware device. /// /// public override bool Deactivate() { CommunicationMonitor.Stop(); Hardware.OnlineStatusChange -= Hardware_OnlineStatusChange; return Hardware.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success; } /// /// Returns a list containing the Outputs that we want to expose. /// public virtual List Feedbacks { get { return new List { IsOnline, IsRegistered, IpConnectionsText }; } } void Hardware_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) { IsOnline.FireUpdate(); } #region IStatusMonitor Members public StatusMonitorBase CommunicationMonitor { get; private set; } #endregion #region IUsageTracking Members public UsageTracking UsageTracker { get; set; } #endregion } //*********************************************************************************** public class CrestronGenericBaseDeviceEventIds { public const uint IsOnline = 1; public const uint IpConnectionsText =2; } /// /// Adds logging to Register() failure /// public static class GenericBaseExtensions { public static eDeviceRegistrationUnRegistrationResponse RegisterWithLogging(this GenericBase device, string key) { var result = device.Register(); if (result != eDeviceRegistrationUnRegistrationResponse.Success) { Debug.LogMessage(LogEventLevel.Information, "Cannot register device '{0}': {1}", key, result); } return result; } } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs ================================================  using System; using System.Collections.Generic; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Represents a GenericDigitalInputDevice /// /// [Description("Wrapper class for Digital Input")] public class GenericDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IHasFeedback { private DigitalInput inputPort; private readonly bool invertState; /// /// Gets or sets the InputStateFeedback /// public BoolFeedback InputStateFeedback { get; private set; } /// public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); /// /// Initializes a new instance of the class. /// /// key for device /// name for device /// function to call after activation. Should return the DigitalInput /// config for device public GenericDigitalInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { invertState = string.Equals(config.CircuitType, "NC", StringComparison.OrdinalIgnoreCase); InputStateFeedback = new BoolFeedback("inputState", () => invertState ? !inputPort.State : inputPort.State); AddPostActivationAction(() => { inputPort = postActivationFunc(config); inputPort.Register(); inputPort.StateChange += InputPort_StateChange; }); } #region Events void InputPort_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args) { InputStateFeedback.FireUpdate(); } #endregion #region PreActivate private static DigitalInput GetDigitalInput(IOPortConfig dc) { if (dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsDigitalInput) { Debug.LogError("GetDigitalInput: Processor does not support Digital Inputs"); return null; } return Global.ControlSystem.DigitalInputPorts[dc.PortNumber]; } if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IDigitalInputPorts ioPortDevice)) { Debug.LogError("GetDigitalInput: Device {key} is not a valid device", dc.PortDeviceKey); return null; } if (dc.PortNumber > ioPortDevice.NumberOfDigitalInputPorts) { Debug.LogError("GetDigitalInput: Device {key} does not contain a digital input port {port}", dc.PortDeviceKey, dc.PortNumber); return null; } return ioPortDevice.DigitalInputPorts[dc.PortNumber]; } #endregion #region Bridge Linking /// /// LinkToApi method /// /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new IDigitalInputJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } try { this.LogDebug("Linking to Trilist '{0}'", trilist.ID.ToString("X")); // Link feedback for input state InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState.JoinNumber]); } catch (Exception e) { this.LogError("Unable to link device {key}. {message}", Key, e.Message); this.LogDebug(e, "Stack Trace: "); } } #endregion #region Factory /// /// Factory for creating GenericDigitalInputDevice devices /// public class GenericDigitalInputDeviceFactory : EssentialsDeviceFactory { /// /// Constructor for GenericDigitalInputDeviceFactory /// public GenericDigitalInputDeviceFactory() { TypeNames = new List() { "digitalinput" }; } /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogDebug("Factory Attempting to create new Generic Digital Input Device"); var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); if (props == null) return null; var portDevice = new GenericDigitalInputDevice(dc.Key, dc.Name, GetDigitalInput, props); return portDevice; } } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/GenericRelayDevice.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Represents a generic device controlled by relays /// [Description("Wrapper class for a Relay")] public class GenericRelayDevice : EssentialsBridgeableDevice, ISwitchedOutput { /// /// The RelayOutput controlled by this device /// public Relay RelayOutput { get; private set; } /// /// Feedback to indicate whether the output is on /// public BoolFeedback OutputIsOnFeedback { get; private set; } //Maintained for compatibility with PepperDash.Essentials.Core.Devices.CrestronProcessor /// /// Constructor for GenericRelayDevice /// /// key of the device /// Relay output controlled by this device public GenericRelayDevice(string key, Relay relay) : base(key) { OutputIsOnFeedback = new BoolFeedback(new Func(() => RelayOutput.State)); RelayOutput = relay; RelayOutput.Register(); RelayOutput.StateChange += RelayOutput_StateChange; } /// /// Constructor for GenericRelayDevice /// /// key of the device /// name of the device /// function to get the relay output /// IO port configuration public GenericRelayDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { OutputIsOnFeedback = new BoolFeedback(() => RelayOutput.State); AddPostActivationAction(() => { RelayOutput = postActivationFunc(config); if (RelayOutput == null) { Debug.LogMessage(LogEventLevel.Information, this, "Unable to get parent relay device for device key {0} and port {1}", config.PortDeviceKey, config.PortNumber); return; } RelayOutput.Register(); RelayOutput.StateChange += RelayOutput_StateChange; }); } #region PreActivate private static Relay GetRelay(IOPortConfig dc) { IRelayPorts relayDevice; if(dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsRelay) { Debug.LogMessage(LogEventLevel.Information, "Processor does not support relays"); return null; } relayDevice = Global.ControlSystem; return relayDevice.RelayPorts[dc.PortNumber]; } var essentialsDevice = DeviceManager.GetDeviceForKey(dc.PortDeviceKey); if (essentialsDevice == null) { Debug.LogMessage(LogEventLevel.Information, "Device {0} was not found in Device Manager. Check configuration or for errors with device.", dc.PortDeviceKey); return null; } relayDevice = essentialsDevice as IRelayPorts; if (relayDevice == null) { Debug.LogMessage(LogEventLevel.Information, "Device {0} is not a valid relay parent. Please check configuration.", dc.PortDeviceKey); return null; } if (dc.PortNumber <= relayDevice.NumberOfRelayPorts) { return relayDevice.RelayPorts[dc.PortNumber]; } Debug.LogMessage(LogEventLevel.Information, "Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); return null; } #endregion #region Events void RelayOutput_StateChange(Relay relay, RelayEventArgs args) { OutputIsOnFeedback.FireUpdate(); } #endregion #region Methods /// /// OpenRelay method /// public void OpenRelay() { RelayOutput.State = false; } /// /// CloseRelay method /// public void CloseRelay() { RelayOutput.State = true; } /// /// ToggleRelayState method /// public void ToggleRelayState() { if (RelayOutput.State == true) OpenRelay(); else CloseRelay(); } #endregion #region ISwitchedOutput Members void ISwitchedOutput.On() { CloseRelay(); } void ISwitchedOutput.Off() { OpenRelay(); } #endregion #region Bridge Linking /// /// LinkToApi method /// /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new GenericRelayControllerJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } if (RelayOutput == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Relay is null", Key); return; } Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); trilist.SetBoolSigAction(joinMap.Relay.JoinNumber, b => { if (b) CloseRelay(); else OpenRelay(); }); // feedback for relay state OutputIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Relay.JoinNumber]); } #endregion #region Factory /// /// Represents a GenericRelayDeviceFactory /// public class GenericRelayDeviceFactory : EssentialsDeviceFactory { /// /// Constructor for GenericRelayDeviceFactory /// public GenericRelayDeviceFactory() { TypeNames = new List() { "relayoutput" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Relay Device"); var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); if (props == null) return null; var portDevice = new GenericRelayDevice(dc.Key, dc.Name, GetRelay, props); return portDevice; } } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs ================================================  using System; using System.Collections.Generic; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Represents a generic digital input deviced tied to a versiport /// public class GenericVersiportAnalogInputDevice : EssentialsBridgeableDevice, IAnalogInput, IHasFeedback { private Versiport inputPort; /// public IntFeedback InputValueFeedback { get; private set; } /// /// Get the InputMinimumChangeFeedback /// /// /// Updates when the analog input minimum change value changes /// public IntFeedback InputMinimumChangeFeedback { get; private set; } /// public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); /// /// Initializes a new instance of the class. /// /// key for the device /// name for the device /// function to call after activation /// IO port configuration public GenericVersiportAnalogInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { InputValueFeedback = new IntFeedback("inputValue", () => inputPort.AnalogIn); InputMinimumChangeFeedback = new IntFeedback("inputMinimumChange", () => inputPort.AnalogMinChange); 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; this.LogDebug("Created GenericVersiportAnalogInputDevice on port {port}. DisablePullUpResistor: {pullUpResistorDisabled}", 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) { this.LogDebug("Versiport change: {event}", 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 { this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } try { this.LogDebug("Linking to Trilist '{trilistId}'", 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) { this.LogError("Unable to link device {key}: {message}", Key, e.Message); this.LogDebug(e, "Stack Trace: "); } trilist.OnlineStatusChange += (d, args) => { if (!args.DeviceOnLine) return; InputValueFeedback.FireUpdate(); InputMinimumChangeFeedback.FireUpdate(); }; } #endregion /// /// GetVersiportDigitalInput method /// public static Versiport GetVersiportDigitalInput(IOPortConfig dc) { if (dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsVersiport) { Debug.LogError("GetVersiportAnalogInput: Processor does not support Versiports"); return null; } return Global.ControlSystem.VersiPorts[dc.PortNumber]; } if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IIOPorts ioPortDevice)) { Debug.LogError("GetVersiportAnalogInput: Device {key} is not a valid device", dc.PortDeviceKey); return null; } if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) { Debug.LogError("GetVersiportAnalogInput: Device {key} does not contain a port {port}", dc.PortDeviceKey, dc.PortNumber); return null; } if (!ioPortDevice.VersiPorts[dc.PortNumber].SupportsAnalogInput) { Debug.LogError("GetVersiportAnalogInput: Device {key} does not support AnalogInput on port {port}", dc.PortDeviceKey, dc.PortNumber); return null; } return ioPortDevice.VersiPorts[dc.PortNumber]; } } /// /// Factory for creating GenericVersiportAnalogInputDevice devices /// public class GenericVersiportAnalogInputDeviceFactory : EssentialsDeviceFactory { /// /// Constructor for GenericVersiportAnalogInputDeviceFactory /// public GenericVersiportAnalogInputDeviceFactory() { TypeNames = new List() { "versiportanaloginput" }; } /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogDebug("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; } } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs ================================================  using System; using System.Collections.Generic; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Represents a generic digital input deviced tied to a versiport /// public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IPartitionStateProvider, IHasFeedback { private Versiport inputPort; private readonly bool invertState; /// /// Gets or sets the InputStateFeedback /// public BoolFeedback InputStateFeedback { get; private set; } /// public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); /// /// Gets or sets the PartitionPresentFeedback /// public BoolFeedback PartitionPresentFeedback { get; } /// /// Get partition state /// public bool PartitionPresent => !inputPort.DigitalIn; /// /// Initializes a new instance of the class. /// /// key for device /// name for device /// function to call after activation. Should return the Versiport /// config for device public GenericVersiportDigitalInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { var circuitType = string.IsNullOrEmpty(config.CircuitType) ? "NO" : config.CircuitType; invertState = circuitType.Equals("NC", StringComparison.OrdinalIgnoreCase); InputStateFeedback = new BoolFeedback("inputState", () => invertState ? !inputPort.DigitalIn : inputPort.DigitalIn); PartitionPresentFeedback = new BoolFeedback("partitionPresent", () => !inputPort.DigitalIn); AddPostActivationAction(() => { inputPort = postActivationFunc(config); inputPort.Register(); inputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); if (config.DisablePullUpResistor) inputPort.DisablePullUpResistor = true; inputPort.VersiportChange += InputPort_VersiportChange; InputStateFeedback.FireUpdate(); PartitionPresentFeedback.FireUpdate(); this.LogDebug("Created GenericVersiportDigitalInputDevice for port {port}. DisablePullUpResistor: {pullUpResistorDisable}", config.PortNumber, inputPort.DisablePullUpResistor); }); Feedbacks.Add(InputStateFeedback); Feedbacks.Add(PartitionPresentFeedback); } void InputPort_VersiportChange(Versiport port, VersiportEventArgs args) { this.LogDebug("Versiport change: {0}", args.Event); if (args.Event == eVersiportEvent.DigitalInChange) { InputStateFeedback.FireUpdate(); PartitionPresentFeedback.FireUpdate(); } } #region Bridge Linking /// /// LinkToApi method /// /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new IDigitalInputJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } try { this.LogDebug("Linking to Trilist '{0}'", trilist.ID.ToString("X")); // Link feedback for input state InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState.JoinNumber]); } catch (Exception e) { this.LogError("Unable to link device {key}. Input is null. {message}", Key, e.Message); this.LogDebug(e, "Stack Trace: "); } } #endregion /// /// GetVersiportDigitalInput method /// public static Versiport GetVersiportDigitalInput(IOPortConfig dc) { if (dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsVersiport) { Debug.LogError("GetVersiportDigitalInput: Processor does not support Versiports"); return null; } return Global.ControlSystem.VersiPorts[dc.PortNumber]; } if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IIOPorts ioPortDevice)) { Debug.LogError("GetVersiportDigitalInput: Device {key} is not a valid device", dc.PortDeviceKey); return null; } if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) { Debug.LogError("GetVersiportDigitalInput: Device {key} does not contain versiport {port}", dc.PortDeviceKey, dc.PortNumber); return null; } return ioPortDevice.VersiPorts[dc.PortNumber]; } } /// /// Factory class for GenericVersiportDigitalInputDevice /// public class GenericVersiportDigitalInputDeviceFactory : EssentialsDeviceFactory { /// /// Constructor for GenericVersiportDigitalInputDeviceFactory /// public GenericVersiportDigitalInputDeviceFactory() { TypeNames = new List() { "versiportinput" }; } /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogDebug("Factory Attempting to create new Generic Versiport Device"); var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); if (props == null) return null; var portDevice = new GenericVersiportDigitalInputDevice(dc.Key, dc.Name, GenericVersiportDigitalInputDevice.GetVersiportDigitalInput, props); return portDevice; } } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs ================================================  using System; using System.Collections.Generic; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Represents a generic digital input deviced tied to a versiport /// public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput, IHasFeedback { private Versiport outputPort; /// /// Gets or sets the OutputStateFeedback /// public BoolFeedback OutputStateFeedback { get; private set; } /// public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); /// /// Initializes a new instance of the class. /// public GenericVersiportDigitalOutputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { OutputStateFeedback = new BoolFeedback("outputState", () => outputPort.DigitalOut); AddPostActivationAction(() => { outputPort = postActivationFunc(config); outputPort.Register(); if (!outputPort.SupportsDigitalOutput) { this.LogError("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) { this.LogDebug("Versiport change: {event}", 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) { this.LogError("Versiport does not support Digital Output Mode"); return; } outputPort.DigitalOut = state; } #region Bridge Linking /// /// LinkToApi method /// /// 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 { this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } try { this.LogDebug("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) { this.LogError("Unable to link device: {message}", e.Message); this.LogDebug(e, "Stack Trace: "); } } #endregion /// /// GetVersiportDigitalOutput method /// public static Versiport GetVersiportDigitalOutput(IOPortConfig dc) { if (dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsVersiport) { Debug.LogError("GetVersiportDigitalOutput: Processor does not support Versiports"); return null; } return Global.ControlSystem.VersiPorts[dc.PortNumber]; } if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IIOPorts ioPortDevice)) { Debug.LogError("GetVersiportDigitalOutput: Device {key} is not a valid device", dc.PortDeviceKey); return null; } if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) { Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOutput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); return null; } return ioPortDevice.VersiPorts[dc.PortNumber]; } } /// /// Represents a GenericVersiportDigitalOutputDeviceFactory /// public class GenericVersiportDigitalOutputDeviceFactory : EssentialsDeviceFactory { /// /// Initialize a new instance of the class. /// public GenericVersiportDigitalOutputDeviceFactory() { TypeNames = new List() { "versiportoutput" }; } /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogDebug("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; } } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Defines the contract for IAnalogInput /// public interface IAnalogInput { /// /// Get the InputValueFeedback. /// /// /// Updates when the analog input value changes /// IntFeedback InputValueFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/IDigitalInput.cs ================================================ 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 IDigitalInput { /// /// Feedback to indicate the state of the input /// BoolFeedback InputStateFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/IDigitalOutput.cs ================================================ 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 { /// /// Feedback to indicate the state of the output /// BoolFeedback OutputStateFeedback { get; } /// /// Sets the output state /// /// The desired state of the output void SetOutput(bool state); } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/IHasCresnetBranches.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IHasCresnetBranches /// public interface IHasCresnetBranches { /// /// Collection of Cresnet branches /// CrestronCollection CresnetBranches { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Represents a IOPortConfig /// public class IOPortConfig { /// /// Gets or sets the PortDeviceKey /// [JsonProperty("portDeviceKey")] public string PortDeviceKey { get; set; } /// /// Gets or sets the PortNumber /// [JsonProperty("portNumber")] public uint PortNumber { get; set; } /// /// Gets or sets the DisablePullUpResistor /// [JsonProperty("disablePullUpResistor")] public bool DisablePullUpResistor { get; set; } /// /// Gets or sets the MinimumChange /// [JsonProperty("minimumChange")] public int MinimumChange { get; set; } /// /// Gets or sets the circuit type: "NO" (Normally Open) or "NC" (Normally Closed) /// If set to "NC", the input state will be inverted. Defaults to "NO" if not specified. /// [JsonProperty("circuitType")] public string CircuitType { get; set; } = "NO"; } } ================================================ FILE: src/PepperDash.Essentials.Core/CrestronIO/ISwitchedOutput.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Describes an output capable of switching on and off /// public interface ISwitchedOutput { /// /// Feedback to indicate whether the output is on /// BoolFeedback OutputIsOnFeedback {get;} /// /// Turns the output on /// void On(); /// /// Turns the output off /// void Off(); } /// /// Describes a collection of switched outputs /// public interface ISwitchedOutputCollection { /// /// Dictionary of switched outputs by their port number /// Dictionary SwitchedOutputs { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Device Info/DeviceInfo.cs ================================================ namespace PepperDash.Essentials.Core.DeviceInfo { /// /// Represents a DeviceInfo /// public class DeviceInfo { /// /// Gets or sets the HostName /// public string HostName { get; set; } /// /// Gets or sets the IpAddress /// public string IpAddress { get; set; } /// /// Gets or sets the MacAddress /// public string MacAddress { get; set; } /// /// Gets or sets the SerialNumber /// public string SerialNumber { get; set; } /// /// Gets or sets the FirmwareVersion /// public string FirmwareVersion { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Device Info/DeviceInfoEventArgs.cs ================================================ using System; namespace PepperDash.Essentials.Core.DeviceInfo { /// /// Represents a DeviceInfoEventArgs /// public class DeviceInfoEventArgs:EventArgs { /// /// Gets or sets the DeviceInfo /// public DeviceInfo DeviceInfo { get; set; } /// /// Constructor /// public DeviceInfoEventArgs() { } /// /// Constructor with DeviceInfo /// /// the DeviceInfo instance public DeviceInfoEventArgs(DeviceInfo devInfo) { DeviceInfo = devInfo; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Device Info/IDeviceInfoProvider.cs ================================================ using System; using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceInfo { /// /// Defines the contract for IDeviceInfoProvider /// public interface IDeviceInfoProvider:IKeyed { /// /// Gets the DeviceInfo /// DeviceInfo DeviceInfo { get; } /// /// Event fired when DeviceInfo changes /// event DeviceInfoChangeHandler DeviceInfoChanged; /// /// Updates the DeviceInfo /// void UpdateDeviceInfo(); } /// /// Delegate for DeviceInfoChangeHandler /// public delegate void DeviceInfoChangeHandler(IKeyed device, DeviceInfoEventArgs args); } ================================================ FILE: src/PepperDash.Essentials.Core/Device Info/NetworkDeviceHelpers.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using PepperDash.Core; using Crestron.SimplSharp; using PepperDash.Essentials.Core; using Serilog.Events; namespace PepperDash.Essentials.Core.DeviceInfo { /// /// Static class NetworkDeviceHelpers /// public static class NetworkDeviceHelpers { /// /// Event raised when ArpTable changes /// public static event ArpTableEventHandler ArpTableUpdated; /// /// Delegate called by ArpTableUpdated /// /// contains the entire ARP table and a bool to note if there was an error in retrieving the data public delegate void ArpTableEventHandler(ArpTableEventArgs args); private static readonly char NewLineSplitter = CrestronEnvironment.NewLine.ToCharArray().First(); private static readonly string NewLine = CrestronEnvironment.NewLine; private static readonly CCriticalSection Lock = new CCriticalSection(); /// /// Gets or sets the ArpTable /// public static List ArpTable { get; private set; } /// /// RefreshArp method /// public static void RefreshArp() { var error = false; try { Lock.Enter(); var consoleResponse = string.Empty; if (!CrestronConsole.SendControlSystemCommand("showarptable", ref consoleResponse)) return; if (string.IsNullOrEmpty(consoleResponse)) { error = true; return; } ArpTable.Clear(); Debug.LogMessage(LogEventLevel.Verbose, "ConsoleResponse of 'showarptable' : {0}{1}", NewLine, consoleResponse); var myLines = consoleResponse.Split(NewLineSplitter) .ToList() .Where(o => (o.Contains(':') && !o.Contains("Type", StringComparison.OrdinalIgnoreCase))) .ToList(); foreach (var line in myLines) { var item = line; var seperator = item.Contains('\t') ? '\t' : ' '; var dataPoints = item.Split(seperator); if (dataPoints == null || dataPoints.Length < 2) continue; var ipAddress = SanitizeIpAddress(dataPoints.First().TrimAll()); var macAddress = dataPoints.Last(); ArpTable.Add(new ArpEntry(ipAddress, macAddress)); } } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Exception in \"RefreshArp\" : {0}", ex.Message); error = true; } finally { Lock.Leave(); OnArpTableUpdated(new ArpTableEventArgs(ArpTable, error)); } } private static void OnArpTableUpdated(ArpTableEventArgs args) { if (args == null) return; var handler = ArpTableUpdated; if (handler == null) return; handler.Invoke(args); } static NetworkDeviceHelpers() { ArpTable = new List(); } /// /// Removes leading zeros, leading whitespace, and trailing whitespace from an IPAddress string /// /// Ip Address to Santitize /// Sanitized Ip Address /// /// SanitizeIpAddress method /// public static string SanitizeIpAddress(string ipAddressIn) { try { var ipAddress = IPAddress.Parse(ipAddressIn.TrimStart('0')); return ipAddress.ToString(); } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Unable to Santize Ip : {0}", ex.Message); return ipAddressIn; } } /// /// Resolves a hostname by IP Address using DNS /// /// IP Address to resolve from /// Resolved Hostname - on failure to determine hostname, will return IP Address /// /// ResolveHostnameFromIp method /// public static string ResolveHostnameFromIp(string ipAddress) { try { var santitizedIp = SanitizeIpAddress(ipAddress); var hostEntry = Dns.GetHostEntry(santitizedIp); return hostEntry == null ? ipAddress : hostEntry.HostName; } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Exception Resolving Hostname from IP Address : {0}", ex.Message); return ipAddress; } } /// /// Resolves an IP Address by hostname using DNS /// /// Hostname to resolve from /// Resolved IP Address - on a failure to determine IP Address, will return hostname /// /// ResolveIpFromHostname method /// public static string ResolveIpFromHostname(string hostName) { try { var hostEntry = Dns.GetHostEntry(hostName); return hostEntry == null ? hostName : hostEntry.AddressList.First().ToString(); } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Exception Resolving IP Address from Hostname : {0}", ex.Message); return hostName; } } } /// /// Represents a ArpEntry /// public class ArpEntry { /// /// The IP Address of the ARP Entry /// public readonly IPAddress IpAddress; /// /// The MAC Address of the ARP Entry /// public readonly string MacAddress; /// /// Constructs new ArpEntry object /// /// string formatted as ipv4 address /// mac address string - format is unimportant public ArpEntry(string ipAddress, string macAddress) { if (string.IsNullOrEmpty(ipAddress)) { throw new ArgumentException("\"ipAddress\" cannot be null or empty"); } if (string.IsNullOrEmpty(macAddress)) { throw new ArgumentException("\"macAddress\" cannot be null or empty"); } IpAddress = IPAddress.Parse(ipAddress.TrimStart().TrimStart('0').TrimEnd()); MacAddress = macAddress; } } /// /// Represents a ArpTableEventArgs /// public class ArpTableEventArgs : EventArgs { /// /// The retrieved ARP Table /// public readonly List ArpTable; /// /// True if there was a problem retrieving the ARP Table /// public readonly bool Error; /// /// Constructor for ArpTableEventArgs /// /// The entirety of the retrieved ARP table /// True of an error was encountered updating the ARP table public ArpTableEventArgs(List arpTable, bool error) { ArpTable = arpTable; Error = error; } /// /// Constructor for ArpTableEventArgs - assumes no error encountered in retrieving ARP Table /// /// The entirety of the retrieved ARP table public ArpTableEventArgs(List arpTable) { ArpTable = arpTable; Error = false; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceControlsParentInterfaces/IPresentationSource.cs ================================================ //using System; //using System.Collections.Generic; //using Crestron.SimplSharpPro; //using Crestron.SimplSharpPro.DeviceSupport; //using PepperDash.Core; //namespace PepperDash.Essentials.Core //{ // public interface IPresentationSource : IKeyed // { // string Name { get; } // PresentationSourceType Type { get; } // string IconName { get; set; } // BoolFeedback HasPowerOnFeedback { get; } // } //} ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IAudioZone.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines minimum functionality for an audio zone /// public interface IAudioZone : IBasicVolumeWithFeedback { /// /// Selects the specified input /// /// The input to select void SelectInput(ushort input); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IAudioZones.cs ================================================ using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// /// Identifies a device that contains audio zones /// public interface IAudioZones : IRouting { /// /// Gets the collection of audio zones /// Dictionary Zone { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IBasicVolumeControls.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines minimal volume and mute control methods /// public interface IBasicVolumeControls : IKeyName { /// /// Increases the volume /// /// Indicates whether the volume change is a press and hold action void VolumeUp(bool pressRelease); /// /// Decreases the volume /// /// Indicates whether the volume change is a press and hold action void VolumeDown(bool pressRelease); /// /// Toggles the mute state /// void MuteToggle(); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IBasicVolumeWithFeedback.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IBasicVolumeWithFeedback /// public interface IBasicVolumeWithFeedback : IBasicVolumeControls { /// /// Gets the mute feedback /// BoolFeedback MuteFeedback { get; } /// /// Mutes the volume /// void MuteOn(); /// /// Unmutes the volume /// void MuteOff(); /// /// Sets the volume to the specified level /// /// The volume level to set void SetVolume(ushort level); /// /// Gets the mute feedback /// IntFeedback VolumeLevelFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IBasicVolumeWithFeedbackAdvanced.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IBasicVolumeWithFeedbackAdvanced /// public interface IBasicVolumeWithFeedbackAdvanced : IBasicVolumeWithFeedback { /// /// Gets the raw volume level /// int RawVolumeLevel { get; } /// /// Gets the volume level units /// eVolumeLevelUnits Units { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IChannel.cs ================================================ using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IChannel /// public interface IChannel { /// /// Channel up /// /// indicates whether this is a press or release /// void ChannelUp(bool pressRelease); /// /// Channel down /// /// indicates whether this is a press or release void ChannelDown(bool pressRelease); /// /// Last channel /// /// indicates whether this is a press or release void LastChannel(bool pressRelease); /// /// Guide /// /// indicates whether this is a press or release /// void Guide(bool pressRelease); /// /// Info /// /// indicates whether this is a press or release void Info(bool pressRelease); /// /// Exit /// /// indicates whether this is a press or release void Exit(bool pressRelease); } /// /// IChannelExtensions class /// public static class IChannelExtensions { /// /// LinkButtons method /// public static void LinkButtons(this IChannel dev, BasicTriList triList) { triList.SetBoolSigAction(123, dev.ChannelUp); triList.SetBoolSigAction(124, dev.ChannelDown); triList.SetBoolSigAction(125, dev.LastChannel); triList.SetBoolSigAction(137, dev.Guide); triList.SetBoolSigAction(129, dev.Info); triList.SetBoolSigAction(134, dev.Exit); } /// /// UnlinkButtons method /// public static void UnlinkButtons(this IChannel dev, BasicTriList triList) { triList.ClearBoolSigAction(123); triList.ClearBoolSigAction(124); triList.ClearBoolSigAction(125); triList.ClearBoolSigAction(137); triList.ClearBoolSigAction(129); triList.ClearBoolSigAction(134); } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IColorFunctions.cs ================================================ using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { /// /// IColor interface /// public interface IColor { /// /// Red button /// /// indicates whether this is a press or release void Red(bool pressRelease); /// /// Green button /// /// indicates whether this is a press or release void Green(bool pressRelease); /// /// Yellow button /// /// indicates whether this is a press or release void Yellow(bool pressRelease); /// /// Blue button /// /// indicates whether this is a press or release void Blue(bool pressRelease); } /// /// IColorExtensions class /// public static class IColorExtensions { /// /// LinkButtons method /// /// The IColor device /// The BasicTriList to link public static void LinkButtons(this IColor dev, BasicTriList TriList) { TriList.SetBoolSigAction(155, dev.Red); TriList.SetBoolSigAction(156, dev.Green); TriList.SetBoolSigAction(157, dev.Yellow); TriList.SetBoolSigAction(158, dev.Blue); } /// /// UnlinkButtons method /// /// The IColor device /// The BasicTriList to unlink public static void UnlinkButtons(this IColor dev, BasicTriList triList) { triList.ClearBoolSigAction(155); triList.ClearBoolSigAction(156); triList.ClearBoolSigAction(157); triList.ClearBoolSigAction(158); } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ICustomMobileControl.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Use this interface on a device or room if it uses custom Mobile Control messengers /// public interface ICustomMobileControl : IKeyed { } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDPad.cs ================================================ using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { /// /// /// public interface IDPad : IKeyed { /// /// Up button press /// /// determines if the button is pressed or released void Up(bool pressRelease); /// /// Down button press /// /// determines if the button is pressed or released void Down(bool pressRelease); /// /// Left button press /// /// determines if the button is pressed or released void Left(bool pressRelease); /// /// Right button press /// /// determines if the button is pressed or released void Right(bool pressRelease); /// /// Select button press /// /// determines if the button is pressed or released void Select(bool pressRelease); /// /// Menu button press /// /// determines if the button is pressed or released void Menu(bool pressRelease); /// /// Exit button press /// /// determines if the button is pressed or released void Exit(bool pressRelease); } /// /// IDPadExtensions class /// public static class IDPadExtensions { /// /// LinkButtons method /// public static void LinkButtons(this IDPad dev, BasicTriList triList) { triList.SetBoolSigAction(138, dev.Up); triList.SetBoolSigAction(139, dev.Down); triList.SetBoolSigAction(140, dev.Left); triList.SetBoolSigAction(141, dev.Right); triList.SetBoolSigAction(142, dev.Select); triList.SetBoolSigAction(130, dev.Menu); triList.SetBoolSigAction(134, dev.Exit); } /// /// UnlinkButtons method /// public static void UnlinkButtons(this IDPad dev, BasicTriList triList) { triList.ClearBoolSigAction(138); triList.ClearBoolSigAction(139); triList.ClearBoolSigAction(140); triList.ClearBoolSigAction(141); triList.ClearBoolSigAction(142); triList.ClearBoolSigAction(130); triList.ClearBoolSigAction(134); } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDiscPlayerControls.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IDiscPlayerControls /// public interface IDiscPlayerControls : IColor, IDPad, INumericKeypad, IHasPowerControl, ITransport, IUiDisplayInfo { } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Interface for display devices that can be controlled and monitored. /// This interface combines functionality for feedback, routing, power control, /// warming/cooling, usage tracking, and key name management. /// It is designed to be implemented by devices that require these capabilities, /// such as projectors, displays, and other visual output devices. /// public interface IDisplay : IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking, IKeyName { } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplayBasic.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core.Devices.DeviceTypeInterfaces { /// /// Defines the contract for IDisplayBasic /// public interface IDisplayBasic { /// /// Sets the input to HDMI 1 /// void InputHdmi1(); /// /// Sets the input to HDMI 2 /// void InputHdmi2(); /// /// Sets the input to HDMI 3 /// void InputHdmi3(); /// /// Sets the input to HDMI 4 /// void InputHdmi4(); /// /// Sets the input to DisplayPort 1 /// void InputDisplayPort1(); /// /// Sets the input to DVI 1 /// void InputDvi1(); /// /// Sets the input to Video 1 /// void InputVideo1(); /// /// Sets the input to VGA 1 /// void InputVga1(); /// /// Sets the input to VGA 2 /// void InputVga2(); /// /// Sets the input to RGB 1 /// void InputRgb1(); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDumbSource.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IDumbSource /// public interface IDumbSource { } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDvr.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { /// /// /// public interface IDvr : IDPad { /// /// DVR List button press /// /// determines if the button is pressed or released void DvrList(bool pressRelease); /// /// Record button press /// /// determines if the button is pressed or released void Record(bool pressRelease); } /// /// IDvrExtensions class /// public static class IDvrExtensions { /// /// LinkButtons method /// /// IDvr device /// BasicTriList to link to public static void LinkButtons(this IDvr dev, BasicTriList triList) { triList.SetBoolSigAction(136, dev.DvrList); triList.SetBoolSigAction(152, dev.Record); } /// /// UnlinkButtons method /// /// IDvr device /// BasicTriList to unlink from public static void UnlinkButtons(this IDvr dev, BasicTriList triList) { triList.ClearBoolSigAction(136); triList.ClearBoolSigAction(152); } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IEmergencyOSD /// public interface IEmergencyOSD { /// /// Shows an emergency message on the OSD /// /// The URL of the emergency message to display void ShowEmergencyMessage(string url); /// /// Hides the emergency message from the OSD /// void HideEmergencyMessage(); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IFullAudioSettings.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IFullAudioSettings /// public interface IFullAudioSettings : IBasicVolumeWithFeedback { /// /// SetBalance method /// /// level to set void SetBalance(ushort level); /// /// BalanceLeft method /// /// determines if the button is pressed or released void BalanceLeft(bool pressRelease); /// /// BalanceRight method /// /// determines if the button is pressed or released void BalanceRight(bool pressRelease); /// /// SetBass method /// /// level to set void SetBass(ushort level); /// /// BassUp method /// /// determines if the button is pressed or released void BassUp(bool pressRelease); /// /// BassDown method /// /// determines if the button is pressed or released void BassDown(bool pressRelease); /// /// SetTreble method /// /// level to set void SetTreble(ushort level); /// /// TrebleUp method /// /// determines if the button is pressed or released void TrebleUp(bool pressRelease); /// /// TrebleDown method /// /// determines if the button is pressed or released void TrebleDown(bool pressRelease); /// /// hasMaxVolume property /// bool hasMaxVolume { get; } /// /// SetMaxVolume method /// /// level to set void SetMaxVolume(ushort level); /// /// MaxVolumeUp method /// /// determines if the button is pressed or released void MaxVolumeUp(bool pressRelease); /// /// MaxVolumeDown method /// /// determines if the button is pressed or released void MaxVolumeDown(bool pressRelease); /// /// hasDefaultVolume property /// bool hasDefaultVolume { get; } /// /// SetDefaultVolume method /// /// level to set void SetDefaultVolume(ushort level); /// /// DefaultVolumeUp method /// /// determines if the button is pressed or released void DefaultVolumeUp(bool pressRelease); /// /// DefaultVolumeDown method /// /// determines if the button is pressed or released void DefaultVolumeDown(bool pressRelease); /// /// LoudnessToggle method /// void LoudnessToggle(); /// /// MonoToggle method /// void MonoToggle(); /// /// LoudnessFeedback property /// BoolFeedback LoudnessFeedback { get; } /// /// MonoFeedback property /// BoolFeedback MonoFeedback { get; } /// /// BalanceFeedback property /// IntFeedback BalanceFeedback { get; } /// /// BassFeedback property /// IntFeedback BassFeedback { get; } /// /// TrebleFeedback property /// IntFeedback TrebleFeedback { get; } /// /// MaxVolumeFeedback property /// IntFeedback MaxVolumeFeedback { get; } /// /// DefaultVolumeFeedback property /// IntFeedback DefaultVolumeFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasBranding.cs ================================================ using System; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IHasBranding /// public interface IHasBranding { /// /// Gets whether branding is enabled /// bool BrandingEnabled { get; } /// /// Initializes branding for the device /// /// The key identifying the room for branding purposes void InitializeBranding(string roomKey); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasCurrentVolumeControls.cs ================================================ using System; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IHasCurrentVolumeControls /// public interface IHasCurrentVolumeControls { /// /// CurrentVolumeControls property /// IBasicVolumeControls CurrentVolumeControls { get; } /// /// CurrentVolumeDeviceChange event /// event EventHandler CurrentVolumeDeviceChange; /// /// SetDefaultLevels method /// void SetDefaultLevels(); /// /// ZeroVolumeWhenSwtichingVolumeDevices property /// bool ZeroVolumeWhenSwtichingVolumeDevices { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasFarEndContentStatus.cs ================================================ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IHasFarEndContentStatus /// public interface IHasFarEndContentStatus { /// /// Gets whether far end content is being received /// BoolFeedback ReceivingContent { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasInputs.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Describes a device that has selectable inputs /// /// the type to use as the key for each input item. Most likely an enum or string\ /// /// See MockDisplay for example implemntation /// public interface IHasInputs : IKeyName { /// /// Gets the collection of inputs /// ISelectableItems Inputs { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasMuteControl.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines basic mute control methods /// public interface IHasMuteControl { /// /// MuteToggle method /// void MuteToggle(); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasMuteControlWithFeedback.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines mute control methods and properties with feedback /// public interface IHasMuteControlWithFeedback : IHasMuteControl { /// /// MuteFeedback property /// BoolFeedback MuteFeedback { get; } /// /// MuteOn method /// void MuteOn(); /// /// MuteOff method /// void MuteOff(); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasPhoneDialing.cs ================================================ using System; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IHasPhoneDialing /// public interface IHasPhoneDialing { /// /// Feedback that indicates whether the phone is off-hook /// BoolFeedback PhoneOffHookFeedback { get; } /// /// Feedback that provides the caller ID name /// StringFeedback CallerIdNameFeedback { get; } /// /// Feedback that provides the caller ID number /// StringFeedback CallerIdNumberFeedback { get; } /// /// Dials a phone call to the specified number /// /// the number to dial void DialPhoneCall(string number); /// /// Ends the current phone call /// void EndPhoneCall(); /// /// Sends a DTMF digit to the phone /// /// the DTMF digit to send void SendDtmfToPhone(string digit); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasScreensWithLayouts.cs ================================================ using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// This defines a device that has screens with layouts /// Simply decorative /// public interface IHasScreensWithLayouts { /// /// A dictionary of screens, keyed by screen ID, that contains information about each screen and its layouts. /// Dictionary Screens { get; } /// /// Applies a specific layout to a screen based on the provided screen ID and layout index. /// /// /// void ApplyLayout(uint screenId, uint layoutIndex); } /// /// Represents information about a screen and its layouts. /// public class ScreenInfo { /// /// Indicates whether the screen is enabled or not. /// [JsonProperty("enabled")] public bool Enabled { get; set; } /// /// The name of the screen. /// [JsonProperty("name")] public string Name { get; set; } /// /// The index of the screen. /// [JsonProperty("screenIndex")] public int ScreenIndex { get; set; } /// /// A dictionary of layout information for the screen, keyed by layout ID. /// [JsonProperty("layouts")] public Dictionary Layouts { get; set; } } /// /// Represents information about a layout on a screen. /// public class LayoutInfo { /// /// The name of the layout. /// [JsonProperty("layoutName")] public string LayoutName { get; set; } /// /// The index of the layout. /// [JsonProperty("layoutIndex")] public int LayoutIndex { get; set; } /// /// The type of the layout, which can be "single", "double", "triple", or "quad". /// [JsonProperty("layoutType")] public string LayoutType { get; set; } /// /// A dictionary of window configurations for the layout, keyed by window ID. /// [JsonProperty("windows")] public Dictionary Windows { get; set; } } /// /// Represents the configuration of a window within a layout on a screen. /// public class WindowConfig { /// /// The display label for the window /// [JsonProperty("label")] public string Label { get; set; } /// /// The input for the window /// [JsonProperty("input")] public string Input { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasSurroundSoundModes.cs ================================================ using PepperDash.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Describes a device that has selectable surround sound modes /// /// the type to use as the key for each input item. Most likely an enum or string /// the type used to select an item. Most likely an enum or string public interface IHasSurroundSoundModes: IKeyName { /// /// The available surround sound modes /// ISelectableItems SurroundSoundModes { get; } /// /// The currently selected surround sound mode /// /// the selector for the surround sound mode void SetSurroundSoundMode(TSelector selector); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasVolumeControl.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IHasVolumeControl /// public interface IHasVolumeControl { /// /// VolumeUp method /// /// determines if the volume up command is a press or release action void VolumeUp(bool pressRelease); /// /// VolumeDown method /// /// determines if the volume down command is a press or release action void VolumeDown(bool pressRelease); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasVolumeControlWithFeedback.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines volume control methods and properties with feedback /// public interface IHasVolumeControlWithFeedback : IHasVolumeControl { /// /// SetVolume method /// /// The volume level to set void SetVolume(ushort level); /// /// VolumeLevelFeedback property /// IntFeedback VolumeLevelFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasVolumeDevice.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IHasVolumeDevice /// public interface IHasVolumeDevice { /// /// VolumeDevice property /// IBasicVolumeControls VolumeDevice { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHasWebView.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the display mode for a webview event, with expected values of "Fullscreen", "Modal", or "Unknown". /// public enum eWebViewEventMode { /// /// The display mode for the webview event is unknown or not specified. This value can be used as a default or fallback when the display mode is not provided or cannot be parsed into a known value. /// Unknown, /// /// The webview event should be displayed in fullscreen mode, covering the entire screen and typically used for immersive experiences or when maximum screen real estate is needed. When a webview event with this display mode is shown, it will typically trigger the WebViewStatusChanged event with a status of "Fullscreen", and when it is cleared/closed, it will trigger the WebViewStatusChanged event with a status of "Cleared". /// Fullscreen, /// /// The webview event should be displayed in modal mode, which typically means it will be shown as a dialog or overlay on top of the existing content, allowing the user to interact with it while still being able to see the underlying content. This display mode is often used for alerts, confirmations, or when the webview content is related to the current context but does not require full immersion. When a webview event with this display mode is shown, it will typically trigger the WebViewStatusChanged event with a status of "Modal", and when it is cleared/closed, it will trigger the WebViewStatusChanged event with a status of "Cleared". /// Modal, } /// /// Defines the target for a webview event, with expected values of "OSD", "Controller", "PersistentWebApp", or "RoomScheduler". /// public enum eWebViewTarget { /// /// The target for the webview event is unknown or not specified. This value can be used as a default or fallback when the target is not provided or cannot be parsed into a known value. /// Unknown, /// /// The webview event should be displayed on the On-Screen Display (OSD). /// OSD, /// /// The webview event should be displayed on the controller. /// Controller, /// /// The webview event should be displayed on the persistent web application. /// PersistentWebApp, /// /// The webview event should be displayed on the room scheduler. /// RoomScheduler } /// /// Represents the reason for an error in a webview event, which can provide additional information about what went wrong. This class is typically only used in the Status property of a WebViewEvent when the status indicates an error, and may be null otherwise. /// public class Reason { /// /// The reason for an error in a webview event as a string, which can provide additional information about what went wrong. This property is typically only populated in case of an error, and may be null otherwise. /// public string Value { get; set; } } /// /// Represents the XPath of a webview event, which can provide information about where an error occurred in the webview. This class is typically only used in the Status property of a WebViewEvent when the status indicates an error, and may be null otherwise. /// public class XPath { /// /// The XPath of a webview event as a string, which can provide information about where an error occurred in the webview. This property is typically only populated in case of an error, and may be null otherwise. /// public string Value { get; set; } } /// /// Represents a base class for properties that have a string value and trigger an action when the value changes. This class can be used as a base for properties like DisplayMode and Target in the WebViewEvent, which have string values that can be set directly or parsed into enums for easier handling of expected values. The ValueChangedAction can be set to trigger any desired behavior when the value changes, such as updating the UI or triggering other events. /// public abstract class ValueProperty { /// /// Triggered when Value is set /// public Action ValueChangedAction { get; set; } /// /// Triggers the ValueChangedAction if it is set. This method should be called whenever the Value property is set to ensure that any desired behavior associated with a change in value is executed. /// protected void OnValueChanged() { var a = ValueChangedAction; if (a != null) a(); } } /// /// Represents a webview event, which can include information about the status of the webview, the display parameters for the webview, and any error information if applicable. This class can be used to represent both show and clear events for a webview, with the Status property indicating the current status of the webview (e.g., "Fullscreen", "Modal", "Cleared", "Error", or "Unknown"), the Display property providing details about how the webview is being displayed (e.g., mode, URL, target, title), and the Cleared property providing details about a cleared/closed webview event (e.g., target and ID). The Id property can be used to correlate show and clear events for the same webview instance. /// public class WebViewEvent { /// /// The unique identifier for the webview event, which can be used to correlate show and clear events for the same webview instance. This property is typically included in both show and clear events for a webview, allowing you to track the lifecycle of a specific webview instance from when it is shown to when it is cleared/closed. The Id can be any string value, but it should be unique for each webview instance to ensure proper correlation between show and clear events. /// [JsonProperty("id")] public string Id { get; set; } /// /// The status of the webview event, which can indicate the current state of the webview (e.g., "Fullscreen", "Modal", "Cleared", "Error", or "Unknown") as well as any error information if applicable (XPath and Reason). The Value property can be used to get or set the current status of the webview, while the XPath and Reason properties can provide additional information in case of an error. The StatusString property can be used to get or set the raw status string from the event, but it is recommended to use the Value property for easier handling of expected values. Setting the Value property will trigger the ValueChangedAction if it is set, allowing you to respond to changes in the webview status as needed. /// [JsonProperty("status")] public Status Status { get; set; } // /Event/UserInterface/WebView/Status /// /// The display parameters for the webview event, which can include the display mode (e.g., "Fullscreen", "Modal", or "Unknown"), the URL to display in the webview, the target for the webview (e.g., "OSD", "Controller", "PersistentWebApp", or "RoomScheduler"), and the title to display on the webview. This property is typically included in show events for a webview, providing details about how the webview is being displayed. When a webview event with these display parameters is shown, it will typically trigger the WebViewStatusChanged event with a status of "Fullscreen" or "Modal" depending on the specified display mode, and when it is cleared/closed, it will trigger the WebViewStatusChanged event with a status of "Cleared". /// [JsonProperty("display")] public WebViewDisplay Display { get; set; } // /Event/UserInterface/WebView/Display /// /// The details for a cleared/closed webview event, which can include the target for the webview that was cleared (e.g., "OSD", "Controller", "PersistentWebApp", or "RoomScheduler") and the unique identifier for the webview event that was cleared. This property is typically included in clear events for a webview, providing details about which webview instance was cleared/closed. When a webview event with this property is cleared/closed, it will typically trigger the WebViewStatusChanged event with a status of "Cleared". /// [JsonProperty("cleared")] public WebViewClear Cleared { get; set; } // /Event/UserInterface/WebView/Cleared } /// /// Represents the display parameters for a webview event, which can include the display mode (e.g., "Fullscreen", "Modal", or "Unknown"), the URL to display in the webview, the target for the webview (e.g., "OSD", "Controller", "PersistentWebApp", or "RoomScheduler"), and the title to display on the webview. This class is typically used in the Display property of a WebViewEvent to provide details about how the webview is being displayed when a show event occurs. When a webview event with these display parameters is shown, it will typically trigger the WebViewStatusChanged event with a status of "Fullscreen" or "Modal" depending on the specified display mode, and when it is cleared/closed, it will trigger the WebViewStatusChanged event with a status of "Cleared". /// public class WebViewDisplay { /// /// The display mode for the webview event. Expected values are "Fullscreen", "Modal", or "Unknown". /// [JsonProperty("mode")] public DisplayMode Mode { get; set; } /// /// The URL to display in the webview. /// [JsonProperty("url")] public string Url { get; set; } /// /// The target for the webview. Expected values are "OSD", "Controller", "PersistentWebApp", or "RoomScheduler". /// [JsonProperty("target")] public Target Target { get; set; } /// /// The title to display on the webview. /// [JsonProperty("title")] public string Title { get; set; } /// /// The unique identifier for the webview event, used to correlate show and clear events for the same webview instance. /// [JsonProperty("id")] public string Id { get; set; } } /// /// Represents the data for a webview cleared event, which indicates that a webview with the specified ID and target has been cleared/closed. /// public class WebViewClear { /// /// The target for the webview that was cleared. Expected values are "OSD", "Controller", "PersistentWebApp", or "RoomScheduler". /// [JsonProperty("target")] public Target Target { get; set; } /// /// The unique identifier for the webview event that was cleared, used to correlate show and clear events for the same webview instance. /// [JsonProperty("id")] public string Id { get; set; } /// /// The URL that was displayed in the webview that was cleared. /// [JsonProperty("url")] public string Url { get; set; } } /// /// Represents the display mode for a webview event, with a string value and a corresponding enum property for easier handling of expected values. /// public class DisplayMode : ValueProperty { private string _value; /// /// The id of the webview event. /// [JsonProperty("id")] public string Id { get; set; } /// /// The string value for the display mode, which can be set directly or parsed into the WebViewEventMode enum using the WebViewEventMode property. Setting this property will also trigger the ValueChangedAction if it is set. /// public string Value { get { return _value; } set { _value = value; OnValueChanged(); } } /// /// The display mode for the webview event as an enum, which can be used for easier handling of expected values. Expected values are Fullscreen, Modal, or Unknown. /// public eWebViewEventMode WebViewEventMode { get { eWebViewEventMode mode; System.Enum.TryParse(Value, true, out mode); return mode; } } } /// /// Represents the target for a webview event, with a string value and a corresponding enum property for easier handling of expected values. Setting the Value property will also trigger the ValueChangedAction if it is set. /// public class Target : ValueProperty { private string _value; /// /// The id of the webview event. /// [JsonProperty("id")] public string Id { get; set; } /// /// The string value for the target, which can be set directly or parsed into the eWebViewTarget enum using the WebViewTarget property. Expected values are "OSD", "Controller", "PersistentWebApp", or "RoomScheduler". Setting this property will also trigger the ValueChangedAction if it is set. /// public string Value { get { return _value; } set { _value = value; OnValueChanged(); } } /// /// The target for the webview event as an enum, which can be used for easier handling of expected values. Expected values are OSD, Controller, PersistentWebApp, or RoomScheduler. /// public eWebViewTarget WebViewTarget { get { eWebViewTarget target; System.Enum.TryParse(Value, true, out target); return target; } } } /// /// Represents the status of a webview event, which can include error information (XPath and Reason) as well as the current status of the webview. The Value property can be used to get or set the current status of the webview, while the XPath and Reason properties can provide additional information in case of an error. The StatusString property can be used to get or set the raw status string from the event. /// public class Status { /// /// The XPath of the webview event, which can provide information about where an error occurred in the webview. This property is typically only populated in case of an error, and may be null otherwise. /// [JsonProperty("XPath", NullValueHandling = NullValueHandling.Ignore)] public XPath XPath { get; set; } /// /// The reason for an error in the webview event, which can provide additional information about what went wrong. This property is typically only populated in case of an error, and may be null otherwise. /// [JsonProperty("Reason", NullValueHandling = NullValueHandling.Ignore)] public Reason Reason { get; set; } /// /// The raw status string from the webview event, which can provide information about the current status of the webview. This property can be used to get or set the status directly, but it is recommended to use the Value property for easier handling of expected values. Setting this property will not trigger any actions, while setting the Value property will trigger the ValueChangedAction if it is set. /// [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] public string StatusString { get; set; } /// /// The current status of the webview as a string, which can be set directly or parsed into a WebViewEventMode enum using the WebViewEventMode property. Expected values are "Fullscreen", "Modal", "Cleared", "Error", or "Unknown". Setting this property will trigger the ValueChangedAction if it is set. /// [JsonProperty("Value", NullValueHandling = NullValueHandling.Ignore)] public string Value { get; set; } } /// /// Defines the contract for IHasWebView /// public interface IHasWebView { /// /// Indicates whether the webview is currently visible /// bool WebviewIsVisible { get; } /// /// Shows the webview with the specified parameters /// /// the URL to display in the webview /// the display mode for the webview /// the title to display on the webview /// the target for the webview void ShowWebView(string url, string mode, string title, string target); /// /// Hides the webview /// void HideWebView(); /// /// Event raised when the webview status changes /// event EventHandler WebViewStatusChanged; } /// /// Defines the contract for IHasWebViewWithPwaMode /// public interface IHasWebViewWithPwaMode : IHasWebView { /// /// Indicates whether the webview is currently in PWA mode /// bool IsInPwaMode { get; } /// /// Gets the BoolFeedback indicating whether the webview is currently in PWA mode /// BoolFeedback IsInPwaModeFeedback { get; } /// /// Sends navigators to the specified PWA URL. Accepts an absolute URL or a relative URL for a mobile control app /// /// The URL to navigate to void SendNavigatorsToPwaUrl(string url); /// /// Exits navigators from PWA mode /// void ExitNavigatorsPwaMode(); } /// /// Represents a WebViewStatusChangedEventArgs /// public class WebViewStatusChangedEventArgs : EventArgs { /// /// Gets or sets the Status /// public string Status { get; } /// /// Gets or sets the WebViewEvent associated with the status change, which can provide additional information about the webview event that triggered the status change, such as display parameters or error information. This property allows you to include the full WebViewEvent in the event args, giving you access to all relevant details about the webview event when handling the WebViewStatusChanged event. /// public WebViewEvent WebView { get; } /// /// Constructor for WebViewStatusChangedEventArgs /// /// the new status of the webview public WebViewStatusChangedEventArgs(string status) { Status = status; } /// /// Constructor for WebViewStatusChangedEventArgs with WebViewEvent parameter, which can provide additional information about the webview event that triggered the status change, such as display parameters or error information. This constructor allows you to include the full WebViewEvent in the event args, giving you access to all relevant details about the webview event when handling the WebViewStatusChanged event. /// /// the new status of the webview /// the WebViewEvent associated with the status change public WebViewStatusChangedEventArgs(string status, WebViewEvent webview) { Status = status; WebView = webview; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IHumiditySensor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IHumiditySensor /// public interface IHumiditySensor { /// /// Reports the relative humidity level. Level ranging from 0 to 100 (for 0% to 100% /// RH). EventIds: HumidityFeedbackFeedbackEventId will trigger to indicate change. /// IntFeedback HumidityFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageDefinition.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for ILanguageDefinition /// public interface ILanguageDefinition { /// /// The locale name for the language definition /// string LocaleName { get; set; } /// /// The friendly name for the language definition /// string FriendlyName { get; set; } /// /// Indicates whether the language definition is enabled /// bool Enable { get; set; } /// /// The UI labels for the language definition /// List UiLabels { get; set; } /// /// The source and destination labels for the language definition /// List Sources { get; set; } /// /// The destination labels for the language definition /// List Destinations { get; set; } /// /// The source group names for the language definition /// List SourceGroupNames { get; set; } /// /// The destination group names for the language definition /// List DestinationGroupNames { get; set; } /// /// The room names for the language definition /// List RoomNames { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILanguageProvider.cs ================================================ using System; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for ILanguageProvider /// public interface ILanguageProvider { /// /// The current language definition /// ILanguageDefinition CurrentLanguage { get; set; } /// /// Event raised when the current language changes /// event EventHandler CurrentLanguageChanged; } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ILevelControls.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for ILevelControls /// public interface ILevelControls { /// /// The level control points /// Dictionary LevelControlPoints { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMeterFeedback.cs ================================================ using System; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Interface for devices that provide audio meter feedback. /// This interface is used to standardize access to meter feedback across different devices. /// public interface IMeterFeedback { /// /// Gets the meter feedback for the device. /// This property provides an IntFeedback that represents the current audio level or meter value. /// IntFeedback MeterFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs ================================================ using System; using Newtonsoft.Json.Linq; using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IMobileControl /// public interface IMobileControl : IKeyed { /// /// Gets the Host /// string Host { get; } /// /// Gets the Client App URL /// string ClientAppUrl { get; } /// /// Gets the System UUID /// string SystemUuid { get; } /// /// Gets the ApiOnlineAndAuthorized feedback /// BoolFeedback ApiOnlineAndAuthorized { get; } /// /// Sends the message object to the AppServer /// /// Message to send void SendMessageObject(IMobileControlMessage o); /// /// Adds an action for a messenger /// /// Messenger type. Must implement IMobileControlMessenger /// messenger to register /// action to add void AddAction(T messenger, Action action) where T : IMobileControlMessenger; /// /// Removes an action for a messenger /// /// key for action void RemoveAction(string key); /// /// Adds a device messenger /// /// Messenger to add void AddDeviceMessenger(IMobileControlMessenger messenger); /// /// Check if a device messenger exists /// /// Messenger key to find bool CheckForDeviceMessenger(string key); /// /// Get a Room Messenger by key /// /// messenger key to find /// Messenger if found, null otherwise IMobileControlRoomMessenger GetRoomMessenger(string key); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlAction.cs ================================================ using System; using Newtonsoft.Json.Linq; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IMobileControlAction /// public interface IMobileControlAction { /// /// The messenger to use for mobile control actions /// IMobileControlMessenger Messenger { get; } /// /// The action to perform for mobile control actions /// Action Action { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlCrestronTouchpanelController.cs ================================================ using System.Collections.ObjectModel; using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Describes a MobileControl Crestron Touchpanel Controller /// This interface extends the IMobileControlTouchpanelController to include connected IP information /// public interface IMobileControlCrestronTouchpanelController : IMobileControlTouchpanelController { /// /// Gets a collection of connected IP information for the touchpanel controller /// ReadOnlyCollection ConnectedIps { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessage.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IMobileControlMessage /// public interface IMobileControlMessage { /// /// The type of mobile control message /// [JsonProperty("type")] string Type { get; } /// /// The client ID for the mobile control message /// [JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)] string ClientId { get; } /// /// The content of the mobile control message /// [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] JToken Content { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessenger.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IMobileControlMessenger /// public interface IMobileControlMessenger : IKeyed { /// /// Parent controller for this messenger /// IMobileControl AppServerController { get; } /// /// Path to listen for messages /// string MessagePath { get; } /// /// Key of the device this messenger is associated with /// string DeviceKey { get; } /// /// Register this messenger with the AppServerController /// /// void RegisterWithAppServer(IMobileControl appServerController); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessengerWithSubscriptions.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IMobileControlMessenger /// public interface IMobileControlMessengerWithSubscriptions : IMobileControlMessenger { /// /// Unsubscribe a client from this messenger /// /// void UnsubscribeClient(string clientId); /// /// Register this messenger with the AppServerController /// /// parent for this messenger /// Enable messenger subscriptions void RegisterWithAppServer(IMobileControl appServerController, bool enableMessengerSubscriptions); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlRoomMessenger.cs ================================================ using System; using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IMobileControlRoomMessenger /// public interface IMobileControlRoomMessenger : IKeyed { /// /// Raised when the user code changes /// event EventHandler UserCodeChanged; /// /// Raised when the user is prompted for the code /// event EventHandler UserPromptedForCode; /// /// Raised when a client joins the room /// event EventHandler ClientJoined; /// /// Raised when the app url changes /// event EventHandler AppUrlChanged; /// /// The user code for joining the room /// string UserCode { get; } /// /// The QR code URL for joining the room /// string QrCodeUrl { get; } /// /// The QR code checksum /// string QrCodeChecksum { get; } /// /// The Mobile Control server URL /// string McServerUrl { get; } /// /// The name of the room /// string RoomName { get; } /// /// The Mobile Control app URL /// string AppUrl { get; } /// /// Updates the url of the Mobile Control app /// /// The new URL of the Mobile Control app void UpdateAppUrl(string url); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlTouchpanelController.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IMobileControlTouchpanelController /// public interface IMobileControlTouchpanelController : IKeyed { /// /// The default room key for the controller /// string DefaultRoomKey { get; } /// /// Sets the application URL for the controller /// /// The application URL void SetAppUrl(string url); /// /// Indicates whether the controller uses a direct server connection /// bool UseDirectServer { get; } /// /// Indicates whether the controller is a Zoom Room controller /// bool ZoomRoomController { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INumeric.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { /// /// Defines the contract for INumericKeypad /// public interface INumericKeypad:IKeyed { /// /// Digit buttons 0 /// /// determines if the digit button command is a press or release action void Digit0(bool pressRelease); /// /// Digit buttons 1 /// /// determines if the digit button command is a press or release action void Digit1(bool pressRelease); /// /// Digit buttons 2 /// /// determines if the digit button command is a press or release action void Digit2(bool pressRelease); /// /// Digit buttons 3 /// /// determines if the digit button command is a press or release action void Digit3(bool pressRelease); /// /// Digit buttons 4 /// /// void Digit4(bool pressRelease); /// /// Digit buttons 5 /// /// determines if the digit button command is a press or release action void Digit5(bool pressRelease); /// /// Digit buttons 6 /// /// determines if the digit button command is a press or release action void Digit6(bool pressRelease); /// /// Digit buttons 7 /// /// determines if the digit button command is a press or release action void Digit7(bool pressRelease); /// /// Digit buttons 8 /// /// determines if the digit button command is a press or release action void Digit8(bool pressRelease); /// /// Digit buttons 9 /// /// determines if the digit button command is a press or release action void Digit9(bool pressRelease); /// /// Used to hide/show the button and/or text on the left-hand keypad button /// bool HasKeypadAccessoryButton1 { get; } /// /// Label for the left-hand keypad button /// string KeypadAccessoryButton1Label { get; } /// /// Left-hand keypad button action /// /// determines if the button command is a press or release action void KeypadAccessoryButton1(bool pressRelease); /// /// Used to hide/show the button and/or text on the right-hand keypad button /// bool HasKeypadAccessoryButton2 { get; } /// /// Label for the right-hand keypad button /// string KeypadAccessoryButton2Label { get; } /// /// Right-hand keypad button action /// /// determines if the button command is a press or release action void KeypadAccessoryButton2(bool pressRelease); } /// /// Defines the contract for ISetTopBoxNumericKeypad /// public interface ISetTopBoxNumericKeypad : INumericKeypad { /// /// Dash button action /// /// determines if the button command is a press or release action void Dash(bool pressRelease); /// /// Keypad Enter button action /// /// determines if the button command is a press or release action void KeypadEnter(bool pressRelease); } /// /// INumericExtensions class /// public static class INumericExtensions { /// /// Links to the smart object, and sets the misc button's labels on joins x and y /// public static void LinkButtons(this INumericKeypad dev, BasicTriList trilist) { trilist.SetBoolSigAction(110, dev.Digit0); trilist.SetBoolSigAction(111, dev.Digit1); trilist.SetBoolSigAction(112, dev.Digit2); trilist.SetBoolSigAction(113, dev.Digit3); trilist.SetBoolSigAction(114, dev.Digit4); trilist.SetBoolSigAction(115, dev.Digit5); trilist.SetBoolSigAction(116, dev.Digit6); trilist.SetBoolSigAction(117, dev.Digit7); trilist.SetBoolSigAction(118, dev.Digit8); trilist.SetBoolSigAction(119, dev.Digit9); trilist.SetBoolSigAction(120, dev.KeypadAccessoryButton1); trilist.SetBoolSigAction(121, dev.KeypadAccessoryButton2); trilist.StringInput[111].StringValue = dev.KeypadAccessoryButton1Label; trilist.StringInput[111].StringValue = dev.KeypadAccessoryButton2Label; } /// /// UnlinkButtons method /// public static void UnlinkButtons(this INumericKeypad dev, BasicTriList trilist) { trilist.ClearBoolSigAction(110); trilist.ClearBoolSigAction(111); trilist.ClearBoolSigAction(112); trilist.ClearBoolSigAction(113); trilist.ClearBoolSigAction(114); trilist.ClearBoolSigAction(115); trilist.ClearBoolSigAction(116); trilist.ClearBoolSigAction(117); trilist.ClearBoolSigAction(118); trilist.ClearBoolSigAction(119); trilist.ClearBoolSigAction(120); trilist.ClearBoolSigAction(121); } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharpPro.DM.Streaming; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Represents a collection of network port information and provides notifications when the information changes. /// /// This interface is designed to provide access to a list of network port details and to notify /// subscribers when the port information is updated. Implementations of this interface should ensure that the event is raised whenever the collection /// changes. public interface INvxNetworkPortInformation : IKeyed { /// /// Occurs when the port information changes. /// /// This event is triggered whenever there is a change in the port information, such as /// updates to port settings or status. Subscribers can handle this event to respond to such changes. event EventHandler PortInformationChanged; /// /// Gets the collection of network port information associated with the current instance. /// /// The collection provides information about the network ports, such as their status, /// configuration, or other relevant details. The returned list is read-only and cannot be modified /// directly. List NetworkPorts { get; } } /// /// Represents information about a network port, including its configuration and associated system details. /// /// This class provides properties to describe various attributes of a network port, such as its /// name, description, VLAN configuration, and management IP address. It is typically used to store and retrieve /// metadata about network ports in a managed environment. public class NvxNetworkPortInformation { private readonly DmNvxBaseClass.DmNvx35xNetwork.DmNvxNetworkLldpPort port; /// /// Gets or sets the index of the device port. /// public uint DevicePortIndex { get; } /// /// Gets or sets the name of the port used for communication. /// public string PortName => port.PortNameFeedback.StringValue; /// /// Gets or sets the description of the port. /// public string PortDescription => port.PortNameDescriptionFeedback.StringValue; /// /// Gets or sets the name of the VLAN (Virtual Local Area Network). /// public string VlanName => port.VlanNameFeedback.StringValue; /// /// Gets the IP management address associated with the port. /// public string IpManagementAddress => port.IpManagementAddressFeedback.StringValue; /// /// Gets the name of the system as reported by the associated port. /// public string SystemName => port.SystemNameFeedback.StringValue; /// /// Gets the description of the system name. /// public string SystemNameDescription => port.SystemNameDescriptionFeedback.StringValue; /// /// Initializes a new instance of the class with the specified network port /// and device port index. /// /// The network port associated with the device. Cannot be . /// The index of the device port. /// Thrown if is . public NvxNetworkPortInformation(DmNvxBaseClass.DmNvx35xNetwork.DmNvxNetworkLldpPort port, uint devicePortIndex) { this.port = port ?? throw new ArgumentNullException(nameof(port), "Port cannot be null"); DevicePortIndex = devicePortIndex; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPasswordPrompt.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Describes the functionality required to prompt a user to enter a password /// public interface IPasswordPrompt { /// /// Notifies when a password is required or is entered incorrectly /// event EventHandler PasswordRequired; /// /// Submits the password /// /// The password to submit void SubmitPassword(string password); } /// /// PasswordPromptEventArgs class /// public class PasswordPromptEventArgs : EventArgs { /// /// Indicates if the last submitted password was incorrect /// public bool LastAttemptWasIncorrect { get; private set; } /// /// Gets or sets the LoginAttemptFailed /// public bool LoginAttemptFailed { get; private set; } /// /// Gets or sets the LoginAttemptCancelled /// public bool LoginAttemptCancelled { get; private set; } /// /// Gets or sets the Message /// public string Message { get; private set; } /// /// Constructor /// /// indicates if the last submitted password was incorrect /// indicates if the login attempt failed /// indicates if the login attempt was cancelled /// provides a message related to the password prompt public PasswordPromptEventArgs(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message) { LastAttemptWasIncorrect = lastAttemptIncorrect; LoginAttemptFailed = loginFailed; LoginAttemptCancelled = loginCancelled; Message = message; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IPower.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.Fusion; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { /// /// Adds feedback for current power state /// public interface IHasPowerControlWithFeedback : IHasPowerControl { /// /// Feedback indicating whether the device is powered on /// BoolFeedback PowerIsOnFeedback { get; } } /// /// Defines the ability to power a device on and off /// public interface IHasPowerControl { /// /// Powers the device on /// void PowerOn(); /// /// Powers the device off /// void PowerOff(); /// /// Toggles the power state of the device /// void PowerToggle(); } /// /// IHasPowerControlExtensions class /// public static class IHasPowerControlExtensions { /// /// LinkButtons method /// public static void LinkButtons(this IHasPowerControl dev, BasicTriList triList) { triList.SetSigFalseAction(101, dev.PowerOn); triList.SetSigFalseAction(102, dev.PowerOff); triList.SetSigFalseAction(103, dev.PowerToggle); var fbdev = dev as IHasPowerControlWithFeedback; if (fbdev != null) { fbdev.PowerIsOnFeedback.LinkInputSig(triList.BooleanInput[101]); } } /// /// UnlinkButtons method /// public static void UnlinkButtons(this IHasPowerControl dev, BasicTriList triList) { triList.ClearBoolSigAction(101); triList.ClearBoolSigAction(102); triList.ClearBoolSigAction(103); var fbdev = dev as IHasPowerControlWithFeedback; if (fbdev != null) { fbdev.PowerIsOnFeedback.UnlinkInputSig(triList.BooleanInput[101]); } } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IProjectorScreenLiftControl.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using System; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IProjectorScreenLiftControl /// public interface IProjectorScreenLiftControl { /// /// Raises the screen/lift /// void Raise(); /// /// Lowers the screen/lift /// void Lower(); /// /// Stops the screen/lift /// BoolFeedback IsInUpPosition { get; } /// /// Gets whether the screen/lift is in the up position /// bool InUpPosition { get; } /// /// Gets whether the screen/lift is in the down position /// event EventHandler PositionChanged; /// /// The device key of the display associated with this screen/lift /// string DisplayDeviceKey { get; } /// /// The type of device /// eScreenLiftControlType Type { get; } // screen/lift } /// /// Enumeration of eScreenLiftControlType values /// public enum eScreenLiftControlType { /// /// Lift type device /// lift, /// /// Screen type device /// screen } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItem.cs ================================================ using System; using Newtonsoft.Json; using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for ISelectableItem /// public interface ISelectableItem : IKeyName { /// /// Raised when the item is updated /// event EventHandler ItemUpdated; /// /// Gets or sets whether the item is selected /// [JsonProperty("isSelected")] bool IsSelected { get; set; } /// /// Selects the item /// void Select(); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISelectableItems.cs ================================================ using Newtonsoft.Json; using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for ISelectableItems /// public interface ISelectableItems where TValue : ISelectableItem { /// /// Raised when the items are updated /// event EventHandler ItemsUpdated; /// /// Raised when the current item changes /// event EventHandler CurrentItemChanged; /// /// Gets or sets the collection of selectable items /// [JsonProperty("items")] Dictionary Items { get; set; } /// /// Gets or sets the current selected item key /// [JsonProperty("currentItem")] TKey CurrentItem { get; set; } } /// /// Describes a collection of items that can be selected /// /// type for the keys in the collection. Probably a string or enum public interface ISelectableItems : ISelectableItems { } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ISetTopBoxControls.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { /// /// Defines the contract for ISetTopBoxControls /// public interface ISetTopBoxControls : IChannel, IColor, IDPad, ISetTopBoxNumericKeypad, ITransport, IUiDisplayInfo { /// /// Show DVR controls? /// bool HasDvr { get; } /// /// Show presets controls? /// bool HasPresets { get; } /// /// Show number pad controls? /// bool HasNumeric { get; } /// /// Show D-pad controls? /// bool HasDpad { get; } /// /// TV Presets model /// PepperDash.Essentials.Core.Presets.DevicePresetsModel TvPresets { get; } /// /// LoadPresets method /// /// path to file that contains the presets void LoadPresets(string filePath); /// /// DvrList button action /// /// determines if the button action is a press or release void DvrList(bool pressRelease); /// /// Replay button action /// /// determines if the button action is a press or release void Replay(bool pressRelease); } /// /// ISetTopBoxControlsExtensions class /// public static class ISetTopBoxControlsExtensions { /// /// LinkButtons method /// /// The ISetTopBoxControls device /// The BasicTriList to link buttons to public static void LinkButtons(this ISetTopBoxControls dev, BasicTriList triList) { triList.SetBoolSigAction(136, dev.DvrList); triList.SetBoolSigAction(152, dev.Replay); } /// /// UnlinkButtons method /// /// The ISetTopBoxControls device /// The BasicTriList to unlink buttons from public static void UnlinkButtons(this ISetTopBoxControls dev, BasicTriList triList) { triList.ClearBoolSigAction(136); triList.ClearBoolSigAction(152); } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs ================================================ using System; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Interface for devices that provide state feedback. /// This interface is used to standardize access to state feedback across different devices. /// public interface IStateFeedback { /// /// Gets the state feedback for the device. /// This property provides a BoolFeedback that represents the current state (on/off) of the device. /// BoolFeedback StateFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITemperatureSensor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for ITemperatureSensor /// public interface ITemperatureSensor { /// /// The values will range from -400 to +1760 (for -40° to +176° F) or -400 to +800 /// (for -40° to +80° C)in tenths of a degree. /// IntFeedback TemperatureFeedback { get; } /// /// The temperature in Celsius format /// BoolFeedback TemperatureInCFeedback { get; } /// /// Sets the temperature format to Celsius or Fahrenheit /// /// If true, sets the format to Celsius; otherwise, sets it to Fahrenheit. void SetTemperatureFormat(bool setToC); } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITransport.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core { /// /// Defines the contract for ITransport /// public interface ITransport { /// /// Play button action /// /// determines if the button action is a press or release void Play(bool pressRelease); /// /// Pause button action /// /// determines if the button action is a press or release void Pause(bool pressRelease); /// /// Rewind button action /// /// determines if the button action is a press or release void Rewind(bool pressRelease); /// /// Fast Forward button action /// /// determines if the button action is a press or release void FFwd(bool pressRelease); /// /// Chapter Minus button action /// /// determines if the button action is a press or release void ChapMinus(bool pressRelease); /// /// Chapter Plus button action /// /// determines if the button action is a press or release void ChapPlus(bool pressRelease); /// /// Stop button action /// /// determines if the button action is a press or release void Stop(bool pressRelease); /// /// Record button action /// /// determines if the button action is a press or release void Record(bool pressRelease); } /// /// ITransportExtensions class /// public static class ITransportExtensions { /// /// Attaches to trilist joins: Play:145, Pause:146, Stop:147, ChapPlus:148, ChapMinus:149, Rewind:150, Ffwd:151, Record:154 /// /// The ITransport device /// The BasicTriList to link buttons to public static void LinkButtons(this ITransport dev, BasicTriList triList) { triList.SetBoolSigAction(145, dev.Play); triList.SetBoolSigAction(146, dev.Pause); triList.SetBoolSigAction(147, dev.Stop); triList.SetBoolSigAction(148, dev.ChapPlus); triList.SetBoolSigAction(149, dev.ChapMinus); triList.SetBoolSigAction(150, dev.Rewind); triList.SetBoolSigAction(151, dev.FFwd); triList.SetBoolSigAction(154, dev.Record); } /// /// UnlinkButtons method /// /// The ITransport device /// The BasicTriList to unlink buttons from public static void UnlinkButtons(this ITransport dev, BasicTriList triList) { triList.ClearBoolSigAction(145); triList.ClearBoolSigAction(146); triList.ClearBoolSigAction(147); triList.ClearBoolSigAction(148); triList.ClearBoolSigAction(149); triList.ClearBoolSigAction(150); triList.ClearBoolSigAction(151); triList.ClearBoolSigAction(154); } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ITvPresetsProvider.cs ================================================ using PepperDash.Essentials.Core.Presets; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for ITvPresetsProvider /// public interface ITvPresetsProvider { /// /// The TV presets model /// DevicePresetsModel TvPresets { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IUiDisplayInfo.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IUiDisplayInfo /// public interface IUiDisplayInfo : IKeyed { /// /// Display UI Type /// uint DisplayUiType { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IWarmingCooling.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Defines a class that has warm up and cool down /// public interface IWarmingCooling { /// /// Feedback indicating whether the device is warming up /// BoolFeedback IsWarmingUpFeedback { get; } /// /// Feedback indicating whether the device is cooling down /// BoolFeedback IsCoolingDownFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/LanguageLabel.cs ================================================ using System; using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Represents a LanguageLabel /// public class LanguageLabel { /// /// Gets or sets the Key /// public string Key { get; set; } /// /// Gets or sets the Description /// public string Description { get; set; } /// /// Gets or sets the DisplayText /// public string DisplayText { get; set; } /// /// Gets or sets the JoinNumber /// public uint JoinNumber { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/Template.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; namespace PepperDash.Essentials.Core { } ================================================ FILE: src/PepperDash.Essentials.Core/DeviceTypeInterfaces/eVolumeLevelUnits.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Volume level units /// public enum eVolumeLevelUnits { /// /// Decibels /// Decibels, /// /// Percent /// Percent, /// /// Relative /// Relative, /// /// Absolute /// Absolute } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/AudioControlListItemBase.cs ================================================ using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core { /// /// Base class for audio control list items /// public abstract class AudioControlListItemBase { /// /// Key of the parent device in the DeviceManager /// [JsonProperty("parentDeviceKey")] public string ParentDeviceKey { get; set; } /// /// Optional key of the item in the parent device /// [JsonProperty("itemKey")] public string ItemKey { get; set; } /// /// A name that will override the items's name on the UI /// [JsonProperty("name")] public string Name { get; set; } /// /// Indicates if the item should be included in the user accessible list /// [JsonProperty("includeInUserList")] public bool IncludeInUserList { get; set; } /// /// Used to specify the order of the items in the source list when displayed /// [JsonProperty("order")] public int Order { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/AudioInterfaces.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core { /// /// Enumeration of AudioChangeType values /// public enum AudioChangeType { /// /// Mute change /// Mute, /// /// Volume change /// Volume } /// /// Represents a AudioChangeEventArgs /// public class AudioChangeEventArgs { /// /// Gets or sets the ChangeType /// public AudioChangeType ChangeType { get; private set; } /// /// Gets or sets the AudioDevice /// public IBasicVolumeControls AudioDevice { get; private set; } /// /// Constructor /// /// device that changed /// type of change public AudioChangeEventArgs(IBasicVolumeControls device, AudioChangeType changeType) { ChangeType = changeType; AudioDevice = device; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/CameraListItem.cs ================================================ using Newtonsoft.Json; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Represents a CameraListItem /// public class CameraListItem { /// /// Key of the camera device /// [JsonProperty("deviceKey")] public string DeviceKey { get; set; } /// /// Returns the source Device for this, if it exists in DeviceManager /// [JsonIgnore] public Device CameraDevice { get { if (_cameraDevice == null) _cameraDevice = DeviceManager.GetDeviceForKey(DeviceKey) as Device; return _cameraDevice; } } Device _cameraDevice; /// /// Gets either the source's Name or this AlternateName property, if /// defined. If source doesn't exist, returns "Missing source" /// [JsonProperty("preferredName")] public string PreferredName { get { if (string.IsNullOrEmpty(Name)) { if (CameraDevice == null) return "---"; return CameraDevice.Name; } return Name; } } /// /// A name that will override the source's name on the UI /// [JsonProperty("name")] public string Name { get; set; } /// /// Specifies and icon for the source list item /// [JsonProperty("icon")] public string Icon { get; set; } /// /// Alternate icon /// [JsonProperty("altIcon", NullValueHandling = NullValueHandling.Ignore)] public string AltIcon { get; set; } /// /// Indicates if the item should be included in the user facing list /// [JsonProperty("includeInUserList")] public bool IncludeInUserList { get; set; } /// /// Used to specify the order of the items in the source list when displayed /// [JsonProperty("order")] public int Order { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/CodecInterfaces.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Adds control of codec receive volume /// public interface IReceiveVolume { // Break this out into 3 interfaces /// /// Sets the receive volume level /// /// volume level to set void SetReceiveVolume(ushort level); /// /// Mutes the receive audio /// void ReceiveMuteOn(); /// /// Unmutes the receive audio /// void ReceiveMuteOff(); /// /// Toggles the receive mute state /// void ReceiveMuteToggle(); /// /// Feedback for the receive volume level /// IntFeedback ReceiveLevelFeedback { get; } /// /// Feedback for the receive mute state /// BoolFeedback ReceiveMuteIsOnFeedback { get; } } /// /// Defines the contract for ITransmitVolume /// public interface ITransmitVolume { /// /// Sets the transmit volume level /// /// volume level to set void SetTransmitVolume(ushort level); /// /// Mutes the transmit audio /// void TransmitMuteOn(); /// /// Unmutes the transmit audio /// void TransmitMuteOff(); /// /// Toggles the transmit mute state /// void TransmitMuteToggle(); /// /// Feedback for the transmit volume level /// IntFeedback TransmitLevelFeedback { get; } /// /// Feedback for the transmit mute state /// BoolFeedback TransmitMuteIsOnFeedback { get; } } /// /// Defines the contract for IPrivacy /// public interface IPrivacy { /// /// Enables privacy mode /// void PrivacyModeOn(); /// /// Disables privacy mode /// void PrivacyModeOff(); /// /// Toggles privacy mode /// void PrivacyModeToggle(); /// /// Feedback for the privacy mode state /// BoolFeedback PrivacyModeIsOnFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/ConfigSnippetAttribute.cs ================================================ using System; namespace PepperDash.Essentials.Core { /// /// Represents a ConfigSnippetAttribute /// [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] public class ConfigSnippetAttribute : Attribute { /// /// Represents a configuration snippet for the device. /// /// public ConfigSnippetAttribute(string configSnippet) { ConfigSnippet = configSnippet; } /// /// Gets the configuration snippet for the device. /// This snippet can be used in the DeviceConfig to instantiate the device. /// public string ConfigSnippet { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; using Serilog.Events; namespace PepperDash.Essentials.Core.Devices { /// /// This wrapper class is meant to allow interfaces to be applied to any Crestron processor /// public class CrestronProcessor : Device, ISwitchedOutputCollection { /// /// Collection of switched outputs (relays) on the processor /// public Dictionary SwitchedOutputs { get; private set; } /// /// The underlying CrestronControlSystem processor /// public Crestron.SimplSharpPro.CrestronControlSystem Processor { get; private set; } /// /// Constructor /// /// key for the processor public CrestronProcessor(string key) : base(key) { SwitchedOutputs = new Dictionary(); Processor = Global.ControlSystem; GetRelays(); } /// /// Creates a GenericRelayDevice for each relay on the processor and adds them to the SwitchedOutputs collection /// void GetRelays() { try { if (Processor.SupportsRelay) { for (uint i = 1; i <= Processor.NumberOfRelayPorts; i++) { var relay = new GenericRelayDevice(string.Format("{0}-relay-{1}", this.Key, i), Processor.RelayPorts[i]); SwitchedOutputs.Add(i, relay); } } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Error Getting Relays from processor:\n '{0}'", e); } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/DescriptionAttribute.cs ================================================ using System; namespace PepperDash.Essentials.Core { /// /// Represents a description attribute for a device. /// [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] public class DescriptionAttribute : Attribute { /// /// Represents a description attribute for a device. /// /// public DescriptionAttribute(string description) { Description = description; } /// /// Gets the description for the device. /// public string Description { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs ================================================  using Newtonsoft.Json; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core { /// /// Represents a destination item in a routing system that can receive audio/video signals. /// Contains information about the destination device, its properties, and location settings. /// public class DestinationListItem { /// /// Gets or sets the key identifier for the sink device that this destination represents. /// [JsonProperty("sinkKey")] public string SinkKey { get; set; } private EssentialsDevice _sinkDevice; /// /// Gets the actual device instance for this destination. /// Lazily loads the device from the DeviceManager using the SinkKey. /// [JsonIgnore] public EssentialsDevice SinkDevice { get { return _sinkDevice ?? (_sinkDevice = DeviceManager.GetDeviceForKey(SinkKey) as EssentialsDevice); } } /// /// Gets the preferred display name for this destination. /// Returns the custom Name if set, otherwise returns the SinkDevice name, or "---" if no device is found. /// [JsonProperty("preferredName")] public string PreferredName { get { if (!string.IsNullOrEmpty(Name)) { return Name; } return SinkDevice == null ? "---" : SinkDevice.Name; } } /// /// Gets or sets the custom name for this destination. /// If set, this name will be used as the PreferredName instead of the device name. /// [JsonProperty("name")] public string Name { get; set; } /// /// Gets or sets a value indicating whether this destination should be included in destination lists. /// [JsonProperty("includeInDestinationList")] public bool IncludeInDestinationList { get; set; } /// /// Gets or sets the display order for this destination in lists. /// Lower values appear first in sorted lists. /// [JsonProperty("order")] public int Order { get; set; } /// /// Gets or sets the surface location identifier for this destination. /// Used to specify which surface or screen this destination is located on. /// [JsonProperty("surfaceLocation")] public int SurfaceLocation { get; set; } /// /// Gets or sets the vertical location position for this destination. /// Used for spatial positioning in multi-display configurations. /// [JsonProperty("verticalLocation")] public int VerticalLocation { get; set; } /// /// Gets or sets the horizontal location position for this destination. /// Used for spatial positioning in multi-display configurations. /// [JsonProperty("horizontalLocation")] public int HorizontalLocation { get; set; } /// /// Gets or sets the signal type that this destination can receive (Audio, Video, AudioVideo, etc.). /// [JsonProperty("sinkType")] public eRoutingSignalType SinkType { get; set; } /// /// Gets or sets a value indicating whether this destination is used for codec content sharing. /// [JsonProperty("isCodecContentDestination")] public bool isCodecContentDestination { get; set; } /// /// Gets or sets a value indicating whether this destination is used for program audio output. /// [JsonProperty("isProgramAudioDestination")] public bool isProgramAudioDestination { get; set; } /// /// Gets or sets a value indicating whether this destination supports USB connections. /// Indicates if the destination can handle USB functionality, such as USB signal routing or device connections. /// This property is used to determine compatibility with USB-based devices or systems. /// [JsonProperty("supportsUsb")] public bool SupportsUsb { get; set; } /// /// The key of the destination port associated with this destination item /// This is used to identify the specific port on the destination device that this item refers to for advanced routing /// [JsonProperty("destinationPortKey")] public string DestinationPortKey { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/DeviceApiBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core.Devices { /// /// Base class for all Device APIs /// public abstract class DeviceApiBase { /// /// Action API dictionary /// public Dictionary ActionApi { get; protected set; } /// /// Feedback API dictionary /// public Dictionary FeedbackApi { get; protected set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/DeviceFeedbackExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// DeviceFeedbackExtensions class /// public static class DeviceFeedbackExtensions { /// /// Attempts to get and return a feedback property from a device by name. /// If unsuccessful, returns null. /// /// device to get feedback from /// name of the feedback property /// Feedback property if found, otherwise null public static Feedback GetFeedbackProperty(this Device device, string propertyName) { var feedback = DeviceJsonApi.GetPropertyByName(device.Key, propertyName) as Feedback; if (feedback != null) { return feedback; } return null; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/DeviceJsonApi.cs ================================================ using Crestron.SimplSharp; using Newtonsoft.Json; using PepperDash.Core; using Serilog.Events; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; namespace PepperDash.Essentials.Core { /// /// Represents a DeviceJsonApi /// public class DeviceJsonApi { /// /// DoDeviceActionWithJson method /// /// json method public static void DoDeviceActionWithJson(string json) { if (String.IsNullOrEmpty(json)) { CrestronConsole.ConsoleCommandResponse( "Please provide a JSON object matching the format {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}.\r\nIf the method has no parameters, the \"params\" object may be omitted."); return; } try { var action = JsonConvert.DeserializeObject(json); DoDeviceAction(action); } catch (Exception) { CrestronConsole.ConsoleCommandResponse("Incorrect format for JSON. Please check that the format matches {\"deviceKey\":\"myDevice\", \"methodName\":\"someMethod\", \"params\": [\"param1\", true]}"); } } /// /// DoDeviceAction method /// /// action method public static void DoDeviceAction(DeviceActionWrapper action) { var key = action.DeviceKey; var obj = FindObjectOnPath(key); if (obj == null) { CrestronConsole.ConsoleCommandResponse("Unable to find object at path {0}", key); return; } if (action.Params == null) { //no params, so setting action.Params to empty array action.Params = new object[0]; } Type t = obj.GetType(); try { var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList(); var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length); if (method == null) { CrestronConsole.ConsoleCommandResponse( "Unable to find method with name {0} and that matches parameters {1}", action.MethodName, action.Params); return; } var mParams = method.GetParameters(); var convertedParams = mParams .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) .ToArray(); Task.Run(() => { try { Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); method.Invoke(obj, convertedParams); } catch (Exception e) { Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); } }); CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name, action.DeviceKey); } catch (Exception ex) { CrestronConsole.ConsoleCommandResponse("Unable to call method with name {0}. {1}", action.MethodName, ex.Message); } } /// /// DoDeviceActionAsync method /// /// action method public static async Task DoDeviceActionAsync(DeviceActionWrapper action) { var key = action.DeviceKey; var obj = FindObjectOnPath(key); if (obj == null) { Debug.LogMessage(LogEventLevel.Warning, "Unable to find object at path {deviceKey}", null, key); return; } if (action.Params == null) { //no params, so setting action.Params to empty array action.Params = new object[0]; } Type t = obj.GetType(); try { var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList(); var method = methods.Count == 1 ? methods[0] : methods.FirstOrDefault(m => m.GetParameters().Length == action.Params.Length); if (method == null) { Debug.LogMessage(LogEventLevel.Warning, "Unable to find method with name {methodName} and that matches parameters {@parameters}", null, action.MethodName, action.Params); return; } var mParams = method.GetParameters(); var convertedParams = mParams .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) .ToArray(); try { Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey} with {@params}", null, method.Name, action.DeviceKey, action.Params); var result = method.Invoke(obj, convertedParams); // If the method returns a Task, await it if (result is Task task) { await task; } // If the method returns a Task, await it else if (result != null && result.GetType().IsGenericType && result.GetType().GetGenericTypeDefinition() == typeof(Task<>)) { await (Task)result; } } catch (Exception e) { Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey); } } catch (Exception ex) { Debug.LogMessage(ex, "Unable to call method with name {methodName} with {@parameters}", null, action.MethodName, action.Params); } } private static object ConvertType(object value, Type conversionType) { if (!conversionType.IsEnum) { return Convert.ChangeType(value, conversionType, System.Globalization.CultureInfo.InvariantCulture); } var stringValue = Convert.ToString(value); if (String.IsNullOrEmpty(stringValue)) { throw new InvalidCastException( String.Format("{0} cannot be converted to a string prior to conversion to enum")); } return Enum.Parse(conversionType, stringValue, true); } /// /// Gets the properties on a device /// /// The path to the device object /// A JSON string representing the properties of the device public static string GetProperties(string deviceObjectPath) { var obj = FindObjectOnPath(deviceObjectPath); if (obj == null) return "{ \"error\":\"No Device\"}"; Type t = obj.GetType(); // get the properties and set them into a new collection of NameType wrappers var props = t.GetProperties().Select(p => new PropertyNameType(p, obj)); return JsonConvert.SerializeObject(props, Formatting.Indented); } /// /// Gets a property from a device path by name /// /// The path to the device object /// The name of the property to get /// The value of the property public static object GetPropertyByName(string deviceObjectPath, string propertyName) { var dev = FindObjectOnPath(deviceObjectPath); if (dev == null) return "{ \"error\":\"No Device\"}"; object prop = dev.GetType().GetProperty(propertyName).GetValue(dev, null); // var prop = t.GetProperty(propertyName); if (prop != null) { return prop; } else { Debug.LogMessage(LogEventLevel.Debug, "Unable to find Property: {0} on Device with path: {1}", propertyName, deviceObjectPath); return null; } } /// /// Gets the methods on a device /// /// The path to the device object /// A JSON string representing the methods of the device public static string GetMethods(string deviceObjectPath) { var obj = FindObjectOnPath(deviceObjectPath); if (obj == null) return "{ \"error\":\"No Device\"}"; // Package up method names using helper objects Type t = obj.GetType(); var methods = t.GetMethods() .Where(m => !m.IsSpecialName) .Select(p => new MethodNameParams(p)); return JsonConvert.SerializeObject(methods, Formatting.Indented); } /// /// Gets the API methods on a device /// /// The path to the device object /// A JSON string representing the API methods of the device public static string GetApiMethods(string deviceObjectPath) { var obj = FindObjectOnPath(deviceObjectPath); if (obj == null) return "{ \"error\":\"No Device\"}"; // Package up method names using helper objects Type t = obj.GetType(); var methods = t.GetMethods() .Where(m => !m.IsSpecialName) .Where(m => m.GetCustomAttributes(typeof(ApiAttribute), true).Any()) .Select(p => new MethodNameParams(p)); return JsonConvert.SerializeObject(methods, Formatting.Indented); } /// /// FindObjectOnPath method /// /// The path to the device object /// The object found at the specified path public static object FindObjectOnPath(string deviceObjectPath) { var path = deviceObjectPath.Split('.'); var dev = DeviceManager.GetDeviceForKey(path[0]); if (dev == null) { Debug.LogMessage(LogEventLevel.Information, "Device {0} not found", path[0]); return null; } // loop through any dotted properties object obj = dev; if (path.Length > 1) { for (int i = 1; i < path.Length; i++) { var objName = path[i]; string indexStr = null; var indexOpen = objName.IndexOf('['); if (indexOpen != -1) { var indexClose = objName.IndexOf(']'); if (indexClose == -1) { Debug.LogMessage(LogEventLevel.Information, dev, "ERROR Unmatched index brackets"); return null; } // Get the index and strip quotes if any indexStr = objName.Substring(indexOpen + 1, indexClose - indexOpen - 1).Replace("\"", ""); objName = objName.Substring(0, indexOpen); Debug.LogMessage(LogEventLevel.Information, dev, " Checking for collection '{0}', index '{1}'", objName, indexStr); } Type oType = obj.GetType(); var prop = oType.GetProperty(objName); if (prop == null) { Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} not found on {1}", objName, path[i - 1]); return null; } // if there's an index, try to get the property if (indexStr != null) { if (!typeof(ICollection).IsAssignableFrom(prop.PropertyType)) { Debug.LogMessage(LogEventLevel.Information, dev, "Property {0} is not collection", objName); return null; } var collection = prop.GetValue(obj, null) as ICollection; // Get the indexed items "property" var indexedPropInfo = prop.PropertyType.GetProperty("Item"); // These are the parameters for the indexing. Only care about one var indexParams = indexedPropInfo.GetIndexParameters(); if (indexParams.Length > 0) { Debug.LogMessage(LogEventLevel.Information, " Indexed, param type: {0}", indexParams[0].ParameterType.Name); var properParam = Convert.ChangeType(indexStr, indexParams[0].ParameterType, System.Globalization.CultureInfo.InvariantCulture); try { obj = indexedPropInfo.GetValue(collection, new object[] { properParam }); } // if the index is bad, catch it here. catch (TargetInvocationException e) { if (e.InnerException is ArgumentOutOfRangeException) Debug.LogMessage(LogEventLevel.Information, " Index Out of range"); else if (e.InnerException is KeyNotFoundException) Debug.LogMessage(LogEventLevel.Information, " Key not found"); return null; } } } else obj = prop.GetValue(obj, null); } } return obj; } /// /// Sets a property on an object. /// /// The path to the device object /// A JSON string representing the result of setting the property public static string SetProperty(string deviceObjectPath) { throw new NotImplementedException("This could be really useful. Finish it please"); //var obj = FindObjectOnPath(deviceObjectPath); //if (obj == null) // return "{\"error\":\"No object found\"}"; //Type t = obj.GetType(); //// get the properties and set them into a new collection of NameType wrappers //var props = t.GetProperties().Select(p => new PropertyNameType(p, obj)); //return JsonConvert.SerializeObject(props, Formatting.Indented); } } /// /// Represents a DeviceActionWrapper /// public class DeviceActionWrapper { /// /// Gets or sets the DeviceKey /// public string DeviceKey { get; set; } /// /// Gets or sets the MethodName /// public string MethodName { get; set; } /// /// Gets or sets the Params /// public object[] Params { get; set; } } /// /// Represents a PropertyNameType /// public class PropertyNameType { private object Parent; /// /// Gets or sets the PropInfo /// [JsonIgnore] public PropertyInfo PropInfo { get; private set; } /// /// Gets or sets the Name /// public string Name { get { return PropInfo.Name; } } /// /// Gets or sets the Type /// public string Type { get { return PropInfo.PropertyType.Name; } } /// /// Gets or sets the Value /// public string Value { get { if (PropInfo.CanRead) { try { return PropInfo.GetValue(Parent, null).ToString(); } catch (Exception) { return null; } } else return null; } } /// /// Gets or sets the CanRead /// public bool CanRead { get { return PropInfo.CanRead; } } /// /// Gets or sets the CanWrite /// public bool CanWrite { get { return PropInfo.CanWrite; } } /// /// PropertyNameType constructor /// /// property info /// parent object public PropertyNameType(PropertyInfo info, object parent) { PropInfo = info; Parent = parent; } } /// /// Represents a MethodNameParams /// public class MethodNameParams { /// /// Gets or sets the MethodInfo /// [JsonIgnore] public MethodInfo MethodInfo { get; private set; } /// /// Gets or sets the Name /// public string Name { get { return MethodInfo.Name; } } /// /// Gets or sets the Params /// public IEnumerable Params { get { return MethodInfo.GetParameters().Select(p => new NameType { Name = p.Name, Type = p.ParameterType.Name }); } } /// /// MethodNameParams constructor /// /// method info public MethodNameParams(MethodInfo info) { MethodInfo = info; } } /// /// Represents a NameType /// public class NameType { /// /// Gets or sets the Name /// public string Name { get; set; } /// /// Gets or sets the Type /// public string Type { get; set; } } /// /// Represents a ApiAttribute /// [AttributeUsage(AttributeTargets.All)] public class ApiAttribute : Attribute { } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/DeviceManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Manages the devices in the system /// public static class DeviceManager { /// /// Raised when all devices have been activated /// public static event EventHandler AllDevicesActivated; /// /// Raised when all devices have been registered /// public static event EventHandler AllDevicesRegistered; /// /// Raised when all devices have been initialized /// public static event EventHandler AllDevicesInitialized; private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection(); private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true); private static readonly Dictionary Devices = new Dictionary(StringComparer.OrdinalIgnoreCase); /// /// Gets or sets the AllDevices /// public static List AllDevices { get { return new List(Devices.Values); } } /// /// Gets or sets the AddDeviceEnabled /// public static bool AddDeviceEnabled; /// /// Initialize method /// public static void Initialize(CrestronControlSystem cs) { AddDeviceEnabled = true; CrestronConsole.AddNewConsoleCommand(ListDeviceCommStatuses, "devcommstatus", "Lists the communication status of all devices", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(ListDeviceFeedbacks, "devfb", "Lists current feedbacks", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(ListDevices, "devlist", "Lists current managed devices", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(DeviceJsonApi.DoDeviceActionWithJson, "devjson", "", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetProperties(s).Replace(Environment.NewLine, "\r\n")), "devprops", "", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetMethods(s).Replace(Environment.NewLine, "\r\n")), "devmethods", "", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetApiMethods(s).Replace(Environment.NewLine, "\r\n")), "apimethods", "", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(SimulateComReceiveOnDevice, "devsimreceive", "Simulates incoming data on a com device", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(SetDeviceStreamDebugging, "setdevicestreamdebug", "set comm debug [deviceKey] [off/rx/tx/both] ([minutes])", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(s => DisableAllDeviceStreamDebugging(), "disableallstreamdebug", "disables stream debugging on all devices", ConsoleAccessLevelEnum.AccessOperator); } /// /// ActivateAll method /// public static void ActivateAll() { try { OnAllDevicesRegistered(); DeviceCriticalSection.Enter(); AddDeviceEnabled = false; // PreActivate all devices Debug.LogMessage(LogEventLevel.Information, "****PreActivation starting...****"); foreach (var d in Devices.Values) { try { if (d is Device) (d as Device).PreActivate(); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PreActivation failure: {0}", e.Message, d.Key); Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace); } } Debug.LogMessage(LogEventLevel.Information, "****PreActivation complete****"); Debug.LogMessage(LogEventLevel.Information, "****Activation starting...****"); // Activate all devices foreach (var d in Devices.Values) { try { if (d is Device) (d as Device).Activate(); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} Activation failure: {0}", e.Message, d.Key); Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace); } } Debug.LogMessage(LogEventLevel.Information, "****Activation complete****"); Debug.LogMessage(LogEventLevel.Information, "****PostActivation starting...****"); // PostActivate all devices foreach (var d in Devices.Values) { try { if (d is Device) (d as Device).PostActivate(); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, d, "ERROR: Device {1} PostActivation failure: {0}", e.Message, d.Key); Debug.LogMessage(LogEventLevel.Debug, d, "Stack Trace: {0}", e.StackTrace); } } Debug.LogMessage(LogEventLevel.Information, "****PostActivation complete****"); OnAllDevicesActivated(); } finally { DeviceCriticalSection.Leave(); } } private static void DeviceManager_Initialized(object sender, EventArgs e) { var allInitialized = Devices.Values.OfType().All(d => d.IsInitialized); if (allInitialized) { Debug.LogMessage(LogEventLevel.Information, "****All Devices Initalized****"); OnAllDevicesInitialized(); } } private static void OnAllDevicesActivated() { var handler = AllDevicesActivated; if (handler != null) { handler(null, new EventArgs()); } } private static void OnAllDevicesRegistered() { var handler = AllDevicesRegistered; if (handler != null) { handler(null, new EventArgs()); } } private static void OnAllDevicesInitialized() { var handler = AllDevicesInitialized; if (handler != null) { handler(null, new EventArgs()); } } /// /// DeactivateAll method /// public static void DeactivateAll() { try { DeviceCriticalSection.Enter(); foreach (var d in Devices.Values.OfType()) { d.Deactivate(); } } finally { DeviceCriticalSection.Leave(); } } private static void ListDevices(string s) { CrestronConsole.ConsoleCommandResponse($"{Devices.Count} Devices registered with Device Manager:\r\n"); var sorted = Devices.Values.ToList(); sorted.Sort((a, b) => a.Key.CompareTo(b.Key)); foreach (var d in sorted) { var name = d is IKeyName ? (d as IKeyName).Name : "---"; CrestronConsole.ConsoleCommandResponse($" [{d.Key}] {name}\r\n"); } } private static void ListDeviceFeedbacks(string devKey) { var dev = GetDeviceForKey(devKey); if (dev == null) { CrestronConsole.ConsoleCommandResponse($"Device '{devKey}' not found\r\n"); return; } if (!(dev is IHasFeedback statusDev)) { CrestronConsole.ConsoleCommandResponse($"Device '{devKey}' does not have visible feedbacks\r\n"); return; } statusDev.DumpFeedbacksToConsole(true); } private static void ListDeviceCommStatuses(string input) { foreach (var dev in Devices.Values.OfType()) { CrestronConsole.ConsoleCommandResponse($"{dev}: {dev.CommunicationMonitor.Status}\r\n"); } } /// /// AddDevice method /// public static void AddDevice(IKeyed newDev) { try { if (!DeviceCriticalSection.TryEnter()) { Debug.LogMessage(LogEventLevel.Information, "Currently unable to add devices to Device Manager. Please try again"); return; } // Check for device with same key //var existingDevice = _Devices.FirstOrDefault(d => d.Key.Equals(newDev.Key, StringComparison.OrdinalIgnoreCase)); ////// If it exists, remove or warn?? //if (existingDevice != null) if (!AddDeviceEnabled) { Debug.LogMessage(LogEventLevel.Information, "All devices have been activated. Adding new devices is not allowed."); return; } if (Devices.ContainsKey(newDev.Key)) { Debug.LogMessage(LogEventLevel.Information, newDev, "WARNING: A device with this key already exists. Not added to manager"); return; } Devices.Add(newDev.Key, newDev); //if (!(_Devices.Contains(newDev))) // _Devices.Add(newDev); if (newDev is EssentialsDevice essentialsDev) essentialsDev.Initialized += DeviceManager_Initialized; } finally { DeviceCriticalSection.Leave(); } } /// /// AddDevice method /// public static void AddDevice(IEnumerable devicesToAdd) { try { if (!DeviceCriticalSection.TryEnter()) { Debug.LogMessage(LogEventLevel.Information, "Currently unable to add devices to Device Manager. Please try again"); return; } if (!AddDeviceEnabled) { Debug.LogMessage(LogEventLevel.Information, "All devices have been activated. Adding new devices is not allowed."); return; } foreach (var dev in devicesToAdd) { try { Devices.Add(dev.Key, dev); } catch (ArgumentException ex) { Debug.LogMessage(LogEventLevel.Information, "Error adding device with key {0} to Device Manager: {1}\r\nStack Trace: {2}", dev.Key, ex.Message, ex.StackTrace); } } } finally { DeviceCriticalSection.Leave(); } } /// /// RemoveDevice method /// public static void RemoveDevice(IKeyed newDev) { try { DeviceCriticalSection.Enter(); if (newDev == null) return; if (Devices.ContainsKey(newDev.Key)) Devices.Remove(newDev.Key); //if (_Devices.Contains(newDev)) // _Devices.Remove(newDev); else Debug.LogMessage(LogEventLevel.Information, "Device manager: Device '{0}' does not exist in manager. Cannot remove", newDev.Key); } finally { DeviceCriticalSection.Leave(); } } /// /// GetDeviceKeys method /// public static IEnumerable GetDeviceKeys() { //return _Devices.Select(d => d.Key).ToList(); return Devices.Keys; } /// /// GetDevices method /// public static IEnumerable GetDevices() { //return _Devices.Select(d => d.Key).ToList(); return Devices.Values; } /// /// GetDeviceForKey method /// public static IKeyed GetDeviceForKey(string key) { //return _Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); if (key != null && Devices.ContainsKey(key)) return Devices[key]; return null; } /// /// GetDeviceForKey method /// /// public static T GetDeviceForKey(string key) { //return _Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); if (key == null || !Devices.ContainsKey(key)) return default; if (!(Devices[key] is T)) { Debug.LogMessage(LogEventLevel.Error, "Device with key '{0}' is not of type '{1}'", key, typeof(T).Name); return default; } return (T)Devices[key]; } /// /// Console handler that simulates com port data receive /// /// /// /// SimulateComReceiveOnDevice method /// public static void SimulateComReceiveOnDevice(string s) { // devcomsim:1 xyzabc var match = Regex.Match(s, @"(\S*)\s*(.*)"); if (match.Groups.Count < 3) { CrestronConsole.ConsoleCommandResponse(" Format: devsimreceive:P "); return; } //Debug.LogMessage(LogEventLevel.Verbose, "**** {0} - {1} ****", match.Groups[1].Value, match.Groups[2].Value); if (!(GetDeviceForKey(match.Groups[1].Value) is ComPortController com)) { CrestronConsole.ConsoleCommandResponse("'{0}' is not a comm port device", match.Groups[1].Value); return; } com.SimulateReceive(match.Groups[2].Value); } /// /// Prints a list of routing inputs and outputs by device key. /// /// Device key from which to report data /// /// GetRoutingPorts method /// public static void GetRoutingPorts(string s) { var device = GetDeviceForKey(s); if (device == null) return; var inputPorts = ((device as IRoutingInputs) != null) ? (device as IRoutingInputs).InputPorts : null; var outputPorts = ((device as IRoutingOutputs) != null) ? (device as IRoutingOutputs).OutputPorts : null; if (inputPorts != null) { CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Input Ports:{2}", s, inputPorts.Count, CrestronEnvironment.NewLine); foreach (var routingInputPort in inputPorts) { CrestronConsole.ConsoleCommandResponse("key: {0} signalType: {1}{2}", routingInputPort.Key, routingInputPort.Type, CrestronEnvironment.NewLine); } } if (outputPorts == null) return; CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Output Ports:{2}", s, outputPorts.Count, CrestronEnvironment.NewLine); foreach (var routingOutputPort in outputPorts) { CrestronConsole.ConsoleCommandResponse("key: {0} signalType: {1}{2}", routingOutputPort.Key, routingOutputPort.Type, CrestronEnvironment.NewLine); } } /// /// Attempts to set the debug level of a device /// /// /// /// SetDeviceStreamDebugging method /// public static void SetDeviceStreamDebugging(string s) { if (String.IsNullOrEmpty(s) || s.Contains("?")) { CrestronConsole.ConsoleCommandResponse( "SETDEVICESTREAMDEBUG [{deviceKey}] [OFF |TX | RX | BOTH] [timeOutInMinutes]\r\n" + " {deviceKey} [OFF | TX | RX | BOTH] - Device to set stream debugging on, and which setting to use\r\n" + " timeOutInMinutes - Set timeout for stream debugging. Default is 30 minutes"); return; } var args = s.Split(' '); var deviceKey = args[0]; var setting = args[1]; var timeout = String.Empty; if (args.Length >= 3) { timeout = args[2]; } if (!(GetDeviceForKey(deviceKey) is IStreamDebugging device)) { CrestronConsole.ConsoleCommandResponse("Unable to get device with key: {0}", deviceKey); return; } eStreamDebuggingSetting debugSetting; try { debugSetting = (eStreamDebuggingSetting)Enum.Parse(typeof(eStreamDebuggingSetting), setting, true); } catch { CrestronConsole.ConsoleCommandResponse("Unable to convert setting value. Please use off/rx/tx/both"); return; } if (!string.IsNullOrEmpty(timeout)) { try { var min = Convert.ToUInt32(timeout); device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, min); CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min); } catch (Exception e) { CrestronConsole.ConsoleCommandResponse("Unable to convert minutes or settings value. Please use an integer value for minutes. Error: {0}", e); } } else { device.StreamDebugging.SetDebuggingWithDefaultTimeout(debugSetting); CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for default time (30 minutes)", deviceKey, debugSetting); } } /// /// DisableAllDeviceStreamDebugging method /// public static void DisableAllDeviceStreamDebugging() { foreach (var device in AllDevices) { if (device is IStreamDebugging streamDevice) { streamDevice.StreamDebugging.SetDebuggingWithDefaultTimeout(eStreamDebuggingSetting.Off); } } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/DisplayUiConstants.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Integers that represent the "source type number" for given sources. /// Primarily used by the UI to calculate subpage join offsets /// Note, for UI, only values 1-49 are valid. /// public class DisplayUiConstants { /// /// TypeRadio constant /// public const uint TypeRadio = 1; /// /// TypeTv constant /// public const uint TypeDirecTv = 9; /// /// TypeBluray constant /// public const uint TypeBluray = 13; /// /// TypeStreamingDevice constant /// public const uint TypeChromeTv = 15; /// /// TypeStreamingDevice constant /// public const uint TypeFireTv = 16; /// /// TypeStreamingDevice constant /// public const uint TypeAppleTv = 17; /// /// TypeStreamingDevice constant /// public const uint TypeRoku = 18; /// /// TypeLaptop constant /// public const uint TypeLaptop = 31; /// /// TypePc constant /// public const uint TypePc = 32; /// /// TypeNoControls constant /// public const uint TypeNoControls = 49; } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core.Bridges; namespace PepperDash.Essentials.Core { /// /// Base class for devices that can be bridged to an EISC API. /// public abstract class EssentialsBridgeableDevice : EssentialsDevice, IBridgeAdvanced { /// /// Initializes a new instance of the class with the specified key. /// /// The unique key for the device. protected EssentialsBridgeableDevice(string key) : base(key) { } /// /// Initializes a new instance of the class with the specified key and name. /// /// The unique key for the device. /// The display name for the device. protected EssentialsBridgeableDevice(string key, string name) : base(key, name) { } /// public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs ================================================ using System; using System.Threading.Tasks; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class /// [Description("The base Essentials Device Class")] public abstract class EssentialsDevice : Device { /// /// Event raised when the device is initialized. /// public event EventHandler Initialized; private bool _isInitialized; /// /// Gets a value indicating whether the device is initialized. /// public bool IsInitialized { get { return _isInitialized; } private set { if (_isInitialized == value) return; _isInitialized = value; if (_isInitialized) { Initialized?.Invoke(this, new EventArgs()); } } } /// /// Initializes a new instance of the EssentialsDevice class. /// /// The unique identifier for the device. protected EssentialsDevice(string key) : base(key) { SubscribeToActivateComplete(); } /// /// Initializes a new instance of the EssentialsDevice class. /// /// The unique identifier for the device. /// The name of the device. protected EssentialsDevice(string key, string name) : base(key, name) { SubscribeToActivateComplete(); } private void SubscribeToActivateComplete() { DeviceManager.AllDevicesActivated += DeviceManagerOnAllDevicesActivated; } private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs) { Task.Run(() => { try { Initialize(); IsInitialized = true; } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Error, this, "Exception initializing device: {0}", ex.Message); Debug.LogMessage(LogEventLevel.Debug, this, "Stack Trace: {0}", ex.StackTrace); } }); } /// /// CustomActivate method /// /// public override bool CustomActivate() { CreateMobileControlMessengers(); return base.CustomActivate(); } /// /// Override this method to build and create custom Mobile Control Messengers during the Activation phase /// protected virtual void CreateMobileControlMessengers() { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs ================================================ using System; using System.Collections.Generic; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { /// /// Provides the basic needs for a Device Factory /// public abstract class EssentialsDeviceFactory : IDeviceFactory where T : EssentialsDevice { /// public Type FactoryType => typeof(T); /// /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device /// public List TypeNames { get; protected set; } /// /// Build the device using the configuration /// /// The device config /// An instance of the device public abstract EssentialsDevice BuildDevice(DeviceConfig dc); } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/EssentialsPluginDevelopmentDeviceFactory.cs ================================================ using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// /// EssentialsPluginDevelopmentDeviceFactory class /// /// public abstract class EssentialsPluginDevelopmentDeviceFactory : EssentialsDeviceFactory, IPluginDevelopmentDeviceFactory where T : EssentialsDevice { /// /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33") /// public string MinimumEssentialsFrameworkVersion { get; protected set; } /// /// Gets or sets the DevelopmentEssentialsFrameworkVersions /// public List DevelopmentEssentialsFrameworkVersions { get; protected set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/EssentialsPluginDeviceFactory.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Devices the basic needs for a Device Factory /// public abstract class EssentialsPluginDeviceFactory : EssentialsDeviceFactory, IPluginDeviceFactory where T : EssentialsDevice { /// /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33") /// public string MinimumEssentialsFrameworkVersion { get; protected set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/GenericIRController.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Bridges.JoinMaps; using Serilog.Events; namespace PepperDash.Essentials.Core.Devices { /// /// Represents a GenericIrController /// public class GenericIrController: EssentialsBridgeableDevice { //data storage for bridging private BasicTriList _trilist; private uint _joinStart; private string _joinMapKey; private EiscApiAdvanced _bridge; private readonly IrOutputPortController _port; /// /// Gets or sets the IrCommands /// public string[] IrCommands {get { return _port.IrFileCommands; }} /// /// Constructor /// /// key for the device /// name of the device /// IR output port controller public GenericIrController(string key, string name, IrOutputPortController irPort) : base(key, name) { _port = irPort; if (_port == null) { Debug.LogMessage(LogEventLevel.Information, this, "IR Port is null, device will not function"); return; } DeviceManager.AddDevice(_port); _port.DriverLoaded.OutputChange += DriverLoadedOnOutputChange; } private void DriverLoadedOnOutputChange(object sender, FeedbackEventArgs args) { if (!args.BoolValue) { return; } if (_trilist == null || _bridge == null) { return; } LinkToApi(_trilist, _joinStart, _joinMapKey, _bridge); } #region Overrides of EssentialsBridgeableDevice /// /// LinkToApi method /// /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { //if driver isn't loaded yet, store the variables until it is loaded, then call the LinkToApi method again if (!_port.DriverIsLoaded) { _trilist = trilist; _joinStart = joinStart; _joinMapKey = joinMapKey; _bridge = bridge; return; } var joinMap = new GenericIrControllerJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (_port.UseBridgeJoinMap) { Debug.LogMessage(LogEventLevel.Information, this, "Using new IR bridge join map"); var bridgeJoins = joinMap.Joins.Where((kv) => _port.IrFileCommands.Any(cmd => cmd == kv.Key)).ToDictionary(kv => kv.Key); if (bridgeJoins == null) { Debug.LogMessage(LogEventLevel.Information, this, "Failed to link new IR bridge join map"); return; } joinMap.Joins.Clear(); foreach (var bridgeJoin in bridgeJoins) { var key = bridgeJoin.Key; var joinDataKey = bridgeJoin.Value.Key; var joinDataValue = bridgeJoin.Value.Value; var joinNumber = bridgeJoin.Value.Value.JoinNumber; Debug.LogMessage(LogEventLevel.Verbose, this, @"bridgeJoin: Key-'{0}' Value.Key-'{1}' Value.JoinNumber-'{2}' Value.Metadata.Description-'{3}'", key, joinDataKey, joinNumber, joinDataValue.Metadata.Description); joinMap.Joins.Add(key, joinDataValue); trilist.SetBoolSigAction(joinNumber, (b) => Press(key, b)); } } else { Debug.LogMessage(LogEventLevel.Information, this, "Using legacy IR join mapping based on available IR commands"); joinMap.Joins.Clear(); for (uint i = 0; i < _port.IrFileCommands.Length; i++) { var cmd = _port.IrFileCommands[i]; var joinData = new JoinDataComplete(new JoinData { JoinNumber = i, JoinSpan = 1 }, new JoinMetadata { Description = cmd, JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); joinData.SetJoinOffset(joinStart); joinMap.Joins.Add(cmd, joinData); trilist.SetBoolSigAction(joinData.JoinNumber, (b) => Press(cmd, b)); } } joinMap.PrintJoinMapInfo(); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } } #endregion /// /// Press method /// public void Press(string command, bool pressRelease) { _port.PressRelease(command, pressRelease); } } /// /// Represents a GenericIrControllerFactory /// public class GenericIrControllerFactory : EssentialsDeviceFactory { /// /// Constructor /// public GenericIrControllerFactory() { TypeNames = new List {"genericIrController"}; } #region Overrides of EssentialsDeviceFactory /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic IR Controller Device"); var irPort = IRPortHelper.GetIrOutputPortController(dc); return new GenericIrController(dc.Key, dc.Name, irPort); } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/GenericMonitoredTcpDevice.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core.Devices { /// /// Represents a GenericCommunicationMonitoredDevice /// public class GenericCommunicationMonitoredDevice : Device, ICommunicationMonitor { IBasicCommunication Client; /// /// Gets or sets the CommunicationMonitor /// public StatusMonitorBase CommunicationMonitor { get; private set; } /// /// Constructor /// /// key of the device /// name of the device /// communication client /// poll string /// poll time /// warning time /// error time public GenericCommunicationMonitoredDevice(string key, string name, IBasicCommunication comm, string pollString, long pollTime, long warningTime, long errorTime) : base(key, name) { Client = comm; CommunicationMonitor = new GenericCommunicationMonitor(this, Client, pollTime, warningTime, errorTime, pollString); // ------------------------------------------------------DELETE THIS CommunicationMonitor.StatusChange += (o, a) => { Debug.LogMessage(LogEventLevel.Verbose, this, "Communication monitor status change: {0}", a.Status); }; } /// /// Constructor with default times /// /// key of the device /// name of the device /// communication client /// poll string public GenericCommunicationMonitoredDevice(string key, string name, IBasicCommunication comm, string pollString) : this(key, name, comm, pollString, 30000, 120000, 300000) { } /// /// CustomActivate method /// /// public override bool CustomActivate() { CommunicationMonitor.Start(); return true; } /// /// Deactivate method /// public override bool Deactivate() { CommunicationMonitor.Stop(); return true; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IAttachVideoStatus.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IAttachVideoStatus /// public interface IAttachVideoStatus : IKeyed { // Extension methods will depend on this } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IAttachVideoStatusExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// IAttachVideoStatusExtensions class /// public static class IAttachVideoStatusExtensions { /// /// Gets the VideoStatusOutputs for the device /// /// /// Attached VideoStatusOutputs or the default if none attached public static VideoStatusOutputs GetVideoStatuses(this IAttachVideoStatus attachedDev) { // See if this device is connected to a status-providing port var tl = TieLineCollection.Default.FirstOrDefault(t => t.SourcePort.ParentDevice == attachedDev && t.DestinationPort is RoutingInputPortWithVideoStatuses); if (tl != null) { // if so, and it's got status, return it -- or null var port = tl.DestinationPort as RoutingInputPortWithVideoStatuses; if (port != null) return port.VideoStatus; } return VideoStatusOutputs.NoStatus; } /// /// HasVideoStatuses method /// public static bool HasVideoStatuses(this IAttachVideoStatus attachedDev) { return TieLineCollection.Default.FirstOrDefault(t => t.SourcePort.ParentDevice == attachedDev && t.DestinationPort is RoutingInputPortWithVideoStatuses) != null; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IDisplayUsage.cs ================================================ namespace PepperDash.Essentials.Core { /// /// For display classes that can provide usage data /// public interface IDisplayUsage { /// /// Gets the LampHours /// IntFeedback LampHours { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IDspPresets.cs ================================================ using PepperDash.Core; using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IDspPresets /// public interface IDspPresets { /// /// Gets the Presets /// Dictionary Presets { get; } /// /// Recalls the preset by key /// /// key of preset to recall void RecallPreset(string key); } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs ================================================ using System; using System.Linq; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IHasFeedback /// public interface IHasFeedback : IKeyed { /// /// This method returns a list of all Output objects on a device, /// including all "aggregate" devices. /// FeedbackCollection Feedbacks { get; } } /// /// Extension methods for IHasFeedback /// public static class IHasFeedbackExtensions { /// /// Gets the feedback type name for sorting purposes /// /// The feedback to get the type name for /// A string representing the feedback type private static string GetFeedbackTypeName(Feedback feedback) { if (feedback is BoolFeedback) return "boolean"; else if (feedback is IntFeedback) return "integer"; else if (feedback is StringFeedback) return "string"; else return feedback.GetType().Name; } /// /// Dumps the feedbacks to the console /// /// /// public static void DumpFeedbacksToConsole(this IHasFeedback source, bool getCurrentStates) { var feedbacks = source.Feedbacks; if (feedbacks == null || feedbacks.Count == 0) { CrestronConsole.ConsoleCommandResponse("No available feedbacks\r\n"); return; } CrestronConsole.ConsoleCommandResponse("Available feedbacks:\r\n"); // Sort feedbacks by type first, then by key var sortedFeedbacks = feedbacks.OrderBy(f => GetFeedbackTypeName(f)).ThenBy(f => string.IsNullOrEmpty(f.Key) ? "" : f.Key); foreach (var feedback in sortedFeedbacks) { string value = ""; string type = ""; if (getCurrentStates) { if (feedback is BoolFeedback) { value = feedback.BoolValue.ToString(); type = "boolean"; } else if (feedback is IntFeedback) { value = feedback.IntValue.ToString(); type = "integer"; } else if (feedback is StringFeedback) { value = feedback.StringValue; type = "string"; } } CrestronConsole.ConsoleCommandResponse($" {type,-12} {(string.IsNullOrEmpty(feedback.Key) ? "-no key-" : feedback.Key),-25} {value}\r\n"); } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IMakeModel.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for device make and model information /// public interface IMakeModel : IKeyed { /// /// Gets the make of the device /// string DeviceMake { get; } /// /// Gets the model of the device /// string DeviceModel { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IOnline.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IOnline /// public interface IOnline { /// /// Gets a value indicating whether the device is online. /// BoolFeedback IsOnline { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IProjectorInterfaces.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IBasicVideoMute /// public interface IBasicVideoMute { /// /// Toggles the video mute /// void VideoMuteToggle(); } /// /// Defines the contract for IBasicVideoMuteWithFeedback /// public interface IBasicVideoMuteWithFeedback : IBasicVideoMute { /// /// Gets the VideoMuteIsOn feedback /// BoolFeedback VideoMuteIsOn { get; } /// /// Sets the video mute on /// void VideoMuteOn(); /// /// Sets the video mute off /// void VideoMuteOff(); } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IReconfigurableDevice.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core.Devices { /// /// Defines the contract for IReconfigurableDevice /// public interface IReconfigurableDevice { /// /// Event fired when the configuration changes /// event EventHandler ConfigChanged; /// /// Gets the current DeviceConfig /// DeviceConfig Config { get; } /// /// Sets the DeviceConfig /// /// config to set void SetConfig(DeviceConfig config); } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IUsageTracking.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IUsageTracking /// public interface IUsageTracking { /// /// Gets or sets the UsageTracker /// UsageTracking UsageTracker { get; set; } } //public static class IUsageTrackingExtensions //{ // public static void EnableUsageTracker(this IUsageTracking device) // { // device.UsageTracker = new UsageTracking(); // } //} /// /// Represents a UsageTracking /// public class UsageTracking { /// /// Event fired when device usage ends /// public event EventHandler DeviceUsageEnded; /// /// Gets or sets the InUseTracker /// public InUseTracking InUseTracker { get; protected set; } /// /// Gets or sets the UsageIsTracked /// public bool UsageIsTracked { get; set; } /// /// Gets or sets the UsageTrackingStarted /// public bool UsageTrackingStarted { get; protected set; } /// /// Gets or sets the UsageStartTime /// public DateTime UsageStartTime { get; protected set; } /// /// Gets or sets the UsageEndTime /// public DateTime UsageEndTime { get; protected set; } /// /// Gets or sets the Parent /// public Device Parent { get; private set; } /// /// Constructor for UsageTracking class /// /// The parent device public UsageTracking(Device parent) { Parent = parent; InUseTracker = new InUseTracking(); InUseTracker.InUseFeedback.OutputChange += InUseFeedback_OutputChange; //new EventHandler(); } void InUseFeedback_OutputChange(object sender, EventArgs e) { if(InUseTracker.InUseFeedback.BoolValue) { StartDeviceUsage(); } else { EndDeviceUsage(); } } /// /// StartDeviceUsage method /// public void StartDeviceUsage() { UsageTrackingStarted = true; UsageStartTime = DateTime.Now; } /// /// Calculates the difference between the usage start and end times, gets the total minutes used and fires an event to pass that info to a consumer /// public void EndDeviceUsage() { try { UsageTrackingStarted = false; UsageEndTime = DateTime.Now; if (UsageStartTime != null) { var timeUsed = UsageEndTime - UsageStartTime; var handler = DeviceUsageEnded; if (handler != null) { Debug.LogMessage(LogEventLevel.Debug, "Device Usage Ended for: {0} at {1}. In use for {2} minutes.", Parent.Name, UsageEndTime, timeUsed.Minutes); handler(this, new DeviceUsageEventArgs() { UsageEndTime = UsageEndTime, MinutesUsed = timeUsed.Minutes }); } } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, "Error ending device usage: {0}", e); } } } /// /// Represents a DeviceUsageEventArgs /// public class DeviceUsageEventArgs : EventArgs { /// /// Gets or sets the UsageEndTime /// public DateTime UsageEndTime { get; set; } /// /// Gets or sets the MinutesUsed /// public int MinutesUsed { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.Config; using PepperDash.Core; using Serilog.Events; using System.IO; using PepperDash.Core.Logging; namespace PepperDash.Essentials.Core { /// /// IR port wrapper. May act standalone /// public class IrOutputPortController : Device { uint IrPortUid; IROutputPort IrPort; /// /// Gets the DriverLoaded feedback /// public BoolFeedback DriverLoaded { get; private set; } /// /// Gets or sets the StandardIrPulseTime /// public ushort StandardIrPulseTime { get; set; } /// /// Gets or sets the DriverFilepath /// public string DriverFilepath { get; private set; } /// /// Gets or sets the DriverIsLoaded /// public bool DriverIsLoaded { get; private set; } /// /// Gets or sets the IrFileCommands /// public string[] IrFileCommands { get { return IrPort.AvailableStandardIRCmds(IrPortUid); } } /// /// Gets or sets the UseBridgeJoinMap /// public bool UseBridgeJoinMap { get; private set; } /// /// Constructor for IrDevice base class. If a null port is provided, this class will /// still function without trying to talk to a port. /// public IrOutputPortController(string key, IROutputPort port, string irDriverFilepath) : base(key) { //if (port == null) throw new ArgumentNullException("port"); DriverLoaded = new BoolFeedback(() => DriverIsLoaded); IrPort = port; if (port == null) { Debug.LogMessage(LogEventLevel.Information, this, "WARNING No valid IR Port assigned to controller. IR will not function"); return; } LoadDriver(irDriverFilepath); } /// /// Constructor for IrDevice base class using post activation function to get port /// /// key of the device /// function to call post activation /// config of the device public IrOutputPortController(string key, Func postActivationFunc, DeviceConfig config) : base(key) { DriverLoaded = new BoolFeedback(() => DriverIsLoaded); UseBridgeJoinMap = config.Properties["control"].Value("useBridgeJoinMap"); AddPostActivationAction(() => { IrPort = postActivationFunc(config); if (IrPort == null) { Debug.LogMessage(LogEventLevel.Information, this, "WARNING No valid IR Port assigned to controller. IR will not function"); return; } // var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value(); var fileName = config.Properties["control"]["irFile"].Value(); var files = Directory.GetFiles(Global.FilePathPrefix, fileName, SearchOption.AllDirectories); if(files.Length == 0) { this.LogError("IR file {fileName} not found in {path}", fileName, Global.FilePathPrefix); return; } if(files.Length > 1) { this.LogError("IR file {fileName} found in multiple locations: {files}", fileName, files); return; } var filePath = files[0]; Debug.LogMessage(LogEventLevel.Debug, "*************Attempting to load IR file: {0}***************", filePath); LoadDriver(filePath); PrintAvailableCommands(); }); } /// /// PrintAvailableCommands method /// public void PrintAvailableCommands() { Debug.LogMessage(LogEventLevel.Verbose, this, "Available IR Commands in IR File {0}", IrPortUid); foreach (var cmd in IrPort.AvailableIRCmds()) { Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", cmd); } } /// /// Loads the IR driver at path /// /// path of the IR driver file public void LoadDriver(string path) { Debug.LogMessage(LogEventLevel.Verbose, this, "***Loading IR File***"); if (string.IsNullOrEmpty(path)) path = DriverFilepath; try { IrPortUid = IrPort.LoadIRDriver(path); DriverFilepath = path; StandardIrPulseTime = 200; DriverIsLoaded = true; DriverLoaded.FireUpdate(); } catch { DriverIsLoaded = false; var message = string.Format("WARNING IR Driver '{0}' failed to load", path); Debug.LogMessage(LogEventLevel.Information, this, message); DriverLoaded.FireUpdate(); } } /// /// PressRelease method /// /// IR command to send /// true to press, false to release /// public virtual void PressRelease(string command, bool state) { Debug.LogMessage(LogEventLevel.Verbose, this, "IR:'{0}'={1}", command, state); if (IrPort == null) { Debug.LogMessage(LogEventLevel.Verbose, this, "WARNING No IR Port assigned to controller"); return; } if (!DriverIsLoaded) { Debug.LogMessage(LogEventLevel.Verbose, this, "WARNING IR driver is not loaded"); return; } if (state) { if (IrPort.IsIRCommandAvailable(IrPortUid, command)) IrPort.Press(IrPortUid, command); else NoIrCommandError(command); } else IrPort.Release(); } /// /// Pulse method /// /// IR command to send /// time to pulse the command /// public virtual void Pulse(string command, ushort time) { if (IrPort == null) { Debug.LogMessage(LogEventLevel.Verbose, this, "WARNING No IR Port assigned to controller"); return; } if (!DriverIsLoaded) { Debug.LogMessage(LogEventLevel.Verbose, this, "WARNING IR driver is not loaded"); return; } if (IrPort.IsIRCommandAvailable(IrPortUid, command)) IrPort.PressAndRelease(IrPortUid, command, time); else NoIrCommandError(command); } /// /// Notifies the console when a bad command is used. /// /// command that was not found protected void NoIrCommandError(string command) { Debug.LogMessage(LogEventLevel.Verbose, this, "Device {0}: IR Driver {1} does not contain command {2}", Key, IrPort.IRDriverFileNameByIRDriverId(IrPortUid), command); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Devices; namespace PepperDash.Essentials.Core { /// /// Represents a level control item in a list, which can be used to control volume or mute functionality. /// public class LevelControlListItem : AudioControlListItemBase { /// /// A reference to the IBasicVolumeWithFeedback device for control. /// [JsonIgnore] public IBasicVolumeWithFeedback LevelControl { get { if (_levelControl == null) _levelControl = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IBasicVolumeWithFeedback; return _levelControl; } } IBasicVolumeWithFeedback _levelControl; /// /// Gets the name from the device if it implements IKeyName or else returns the Name property /// [JsonProperty("preferredName")] public string PreferredName { get { if (!string.IsNullOrEmpty(Name)) return Name; else { if (LevelControl is IKeyName namedLevelControl) { if (namedLevelControl == null) return "---"; return namedLevelControl.Name; } else return "---"; } } } /// /// The key of the device in the DeviceManager for control /// [JsonProperty("deviceKey")] public string DeviceKey { get { if (string.IsNullOrEmpty(ItemKey)) return ParentDeviceKey; else { return DeviceManager.AllDevices. Where(d => d.Key.Contains(ParentDeviceKey) && d.Key.Contains(ItemKey)).FirstOrDefault()?.Key ?? $"{ParentDeviceKey}--{ItemKey}"; } } } /// /// Indicates if the item is a level, mute , or both /// [JsonProperty("type")] [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public eLevelControlType Type { get; set; } /// /// Indicates if the item is a mic or not. /// [JsonProperty("isMic", NullValueHandling = NullValueHandling.Ignore)] public bool? IsMic { get; set; } /// /// Indicates if the item should show the raw level in the UI. /// [JsonProperty("showRawLevel", NullValueHandling = NullValueHandling.Ignore)] public bool? ShowRawLevel { get; set; } } /// /// Indicates the type of level control item. /// [Flags] public enum eLevelControlType { /// /// Indicates that the item is a level control only /// Level = 1, /// /// Indicates that the item is a mute control only /// Mute = 2, /// /// Indicates that the item is both a level and mute control /// LevelAndMute = Level | Mute, } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/PduInterfaces.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Devices { /// /// Interface for any device that is able to control it'spower and has a configurable reboot time /// public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback { /// /// Delay between power off and power on for reboot /// int PowerCycleTimeMs { get;} /// /// Reboot outlet /// void PowerCycle(); } /// /// Interface for any device that contains a collection of IHasPowerReboot Devices /// public interface IHasControlledPowerOutlets : IKeyName { /// /// Collection of IPduOutlets /// ReadOnlyDictionary PduOutlets { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/PowerInterfaces.cs ================================================ using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IHasBatteryStats /// public interface IHasBatteryStats : IKeyName { /// /// Gets the BatteryPercentage /// int BatteryPercentage { get; } /// /// Gets the BatteryCautionThresholdPercentage /// int BatteryCautionThresholdPercentage { get; } /// /// Gets the BatteryWarningThresholdPercentage /// int BatteryWarningThresholdPercentage { get; } /// /// Gets the BatteryIsWarningFeedback /// BoolFeedback BatteryIsWarningFeedback { get; } /// /// Gets the BatteryIsCautionFeedback /// BoolFeedback BatteryIsCautionFeedback { get; } /// /// Gets the BatteryIsOkFeedback /// BoolFeedback BatteryIsOkFeedback { get; } /// /// Gets the BatteryPercentageFeedback /// IntFeedback BatteryPercentageFeedback { get; } } /// /// Defines the contract for IHasBatteryCharging /// public interface IHasBatteryCharging : IHasBatteryStats { /// /// Gets the BatteryIsCharging /// BoolFeedback BatteryIsCharging { get; } } /// /// Interface for any device that has multiple batteries that can be monitored /// public interface IHasBatteries : IKeyName { /// /// Collection of batteries /// ReadOnlyDictionary Batteries { get; } } /// /// Defines the contract for IHasBatteryStatsExtended /// public interface IHasBatteryStatsExtended : IHasBatteryStats { /// /// Gets the InputVoltage in millivolts /// int InputVoltage { get; } /// /// Gets the OutputVoltage in millivolts /// int OutputVoltage { get; } /// /// Gets the InputCurrent in milliamps /// int InptuCurrent { get; } /// /// Gets the OutputCurrent in milliamps /// int OutputCurrent { get; } /// /// Gets the InputVoltageFeedback /// IntFeedback InputVoltageFeedback { get; } /// /// Gets the OutputVoltageFeedback /// IntFeedback OutputVoltageFeedback { get; } /// /// Gets the InputCurrentFeedback /// IntFeedback InputCurrentFeedback { get; } /// /// Gets the OutputCurrentFeedback /// IntFeedback OutputCurrentFeedback { get; } } /// /// Defines the contract for IHasPowerCycleWithBattery /// public interface IHasPowerCycleWithBattery : IHasPowerCycle, IHasBatteryStats { } /// /// Interface for any device that is able to control it's power and has a configurable reboot time /// public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback { /// /// Delay between power off and power on for reboot /// int PowerCycleTimeMs { get; } /// /// Reboot outlet /// void PowerCycle(); } /// /// Interface for any device that contains a collection of IHasPowerReboot Devices /// public interface IHasControlledPowerOutlets : IKeyName { /// /// Collection of IPduOutlets /// ReadOnlyDictionary PduOutlets { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/PresentationDeviceType.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.EthernetCommunication; using Crestron.SimplSharpPro.UI; namespace PepperDash.Essentials.Core { /// /// Enumeration of PresentationSourceType values /// public enum PresentationSourceType { /// /// No source type assigned /// None, /// /// DVD source type /// Dvd, /// /// Document Camera source type /// Laptop, /// /// PC source type /// PC, /// /// Set Top Box source type /// SetTopBox, /// /// VCR source type /// VCR } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/PresetListItem.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Represents a PresetListItem /// public class PresetListItem : AudioControlListItemBase { /// /// Gets the preset associated with this list item /// [JsonIgnore] public IKeyName Preset { get { if (_preset == null) { var parent = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IDspPresets; if (parent == null || !parent.Presets.ContainsKey(ItemKey)) return null; _preset = parent.Presets[ItemKey]; } return _preset; } } private IKeyName _preset; /// /// Gets the name from the device if it implements IKeyName or else returns the Name property /// [JsonProperty("preferredName")] public string PreferredName { get { if (!string.IsNullOrEmpty(Name)) return Name; else return Preset.Name; } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/ProcessorExtensionDeviceFactory.cs ================================================ using System; using System.Collections.Generic; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { /// /// Represents a factory for creating processor extension devices. /// /// The type of the processor extension device. [Obsolete("will be removed in a future version")] public abstract class ProcessorExtensionDeviceFactory : IProcessorExtensionDeviceFactory where T : EssentialsDevice { #region IProcessorExtensionDeviceFactory Members /// /// Gets or sets the TypeNames /// public List TypeNames { get; protected set; } /// /// LoadFactories method /// public void LoadFactories() { foreach (var typeName in TypeNames) { string description = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0 ? descriptionAttribute[0].Description : "No description available"; ProcessorExtensionDeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice); } } /// /// The method that will build the device /// /// The device config /// An instance of the device public abstract EssentialsDevice BuildDevice(DeviceConfig dc); #endregion } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/ReconfigurableDevice.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace PepperDash.Essentials.Core.Devices { /// /// /// public abstract class ReconfigurableDevice : EssentialsDevice, IReconfigurableDevice { /// /// Event fired when the configuration changes /// public event EventHandler ConfigChanged; /// /// Gets the current DeviceConfig /// public DeviceConfig Config { get; private set; } /// /// Constructor /// /// config of the device protected ReconfigurableDevice(DeviceConfig config) : base(config.Key) { SetNameHelper(config); Config = config; } /// /// Sets the Config, calls CustomSetConfig and fires the ConfigChanged event /// /// /// /// SetConfig method /// public void SetConfig(DeviceConfig config) { Config = config; SetNameHelper(config); CustomSetConfig(config); var handler = ConfigChanged; if (handler != null) { handler(this, new EventArgs()); } } void SetNameHelper(DeviceConfig config) { if (!string.IsNullOrEmpty(config.Name)) Name = config.Name; } /// /// Used by the extending class to allow for any custom actions to be taken (tell the ConfigWriter to write config, etc) /// /// config of the device protected virtual void CustomSetConfig(DeviceConfig config) { ConfigWriter.UpdateDeviceConfig(config); } } /// /// A ReconfigurableDevice that is also bridgeable /// public abstract class ReconfigurableBridgableDevice : ReconfigurableDevice, IBridgeAdvanced { /// /// Constructor /// /// config of the device protected ReconfigurableBridgableDevice(DeviceConfig config) : base(config) { } /// /// LinkToApi method /// /// trilist to link /// the join to start at /// key to the join map /// the bridge to use public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/SmartObjectBaseTypes.cs ================================================  namespace PepperDash.Essentials.Core { /// /// Represents a SmartObjectJoinOffsets /// public class SmartObjectJoinOffsets { /// /// Dpad Join Offset /// public const ushort Dpad = 1; /// /// Numpad Join Offset /// public const ushort Numpad = 2; /// /// PresetList Join Offset /// public const ushort PresetList = 6; } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/SourceListItem.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the type of source list item, which can be a route, off, or other. /// This is used to categorize the source list items in a room. /// The type is serialized to JSON and can be used to determine how the item should be displayed or handled in the UI. /// public enum eSourceListItemType { /// /// Represents a typical route. /// Route, /// /// Represents an off route. /// Off, /// /// Represents some other type of route /// Other, } /// /// Represents a SourceListItem /// public class SourceListItem { /// /// The key of the source item, which is used to identify it in the DeviceManager /// [JsonProperty("sourceKey")] public string SourceKey { get; set; } /// /// Returns the source Device for this, if it exists in DeviceManager /// [JsonIgnore] public Device SourceDevice { get { if (_SourceDevice == null) _SourceDevice = DeviceManager.GetDeviceForKey(SourceKey) as Device; return _SourceDevice; } } private Device _SourceDevice; /// /// Gets either the source's Name or this AlternateName property, if /// defined. If source doesn't exist, returns "Missing source" /// [JsonProperty("preferredName")] public string PreferredName { get { if (string.IsNullOrEmpty(Name)) { if (SourceDevice == null) return "---"; return SourceDevice.Name; } return Name; } } /// /// A name that will override the source's name on the UI /// [JsonProperty("name")] public string Name { get; set; } /// /// Specifies and icon for the source list item /// [JsonProperty("icon")] public string Icon { get; set; } /// /// Alternate icon /// [JsonProperty("altIcon")] public string AltIcon { get; set; } /// /// Indicates if the item should be included in the source list /// [JsonProperty("includeInSourceList")] public bool IncludeInSourceList { get; set; } /// /// Used to specify the order of the items in the source list when displayed /// [JsonProperty("order")] public int Order { get; set; } /// /// The key of the device for volume control /// [JsonProperty("volumeControlKey")] public string VolumeControlKey { get; set; } /// /// The type of source list item /// [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter))] public eSourceListItemType Type { get; set; } /// /// The list of routes to execute for this source list item /// [JsonProperty("routeList")] public List RouteList { get; set; } /// /// Indicates if this source should be disabled for sharing to the far end call participants via codec content /// [JsonProperty("disableCodecSharing")] public bool DisableCodecSharing { get; set; } /// /// Indicates if this source should be disabled for routing to a shared output /// [JsonProperty("disableRoutedSharing")] public bool DisableRoutedSharing { get; set; } /// /// /// [JsonProperty("destinations")] public List Destinations { get; set; } /// /// A means to reference a source list for this source item, in the event that this source has an input that can have sources routed to it /// [JsonProperty("sourceListKey")] public string SourceListKey { get; set; } /// /// Indicates if the device associated with this source is controllable /// [JsonProperty("isControllable")] public bool IsControllable { get; set; } /// /// Indicates that the device associated with this source has audio available /// [JsonProperty("isAudioSource")] public bool IsAudioSource { get; set; } /// /// Hide source on UI when Avanced Sharing is enabled /// [JsonProperty("disableAdvancedRouting")] public bool DisableAdvancedRouting { get; set; } /// /// Hide source on UI when Simpl Sharing is enabled /// [JsonProperty("disableSimpleRouting")] public bool DisableSimpleRouting { get; set; } /// /// The key of the device that provides video sync for this source item /// [JsonProperty("syncProviderDeviceKey")] public string SyncProviderDeviceKey { get; set; } /// /// Indicates if the source supports USB connections /// [JsonProperty("supportsUsb")] public bool SupportsUsb { get; set; } /// /// The key of the source port associated with this source item /// This is used to identify the specific port on the source device that this item refers to for advanced routing /// [JsonProperty("sourcePortKey")] public string SourcePortKey { get; set; } /// /// Default constructor for SourceListItem, initializes the Icon to "Blank" /// public SourceListItem() { Icon = "Blank"; } /// /// Returns a string representation of the SourceListItem, including the SourceKey and Name /// /// A string representation of the SourceListItem public override string ToString() { return $"{SourceKey}:{Name}"; } } /// /// Represents a route in a source list item, which defines the source and destination keys and the type of signal being routed /// public class SourceRouteListItem { /// /// The key of the source device to route from /// [JsonProperty("sourceKey")] public string SourceKey { get; set; } /// /// The key of the source port to route from /// [JsonProperty("sourcePortKey")] public string SourcePortKey { get; set; } /// /// The key of the destination device to route to /// [JsonProperty("destinationKey")] public string DestinationKey { get; set; } /// /// The key of the destination port to route to /// [JsonProperty("destinationPortKey")] public string DestinationPortKey { get; set; } /// /// The type of signal being routed, such as audio or video /// [JsonProperty("type")] public eRoutingSignalType Type { get; set; } /// /// Key for a destination list item. If BOTH SourceListItemKey AND DestinationListItemKey are defined, /// then the direct route method should be used. /// [JsonProperty("destinationListItemKey", NullValueHandling = NullValueHandling.Ignore)] public string DestinationListItemKey { get; set; } /// /// Key for a source list item. If BOTH SourceListItemKey AND DestinationListItemKey are defined, /// then the direct route method should be used. /// [JsonProperty("sourceListItemKey", NullValueHandling = NullValueHandling.Ignore)] public string SourceListItemKey { get; set; } } /// /// Defines the valid destination types for SourceListItems in a room /// [Obsolete] public enum eSourceListItemDestinationTypes { /// /// Default display, used for the main video output in a room /// defaultDisplay, /// /// Left display /// leftDisplay, /// /// Right display /// rightDisplay, /// /// Center display /// centerDisplay, /// /// Program audio, used for the main audio output in a room /// programAudio, /// /// Codec content, used for sharing content to the far end in a video call /// codecContent, /// /// Front left display, used for rooms with multiple displays /// frontLeftDisplay, /// /// Front right display, used for rooms with multiple displays /// frontRightDisplay, /// /// Rear left display, used for rooms with multiple displays /// rearLeftDisplay, /// /// Rear right display, used for rooms with multiple displays /// rearRightDisplay, /// /// Auxiliary display 1, used for additional displays in a room /// auxDisplay1, /// /// Auxiliary display 2, used for additional displays in a room /// auxDisplay2, /// /// Auxiliary display 3, used for additional displays in a room /// auxDisplay3, /// /// Auxiliary display 4, used for additional displays in a room /// auxDisplay4, /// /// Auxiliary display 5, used for additional displays in a room /// auxDisplay5, /// /// Auxiliary display 6, used for additional displays in a room /// auxDisplay6, /// /// Auxiliary display 7, used for additional displays in a room /// auxDisplay7, /// /// Auxiliary display 8, used for additional displays in a room /// auxDisplay8, /// /// Auxiliary display 9, used for additional displays in a room /// auxDisplay9, /// /// Auxiliary display 10, used for additional displays in a room /// auxDisplay10, } } ================================================ FILE: src/PepperDash.Essentials.Core/Devices/VolumeDeviceChangeEventArgs.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core { /// /// /// public class VolumeDeviceChangeEventArgs : EventArgs { /// /// The old device /// public IBasicVolumeControls OldDev { get; private set; } /// /// The new device /// public IBasicVolumeControls NewDev { get; private set; } /// /// The type of change /// public ChangeType Type { get; private set; } /// /// Constructor /// /// the old device /// the new device /// the type of change public VolumeDeviceChangeEventArgs(IBasicVolumeControls oldDev, IBasicVolumeControls newDev, ChangeType type) { OldDev = oldDev; NewDev = newDev; Type = type; } } /// /// Enumeration of ChangeType values /// public enum ChangeType { /// /// Will change /// WillChange, /// /// Did change /// DidChange } } ================================================ FILE: src/PepperDash.Essentials.Core/Ethernet/EthernetStatistics.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Ethernet { /// /// Ethernet settings feedbacks /// public static class EthernetSettings { /// /// Link active feedback /// public static readonly BoolFeedback LinkActive = new BoolFeedback("LinkActive", () => true); /// /// DHCP active feedback /// public static readonly BoolFeedback DhcpActive = new BoolFeedback("DhcpActive", () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, 0) == "ON"); /// /// Hostname feedback /// public static readonly StringFeedback Hostname = new StringFeedback("Hostname", () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0)); /// /// IP Address feedback /// public static readonly StringFeedback IpAddress0 = new StringFeedback("IpAddress0", () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)); /// /// Subnet Mask feedback /// public static readonly StringFeedback SubnetMask0 = new StringFeedback("SubnetMask0", () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 0)); /// /// Default Gateway feedback /// public static readonly StringFeedback DefaultGateway0 = new StringFeedback("DefaultGateway0", () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0)); } } ================================================ FILE: src/PepperDash.Essentials.Core/Extensions/IpAddressExtensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core { /// /// Extensions for IPAddress to provide additional functionality such as getting broadcast address, network address, and checking if two addresses are in the same subnet. /// public static class IPAddressExtensions { /// /// Get the broadcast address for a given IP address and subnet mask. /// /// Address to check /// Subnet mask in a.b.c.d format /// Broadcast address /// /// If the input IP address is 192.168.1.100 and the subnet mask is 255.255.255.0, the broadcast address will be 192.168.1.255 /// /// public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask) { byte[] ipAdressBytes = address.GetAddressBytes(); byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); if (ipAdressBytes.Length != subnetMaskBytes.Length) throw new ArgumentException("Lengths of IP address and subnet mask do not match."); byte[] broadcastAddress = new byte[ipAdressBytes.Length]; for (int i = 0; i < broadcastAddress.Length; i++) { broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255)); } return new IPAddress(broadcastAddress); } /// /// Get the network address for a given IP address and subnet mask. /// /// Address to check /// Subnet mask in a.b.c.d /// Network Address /// /// /// If the input IP address is 192.168.1.100 and the subnet mask is 255.255.255.0, the network address will be 192.168.1.0 /// /// public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask) { byte[] ipAdressBytes = address.GetAddressBytes(); byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); if (ipAdressBytes.Length != subnetMaskBytes.Length) throw new ArgumentException("Lengths of IP address and subnet mask do not match."); byte[] broadcastAddress = new byte[ipAdressBytes.Length]; for (int i = 0; i < broadcastAddress.Length; i++) { broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i])); } return new IPAddress(broadcastAddress); } /// /// Determine if two IP addresses are in the same subnet. /// /// Address to check /// Second address to check /// Subnet mask to use to compare the 2 IP Address /// True if addresses are in the same subnet /// /// If the input IP addresses are 192.168.1.100 and 192.168.1.200, and the subnet mask is 255.255.255.0, this will return true. /// If the input IP addresses are 10.1.1.100 and 192.168.1.100, and the subnet mask is 255.255.255.0, this will return false. /// public static bool IsInSameSubnet(this IPAddress address2, IPAddress address, IPAddress subnetMask) { IPAddress network1 = address.GetNetworkAddress(subnetMask); IPAddress network2 = address2.GetNetworkAddress(subnetMask); return network1.Equals(network2); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Extensions/JsonExtensions.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace PepperDash.Essentials.Core { /// /// JsonExtensions class /// public static class JsonExtensions { /// /// FindTokens method /// /// token for the container /// name of the token to find /// list of matching tokens public static List FindTokens(this JToken containerToken, string name) { List matches = new List(); FindTokens(containerToken, name, matches); return matches; } private static void FindTokens(JToken containerToken, string name, List matches) { if (containerToken.Type == JTokenType.Object) { foreach (JProperty child in containerToken.Children()) { if (child.Name == name) { matches.Add(child.Value); } FindTokens(child.Value, name, matches); } } else if (containerToken.Type == JTokenType.Array) { foreach (JToken child in containerToken.Children()) { FindTokens(child, name, matches); } } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Extensions/StringExtensions.cs ================================================ using System; using System.ComponentModel; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// StringExtensions class /// public static class StringExtensions { /// /// Returns null if a string is empty, otherwise returns the string /// /// string input /// null if the string is emtpy, otherwise returns the string public static string NullIfEmpty(this string s) { return string.IsNullOrEmpty(s) ? null : s; } /// /// Returns null if a string is empty or made of only whitespace characters, otherwise returns the string /// /// string input /// null if the string is wempty or made of only whitespace characters, otherwise returns the string public static string NullIfWhiteSpace(this string s) { return string.IsNullOrEmpty(s.Trim()) ? null : s; } /// /// Returns a replacement string if the input string is empty or made of only whitespace characters, otherwise returns the input string /// /// input string /// string to replace with if input string is empty or whitespace /// returns newString if s is null, emtpy, or made of whitespace characters, otherwise returns s public static string ReplaceIfNullOrEmpty(this string s, string newString) { return string.IsNullOrEmpty(s) ? newString : s; } /// /// Overload for Contains that allows setting an explicit String Comparison /// /// Source String /// String to check in Source String /// Comparison parameters /// true of string contains "toCheck" public static bool Contains(this string source, string toCheck, StringComparison comp) { if (string.IsNullOrEmpty(source)) return false; return source.IndexOf(toCheck, comp) >= 0; } /// /// Performs TrimStart() and TrimEnd() on source string /// /// String to Trim /// Trimmed String public static string TrimAll(this string source) { return string.IsNullOrEmpty(source) ? string.Empty : source.TrimStart().TrimEnd(); } /// /// Performs TrimStart(chars char[]) and TrimEnd(chars char[]) on source string. /// /// String to Trim /// Char Array to trim from string /// Trimmed String public static string TrimAll(this string source, char[] chars) { return string.IsNullOrEmpty(source) ? string.Empty : source.TrimStart(chars).TrimEnd(chars); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs ================================================  using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Crestron.SimplSharp; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Provides functionality for managing and registering device factories, including loading plugin-based factories and /// retrieving devices based on their configuration. /// /// The class is responsible for discovering and registering device factories /// from plugins, as well as providing methods to retrieve devices based on their configuration. It maintains a /// collection of factory methods that are keyed by device type names, allowing for extensibility through plugins. This /// class also handles metadata retrieval and secret management for device configurations. public class DeviceFactory { /// /// Initializes a new instance of the class and loads all available device factories /// from the current assembly. /// /// This constructor scans the executing assembly for types that implement the interface and are not abstract or interfaces. For each valid type, an instance is /// created and passed to the LoadDeviceFactories method for further processing. If a type cannot be /// instantiated, an informational log message is generated, and the process continues with the remaining /// types. public DeviceFactory() { var programAssemblies = Directory.GetFiles(InitialParametersClass.ProgramDirectory.ToString(), "*.dll"); // Assemblies known to cause load errors that should be skipped var assembliesToSkip = new[] { "CrestronOnvif.dll" }; foreach (var assembly in programAssemblies) { if (assembliesToSkip.Any(a => Path.GetFileName(assembly).Equals(a, StringComparison.OrdinalIgnoreCase))) { Debug.LogMessage(LogEventLevel.Verbose, "Skipping assembly: {assemblyName}", Path.GetFileName(assembly)); continue; } try { Assembly.LoadFrom(assembly); } catch (Exception e) { Debug.LogError("Unable to load assembly: {assemblyName} - {message}", assembly, e.Message); } } var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); // Loop through all loaded assemblies that contain at least 1 type that implements IDeviceFactory foreach (var assembly in loadedAssemblies) { Debug.LogDebug("loaded assembly: {assemblyName}", assembly.GetName()?.Name ?? "Unknown"); PluginLoader.AddLoadedAssembly(assembly.GetName()?.Name ?? "Unknown", assembly); var types = assembly.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract); if (types == null || !types.Any()) { Debug.LogDebug("No DeviceFactory types found in assembly: {assemblyName}", assembly.GetName().Name); continue; } foreach (var type in types) { try { var factory = (IDeviceFactory)Activator.CreateInstance(type); LoadDeviceFactories(factory); } catch (Exception e) { Debug.LogError("Unable to load type: '{message}' DeviceFactory: {type}", e.Message, type.Name); } } } } /// /// Loads device factories from the specified plugin device factory and registers them for use. /// /// This method retrieves metadata from the provided , including /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type /// names are converted to lowercase for registration. /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered. private static void LoadDeviceFactories(IDeviceFactory deviceFactory) { foreach (var typeName in deviceFactory.TypeNames) { string description = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0 ? descriptionAttribute[0].Description : "No description available"; AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice); } } /// /// A dictionary of factory methods, keyed by config types, added by plugins. /// These methods are looked up and called by GetDevice in this class. /// private static readonly Dictionary FactoryMethods = new Dictionary(StringComparer.OrdinalIgnoreCase); /// /// Registers a factory method for creating instances of a specific type. /// /// This method associates a type name with a factory method, allowing instances of the type to /// be created dynamically. The factory method is stored internally and can be retrieved or invoked as /// needed. /// The name of the type for which the factory method is being registered. This value cannot be null or empty. /// A delegate that defines the factory method. The delegate takes a parameter and /// returns an instance of . public static void AddFactoryForType(string typeName, Func method) { FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method }); } /// /// Registers a factory method for creating instances of a specific device type. /// /// If a factory method for the specified already exists, the method /// will not overwrite it and will log an informational message instead. /// The unique name of the device type. This serves as the key for identifying the factory method. /// A brief description of the device type. This is used for informational purposes. /// The of the device being registered. This represents the runtime type of the device. /// A factory method that takes a as input and returns an instance of . public static void AddFactoryForType(string typeName, string description, Type Type, Func method) { if (FactoryMethods.ContainsKey(typeName)) { Debug.LogInformation("Unable to add type: '{typeName}'. Already exists in DeviceFactory", typeName); return; } var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method }; FactoryMethods.Add(typeName, wrapper); } private static void CheckForSecrets(IEnumerable obj) { foreach (var prop in obj.Where(prop => prop.Value as JObject != null)) { if (prop.Name.Equals("secret", StringComparison.CurrentCultureIgnoreCase)) { var secret = GetSecret(prop.Children().First().ToObject()); prop.Parent.Replace(secret); } if (!(prop.Value is JObject recurseProp)) continue; CheckForSecrets(recurseProp.Properties()); } } private static string GetSecret(SecretsPropertiesConfig data) { var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider); if (secretProvider == null) return null; var secret = secretProvider.GetSecret(data.Key); if (secret != null) return (string)secret.Value; Debug.LogMessage(LogEventLevel.Debug, "Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider", data.Provider, data.Key); return string.Empty; } /// /// Creates and returns a device instance based on the provided . /// /// This method attempts to create a device using the type specified in the /// parameter. If the type corresponds to a registered factory method, the device is created and returned. If the /// type is unrecognized or an exception occurs, the method logs the error and returns . /// The configuration object containing the key, name, type, and properties required to create the device. /// An instance of a device that implements , or if the device type is /// not recognized or an error occurs during creation. public static IKeyed GetDevice(DeviceConfig dc) { try { var localDc = new DeviceConfig(dc); var key = localDc.Key; var name = localDc.Name; var type = localDc.Type; var properties = localDc.Properties; var typeName = localDc.Type.ToLower(); if (properties is JObject jObject) { var jProp = jObject.Properties(); CheckForSecrets(jProp); } if (!FactoryMethods.TryGetValue(typeName, out var wrapper)) { Debug.LogWarning("Device type '{typeName}' not found in DeviceFactory", typeName); return null; } Debug.LogInformation("Loading '{type}' from {assemblyName}", typeName, wrapper.Type.Assembly.FullName); // Check for types that have been added by plugin dlls. return wrapper.FactoryMethod(localDc); } catch (Exception ex) { Debug.LogError(ex, "Exception occurred while creating device {key}: {message}", dc.Key, ex.Message); Debug.LogDebug(ex, "Exception details: {stackTrace}", ex.StackTrace); return null; } } /// /// Displays a list of device factory types that match the specified filter. /// /// The method outputs the filtered list of device factory types to the console, including their /// key, type, and description. If a type is not specified by the plugin, it will be displayed as "Not Specified by /// Plugin." /// A string used to filter the device factory types by their keys. If the filter is null or empty, all device /// factory types are displayed. public static void GetDeviceFactoryTypes(string filter) { var types = !string.IsNullOrEmpty(filter) ? FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value) : FactoryMethods; CrestronConsole.ConsoleCommandResponse("Device Types:"); foreach (var type in types.OrderBy(t => t.Key)) { var description = type.Value.Description; var Type = "Not Specified by Plugin"; if (type.Value.Type != null) { Type = type.Value.Type.FullName; } CrestronConsole.ConsoleCommandResponse( "Type: '{0}'\r\n" + " Type: '{1}'\r\n" + " Description: {2}{3}", type.Key, Type, description, CrestronEnvironment.NewLine); } } /// /// Retrieves a dictionary of device factory wrappers, optionally filtered by a specified string. /// /// A string used to filter the dictionary keys. Only entries with keys containing the specified filter will be /// included. If or empty, all entries are returned. /// A dictionary where the keys are strings representing device identifiers and the values are instances. The dictionary may be empty if no entries match the filter. public static Dictionary GetDeviceFactoryDictionary(string filter) { return string.IsNullOrEmpty(filter) ? FactoryMethods : FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Factory/DeviceFactoryWrapper.cs ================================================ using System; using PepperDash.Core; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { /// /// Wraps a device factory, providing metadata and a factory method for creating devices. /// public class DeviceFactoryWrapper { /// /// Gets or sets the type associated with the current instance. /// public Type Type { get; set; } /// /// Gets or sets the description associated with the object. /// public string Description { get; set; } /// /// Gets or sets the factory method used to create an instance based on the provided . /// /// The factory method allows customization of how instances are created for /// specific inputs. Ensure the delegate is not null before invoking it. public Func FactoryMethod { get; set; } /// /// Initializes a new instance of the class with default values. /// /// The property is initialized to , and the property is set to "Not Available". public DeviceFactoryWrapper() { Type = null; Description = "Not Available"; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs ================================================ using System; using System.Collections.Generic; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IDeviceFactory /// public interface IDeviceFactory { /// /// Gets the type of the factory associated with the current instance. /// Type FactoryType { get; } /// /// Gets a list of type names associated with the current plugin. /// List TypeNames { get; } /// /// Builds and returns an instance based on the provided configuration. /// /// The configuration settings used to initialize the device. This parameter cannot be null. /// An instance configured according to the specified . EssentialsDevice BuildDevice(DeviceConfig deviceConfig); } } ================================================ FILE: src/PepperDash.Essentials.Core/Factory/IProcessorExtensionDeviceFactory.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IProcessorExtensionDeviceFactory /// public interface IProcessorExtensionDeviceFactory { /// /// Loads all the extension factories to the ProcessorExtensionDeviceFactory /// void LoadFactories(); } } ================================================ FILE: src/PepperDash.Essentials.Core/Factory/ProcessorExtensionDeviceFactory.cs ================================================  using System.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; using System; using System.Collections.Generic; using System.Linq; namespace PepperDash.Essentials.Core { /// /// Represents a ProcessorExtensionDeviceFactory /// public class ProcessorExtensionDeviceFactory { /// /// Constructor /// public ProcessorExtensionDeviceFactory() { var assy = Assembly.GetExecutingAssembly(); PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy); var extensions = assy.GetTypes().Where(ct => typeof(IProcessorExtensionDeviceFactory) .IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract); if (extensions != null ) { foreach ( var extension in extensions ) { try { var factory = (IProcessorExtensionDeviceFactory)Activator.CreateInstance(extension); factory.LoadFactories(); } catch( Exception e ) { Debug.LogMessage(LogEventLevel.Information, "Unable to load extension device: '{1}' ProcessorExtensionDeviceFactory: {0}", e, extension.Name); } } } } /// /// A dictionary of factory methods, keyed by config types, added by plugins. /// These methods are looked up and called by GetDevice in this class. /// static Dictionary ProcessorExtensionFactoryMethods = new Dictionary(StringComparer.OrdinalIgnoreCase); /// /// Adds a plugin factory method /// /// name fo extension to add /// method to add /// public static void AddFactoryForType(string extensionName, Func method) { //Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName); ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, new DeviceFactoryWrapper() { FactoryMethod = method }); } /// /// Adds a plugin factory method with type and description /// /// name of extension to add /// description of extension to add /// type of extension to add /// method to add public static void AddFactoryForType(string extensionName, string description, Type Type, Func method) { //Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName); if (ProcessorExtensionFactoryMethods.ContainsKey(extensionName)) { Debug.LogMessage(LogEventLevel.Information, "Unable to add extension device: '{0}'. Already exists in ProcessorExtensionDeviceFactory", extensionName); return; } var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method }; ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, wrapper); } private static void CheckForSecrets(IEnumerable obj) { foreach (var prop in obj.Where(prop => prop.Value as Newtonsoft.Json.Linq.JObject != null)) { if (prop.Name.ToLower() == "secret") { var secret = GetSecret(prop.Children().First().ToObject()); //var secret = GetSecret(JsonConvert.DeserializeObject(prop.Children().First().ToString())); prop.Parent.Replace(secret); } var recurseProp = prop.Value as Newtonsoft.Json.Linq.JObject; if (recurseProp == null) return; CheckForSecrets(recurseProp.Properties()); } } private static string GetSecret(SecretsPropertiesConfig data) { var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider); if (secretProvider == null) return null; var secret = secretProvider.GetSecret(data.Key); if (secret != null) return (string)secret.Value; Debug.LogMessage(LogEventLevel.Debug, "Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider", data.Provider, data.Key); return String.Empty; } /// /// The factory method for processor extension devices. Also iterates the Factory methods that have /// been loaded from plugins /// /// /// /// /// GetExtensionDevice method /// public static IKeyed GetExtensionDevice(DeviceConfig dc) { try { Debug.LogMessage(LogEventLevel.Information, "Loading '{0}' from Essentials Core", dc.Type); var localDc = new DeviceConfig(dc); var key = localDc.Key; var name = localDc.Name; var type = localDc.Type; var properties = localDc.Properties; //var propRecurse = properties; var typeName = localDc.Type.ToLower(); var jObject = properties as Newtonsoft.Json.Linq.JObject; if (jObject != null) { var jProp = jObject.Properties(); CheckForSecrets(jProp); } Debug.LogMessage(LogEventLevel.Verbose, "typeName = {0}", typeName); // Check for types that have been added by plugin dlls. return !ProcessorExtensionFactoryMethods.ContainsKey(typeName) ? null : ProcessorExtensionFactoryMethods[typeName].FactoryMethod(localDc); } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, "Exception occurred while creating device {0}: {1}", dc.Key, ex.Message); Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.StackTrace); if (ex.InnerException == null) { return null; } Debug.LogMessage(LogEventLevel.Information, "Inner exception while creating device {0}: {1}", dc.Key, ex.InnerException.Message); Debug.LogMessage(LogEventLevel.Verbose, "{0}", ex.InnerException.StackTrace); return null; } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Factory/ReadyEventArgs.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core { /// /// Represents a IsReadyEventArgs /// public class IsReadyEventArgs : EventArgs { /// /// Gets or sets the IsReady /// public bool IsReady { get; set; } /// /// Constructor /// /// indicates if the object is ready public IsReadyEventArgs(bool data) { IsReady = data; } } /// /// Defines the contract for IHasReady /// public interface IHasReady { /// /// Fires when the IsReady property changes /// event EventHandler IsReadyEvent; /// /// indicates whether the object is ready /// bool IsReady { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/BoolFeedback.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Core { /// /// A Feedback whose output is derived from the return value of a provided Func. /// public class BoolFeedback : Feedback { /// /// Returns the current value of the feedback, derived from the ValueFunc. The ValueFunc is /// evaluated whenever FireUpdate() is called /// public override bool BoolValue { get { return _BoolValue; } } bool _BoolValue; /// /// Fake value to be used in test mode /// public bool TestValue { get; private set; } /// /// Gets or sets the ValueFunc /// public Func ValueFunc { get; private set; } List LinkedInputSigs = new List(); List LinkedComplementInputSigs = new List(); List LinkedCrestronFeedbacks = new List(); /// /// Creates the feedback with the Func as described. /// /// /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, /// it will NOT reflect an actual value from a device until has been called /// /// Delegate to invoke when this feedback needs to be updated [Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")] public BoolFeedback(Func valueFunc) : this(null, valueFunc) { } /// /// Creates the feedback with the Func as described. /// /// /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, /// it will NOT reflect an actual value from a device until has been called /// /// Key to find this Feedback /// Delegate to invoke when this feedback needs to be updated public BoolFeedback(string key, Func valueFunc) : base(key) { ValueFunc = valueFunc; } /// /// Sets the ValueFunc /// /// New function to set as the ValueFunc public void SetValueFunc(Func newFunc) { ValueFunc = newFunc; } /// /// FireUpdate method /// /// public override void FireUpdate() { bool newValue = InTestMode ? TestValue : ValueFunc.Invoke(); if (newValue != _BoolValue) { _BoolValue = newValue; LinkedInputSigs.ForEach(s => UpdateSig(s)); LinkedComplementInputSigs.ForEach(s => UpdateComplementSig(s)); OnOutputChange(newValue); } } /// /// Links an input sig /// /// /// /// LinkInputSig method /// public void LinkInputSig(BoolInputSig sig) { LinkedInputSigs.Add(sig); UpdateSig(sig); } /// /// Unlinks an inputs sig /// /// /// /// UnlinkInputSig method /// public void UnlinkInputSig(BoolInputSig sig) { LinkedInputSigs.Remove(sig); } /// /// Links an input sig to the complement value /// /// public void LinkComplementInputSig(BoolInputSig sig) { LinkedComplementInputSigs.Add(sig); UpdateComplementSig(sig); } /// /// Unlinks an input sig to the complement value /// /// /// /// UnlinkComplementInputSig method /// public void UnlinkComplementInputSig(BoolInputSig sig) { LinkedComplementInputSigs.Remove(sig); } /// /// Links a Crestron Feedback object /// /// public void LinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) { LinkedCrestronFeedbacks.Add(feedback); UpdateCrestronFeedback(feedback); } /// /// /// /// /// /// UnlinkCrestronFeedback method /// public void UnlinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) { LinkedCrestronFeedbacks.Remove(feedback); } /// /// ToString override /// /// public override string ToString() { return (InTestMode ? "TEST -- " : "") + BoolValue.ToString(); } /// /// Puts this in test mode, sets the test value and fires an update. /// /// /// /// SetTestValue method /// public void SetTestValue(bool value) { TestValue = value; InTestMode = true; FireUpdate(); } void UpdateSig(BoolInputSig sig) { sig.BoolValue = _BoolValue; } void UpdateComplementSig(BoolInputSig sig) { sig.BoolValue = !_BoolValue; } void UpdateCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) { feedback.State = _BoolValue; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackOneShot.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Core { /// /// Represents a BoolFeedbackPulse /// public class BoolFeedbackPulse { /// /// Gets or sets the TimeoutMs /// public uint TimeoutMs { get; set; } /// /// Gets or sets the CanRetrigger /// public bool CanRetrigger { get; set; } /// /// Gets or sets the Feedback /// public BoolFeedback Feedback { get; private set; } CTimer Timer; bool _BoolValue; /// /// Creates a non-retriggering one shot /// public BoolFeedbackPulse(uint timeoutMs) : this(timeoutMs, false) { } /// /// Create a retriggerable one shot by setting canRetrigger true /// public BoolFeedbackPulse(uint timeoutMs, bool canRetrigger) { TimeoutMs = timeoutMs; CanRetrigger = canRetrigger; Feedback = new BoolFeedback(() => _BoolValue); } /// /// Start method /// public void Start() { if (Timer == null) { _BoolValue = true; Feedback.FireUpdate(); Timer = new CTimer(o => { _BoolValue = false; Feedback.FireUpdate(); Timer = null; }, TimeoutMs); } // Timer is running, if retrigger is set, reset it. else if (CanRetrigger) Timer.Reset(TimeoutMs); } /// /// Cancel method /// public void Cancel() { if(Timer != null) Timer.Reset(0); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/BoolFeedbackPulseExtender.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Core { /// /// A class that wraps a BoolFeedback with logic that extends it's true state for /// a time period after the value goes false. /// public class BoolFeedbackPulseExtender { /// /// Gets or sets the TimeoutMs /// public uint TimeoutMs { get; set; } /// /// Gets the Feedback /// public BoolFeedback Feedback { get; private set; } CTimer Timer; /// /// When set to true, will cause Feedback to go high, and cancel the timer. /// When false, will start the timer, and after timeout, will go low and /// feedback will go low. /// public bool BoolValue { get { return _BoolValue; } set { if (value) { // if Timer is running and the value goes high, cancel it. if (Timer != null) { Timer.Stop(); Timer = null; } // if it's already true, don't fire again if (_BoolValue == true) return; _BoolValue = true; Feedback.FireUpdate(); } else { if (Timer == null) Timer = new CTimer(o => ClearFeedback(), TimeoutMs); } } } bool _BoolValue; /// /// Constructor /// /// The time which the true state will be extended after set to false public BoolFeedbackPulseExtender(uint timeoutMs) { TimeoutMs = timeoutMs; Feedback = new BoolFeedback(() => this.BoolValue); } /// /// Forces the feedback to false regardless of timeout /// public void ClearNow() { if (Timer != null) Timer.Stop(); ClearFeedback(); } void ClearFeedback() { _BoolValue = false; Feedback.FireUpdate(); Timer = null; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/BoolOutputLogicals.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Core { /// /// Abstract base class for BoolOutputLogicals /// public abstract class BoolFeedbackLogic { /// /// Gets or sets the Output /// public BoolFeedback Output { get; private set; } /// /// List of all connected outputs /// protected List OutputsIn = new List(); /// /// Gets or sets the ComputedValue /// protected bool ComputedValue; /// /// Constructor /// protected BoolFeedbackLogic() { Output = new BoolFeedback(() => ComputedValue); } /// /// AddOutputIn method /// /// feedback to add public void AddOutputIn(BoolFeedback output) { // Don't double up outputs if(OutputsIn.Contains(output)) return; OutputsIn.Add(output); output.OutputChange += AnyInput_OutputChange; Evaluate(); } /// /// AddOutputsIn method /// /// feedbacks to add public void AddOutputsIn(List outputs) { foreach (var o in outputs.Where(o => !OutputsIn.Contains(o))) { OutputsIn.Add(o); o.OutputChange += AnyInput_OutputChange; } Evaluate(); } /// /// RemoveOutputIn method /// /// feedback to remove public void RemoveOutputIn(BoolFeedback output) { // Don't double up outputs if (!OutputsIn.Contains(output)) return; OutputsIn.Remove(output); output.OutputChange -= AnyInput_OutputChange; Evaluate(); } /// /// RemoveOutputsIn method /// /// feedbacks to remove public void RemoveOutputsIn(List outputs) { foreach (var o in outputs) { OutputsIn.Remove(o); o.OutputChange -= AnyInput_OutputChange; } Evaluate(); } /// /// ClearOutputs method /// public void ClearOutputs() { OutputsIn.Clear(); Evaluate(); } /// /// AnyInput_OutputChange event handler /// /// /// void AnyInput_OutputChange(object sender, EventArgs e) { Evaluate(); } /// /// Evaluate method /// protected abstract void Evaluate(); } /// /// Represents a BoolFeedbackAnd /// public class BoolFeedbackAnd : BoolFeedbackLogic { /// /// Evaluate method /// protected override void Evaluate() { var prevValue = ComputedValue; var newValue = OutputsIn.All(o => o.BoolValue); if (newValue == prevValue) { return; } ComputedValue = newValue; Output.FireUpdate(); } } /// /// Represents a BoolFeedbackOr /// public class BoolFeedbackOr : BoolFeedbackLogic { /// /// Evaluate method /// protected override void Evaluate() { var prevValue = ComputedValue; var newValue = OutputsIn.Any(o => o.BoolValue); if (newValue == prevValue) { return; } ComputedValue = newValue; Output.FireUpdate(); } } /// /// Represents a BoolFeedbackLinq /// public class BoolFeedbackLinq : BoolFeedbackLogic { readonly Func, bool> _predicate; /// /// Constructor /// /// public BoolFeedbackLinq(Func, bool> predicate) : base() { _predicate = predicate; } /// /// Evaluate method /// protected override void Evaluate() { var prevValue = ComputedValue; var newValue = _predicate(OutputsIn); if (newValue == prevValue) { return; } ComputedValue = newValue; Output.FireUpdate(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/FeedbackBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Base class for all feedback types /// public abstract class Feedback : IKeyed { /// /// Occurs when the output value changes /// public event EventHandler OutputChange; /// /// Gets or sets the Key /// public string Key { get; private set; } /// /// Gets or sets the BoolValue /// /// public virtual bool BoolValue { get { return false; } } /// /// Gets or sets the IntValue /// public virtual int IntValue { get { return 0; } } /// /// Gets or sets the StringValue /// public virtual string StringValue { get { return ""; } } /// /// Gets or sets the SerialValue /// public virtual string SerialValue { get { return ""; } } /// /// Gets or sets the InTestMode /// public bool InTestMode { get; protected set; } /// /// Base Constructor - empty /// [Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")] protected Feedback() : this(null) { } /// /// Constructor with Key parameter /// /// The key for the feedback protected Feedback(string key) { if (key == null) Key = ""; else Key = key; } /// /// ClearTestValue method /// public void ClearTestValue() { InTestMode = false; FireUpdate(); } /// /// Fires an update synchronously /// public abstract void FireUpdate(); /// /// Fires the update asynchronously within a CrestronInvoke /// public void InvokeFireUpdate() { CrestronInvoke.BeginInvoke(o => FireUpdate()); } /// /// Helper method that fires event. Use this intstead of calling OutputChange /// //protected void OnOutputChange() //{ // if (OutputChange != null) OutputChange(this, EventArgs.Empty); //} protected void OnOutputChange(bool value) { if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); } /// /// Helper method that fires event. Use this intstead of calling OutputChange /// /// value to seed eventArgs protected void OnOutputChange(int value) { if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); } /// /// Helper method that fires event. Use this intstead of calling OutputChange /// /// value to seed eventArgs protected void OnOutputChange(string value) { if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value)); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/FeedbackCollection.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Basically a List , with an indexer to find feedbacks by key name /// public class FeedbackCollection : List where T : Feedback { /// /// Case-insensitive port lookup linked to feedbacks' keys /// public T this[string key] { get { return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/FeedbackEventArgs.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Represents a FeedbackEventArgs /// public class FeedbackEventArgs : EventArgs { /// /// Gets or sets the BoolValue /// public bool BoolValue { get; private set; } /// /// Gets or sets the IntValue /// public int IntValue { get; private set; } /// /// Gets or sets the UShortValue /// public ushort UShortValue { get { return (ushort)IntValue; } } /// /// Gets or sets the StringValue /// public string StringValue { get; private set; } /// /// Gets or sets the Type /// public eFeedbackEventType Type { get; private set; } /// /// Constructor for BoolValue /// /// value to set public FeedbackEventArgs(bool value) { BoolValue = value; Type = eFeedbackEventType.TypeBool; } /// /// Constructor for IntValue /// /// value to set public FeedbackEventArgs(int value) { IntValue = value; Type = eFeedbackEventType.TypeInt; } /// /// Constructor for StringValue /// /// value to set public FeedbackEventArgs(string value) { StringValue = value; Type = eFeedbackEventType.TypeString; } } /// /// Enumeration of eFeedbackEventType values /// public enum eFeedbackEventType { /// /// Boolean type feedback event /// TypeBool, /// /// Integer type feedback event /// TypeInt, /// /// String type feedback event /// TypeString } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/IntFeedback.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Core { /// /// Represents a IntFeedback /// public class IntFeedback : Feedback { /// /// Gets or sets the IntValue /// public override int IntValue { get { return _IntValue; } } // ValueFunc.Invoke(); } } int _IntValue; /// /// Gets or sets the UShortValue /// public ushort UShortValue { get { return (ushort)_IntValue; } } //public override eCueType Type { get { return eCueType.Int; } } /// /// Gets or sets the TestValue /// public int TestValue { get; private set; } /// /// Func evaluated on FireUpdate /// Func ValueFunc; List LinkedInputSigs = new List(); /// /// Creates the feedback with the Func as described. /// /// /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, /// it will NOT reflect an actual value from a device until has been called /// /// Delegate to invoke when this feedback needs to be updated [Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")] public IntFeedback(Func valueFunc) : this(null, valueFunc) { } /// /// Creates the feedback with the Func as described. /// /// /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, /// it will NOT reflect an actual value from a device until has been called /// /// Key to find this Feedback /// Delegate to invoke when this feedback needs to be updated public IntFeedback(string key, Func valueFunc) : base(key) { ValueFunc = valueFunc; } /// /// Sets the ValueFunc /// /// function to set public void SetValueFunc(Func newFunc) { ValueFunc = newFunc; } /// /// FireUpdate method /// /// public override void FireUpdate() { var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); if (newValue != _IntValue) { _IntValue = newValue; LinkedInputSigs.ForEach(s => UpdateSig(s)); OnOutputChange(newValue); } } /// /// LinkInputSig method /// public void LinkInputSig(UShortInputSig sig) { LinkedInputSigs.Add(sig); UpdateSig(sig); } /// /// UnlinkInputSig method /// public void UnlinkInputSig(UShortInputSig sig) { LinkedInputSigs.Remove(sig); } /// /// ToString method /// public override string ToString() { return (InTestMode ? "TEST -- " : "") + IntValue.ToString(); } /// /// Puts this in test mode, sets the test value and fires an update. /// /// /// /// SetTestValue method /// public void SetTestValue(int value) { TestValue = value; InTestMode = true; FireUpdate(); } void UpdateSig(UShortInputSig sig) { sig.UShortValue = UShortValue; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/SerialFeedback.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Core { /// /// To be used for serial data feedback where the event chain / asynchronicity must be maintained /// and calculating the value based on a Func when it is needed will not suffice. /// public class SerialFeedback : Feedback { /// /// Gets the SerialValue /// public override string SerialValue { get { return _SerialValue; } } string _SerialValue; //public override eCueType Type { get { return eCueType.Serial; } } /// /// Gets or sets the TestValue /// public string TestValue { get; private set; } List LinkedInputSigs = new List(); /// /// Constructor /// [Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")] public SerialFeedback() { } /// /// Constructor with Key parameter /// /// Key to find this Feedback public SerialFeedback(string key) : base(key) { } /// /// FireUpdate method /// /// public override void FireUpdate() { throw new NotImplementedException("This feedback type does not use Funcs"); } /// /// FireUpdate method /// public void FireUpdate(string newValue) { _SerialValue = newValue; LinkedInputSigs.ForEach(s => UpdateSig(s, newValue)); OnOutputChange(newValue); } /// /// LinkInputSig method /// public void LinkInputSig(StringInputSig sig) { LinkedInputSigs.Add(sig); UpdateSig(sig); } /// /// UnlinkInputSig method /// public void UnlinkInputSig(StringInputSig sig) { LinkedInputSigs.Remove(sig); } /// /// ToString method /// public override string ToString() { return (InTestMode ? "TEST -- " : "") + SerialValue; } /// /// Puts this in test mode, sets the test value and fires an update. /// /// /// /// SetTestValue method /// public void SetTestValue(string value) { TestValue = value; InTestMode = true; FireUpdate(TestValue); } void UpdateSig(StringInputSig sig) { sig.StringValue = _SerialValue; } void UpdateSig(StringInputSig sig, string value) { sig.StringValue = value; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Feedbacks/StringFeedback.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Core { /// /// Represents a StringFeedback /// public class StringFeedback : Feedback { /// /// Gets or sets the StringValue /// public override string StringValue { get { return _StringValue; } } // ValueFunc.Invoke(); } } string _StringValue; /// /// Gets or sets the TestValue /// public string TestValue { get; private set; } /// /// Gets or sets the ValueFunc /// public Func ValueFunc { get; private set; } List LinkedInputSigs = new List(); /// /// Creates the feedback with the Func as described. /// /// /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, /// it will NOT reflect an actual value from a device until has been called /// /// Delegate to invoke when this feedback needs to be updated [Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")] public StringFeedback(Func valueFunc) : this(null, valueFunc) { } /// /// Creates the feedback with the Func as described. /// /// /// While the linked sig value will be updated with the current value stored when it is linked to a EISC Bridge, /// it will NOT reflect an actual value from a device until has been called /// /// Key to find this Feedback /// Delegate to invoke when this feedback needs to be updated public StringFeedback(string key, Func valueFunc) : base(key) { ValueFunc = valueFunc; } /// /// Sets the ValueFunc /// /// function to set public void SetValueFunc(Func newFunc) { ValueFunc = newFunc; } /// /// FireUpdate method /// /// public override void FireUpdate() { var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); if (newValue != _StringValue) { _StringValue = newValue; LinkedInputSigs.ForEach(s => UpdateSig(s)); OnOutputChange(newValue); } } /// /// LinkInputSig method /// public void LinkInputSig(StringInputSig sig) { LinkedInputSigs.Add(sig); UpdateSig(sig); } /// /// UnlinkInputSig method /// public void UnlinkInputSig(StringInputSig sig) { LinkedInputSigs.Remove(sig); } /// /// ToString method /// public override string ToString() { return (InTestMode ? "TEST -- " : "") + StringValue; } /// /// Puts this in test mode, sets the test value and fires an update. /// /// /// /// SetTestValue method /// public void SetTestValue(string value) { TestValue = value; InTestMode = true; FireUpdate(); } void UpdateSig(StringInputSig sig) { sig.StringValue = _StringValue; } } } ================================================ FILE: src/PepperDash.Essentials.Core/File/FileIO.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using PepperDash.Core; using Crestron.SimplSharpPro.CrestronThread; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Static class for FileIO operations /// public static class FileIO { static CCriticalSection fileLock = new CCriticalSection(); /// /// Delegate for GotFileEventHandler /// /// /// public delegate void GotFileEventHandler(object sender, FileEventArgs e); /// /// Event for GotFileEvent /// public static event GotFileEventHandler GotFileEvent; /// /// Get the full file info from a path/filename, can include wildcards. /// /// /// /// /// GetFiles method /// public static FileInfo[] GetFiles(string fileName) { string fullFilePath = Global.FilePathPrefix + fileName; DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fullFilePath)); var files = dirInfo.GetFiles(Path.GetFileName(fullFilePath)); Debug.LogMessage(LogEventLevel.Information, "FileIO found: {0}, {1}", files.Count(), fullFilePath); if (files.Count() > 0) { return files; } else { return null; } } /// /// GetFile method /// public static FileInfo GetFile(string fileName) { string fullFilePath = Global.FilePathPrefix + fileName; DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fullFilePath)); var files = dirInfo.GetFiles(Path.GetFileName(fullFilePath)); Debug.LogMessage(LogEventLevel.Information, "FileIO found: {0}, {1}", files.Count(), fullFilePath); if (files.Count() > 0) { return files.FirstOrDefault(); } else { return null; } } /// /// Get the data from string path/filename /// /// /// /// /// ReadDataFromFile method /// public static string ReadDataFromFile(string fileName) { try { return ReadDataFromFile(GetFile(fileName)); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Error: FileIO read failed: \r{0}", e); return ""; } } /// /// Get the data with fileInfo object /// /// /// /// /// ReadDataFromFile method /// public static string ReadDataFromFile(FileInfo file) { try { if (fileLock.TryEnter()) { DirectoryInfo dirInfo = new DirectoryInfo(file.DirectoryName); Debug.LogMessage(LogEventLevel.Verbose, "FileIO Getting Data {0}", file.FullName); if (File.Exists(file.FullName)) { using (StreamReader r = new StreamReader(file.FullName)) { return r.ReadToEnd(); } } else { Debug.LogMessage(LogEventLevel.Verbose, "File {0} does not exsist", file.FullName); return ""; } } else { Debug.LogMessage(LogEventLevel.Information, "FileIO Unable to enter FileLock"); return ""; } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Error: FileIO read failed: \r{0}", e); return ""; } finally { if (fileLock != null && !fileLock.Disposed) fileLock.Leave(); } } /// /// ReadDataFromFileASync method /// public static void ReadDataFromFileASync(string fileName) { try { ReadDataFromFileASync(GetFile(fileName)); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Error: FileIO read failed: \r{0}", e); } } /// /// ReadDataFromFileASync method /// public static void ReadDataFromFileASync(FileInfo file) { try { CrestronInvoke.BeginInvoke(o => _ReadDataFromFileASync(file)); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Error: FileIO read failed: \r{0}", e); } } private static void _ReadDataFromFileASync(FileInfo file) { string data; try { if (fileLock.TryEnter()) { DirectoryInfo dirInfo = new DirectoryInfo(file.Name); Debug.LogMessage(LogEventLevel.Verbose, "FileIO Getting Data {0}", file.FullName); if (File.Exists(file.FullName)) { using (StreamReader r = new StreamReader(file.FullName)) { data = r.ReadToEnd(); } } else { Debug.LogMessage(LogEventLevel.Verbose, "File {0} Does not exsist", file.FullName); data = ""; } GotFileEvent.Invoke(null, new FileEventArgs(data)); } else { Debug.LogMessage(LogEventLevel.Information, "FileIO Unable to enter FileLock"); } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Error: FileIO read failed: \r{0}", e); data = ""; } finally { if (fileLock != null && !fileLock.Disposed) fileLock.Leave(); } } /// /// /// /// /// public static void WriteDataToFile(string data, string filePath) { Thread _WriteFileThread; _WriteFileThread = new Thread((O) => _WriteFileMethod(data, Global.FilePathPrefix + "/" + filePath), null, Thread.eThreadStartOptions.CreateSuspended); _WriteFileThread.Priority = Thread.eThreadPriority.LowestPriority; _WriteFileThread.Start(); Debug.LogMessage(LogEventLevel.Information, "New WriteFile Thread"); } static object _WriteFileMethod(string data, string filePath) { Debug.LogMessage(LogEventLevel.Information, "Attempting to write file: '{0}'", filePath); try { if (fileLock.TryEnter()) { using (StreamWriter sw = new StreamWriter(filePath)) { sw.Write(data); sw.Flush(); } } else { Debug.LogMessage(LogEventLevel.Information, "FileIO Unable to enter FileLock"); } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Error, "Error: FileIO write failed: \r{0}", e); } finally { if (fileLock != null && !fileLock.Disposed) fileLock.Leave(); } return null; } /// /// /// /// /// /// FileIoUnitTest method /// public static bool FileIoUnitTest() { var testData = "Testing FileIO"; FileIO.WriteDataToFile(testData, "\\user\\FileIOTest.pdt"); var file = FileIO.GetFile("\\user\\*FileIOTest*"); var readData = FileIO.ReadDataFromFile(file); Debug.LogMessage(LogEventLevel.Information, "Returned {0}", readData); File.Delete(file.FullName); if (testData == readData) { return true; } else { return false; } } } /// /// Represents a FileEventArgs /// public class FileEventArgs { /// /// Constructor /// /// public FileEventArgs(string data) { Data = data; } /// /// Gets or sets the Data /// public string Data { get; private set; } // readonly } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core.Bridges; namespace PepperDash.Essentials.Core.Fusion { /// /// Represents a EssentialsHuddleSpaceRoomFusionRoomJoinMap /// public class EssentialsHuddleSpaceRoomFusionRoomJoinMap : JoinMapBaseAdvanced { // Processor Attributes /// /// Processor IP 1 /// [JoinName("ProcessorIp1")] public JoinDataComplete ProcessorIp1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Info - Processor - IP 1" }, new JoinMetadata { Description = "Info - Processor - IP 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor IP 2 /// [JoinName("ProcessorIp2")] public JoinDataComplete ProcessorIp2 = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1, AttributeName = "Info - Processor - IP 2" }, new JoinMetadata { Description = "Info - Processor - IP 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor Gateway /// [JoinName("ProcessorGateway")] public JoinDataComplete ProcessorGateway = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1, AttributeName = "Info - Processor - Gateway" }, new JoinMetadata { Description = "Info - Processor - Gateway", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor Hostname /// [JoinName("ProcessorHostname")] public JoinDataComplete ProcessorHostname = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1, AttributeName = "Info - Processor - Hostname" }, new JoinMetadata { Description = "Info - Processor - Hostname", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor Domain /// [JoinName("ProcessorDomain")] public JoinDataComplete ProcessorDomain = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1, AttributeName = "Info - Processor - Domain" }, new JoinMetadata { Description = "Info - Processor - Domain", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor DNS 1 /// [JoinName("ProcessorDns1")] public JoinDataComplete ProcessorDns1 = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1, AttributeName = "Info - Processor - DNS 1" }, new JoinMetadata { Description = "Info - Processor - DNS 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor DNS 2 /// [JoinName("ProcessorDns2")] public JoinDataComplete ProcessorDns2 = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1, AttributeName = "Info - Processor - DNS 2" }, new JoinMetadata { Description = "Info - Processor - DNS 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor MAC 1 /// [JoinName("ProcessorMac1")] public JoinDataComplete ProcessorMac1 = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1, AttributeName = "Info - Processor - MAC 1" }, new JoinMetadata { Description = "Info - Processor - MAC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor MAC 2 /// [JoinName("ProcessorMac2")] public JoinDataComplete ProcessorMac2 = new JoinDataComplete(new JoinData { JoinNumber = 58, JoinSpan = 1, AttributeName = "Info - Processor - MAC 2" }, new JoinMetadata { Description = "Info - Processor - MAC 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor Net Mask 1 /// [JoinName("ProcessorNetMask1")] public JoinDataComplete ProcessorNetMask1 = new JoinDataComplete(new JoinData { JoinNumber = 59, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 1" }, new JoinMetadata { Description = "Info - Processor - Net Mask 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor Net Mask 2 /// [JoinName("ProcessorNetMask2")] public JoinDataComplete ProcessorNetMask2 = new JoinDataComplete(new JoinData { JoinNumber = 60, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 2" }, new JoinMetadata { Description = "Info - Processor - Net Mask 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor Firmware /// [JoinName("ProcessorFirmware")] public JoinDataComplete ProcessorFirmware = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1, AttributeName = "Info - Processor - Firmware" }, new JoinMetadata { Description = "Info - Processor - Firmware", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Program Name Start /// [JoinName("ProgramNameStart")] public JoinDataComplete ProgramNameStart = new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 10, AttributeName = "Info - Processor - Program" }, new JoinMetadata { Description = "Info - Processor - Program", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// Processor Reboot /// [JoinName("ProcessorReboot")] public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 74, JoinSpan = 1, AttributeName = "Processor - Reboot" }, new JoinMetadata { Description = "Processor - Reboot", JoinCapabilities = eJoinCapabilities.FromFusion, JoinType = eJoinType.Digital }); // Volume Controls /// /// Volume Fader 1 /// [JoinName("VolumeFader1")] public JoinDataComplete VolumeFader1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Volume - Fader01" }, new JoinMetadata { Description = "Volume - Fader01", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Analog }); // Codec Info /// /// VC Codec In Call /// [JoinName("VcCodecInCall")] public JoinDataComplete VcCodecInCall = new JoinDataComplete(new JoinData { JoinNumber = 69, JoinSpan = 1, AttributeName = "Conf - VC 1 In Call" }, new JoinMetadata { Description = "Conf - VC 1 In Call", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); /// /// VC Codec Online /// [JoinName("VcCodecOnline")] public JoinDataComplete VcCodecOnline = new JoinDataComplete(new JoinData { JoinNumber = 122, JoinSpan = 1, AttributeName = "Online - VC 1" }, new JoinMetadata { Description = "Online - VC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); /// /// VC Codec IP Address /// [JoinName("VcCodecIpAddress")] public JoinDataComplete VcCodecIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 121, JoinSpan = 1, AttributeName = "IP Address - VC" }, new JoinMetadata { Description = "IP Address - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); /// /// VC Codec IP Port /// [JoinName("VcCodecIpPort")] public JoinDataComplete VcCodecIpPort = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 1, AttributeName = "IP Port - VC" }, new JoinMetadata { Description = "IP Port - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); // Source Attributes /// /// Display 1 Current Source Name /// [JoinName("Display1CurrentSourceName")] public JoinDataComplete Display1CurrentSourceName = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1, AttributeName = "Display 1 - Current Source" }, new JoinMetadata { Description = "Display 1 - Current Source", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); // Device Online Status /// /// Touchpanel Online Start /// [JoinName("TouchpanelOnlineStart")] public JoinDataComplete TouchpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 10, AttributeName = "Online - Touch Panel" }, new JoinMetadata { Description = "Online - Touch Panel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); /// /// Xpanel Online Start /// [JoinName("XpanelOnlineStart")] public JoinDataComplete XpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 160, JoinSpan = 5, AttributeName = "Online - XPanel" }, new JoinMetadata { Description = "Online - XPanel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); /// /// Display Online Start /// [JoinName("DisplayOnlineStart")] public JoinDataComplete DisplayOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 170, JoinSpan = 10, AttributeName = "Online - Display" }, new JoinMetadata { Description = "Online - Display", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); /// /// Display 1 Laptop Source Start /// [JoinName("Display1LaptopSourceStart")] public JoinDataComplete Display1LaptopSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 165, JoinSpan = 5, AttributeName = "Display 1 - Source Laptop" }, new JoinMetadata { Description = "Display 1 - Source Laptop", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); /// /// Display 1 Disc Player Source Start /// [JoinName("Display1DiscPlayerSourceStart")] public JoinDataComplete Display1DiscPlayerSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 180, JoinSpan = 5, AttributeName = "Display 1 - Source Disc Player" }, new JoinMetadata { Description = "Display 1 - Source Disc Player", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); /// /// Display 1 Set Top Box Source Start /// [JoinName("Display1SetTopBoxSourceStart")] public JoinDataComplete Display1SetTopBoxSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 185, JoinSpan = 5, AttributeName = "Display 1 - Source TV" }, new JoinMetadata { Description = "Display 1 - Source TV", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); // Display 1 /// /// Display 1 Start /// [JoinName("Display1Start")] public JoinDataComplete Display1Start = new JoinDataComplete(new JoinData { JoinNumber = 190, JoinSpan = 1 }, new JoinMetadata { Description = "Display 1 Start", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); /// /// Constructor to use when instantiating this Join Map without inheriting from it /// /// Join this join map will start at public EssentialsHuddleSpaceRoomFusionRoomJoinMap(uint joinStart) : base(joinStart, typeof(EssentialsHuddleSpaceRoomFusionRoomJoinMap)) { } /// /// Constructor to use when extending this Join map /// /// Join this join map will start at /// Type of the child join map public EssentialsHuddleSpaceRoomFusionRoomJoinMap(uint joinStart, Type type) : base(joinStart, type) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/FusionCustomPropertiesBridge.cs ================================================  using System; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.Devices; using Serilog.Events; namespace PepperDash.Essentials.Core.Fusion { /// /// Handles mapping Fusion Custom Property values to system properties /// public class FusionCustomPropertiesBridge { /// /// Evaluates the room info and custom properties from Fusion and updates the system properties aa needed /// /// The room associated with this Fusion instance /// The room information from Fusion /// public void EvaluateRoomInfo(IEssentialsRoom room, RoomInformation roomInfo, bool useFusionRoomName) { try { var reconfigurableDevices = DeviceManager.AllDevices.OfType(); foreach (var device in reconfigurableDevices) { // Get the current device config so new values can be overwritten over existing var deviceConfig = device.Config; if (device is IEssentialsRoom) { // Skipping room name as this will affect ALL room instances in the configuration and cause unintended consequences when multiple rooms are present and multiple Fusion instances are used continue; } if (device is RoomOnToDefaultSourceWhenOccupied) { Debug.LogMessage(LogEventLevel.Debug, "Mapping Room on via Occupancy values from Fusion"); var devProps = JsonConvert.DeserializeObject(deviceConfig.Properties.ToString()); var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupied")); if (enableFeature != null) devProps.EnableRoomOnWhenOccupied = bool.Parse(enableFeature.CustomFieldValue); var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedStartTime")); if (enableTime != null) devProps.OccupancyStartTime = enableTime.CustomFieldValue; var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedEndTime")); if (disableTime != null) devProps.OccupancyEndTime = disableTime.CustomFieldValue; var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSun")); if (enableSunday != null) devProps.EnableSunday = bool.Parse(enableSunday.CustomFieldValue); var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedMon")); if (enableMonday != null) devProps.EnableMonday = bool.Parse(enableMonday.CustomFieldValue); var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedTue")); if (enableTuesday != null) devProps.EnableTuesday = bool.Parse(enableTuesday.CustomFieldValue); var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedWed")); if (enableWednesday != null) devProps.EnableWednesday = bool.Parse(enableWednesday.CustomFieldValue); var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedThu")); if (enableThursday != null) devProps.EnableThursday = bool.Parse(enableThursday.CustomFieldValue); var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedFri")); if (enableFriday != null) devProps.EnableFriday = bool.Parse(enableFriday.CustomFieldValue); var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSat")); if (enableSaturday != null) devProps.EnableSaturday = bool.Parse(enableSaturday.CustomFieldValue); deviceConfig.Properties = JToken.FromObject(devProps); } // Set the config on the device device.SetConfig(deviceConfig); } if (!(room is ReconfigurableDevice reconfigurable)) { Debug.LogWarning("FusionCustomPropertiesBridge: Room is not a ReconfigurableDevice. Cannot map custom properties."); return; } var roomConfig = reconfigurable.Config; var updateConfig = false; // Set the room name if (!string.IsNullOrEmpty(roomInfo.Name) && useFusionRoomName) { Debug.LogDebug("Current Room Name: {currentName}. New Room Name: {fusionName}", roomConfig.Name, roomInfo.Name); // Set the name in config roomConfig.Name = roomInfo.Name; updateConfig = true; Debug.LogDebug("Room Name Successfully Changed."); } // Set the help message var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage")); if (helpMessage != null) { roomConfig.Properties["helpMessage"] = helpMessage.CustomFieldValue; updateConfig = true; } if (updateConfig) { reconfigurable.SetConfig(roomConfig); } } catch (Exception e) { Debug.LogError("FusionCustomPropetiesBridge: Exception mapping properties for {roomKey}: {message}", room.Key, e.Message); Debug.LogDebug(e, "Stack Trace: "); } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/FusionEventHandlers.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core.Fusion { /// /// Represents a ScheduleChangeEventArgs /// public class ScheduleChangeEventArgs : EventArgs { /// /// Gets or sets the Schedule /// public RoomSchedule Schedule { get; set; } } /// /// Represents a MeetingChangeEventArgs /// public class MeetingChangeEventArgs : EventArgs { /// /// Gets or sets the Meeting /// public Event Meeting { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/FusionProcessorQueries.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core.Fusion { /// /// When created, runs progcomments on every slot and stores the program names in a list /// public class ProcessorProgReg { //public static Dictionary Programs { get; private set; } /// /// Gets the processor program registry /// /// public static Dictionary GetProcessorProgReg() { var programs = new Dictionary(); for (int i = 1; i <= Global.ControlSystem.NumProgramsSupported; i++) { string response = null; var success = CrestronConsole.SendControlSystemCommand("progcomments:" + i, ref response); var item = new ProcessorProgramItem(); if (!success) item.Name = "Error: PROGCOMMENTS failed"; else { if (response.ToLower().Contains("bad or incomplete")) item.Name = ""; else { var startPos = response.IndexOf("Program File"); var colonPos = response.IndexOf(":", startPos) + 1; var endPos = response.IndexOf(CrestronEnvironment.NewLine, colonPos); item.Name = response.Substring(colonPos, endPos - colonPos).Trim(); item.Exists = true; if (item.Name.Contains(".dll")) { startPos = response.IndexOf("Compiler Revision"); colonPos = response.IndexOf(":", startPos) + 1; endPos = response.IndexOf(CrestronEnvironment.NewLine, colonPos); item.Name = item.Name + "_v" + response.Substring(colonPos, endPos - colonPos).Trim(); } } } programs[i] = item; Debug.LogMessage(LogEventLevel.Debug, "Program {0}: {1}", i, item.Name); } return programs; } } /// /// Represents a ProcessorProgramItem /// public class ProcessorProgramItem { /// /// Gets or sets the Exists /// public bool Exists { get; set; } /// /// Gets or sets the Name /// public string Name { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/FusionRviDataClasses.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.Fusion; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core.Fusion { // Helper Classes for GUIDs /// /// Stores GUIDs to be written to a file in NVRAM /// public class FusionRoomGuids { /// /// Gets or sets the RoomName /// public string RoomName { get; set; } /// /// Gets or sets the IpId /// public uint IpId { get; set; } /// /// Gets or sets the RoomGuid /// public string RoomGuid { get; set; } /// /// Gets or sets the OccupancyAsset /// public FusionOccupancySensorAsset OccupancyAsset { get; set; } /// /// Gets or sets the StaticAssets /// public Dictionary StaticAssets { get; set; } /// /// FusionRoomGuids constructor /// public FusionRoomGuids() { StaticAssets = new Dictionary(); OccupancyAsset = new FusionOccupancySensorAsset(); } /// /// FusionRoomGuids constructor /// /// name of the fusion room /// ipID of the fusion room /// room GUID /// dictionary of assets public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary staticAssets) { RoomName = roomName; IpId = ipId; RoomGuid = roomGuid; StaticAssets = staticAssets; OccupancyAsset = new FusionOccupancySensorAsset(); } /// /// FusionRoomGuids constructor /// /// name of the fusion room /// ipID of the fusion room /// room GUID /// dictionary of assets /// occupancy asset public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary staticAssets, FusionOccupancySensorAsset occAsset) { RoomName = roomName; IpId = ipId; RoomGuid = roomGuid; StaticAssets = staticAssets; OccupancyAsset = occAsset; } /// /// Generates a new room GUID prefixed by the program slot number and NIC MAC address /// /// /// /// /// GenerateNewRoomGuid method /// public string GenerateNewRoomGuid(uint progSlot, string mac) { Guid roomGuid = Guid.NewGuid(); return string.Format("{0}-{1}-{2}", progSlot, mac, roomGuid.ToString()); } /// /// Adds an asset to the StaticAssets collection and returns the new asset /// /// /// /// /// /// /// public FusionAsset AddStaticAsset(FusionRoom room, int uid, string assetName, string type, string instanceId) { var slotNum = GetNextAvailableAssetNumber(room); Debug.LogMessage(LogEventLevel.Verbose, "Adding Fusion Asset: {0} of Type: {1} at Slot Number: {2} with GUID: {3}", assetName, type, slotNum, instanceId); var tempAsset = new FusionAsset(slotNum, assetName, type, instanceId); StaticAssets.Add(uid, tempAsset); return tempAsset; } /// /// Returns the next available slot number in the Fusion UserConfigurableAssetDetails collection /// /// /// /// /// GetNextAvailableAssetNumber method /// public static uint GetNextAvailableAssetNumber(FusionRoom room) { uint slotNum = 0; foreach (var item in room.UserConfigurableAssetDetails) { if(item.Number > slotNum) slotNum = item.Number; } if (slotNum < 5) { slotNum = 5; } else slotNum = slotNum + 1; Debug.LogMessage(LogEventLevel.Verbose, "#Next available fusion asset number is: {0}", slotNum); return slotNum; } } /// /// Represents a FusionOccupancySensorAsset /// public class FusionOccupancySensorAsset { // SlotNumber fixed at 4 /// /// Gets or sets the SlotNumber /// public uint SlotNumber { get { return 4; } } /// /// Gets or sets the Name /// public string Name { get { return "Occupancy Sensor"; } } /// /// Gets or sets the Type /// public eAssetType Type { get; set; } /// /// Gets or sets the InstanceId /// public string InstanceId { get; set; } /// /// Default constructor /// public FusionOccupancySensorAsset() { } /// /// FusionOccupancySensorAsset constructor /// /// asset type public FusionOccupancySensorAsset(eAssetType type) { Type = type; InstanceId = Guid.NewGuid().ToString(); } } /// /// Represents a FusionAsset /// public class FusionAsset { /// /// Gets or sets the SlotNumber /// public uint SlotNumber { get; set; } /// /// Gets or sets the Name /// public string Name { get; set; } /// /// Gets or sets the Type /// public string Type { get; set; } /// /// Gets or sets the InstanceId /// public string InstanceId { get;set; } /// /// Default constructor /// public FusionAsset() { } /// /// FusionAsset constructor /// /// slot number of asset /// name of the asset /// type of the asset /// instance ID of the asset public FusionAsset(uint slotNum, string assetName, string type, string instanceId) { SlotNumber = slotNum; Name = assetName; Type = type; if (string.IsNullOrEmpty(instanceId)) { InstanceId = Guid.NewGuid().ToString(); } else { InstanceId = instanceId; } } } //*************************************************************************************************** /// /// Represents a RoomSchedule /// public class RoomSchedule { /// /// Gets or sets the Meetings /// public List Meetings { get; set; } /// /// RoomSchedule constructor /// public RoomSchedule() { Meetings = new List(); } } //**************************************************************************************************** // Helper Classes for XML API /// /// Represents a LocalTimeRequest /// public class LocalTimeRequest { /// /// Gets or sets the RequestID /// public string RequestID { get; set; } } /// /// All the data needed for a full schedule request in a room /// /// //[XmlRoot(ElementName = "RequestSchedule")] public class RequestSchedule { //[XmlElement(ElementName = "RequestID")] /// /// Gets or sets the RequestID /// public string RequestID { get; set; } //[XmlElement(ElementName = "RoomID")] /// /// Gets or sets the RoomID /// public string RoomID { get; set; } //[XmlElement(ElementName = "Start")] /// /// Gets or sets the Start /// public DateTime Start { get; set; } //[XmlElement(ElementName = "HourSpan")] /// /// Gets or sets the HourSpan /// public double HourSpan { get; set; } /// /// RequestSchedule constructor /// /// id of the request /// id of the room public RequestSchedule(string requestID, string roomID) { RequestID = requestID; RoomID = roomID; Start = DateTime.Now; HourSpan = 24; } } //[XmlRoot(ElementName = "RequestAction")] /// /// Represents a RequestAction /// public class RequestAction { //[XmlElement(ElementName = "RequestID")] /// /// Gets or sets the RequestID /// public string RequestID { get; set; } //[XmlElement(ElementName = "RoomID")] /// /// Gets or sets the RoomID /// public string RoomID { get; set; } //[XmlElement(ElementName = "ActionID")] /// /// Gets or sets the ActionID /// public string ActionID { get; set; } //[XmlElement(ElementName = "Parameters")] /// /// Gets or sets the Parameters /// public List Parameters { get; set; } /// /// RequestAction constructor /// /// id of the room /// id of the action /// list of parameters public RequestAction(string roomID, string actionID, List parameters) { RoomID = roomID; ActionID = actionID; Parameters = parameters; } } //[XmlRoot(ElementName = "ActionResponse")] /// /// Represents a ActionResponse /// public class ActionResponse { //[XmlElement(ElementName = "RequestID")] /// /// Gets or sets the RequestID /// public string RequestID { get; set; } //[XmlElement(ElementName = "ActionID")] /// /// Gets or sets the ActionID /// public string ActionID { get; set; } //[XmlElement(ElementName = "Parameters")] /// /// Gets or sets the Parameters /// public List Parameters { get; set; } } //[XmlRoot(ElementName = "Parameter")] /// /// Represents a Parameter /// public class Parameter { //[XmlAttribute(AttributeName = "ID")] /// /// Gets or sets the ID /// public string ID { get; set; } //[XmlAttribute(AttributeName = "Value")] /// /// Gets or sets the Value /// public string Value { get; set; } } ////[XmlRoot(ElementName = "Parameters")] //public class Parameters //{ // //[XmlElement(ElementName = "Parameter")] // public List Parameter { get; set; } //} /// /// Data structure for a ScheduleResponse from Fusion /// /// //[XmlRoot(ElementName = "ScheduleResponse")] public class ScheduleResponse { //[XmlElement(ElementName = "RequestID")] /// /// Gets or sets the RequestID /// public string RequestID { get; set; } //[XmlElement(ElementName = "RoomID")] /// /// Gets or sets the RoomID /// public string RoomID { get; set; } //[XmlElement(ElementName = "RoomName")] /// /// Gets or sets the RoomName /// public string RoomName { get; set; } //[XmlElement("Event")] /// /// Gets or sets the Events /// public List Events { get; set; } /// /// ScheduleResponse constructor /// public ScheduleResponse() { Events = new List(); } } //[XmlRoot(ElementName = "Event")] /// /// Represents a Event /// public class Event { //[XmlElement(ElementName = "MeetingID")] /// /// Gets or sets the MeetingID /// public string MeetingID { get; set; } //[XmlElement(ElementName = "RVMeetingID")] /// /// Gets or sets the RVMeetingID /// public string RVMeetingID { get; set; } //[XmlElement(ElementName = "Recurring")] /// /// Gets or sets the Recurring /// public string Recurring { get; set; } //[XmlElement(ElementName = "InstanceID")] /// /// Gets or sets the InstanceID /// public string InstanceID { get; set; } //[XmlElement(ElementName = "dtStart")] /// /// Gets or sets the dtStart /// public DateTime dtStart { get; set; } //[XmlElement(ElementName = "dtEnd")] /// /// Gets or sets the dtEnd /// public DateTime dtEnd { get; set; } //[XmlElement(ElementName = "Organizer")] /// /// Gets or sets the Organizer /// public string Organizer { get; set; } //[XmlElement(ElementName = "Attendees")] /// /// Gets or sets the Attendees /// public Attendees Attendees { get; set; } //[XmlElement(ElementName = "Resources")] /// /// Gets or sets the Resources /// public Resources Resources { get; set; } //[XmlElement(ElementName = "IsEvent")] /// /// Gets or sets the IsEvent /// public string IsEvent { get; set; } //[XmlElement(ElementName = "IsRoomViewMeeting")] /// /// Gets or sets the IsRoomViewMeeting /// public string IsRoomViewMeeting { get; set; } //[XmlElement(ElementName = "IsPrivate")] /// /// Gets or sets the IsPrivate /// public string IsPrivate { get; set; } //[XmlElement(ElementName = "IsExchangePrivate")] /// /// Gets or sets the IsExchangePrivate /// public string IsExchangePrivate { get; set; } //[XmlElement(ElementName = "MeetingTypes")] /// /// Gets or sets the MeetingTypes /// public MeetingTypes MeetingTypes { get; set; } //[XmlElement(ElementName = "ParticipantCode")] /// /// Gets or sets the ParticipantCode /// public string ParticipantCode { get; set; } //[XmlElement(ElementName = "PhoneNo")] /// /// Gets or sets the PhoneNo /// public string PhoneNo { get; set; } //[XmlElement(ElementName = "WelcomeMsg")] /// /// Gets or sets the WelcomeMsg /// public string WelcomeMsg { get; set; } //[XmlElement(ElementName = "Subject")] /// /// Gets or sets the Subject /// public string Subject { get; set; } //[XmlElement(ElementName = "LiveMeeting")] /// /// Gets or sets the LiveMeeting /// public LiveMeeting LiveMeeting { get; set; } //[XmlElement(ElementName = "ShareDocPath")] /// /// Gets or sets the ShareDocPath /// public string ShareDocPath { get; set; } //[XmlElement(ElementName = "HaveAttendees")] /// /// Gets or sets the HaveAttendees /// public string HaveAttendees { get; set; } //[XmlElement(ElementName = "HaveResources")] /// /// Gets or sets the HaveResources /// public string HaveResources { get; set; } /// /// Gets the duration of the meeting /// public string DurationInMinutes { get { string duration; var timeSpan = dtEnd.Subtract(dtStart); int hours = timeSpan.Hours; double minutes = timeSpan.Minutes; double roundedMinutes = Math.Round(minutes); if (hours > 0) { duration = string.Format("{0} hours {1} minutes", hours, roundedMinutes); } else { duration = string.Format("{0} minutes", roundedMinutes); } return duration; } } /// /// Gets the remaining time in the meeting. Returns null if the meeting is not currently in progress. /// public string RemainingTime { get { var now = DateTime.Now; string remainingTime; if (GetInProgress()) { var timeSpan = dtEnd.Subtract(now); int hours = timeSpan.Hours; double minutes = timeSpan.Minutes; double roundedMinutes = Math.Round(minutes); if (hours > 0) { remainingTime = string.Format("{0} hours {1} minutes", hours, roundedMinutes); } else { remainingTime = string.Format("{0} minutes", roundedMinutes); } return remainingTime; } else return null; } } /// /// Indicates that the meeting is in progress /// public bool isInProgress { get { return GetInProgress(); } } /// /// Determines if the meeting is in progress /// /// Returns true if in progress bool GetInProgress() { var now = DateTime.Now; if (now > dtStart && now < dtEnd) { return true; } else return false; } } //[XmlRoot(ElementName = "Resources")] /// /// Represents a Resources /// public class Resources { //[XmlElement(ElementName = "Rooms")] /// /// Gets or sets the Rooms /// public Rooms Rooms { get; set; } } //[XmlRoot(ElementName = "Rooms")] /// /// Represents a Rooms /// public class Rooms { //[XmlElement(ElementName = "Room")] /// /// Gets or sets the Room /// public List Room { get; set; } } //[XmlRoot(ElementName = "Room")] /// /// Represents a Room /// public class Room { //[XmlElement(ElementName = "Name")] /// /// Gets or sets the Name /// public string Name { get; set; } //[XmlElement(ElementName = "ID")] /// /// Gets or sets the ID /// public string ID { get; set; } //[XmlElement(ElementName = "MPType")] /// /// Gets or sets the MPType /// public string MPType { get; set; } } //[XmlRoot(ElementName = "Attendees")] /// /// Represents a Attendees /// public class Attendees { //[XmlElement(ElementName = "Required")] /// /// Gets or sets the Required /// public Required Required { get; set; } //[XmlElement(ElementName = "Optional")] /// /// Gets or sets the Optional /// public Optional Optional { get; set; } } //[XmlRoot(ElementName = "Required")] /// /// Represents a Required /// public class Required { //[XmlElement(ElementName = "Attendee")] /// /// Gets or sets the Attendee /// public List Attendee { get; set; } } //[XmlRoot(ElementName = "Optional")] /// /// Represents a Optional /// public class Optional { //[XmlElement(ElementName = "Attendee")] /// /// Gets or sets the Attendee /// public List Attendee { get; set; } } //[XmlRoot(ElementName = "MeetingType")] /// /// Represents a MeetingType /// public class MeetingType { //[XmlAttribute(AttributeName = "ID")] /// /// Gets or sets the ID /// public string ID { get; set; } //[XmlAttribute(AttributeName = "Value")] /// /// Gets or sets the Value /// public string Value { get; set; } } //[XmlRoot(ElementName = "MeetingTypes")] /// /// Represents a MeetingTypes /// public class MeetingTypes { //[XmlElement(ElementName = "MeetingType")] /// /// Gets or sets the MeetingType /// public List MeetingType { get; set; } } //[XmlRoot(ElementName = "LiveMeeting")] /// /// Represents a LiveMeeting /// public class LiveMeeting { //[XmlElement(ElementName = "URL")] /// /// Gets or sets the URL /// public string URL { get; set; } //[XmlElement(ElementName = "ID")] /// /// Gets or sets the ID /// public string ID { get; set; } //[XmlElement(ElementName = "Key")] /// /// Gets or sets the Key /// public string Key { get; set; } //[XmlElement(ElementName = "Subject")] /// /// Gets or sets the Subject /// public string Subject { get; set; } } //[XmlRoot(ElementName = "LiveMeetingURL")] /// /// Represents a LiveMeetingURL /// public class LiveMeetingURL { //[XmlElement(ElementName = "LiveMeeting")] /// /// Gets or sets the LiveMeeting /// public LiveMeeting LiveMeeting { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Timers; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronXml; using Crestron.SimplSharp.CrestronXml.Serialization; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.Fusion; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; namespace PepperDash.Essentials.Core.Fusion { /// /// Represents a EssentialsHuddleSpaceFusionSystemControllerBase /// public class IEssentialsRoomFusionController : EssentialsDevice, IOccupancyStatusProvider, IFusionHelpRequest, IHasFeedback { private IEssentialsRoomFusionControllerPropertiesConfig _config; private EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; private const string RemoteOccupancyXml = "Local{0}"; private bool _guidFileExists; private readonly Dictionary _sourceToFeedbackSigs = new Dictionary(); /// /// Gets or sets the CurrentRoomSourceNameSig /// protected StringSigData CurrentRoomSourceNameSig; private readonly FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge(); /// /// Gets or sets the FusionOccSensor /// protected FusionOccupancySensorAsset FusionOccSensor; private readonly FusionRemoteOccupancySensor FusionRemoteOccSensor; /// /// Gets or sets the FusionRoom /// protected FusionRoom FusionRoom; /// /// Gets or sets the FusionStaticAssets /// protected Dictionary FusionStaticAssets; private readonly long PushNotificationTimeout = 5000; private IEssentialsRoom Room; private readonly long SchedulePollInterval = 300000; private Event _currentMeeting; private RoomSchedule _currentSchedule; private CTimer _dailyTimeRequestTimer; private StatusMonitorCollection _errorMessageRollUp; private FusionRoomGuids _guids; private bool _isRegisteredForSchedulePushNotifications; private Event _nextMeeting; private CTimer _pollTimer; private CTimer _pushNotificationTimer; private string _roomOccupancyRemoteString; private bool _helpRequestSent; private eFusionHelpResponse _helpRequestStatus; /// public StringFeedback HelpRequestResponseFeedback { get; private set; } /// public BoolFeedback HelpRequestSentFeedback { get; private set; } /// public StringFeedback HelpRequestStatusFeedback { get; private set; } private Timer _helpRequestTimeoutTimer; /// /// Gets the DefaultHelpRequestTimeoutMs /// public int HelpRequestTimeoutMs => _config.HelpRequestTimeoutMs; /// /// Gets whether to use a timer for help requests /// public bool UseHelpRequestTimer => _config.UseTimeoutForHelpRequests; #region Processor Info Sigs private readonly StringSigData[] _program = new StringSigData[10]; private StringSigData _dns1; private StringSigData _dns2; private StringSigData _domain; private StringSigData _firmware; private StringSigData _gateway; private StringSigData _hostname; private StringSigData _ip1; private StringSigData _ip2; private StringSigData _mac1; private StringSigData _mac2; private StringSigData _netMask1; private StringSigData _netMask2; #endregion #region Default Display Source Sigs private readonly BooleanSigData[] _source = new BooleanSigData[10]; #endregion /// /// Constructor /// public IEssentialsRoomFusionController(string key, string name, IEssentialsRoomFusionControllerPropertiesConfig config) : base(key, name) { _config = config; AddPostActivationAction(() => { var room = DeviceManager.GetDeviceForKey(_config.RoomKey); if (room == null) { this.LogError("Error Creating Fusion Room Controller. No room found with key '{0}'", _config.RoomKey); return; } this.LogInformation("Creating Fusion Room Controller for room '{0}' at IPID: {1:X2}", room.Key, _config.IpIdInt); ConstructorHelper(room, _config.IpIdInt, _config.JoinMapKey); }); } /// /// /// /// /// /// public IEssentialsRoomFusionController(IEssentialsRoom room, string ipId, string joinMapKey) : base(room.Key + "-fusion") { _config = new IEssentialsRoomFusionControllerPropertiesConfig() { IpId = ipId, RoomKey = room.Key, JoinMapKey = joinMapKey }; ConstructorHelper(room, _config.IpIdInt, joinMapKey); } private void ConstructorHelper(IEssentialsRoom room, uint ipId, string joinMapKey) { try { this.LogDebug("ConstructorHelper called for Fusion Room Controller for room '{0}' with IPID {1:X2}", room.Key, ipId); this.LogDebug("JoinMap Key: {0}", joinMapKey); JoinMap = new EssentialsHuddleSpaceRoomFusionRoomJoinMap(1); this.LogDebug("JoinMap created"); CrestronConsole.AddNewConsoleCommand((o) => { if (o is string deviceKey) { if (string.IsNullOrEmpty(deviceKey) || deviceKey == "?") { CrestronConsole.ConsoleCommandResponse("Please provide a device key for a Fusion Room instance"); return; } else if (deviceKey != this.Key) { return; } } else { CrestronConsole.ConsoleCommandResponse("Invalid parameter. Please provide a device key for a Fusion Room instance"); return; } JoinMap.PrintJoinMapInfo(); }, "printfusionjoinmap", "Prints Attribute Join Map", ConsoleAccessLevelEnum.AccessOperator); if (!string.IsNullOrEmpty(joinMapKey)) { // this.LogDebug("Attempting to get custom join map for key: {0}", joinMapKey); var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); if (customJoins != null) { JoinMap.SetCustomJoinData(customJoins); } } Room = room; this.LogDebug("Room found: {0}", Room.Key); FusionStaticAssets = new Dictionary(); this.LogDebug("FusionStaticAssets dictionary created"); _guids = new FusionRoomGuids(); this.LogDebug("FusionRoomGuids created"); if (Room is IRoomOccupancy occupancyRoom) { Debug.LogDebug(this, "Room '{0}' supports IRoomOccupancy", Room.Key); if (occupancyRoom.RoomOccupancy != null) { if (occupancyRoom.OccupancyStatusProviderIsRemote) { SetUpRemoteOccupancy(); } else { SetUpLocalOccupancy(); } } } this.LogDebug("Occupancy setup complete"); HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.OutputSig.StringValue); HelpRequestSentFeedback = new BoolFeedback("HelpRequestSent", () => _helpRequestSent); HelpRequestStatusFeedback = new StringFeedback("HelpRequestStatus", () => _helpRequestStatus.ToString()); Feedbacks.Add(HelpRequestResponseFeedback); Feedbacks.Add(HelpRequestSentFeedback); Feedbacks.Add(HelpRequestStatusFeedback); if (RoomOccupancyRemoteStringFeedback != null) Feedbacks.Add(RoomOccupancyRemoteStringFeedback); if (RoomIsOccupiedFeedback != null) Feedbacks.Add(RoomIsOccupiedFeedback); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, this, "Error Building Fusion System Controller: {0}", e); } } private string GetGuidFilePath(uint ipId) { var mac = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); var slot = Global.ControlSystem.ProgramNumber; var guidFilePath = Global.FilePathPrefix + string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _config.IpIdInt); var oldGuidFilePath = Global.FilePathPrefix + string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); if (File.Exists(oldGuidFilePath)) { Debug.LogMessage(LogEventLevel.Information, this, "Migrating from old Fusion GUID file to new Fusion GUID File"); File.Copy(oldGuidFilePath, guidFilePath); File.Delete(oldGuidFilePath); } _guidFileExists = File.Exists(guidFilePath); // Check if file exists if (!_guidFileExists) { // Does not exist. Create GUIDs _guids = new FusionRoomGuids(Room.Name, ipId, _guids.GenerateNewRoomGuid(slot, mac), FusionStaticAssets); } else { // Exists. Read GUIDs ReadGuidFile(guidFilePath); } return guidFilePath; } /// public override void Initialize() { GenerateGuidFile(GetGuidFilePath(_config.IpIdInt)); CreateSymbolAndBasicSigs(_config.IpIdInt); SetUpSources(); SetUpCommunitcationMonitors(); SetUpDisplay(); SetUpError(); ExecuteCustomSteps(); FusionRVI.GenerateFileForAllFusionDevices(); } /// /// Gets the RoomGuid /// protected string RoomGuid { get { return _guids.RoomGuid; } } /// /// Gets or sets the RoomOccupancyRemoteStringFeedback /// public StringFeedback RoomOccupancyRemoteStringFeedback { get; private set; } /// /// Gets the RoomIsOccupiedFeedbackFunc /// protected Func RoomIsOccupiedFeedbackFunc { get { return () => FusionRemoteOccSensor.RoomOccupied.OutputSig.BoolValue; } } #region IOccupancyStatusProvider Members /// /// Gets or sets the RoomIsOccupiedFeedback /// public BoolFeedback RoomIsOccupiedFeedback { get; private set; } #endregion /// public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); /// /// ScheduleChange event /// public event EventHandler ScheduleChange; //public event EventHandler MeetingEndWarning; //public event EventHandler NextMeetingBeginWarning; /// /// RoomInfoChange event /// public event EventHandler RoomInfoChange; //ScheduleResponseEvent NextMeeting; /// /// Used for extension classes to execute whatever steps are necessary before generating the RVI and GUID files /// protected virtual void ExecuteCustomSteps() { } /// /// Generates the guid file in NVRAM. If the file already exists it will be overwritten. /// /// path for the file private void GenerateGuidFile(string filePath) { if (string.IsNullOrEmpty(filePath)) { Debug.LogMessage(LogEventLevel.Information, this, "Error writing guid file. No path specified."); return; } var fileLock = new CCriticalSection(); try { if (fileLock.Disposed) { return; } fileLock.Enter(); Debug.LogMessage(LogEventLevel.Debug, this, "Writing GUIDs to file"); _guids = FusionOccSensor == null ? new FusionRoomGuids(Room.Name, _config.IpIdInt, RoomGuid, FusionStaticAssets) : new FusionRoomGuids(Room.Name, _config.IpIdInt, RoomGuid, FusionStaticAssets, FusionOccSensor); var json = JsonConvert.SerializeObject(_guids, Newtonsoft.Json.Formatting.Indented); using (var sw = new StreamWriter(filePath)) { sw.Write(json); sw.Flush(); } Debug.LogMessage(LogEventLevel.Debug, this, "Guids successfully written to file '{0}'", filePath); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, this, "Error writing guid file: {0}", e); } finally { if (!fileLock.Disposed) { fileLock.Leave(); } } } /// /// Reads the guid file from NVRAM /// /// path for te file private void ReadGuidFile(string filePath) { if (string.IsNullOrEmpty(filePath)) { Debug.LogMessage(LogEventLevel.Information, this, "Error reading guid file. No path specified."); return; } var fileLock = new CCriticalSection(); try { if (fileLock.Disposed) { return; } fileLock.Enter(); if (File.Exists(filePath)) { var json = File.ReadToEnd(filePath, Encoding.ASCII); _guids = JsonConvert.DeserializeObject(json); // _config.IpId = _guids.IpId; FusionStaticAssets = _guids.StaticAssets; } Debug.LogMessage(LogEventLevel.Information, this, "Fusion Guids successfully read from file: {0}", filePath); Debug.LogMessage(LogEventLevel.Debug, this, "\r\n********************\r\n\tRoom Name: {0}\r\n\tIPID: {1:X}\r\n\tRoomGuid: {2}\r\n*******************", Room.Name, _config.IpIdInt, RoomGuid); foreach (var item in FusionStaticAssets) { Debug.LogMessage(LogEventLevel.Debug, this, "\nAsset Name: {0}\nAsset No: {1}\n Guid: {2}", item.Value.Name, item.Value.SlotNumber, item.Value.InstanceId); } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, this, "Error reading guid file: {0}", e); } finally { if (!fileLock.Disposed) { fileLock.Leave(); } } } /// /// CreateSymbolAndBasicSigs method /// /// protected virtual void CreateSymbolAndBasicSigs(uint ipId) { Debug.LogMessage(LogEventLevel.Information, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId); FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use(); FusionRoom.ExtenderFusionRoomDataReservedSigs.Use(); FusionRoom.Register(); FusionRoom.FusionStateChange += FusionRoom_FusionStateChange; FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange += FusionRoomSchedule_DeviceExtenderSigChange; FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange += ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange; FusionRoom.OnlineStatusChange += FusionRoom_OnlineStatusChange; CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(CreateAdHocMeeting, "FusCreateMeeting", "Creates and Ad Hoc meeting for on hour or until the next meeting", ConsoleAccessLevelEnum.AccessOperator); // Room to fusion room Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig); // Moved to CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(JoinMap.Display1CurrentSourceName.JoinNumber, JoinMap.Display1CurrentSourceName.AttributeName, eSigIoMask.InputSigOnly); // Don't think we need to get current status of this as nothing should be alive yet. if (Room is IHasCurrentSourceInfoChange hasCurrentSourceInfoChange) { hasCurrentSourceInfoChange.CurrentSourceChange += Room_CurrentSourceInfoChange; } FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction(Room.PowerOnToDefaultOrLastSource); FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => { if (Room is IRunRouteAction runRouteAction) { runRouteAction.RunRouteAction("roomOff", Room.SourceListKey); } }); // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); FusionRoom.ErrorMessage.InputSig.StringValue = "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; SetUpEthernetValues(); GetProcessorEthernetValues(); GetSystemInfo(); GetProcessorInfo(); CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } /// /// CrestronEnvironment_EthernetEventHandler method /// /// protected void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) { if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp) { GetProcessorEthernetValues(); } } /// /// GetSystemInfo method /// protected void GetSystemInfo() { //SystemName.InputSig.StringValue = Room.Name; //Model.InputSig.StringValue = InitialParametersClass.ControllerPromptName; //SerialNumber.InputSig.StringValue = InitialParametersClass. var response = string.Empty; var systemReboot = FusionRoom.CreateOffsetBoolSig(JoinMap.ProcessorReboot.JoinNumber, JoinMap.ProcessorReboot.AttributeName, eSigIoMask.OutputSigOnly); systemReboot.OutputSig.SetSigFalseAction( () => CrestronConsole.SendControlSystemCommand("reboot", ref response)); } /// /// SetUpEthernetValues method /// protected void SetUpEthernetValues() { _ip1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp1.JoinNumber, JoinMap.ProcessorIp1.AttributeName, eSigIoMask.InputSigOnly); _ip2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp2.JoinNumber, JoinMap.ProcessorIp2.AttributeName, eSigIoMask.InputSigOnly); _gateway = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorGateway.JoinNumber, JoinMap.ProcessorGateway.AttributeName, eSigIoMask.InputSigOnly); _hostname = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorHostname.JoinNumber, JoinMap.ProcessorHostname.AttributeName, eSigIoMask.InputSigOnly); _domain = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDomain.JoinNumber, JoinMap.ProcessorDomain.AttributeName, eSigIoMask.InputSigOnly); _dns1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDns1.JoinNumber, JoinMap.ProcessorDns1.AttributeName, eSigIoMask.InputSigOnly); _dns2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorDns2.JoinNumber, JoinMap.ProcessorDns2.AttributeName, eSigIoMask.InputSigOnly); _mac1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorMac1.JoinNumber, JoinMap.ProcessorMac1.AttributeName, eSigIoMask.InputSigOnly); _mac2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorMac2.JoinNumber, JoinMap.ProcessorMac2.AttributeName, eSigIoMask.InputSigOnly); _netMask1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask1.JoinNumber, JoinMap.ProcessorNetMask1.AttributeName, eSigIoMask.InputSigOnly); _netMask2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask2.JoinNumber, JoinMap.ProcessorNetMask2.AttributeName, eSigIoMask.InputSigOnly); } /// /// GetProcessorEthernetValues method /// protected void GetProcessorEthernetValues() { _ip1.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); _gateway.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); _hostname.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); _domain.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0); var dnsServers = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, 0).Split(','); _dns1.InputSig.StringValue = dnsServers[0]; if (dnsServers.Length > 1) { _dns2.InputSig.StringValue = dnsServers[1]; } _mac1.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); _netMask1.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 0); // Interface 1 if (InitialParametersClass.NumberOfEthernetInterfaces > 1) // Only get these values if the processor has more than 1 NIC { _ip2.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 1); _mac2.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 1); _netMask2.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 1); } } /// /// GetProcessorInfo method /// protected void GetProcessorInfo() { _firmware = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorFirmware.JoinNumber, JoinMap.ProcessorFirmware.AttributeName, eSigIoMask.InputSigOnly); if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) { for (var i = 0; i < Global.ControlSystem.NumProgramsSupported; i++) { var join = JoinMap.ProgramNameStart.JoinNumber + i; var progNum = i + 1; _program[i] = FusionRoom.CreateOffsetStringSig((uint)join, string.Format("{0} {1}", JoinMap.ProgramNameStart.AttributeName, progNum), eSigIoMask.InputSigOnly); } } _firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion; } /// /// GetCustomProperties method /// protected void GetCustomProperties() { if (FusionRoom.IsOnline) { const string fusionRoomCustomPropertiesRequest = @"RoomConfigurationRequest"; FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigQuery.StringValue = fusionRoomCustomPropertiesRequest; } } private void GetTouchpanelInfo() { // TODO: Get IP and Project Name from TP } /// /// FusionRoom_OnlineStatusChange method /// /// /// protected void FusionRoom_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) { if (!args.DeviceOnLine) { return; } if (!_config.EnableSchedulePushNotifications) { return; } Task.Run(() => { // CrestronEnvironment.Sleep(200); // Send Push Notification Action request: const string requestId = "InitialPushRequest"; var actionRequest = string.Format("\n{0}\n", requestId) + "RegisterPushModel\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n"; Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ActionRequest: \n{0}", actionRequest); FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = actionRequest; GetCustomProperties(); // Request current Fusion Server Time RequestLocalDateTime(null); // Setup timer to request time daily if (_dailyTimeRequestTimer != null && !_dailyTimeRequestTimer.Disposed) { _dailyTimeRequestTimer.Stop(); _dailyTimeRequestTimer.Dispose(); } _dailyTimeRequestTimer = new CTimer(RequestLocalDateTime, null, 86400000, 86400000); _dailyTimeRequestTimer.Reset(86400000, 86400000); }); } /// /// Requests the local date and time from the Fusion Server /// /// /// /// RequestLocalDateTime method /// public void RequestLocalDateTime(object callbackObject) { const string timeRequestId = "TimeRequest"; var timeRequest = string.Format("{0}", timeRequestId); FusionRoom.ExtenderFusionRoomDataReservedSigs.LocalDateTimeQuery.StringValue = timeRequest; } /// /// RequestFullRoomSchedule method /// public void RequestFullRoomSchedule(object callbackObject) { var now = DateTime.Today; var currentTime = now.ToString("s"); var requestTest = string.Format( "FullScheduleRequest{0}{1}24", RoomGuid, currentTime); Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ScheduleQuery: \n{0}", requestTest); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleQuery.StringValue = requestTest; if (_isRegisteredForSchedulePushNotifications) { _pushNotificationTimer.Stop(); } } /// /// Wrapper method to allow console commands to modify the current meeting end time /// /// meetingID extendTime /// /// ModifyMeetingEndTimeConsoleHelper method /// public void ModifyMeetingEndTimeConsoleHelper(string command) { var extendMinutes = -1; const string requestId = "ModifyMeetingTest12345"; try { var tokens = command.Split(' '); extendMinutes = Int32.Parse(tokens[1]); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing console command: {0}", e); } ModifyMeetingEndTime(requestId, extendMinutes); } /// /// Ends or Extends the current meeting by the specified number of minutes. /// /// /// Number of minutes to extend the meeting. A value of 0 will end the meeting. /// /// ModifyMeetingEndTime method /// public void ModifyMeetingEndTime(string requestId, int extendMinutes) { if (_currentMeeting == null) { Debug.LogMessage(LogEventLevel.Debug, this, "No meeting in progress. Unable to modify end time."); return; } if (extendMinutes > -1) { if (extendMinutes > 0) { var extendTime = _currentMeeting.dtEnd - DateTime.Now; var extendMinutesRaw = extendTime.TotalMinutes; extendMinutes += (int)Math.Round(extendMinutesRaw); } var requestTest = string.Format( "{0}{1}MeetingChange" , requestId, RoomGuid, _currentMeeting.MeetingID, extendMinutes); Debug.LogMessage(LogEventLevel.Debug, this, "Sending MeetingChange Request: \n{0}", requestTest); FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = requestTest; } else { Debug.LogMessage(LogEventLevel.Debug, this, "Invalid time specified"); } } /// /// CreateAdHocMeeting method /// public void CreateAdHocMeeting(string command) { const string requestId = "CreateAdHocMeeting"; var now = DateTime.Now.AddMinutes(1); now.AddSeconds(-now.Second); // Assume 1 hour meeting if possible var dtEnd = now.AddHours(1); // Check if room is available for 1 hour before next meeting if (_nextMeeting != null) { var roomAvailable = _nextMeeting.dtEnd.Subtract(dtEnd); if (roomAvailable.TotalMinutes < 60) { // Room not available for full hour, book until next meeting starts dtEnd = _nextMeeting.dtEnd; } } var createMeetingRequest = "" + string.Format("{0}", requestId) + string.Format("{0}", RoomGuid) + "" + string.Format("{0}", now.ToString("s")) + string.Format("{0}", dtEnd.ToString("s")) + "AdHoc Meeting" + "Room User" + "Example Message" + "" + ""; Debug.LogMessage(LogEventLevel.Verbose, this, "Sending CreateMeeting Request: \n{0}", createMeetingRequest); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = createMeetingRequest; //Debug.LogMessage(LogEventLevel.Debug, this, "Sending CreateMeeting Request: \n{0}", command); //FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = command; } /// /// Event handler method for Device Extender sig changes /// /// /// protected void ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) { Debug.LogMessage(LogEventLevel.Verbose, this, "Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue); if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQueryResponse) { try { var message = new XmlDocument(); message.LoadXml(args.Sig.StringValue); var actionResponse = message["ActionResponse"]; if (actionResponse == null) { return; } var requestId = actionResponse["RequestID"]; if (requestId.InnerText != "InitialPushRequest") { return; } if (actionResponse["ActionID"].InnerText != "RegisterPushModel") { return; } var parameters = actionResponse["Parameters"]; foreach (var isRegistered in from XmlElement parameter in parameters where parameter.HasAttributes select parameter.Attributes into attributes where attributes["ID"].Value == "Registered" select int.Parse(attributes["Value"].Value)) { switch (isRegistered) { case 1: _isRegisteredForSchedulePushNotifications = true; if (_pollTimer != null && !_pollTimer.Disposed) { _pollTimer.Stop(); _pollTimer.Dispose(); } _pushNotificationTimer = new CTimer(RequestFullRoomSchedule, null, PushNotificationTimeout, PushNotificationTimeout); _pushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); break; case 0: _isRegisteredForSchedulePushNotifications = false; if (_pushNotificationTimer != null && !_pushNotificationTimer.Disposed) { _pushNotificationTimer.Stop(); _pushNotificationTimer.Dispose(); } _pollTimer = new CTimer(RequestFullRoomSchedule, null, SchedulePollInterval, SchedulePollInterval); _pollTimer.Reset(SchedulePollInterval, SchedulePollInterval); break; } } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing ActionQueryResponse: {0}", e); } } else if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.LocalDateTimeQueryResponse) { try { var message = new XmlDocument(); message.LoadXml(args.Sig.StringValue); var localDateTimeResponse = message["LocalTimeResponse"]; if (localDateTimeResponse != null) { var localDateTime = localDateTimeResponse["LocalDateTime"]; if (localDateTime != null) { var tempLocalDateTime = localDateTime.InnerText; var currentTime = DateTime.Parse(tempLocalDateTime); Debug.LogMessage(LogEventLevel.Debug, this, "DateTime from Fusion Server: {0}", currentTime); // Parse time and date from response and insert values CrestronEnvironment.SetTimeAndDate((ushort)currentTime.Hour, (ushort)currentTime.Minute, (ushort)currentTime.Second, (ushort)currentTime.Month, (ushort)currentTime.Day, (ushort)currentTime.Year); Debug.LogMessage(LogEventLevel.Debug, this, "Processor time set to {0}", CrestronEnvironment.GetLocalTime()); } } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing LocalDateTimeQueryResponse: {0}", e); } } else if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigResponse) { // Room info response with custom properties var roomConfigResponseArgs = args.Sig.StringValue.Replace("&", "and"); Debug.LogMessage(LogEventLevel.Verbose, this, "Fusion Response: \n {0}", roomConfigResponseArgs); try { var roomConfigResponse = new XmlDocument(); roomConfigResponse.LoadXml(roomConfigResponseArgs); var requestRoomConfiguration = roomConfigResponse["RoomConfigurationResponse"]; if (requestRoomConfiguration != null) { var roomInformation = new RoomInformation(); foreach (XmlElement e in roomConfigResponse.FirstChild.ChildNodes) { if (e.Name == "RoomInformation") { var roomInfo = new XmlReader(e.OuterXml); roomInformation = CrestronXMLSerialization.DeSerializeObject(roomInfo); } else if (e.Name == "CustomFields") { foreach (XmlElement el in e) { var customProperty = new FusionCustomProperty(); if (el.Name == "CustomField") { customProperty.ID = el.Attributes["ID"].Value; } foreach (XmlElement elm in el) { if (elm.Name == "CustomFieldName") { customProperty.CustomFieldName = elm.InnerText; } if (elm.Name == "CustomFieldType") { customProperty.CustomFieldType = elm.InnerText; } if (elm.Name == "CustomFieldValue") { customProperty.CustomFieldValue = elm.InnerText; } } roomInformation.FusionCustomProperties.Add(customProperty); } } } RoomInfoChange?.Invoke(this, new EventArgs()); CustomPropertiesBridge.EvaluateRoomInfo(Room, roomInformation, _config.UseFusionRoomName); } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing Custom Properties response: {0}", e); } //PrintRoomInfo(); //getRoomInfoBusy = false; //_DynFusion.API.EISC.BooleanInput[Constants.GetRoomInfo].BoolValue = getRoomInfoBusy; } } /// /// Event handler method for Device Extender sig changes /// /// /// protected void FusionRoomSchedule_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) { Debug.LogMessage(LogEventLevel.Verbose, this, "Schedule Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue); if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleResponse) { try { var scheduleResponse = new ScheduleResponse(); var message = new XmlDocument(); message.LoadXml(args.Sig.StringValue); var response = message["ScheduleResponse"]; if (response != null) { // Check for push notification if (response["RequestID"].InnerText == "RVRequest") { var action = response["Action"]; if (action.OuterXml.IndexOf("RequestSchedule", StringComparison.Ordinal) > -1) { _pushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); } } else // Not a push notification { _currentSchedule = new RoomSchedule(); // Clear Current Schedule _currentMeeting = null; // Clear Current Meeting _nextMeeting = null; // Clear Next Meeting var isNextMeeting = false; foreach (XmlElement element in message.FirstChild.ChildNodes) { if (element.Name == "RequestID") { scheduleResponse.RequestID = element.InnerText; } else if (element.Name == "RoomID") { scheduleResponse.RoomID = element.InnerText; } else if (element.Name == "RoomName") { scheduleResponse.RoomName = element.InnerText; } else if (element.Name == "Event") { Debug.LogMessage(LogEventLevel.Verbose, this, "Event Found:\n{0}", element.OuterXml); var reader = new XmlReader(element.OuterXml); var tempEvent = CrestronXMLSerialization.DeSerializeObject(reader); scheduleResponse.Events.Add(tempEvent); // Check is this is the current event if (tempEvent.dtStart <= DateTime.Now && tempEvent.dtEnd >= DateTime.Now) { _currentMeeting = tempEvent; // Set Current Meeting isNextMeeting = true; // Flag that next element is next meeting } if (isNextMeeting) { _nextMeeting = tempEvent; // Set Next Meeting isNextMeeting = false; } _currentSchedule.Meetings.Add(tempEvent); } } PrintTodaysSchedule(); if (!_isRegisteredForSchedulePushNotifications) { _pollTimer.Reset(SchedulePollInterval, SchedulePollInterval); } // Fire Schedule Change Event ScheduleChange?.Invoke(this, new ScheduleChangeEventArgs { Schedule = _currentSchedule }); } } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Error parsing ScheduleResponse: {0}", e); } } else if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateResponse) { Debug.LogMessage(LogEventLevel.Verbose, this, "Create Meeting Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue); } } /// /// Prints today's schedule to console for debugging /// private void PrintTodaysSchedule() { if (Debug.Level > 1) { if (_currentSchedule.Meetings.Count > 0) { Debug.LogMessage(LogEventLevel.Debug, this, "Today's Schedule for '{0}'\n", Room.Name); foreach (var e in _currentSchedule.Meetings) { Debug.LogMessage(LogEventLevel.Debug, this, "Subject: {0}", e.Subject); Debug.LogMessage(LogEventLevel.Debug, this, "Organizer: {0}", e.Organizer); Debug.LogMessage(LogEventLevel.Debug, this, "MeetingID: {0}", e.MeetingID); Debug.LogMessage(LogEventLevel.Debug, this, "Start Time: {0}", e.dtStart); Debug.LogMessage(LogEventLevel.Debug, this, "End Time: {0}", e.dtEnd); Debug.LogMessage(LogEventLevel.Debug, this, "Duration: {0}\n", e.DurationInMinutes); } } } } /// /// SetUpSources method /// protected virtual void SetUpSources() { // Sources var dict = ConfigReader.ConfigObject.GetSourceListForKey(Room.SourceListKey); if (dict != null) { // NEW PROCESS: // Make these lists and insert the fusion attributes by iterating these var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls); uint i = 0; foreach (var kvp in setTopBoxes) { TryAddRouteActionSigs(JoinMap.Display1SetTopBoxSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1SetTopBoxSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); i++; if (i > JoinMap.Display1SetTopBoxSourceStart.JoinSpan) // We only have five spots { break; } } var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls); i = 0; foreach (var kvp in discPlayers) { TryAddRouteActionSigs(JoinMap.Display1DiscPlayerSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1DiscPlayerSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); i++; if (i > JoinMap.Display1DiscPlayerSourceStart.JoinSpan) // We only have five spots { break; } } var laptops = dict.Where(d => d.Value.SourceDevice is IRoutingSource); i = 0; foreach (var kvp in laptops) { TryAddRouteActionSigs(JoinMap.Display1LaptopSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1LaptopSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); i++; if (i > JoinMap.Display1LaptopSourceStart.JoinSpan) // We only have ten spots??? { break; } } foreach (var usageDevice in dict.Select(kvp => kvp.Value.SourceDevice).OfType()) { usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) { UsageIsTracked = true }; usageDevice.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; } } else { Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Config source list '{0}' not found for room '{1}'", Room.SourceListKey, Room.Key); } } /// /// Collects usage data from source and sends to Fusion /// /// /// protected void UsageTracker_DeviceUsageEnded(object sender, DeviceUsageEventArgs e) { if (!(sender is UsageTracking deviceTracker)) { return; } var group = ConfigReader.GetGroupForDeviceKey(deviceTracker.Parent.Key); var currentMeetingId = "-"; if (_currentMeeting != null) { currentMeetingId = _currentMeeting.MeetingID; } //String Format: "USAGE||[Date YYYY-MM-DD]||[Time HH-mm-ss]||TIME||[Asset_Type]||[Asset_Name]||[Minutes_used]||[Asset_ID]||[Meeting_ID]" // [Asset_ID] property does not appear to be used in Crestron SSI examples. They are sending "-" instead so that's what is replicated here var deviceUsage = string.Format("USAGE||{0}||{1}||TIME||{2}||{3}||-||{4}||-||{5}||{6}||\r\n", e.UsageEndTime.ToString("yyyy-MM-dd"), e.UsageEndTime.ToString("HH:mm:ss"), @group, deviceTracker.Parent.Name, e.MinutesUsed, "-", currentMeetingId); Debug.LogMessage(LogEventLevel.Debug, this, "Device usage for: {0} ended at {1}. In use for {2} minutes", deviceTracker.Parent.Name, e.UsageEndTime, e.MinutesUsed); FusionRoom.DeviceUsage.InputSig.StringValue = deviceUsage; Debug.LogMessage(LogEventLevel.Debug, this, "Device usage string: {0}", deviceUsage); } /// /// Tries to add route action sigs for a source /// /// /// /// /// protected void TryAddRouteActionSigs(string attrName, uint attrNum, string routeKey, Device pSrc) { this.LogVerbose("Creating attribute '{0}' with join {1} for source {2}", attrName, attrNum, pSrc.Key); try { var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputOutputSig); // Need feedback when this source is selected // Event handler, added below, will compare source changes with this sig dict if (!_sourceToFeedbackSigs.ContainsKey(pSrc)) { _sourceToFeedbackSigs.Add(pSrc, sigD.InputSig); } else { this.LogWarning("Source '{0}' already has a feedback sig mapped. Overwriting.", pSrc.Key); _sourceToFeedbackSigs[pSrc] = sigD.InputSig; } // And respond to selection in Fusion sigD.OutputSig.SetSigFalseAction(() => { if (Room is IRunRouteAction runRouteAction) { runRouteAction.RunRouteAction(routeKey, Room.SourceListKey); } }); } catch (Exception) { this.LogVerbose("Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING", attrNum, attrName, pSrc.Key); } } private void SetUpCommunitcationMonitors() { uint displayNum = 0; uint touchpanelNum = 0; uint xpanelNum = 0; // Attach to all room's devices with monitors. //foreach (var dev in DeviceManager.Devices) foreach (var dev in DeviceManager.GetDevices()) { if (!(dev is ICommunicationMonitor)) { continue; } string attrName = null; uint attrNum = 1; //var keyNum = ExtractNumberFromKey(dev.Key); //if (keyNum == -1) //{ // Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Cannot link device '{0}' to numbered Fusion monitoring attributes", // dev.Key); // continue; //} //uint attrNum = Convert.ToUInt32(keyNum); // Check for UI devices if (dev is IHasBasicTriListWithSmartObject uiDev) { if (uiDev.Panel is Crestron.SimplSharpPro.UI.XpanelForSmartGraphics) { attrNum += touchpanelNum; if (attrNum > JoinMap.XpanelOnlineStart.JoinSpan) { continue; } attrName = JoinMap.XpanelOnlineStart.AttributeName + " " + attrNum; attrNum += JoinMap.XpanelOnlineStart.JoinNumber; touchpanelNum++; } else { attrNum += xpanelNum; if (attrNum > JoinMap.TouchpanelOnlineStart.JoinSpan) { continue; } attrName = JoinMap.TouchpanelOnlineStart.AttributeName + " " + attrNum; attrNum += JoinMap.TouchpanelOnlineStart.JoinNumber; xpanelNum++; } } //else if (dev is IDisplay) { attrNum += displayNum; if (attrNum > JoinMap.DisplayOnlineStart.JoinSpan) { continue; } attrName = JoinMap.DisplayOnlineStart.AttributeName + " " + attrNum; attrNum += JoinMap.DisplayOnlineStart.JoinNumber; displayNum++; } //else if (dev is DvdDeviceBase) //{ // if (attrNum > 5) // continue; // attrName = "Device Ok - DVD " + attrNum; // attrNum += 260; //} // add set top box // add Cresnet roll-up // add DM-devices roll-up if (attrName != null) { this.LogDebug("Linking communication monitor for device '{0}' to Fusion attribute '{1}' at join {2}", dev.Key, attrName, attrNum); // Link comm status to sig and update var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly); var smd = dev as ICommunicationMonitor; sigD.InputSig.BoolValue = smd.CommunicationMonitor.Status == MonitorStatus.IsOk; smd.CommunicationMonitor.StatusChange += (o, a) => { sigD.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; }; Debug.LogMessage(LogEventLevel.Information, this, "Linking '{0}' communication monitor to Fusion '{1}'", dev.Key, attrName); } } } /// /// SetUpDisplay method /// protected virtual void SetUpDisplay() { try { //Setup Display Usage Monitoring var displays = DeviceManager.AllDevices.Where(d => d is IDisplay); // Consider updating this in multiple display systems foreach (var display in displays.Cast()) { display.UsageTracker = new UsageTracking(display as Device) { UsageIsTracked = true }; display.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; } if (!(Room is IHasDefaultDisplay hasDefaultDisplay)) { return; } if (!(hasDefaultDisplay.DefaultDisplay is IDisplay defaultDisplay)) { Debug.LogMessage(LogEventLevel.Debug, this, "Cannot link null display to Fusion because default display is null"); return; } var dispPowerOnAction = new Action(b => { if (!b) { defaultDisplay.PowerOn(); } }); var dispPowerOffAction = new Action(b => { if (!b) { defaultDisplay.PowerOff(); } }); // Display to fusion room sigs FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction; FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction; MapDisplayToRoomJoins(1, JoinMap.Display1Start.JoinNumber, defaultDisplay); var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); //Check for existing asset in GUIDs collection FusionAsset tempAsset; if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) { tempAsset = FusionStaticAssets[deviceConfig.Uid]; } else { // Create a new asset tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), defaultDisplay.Name, "Display", ""); FusionStaticAssets.Add(deviceConfig.Uid, tempAsset); } var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId); dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; if (defaultDisplay is IHasPowerControlWithFeedback defaultTwoWayDisplay) { defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig); if (defaultDisplay is IDisplayUsage) { (defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig); } defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig); } // Use extension methods dispAsset.TrySetMakeModel(defaultDisplay as Device); dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay as Device); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Error setting up display in Fusion: {0}", e); } } /// /// Maps room attributes to a display at a specified index /// /// /// /// /// a protected virtual void MapDisplayToRoomJoins(int displayIndex, uint joinOffset, IDisplay display) { var displayName = string.Format("Display {0} - ", displayIndex); if (!(Room is IHasDefaultDisplay hasDefaultDisplay) || display != hasDefaultDisplay.DefaultDisplay) { return; } // Display volume var defaultDisplayVolume = FusionRoom.CreateOffsetUshortSig(JoinMap.VolumeFader1.JoinNumber, JoinMap.VolumeFader1.AttributeName, eSigIoMask.InputOutputSig); defaultDisplayVolume.OutputSig.UserObject = new Action(b => { if (!(display is IBasicVolumeWithFeedback basicVolumeWithFeedback)) { return; } basicVolumeWithFeedback.SetVolume(b); basicVolumeWithFeedback.VolumeLevelFeedback.LinkInputSig(defaultDisplayVolume.InputSig); }); // Power on var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig); defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => { if (!b) { display.PowerOn(); } }); // Power Off var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 1, displayName + "Power Off", eSigIoMask.InputOutputSig); defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => { if (!b) { display.PowerOff(); } }); if (display is IHasPowerControlWithFeedback defaultTwoWayDisplay) { defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); defaultTwoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(defaultDisplayPowerOff.InputSig); } // Current Source var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig); defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) { if (Room is IRunRouteAction runRouteAction) { runRouteAction.RunRouteAction("roomOff", Room.SourceListKey); } } }); } private void SetUpError() { // Roll up ALL device errors _errorMessageRollUp = new StatusMonitorCollection(this); foreach (var dev in DeviceManager.GetDevices()) { if (dev is ICommunicationMonitor md) { _errorMessageRollUp.AddMonitor(md.CommunicationMonitor); Debug.LogMessage(LogEventLevel.Verbose, this, "Adding '{0}' to room's overall error monitor", md.CommunicationMonitor.Parent.Key); } } _errorMessageRollUp.Start(); FusionRoom.ErrorMessage.InputSig.StringValue = _errorMessageRollUp.Message; _errorMessageRollUp.StatusChange += (o, a) => { FusionRoom.ErrorMessage.InputSig.StringValue = _errorMessageRollUp.Message; }; } /// /// Sets up a local occupancy sensor, such as one attached to a Fusion Scheduling panel. The occupancy status of the room will be read from Fusion /// private void SetUpLocalOccupancy() { RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc); FusionRoom.FusionAssetStateChange += FusionRoom_FusionAssetStateChange; // Build Occupancy Asset? // Link sigs? //Room.SetRoomOccupancy(this as IOccupancyStatusProvider, 0); } private void FusionRoom_FusionAssetStateChange(FusionBase device, FusionAssetStateEventArgs args) { if (args.EventId == FusionAssetEventId.RoomOccupiedReceivedEventId || args.EventId == FusionAssetEventId.RoomUnoccupiedReceivedEventId) { RoomIsOccupiedFeedback.FireUpdate(); } } /// /// Sets up remote occupancy that will relay the occupancy status determined by local system devices to Fusion /// private void SetUpRemoteOccupancy() { // Need to have the room occupancy object first and somehow determine the slot number of the Occupancy asset but will not be able to use the UID from config likely. // Consider defining an object just for Room Occupancy (either eAssetType.Occupancy Sensor (local) or eAssetType.RemoteOccupancySensor (from Fusion sched. panel)) and reserving slot 4 for that asset (statics would start at 5) //if (Room.OccupancyObj != null) //{ var tempOccAsset = _guids.OccupancyAsset; if (tempOccAsset == null) { FusionOccSensor = new FusionOccupancySensorAsset(eAssetType.OccupancySensor); tempOccAsset = FusionOccSensor; } var occSensorAsset = FusionRoom.CreateOccupancySensorAsset(tempOccAsset.SlotNumber, tempOccAsset.Name, "Occupancy Sensor", tempOccAsset.InstanceId); occSensorAsset.RoomOccupied.AddSigToRVIFile = true; //var occSensorShutdownMinutes = FusionRoom.CreateOffsetUshortSig(70, "Occ Shutdown - Minutes", eSigIoMask.InputOutputSig); // Tie to method on occupancy object //occSensorShutdownMinutes.OutputSig.UserObject(new Action(ushort)(b => Room.OccupancyObj.SetShutdownMinutes(b)); if (Room is IRoomOccupancy occRoom) { occRoom.RoomOccupancy.RoomIsOccupiedFeedback.LinkInputSig(occSensorAsset.RoomOccupied.InputSig); occRoom.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; } RoomOccupancyRemoteStringFeedback = new StringFeedback(() => _roomOccupancyRemoteString); RoomOccupancyRemoteStringFeedback.LinkInputSig(occSensorAsset.RoomOccupancyInfo.InputSig); //} } private void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) { _roomOccupancyRemoteString = String.Format(RemoteOccupancyXml, e.BoolValue ? "Occupied" : "Unoccupied"); RoomOccupancyRemoteStringFeedback.FireUpdate(); } /// /// Helper to get the number from the end of a device's key string /// /// -1 if no number matched private int ExtractNumberFromKey(string key) { var capture = System.Text.RegularExpressions.Regex.Match(key, @"\b(\d+)"); if (!capture.Success) { return -1; } return Convert.ToInt32(capture.Groups[1].Value); } /// /// Event handler for when room source changes /// protected void Room_CurrentSourceInfoChange(SourceListItem info, ChangeType type) { // Handle null. Nothing to do when switching from or to null if (info == null || info.SourceDevice == null) { return; } var dev = info.SourceDevice; if (type == ChangeType.WillChange) { if (_sourceToFeedbackSigs.ContainsKey(dev)) { _sourceToFeedbackSigs[dev].BoolValue = false; } } else { if (_sourceToFeedbackSigs.ContainsKey(dev)) { _sourceToFeedbackSigs[dev].BoolValue = true; } //var name = (room == null ? "" : room.Name); CurrentRoomSourceNameSig.InputSig.StringValue = info.SourceDevice.Name; } } /// /// Event handler for Fusion state changes /// /// /// protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args) { if (args.EventId == FusionEventIds.HelpMessageReceivedEventId) { this.LogInformation("Help message received from Fusion for room '{0}'", Room.Name); this.LogDebug("Help message content: {0}", FusionRoom.Help.OutputSig.StringValue); // Fire help request event HelpRequestResponseFeedback.FireUpdate(); if (!string.IsNullOrEmpty(FusionRoom.Help.OutputSig.StringValue)) { switch (FusionRoom.Help.OutputSig.StringValue) { case "Please wait, a technician is on his / her way.": // this.LogInformation("Please wait, a technician is on his / her way.", // Room.Name); _helpRequestStatus = eFusionHelpResponse.HelpOnTheWay; break; case "Please call the helpdesk.": // this.LogInformation("Please call the helpdesk."); _helpRequestStatus = eFusionHelpResponse.CallHelpDesk; break; case "Please wait, I will reschedule your meeting to a different room.": // this.LogInformation("Please wait, I will reschedule your meeting to a different room.", // Room.Name); _helpRequestStatus = eFusionHelpResponse.ReschedulingMeeting; break; case "I will be taking control of your system. Please be patient while I adjust the settings.": // this.LogInformation("I will be taking control of your system. Please be patient while I adjust the settings.", // Room.Name); _helpRequestStatus = eFusionHelpResponse.TakingControl; break; default: // this.LogInformation("Unknown help request code received from Fusion for room '{0}'", // Room.Name); _helpRequestStatus = eFusionHelpResponse.None; break; } } else { _helpRequestStatus = eFusionHelpResponse.None; } if (_helpRequestStatus == eFusionHelpResponse.None) { _helpRequestSent = false; HelpRequestSentFeedback.FireUpdate(); } HelpRequestStatusFeedback.FireUpdate(); if (_helpRequestTimeoutTimer != null) { _helpRequestTimeoutTimer.Stop(); _helpRequestTimeoutTimer.Elapsed -= OnTimedEvent; _helpRequestTimeoutTimer.Dispose(); _helpRequestTimeoutTimer = null; } } // The sig/UO method: Need separate handlers for fixed and user sigs, all flavors, // even though they all contain sigs. BoolOutputSig outSig; if (args.UserConfiguredSigDetail is BooleanSigDataFixedName sigData) { outSig = sigData.OutputSig; if (outSig.UserObject is Action) { (outSig.UserObject as Action).Invoke(outSig.BoolValue); } else if (outSig.UserObject is Action) { (outSig.UserObject as Action).Invoke(outSig.UShortValue); } else if (outSig.UserObject is Action) { (outSig.UserObject as Action).Invoke(outSig.StringValue); } return; } var attrData = (args.UserConfiguredSigDetail as BooleanSigData); if (attrData == null) { return; } outSig = attrData.OutputSig; if (outSig.UserObject is Action) { (outSig.UserObject as Action).Invoke(outSig.BoolValue); } else if (outSig.UserObject is Action) { (outSig.UserObject as Action).Invoke(outSig.UShortValue); } else if (outSig.UserObject is Action) { (outSig.UserObject as Action).Invoke(outSig.StringValue); } } /// public void SendHelpRequest() { var now = DateTime.Now; var breakString = _config.UseHtmlFormatForHelpRequests ? "
" : "\r\n"; var date = now.ToString("MMMM dd, yyyy"); var time = now.ToString("hh:mm tt"); if (_config.Use24HourTimeFormat) { time = now.ToString("HH:mm"); } var requestString = $"HR00: {breakString} Assistance has been requested from room {Room.Name}{breakString}on {date} at {time}"; FusionRoom.Help.InputSig.StringValue = requestString; this.LogInformation("Help request sent to Fusion from room '{0}'", Room.Name); this.LogDebug("Help request content: {0}", FusionRoom.Help.InputSig.StringValue); _helpRequestSent = true; HelpRequestSentFeedback.FireUpdate(); if (UseHelpRequestTimer) { if (_helpRequestTimeoutTimer == null) { _helpRequestTimeoutTimer = new Timer(HelpRequestTimeoutMs); _helpRequestTimeoutTimer.AutoReset = false; _helpRequestTimeoutTimer.Enabled = true; _helpRequestTimeoutTimer.Elapsed += OnTimedEvent; } _helpRequestTimeoutTimer.Interval = HelpRequestTimeoutMs; _helpRequestTimeoutTimer.Start(); this.LogDebug("Help request timeout timer started for room '{0}' with timeout of {1} ms.", Room.Name, HelpRequestTimeoutMs); } _helpRequestStatus = eFusionHelpResponse.HelpRequested; HelpRequestStatusFeedback.FireUpdate(); } private void OnTimedEvent(object source, ElapsedEventArgs e) { this.LogInformation("Help request timeout reached for room '{0}'. Cancelling help request.", Room.Name); CancelHelpRequest(); } /// public void CancelHelpRequest() { if (_helpRequestSent) { FusionRoom.Help.InputSig.StringValue = ""; _helpRequestSent = false; HelpRequestSentFeedback.FireUpdate(); _helpRequestStatus = eFusionHelpResponse.None; HelpRequestStatusFeedback.FireUpdate(); Debug.LogMessage(LogEventLevel.Information, this, "Help request cancelled for room '{0}'", Room.Name); } if (_helpRequestTimeoutTimer != null) { _helpRequestTimeoutTimer.Stop(); _helpRequestTimeoutTimer.Elapsed -= OnTimedEvent; _helpRequestTimeoutTimer.Dispose(); _helpRequestTimeoutTimer = null; this.LogDebug("Help request timeout timer stopped for room '{0}'.", Room.Name); } } /// public void ToggleHelpRequest() { if (_helpRequestSent) { CancelHelpRequest(); } else { SendHelpRequest(); } } } /// /// Extensions to enhance Fusion room, asset and signal creation. /// public static class FusionRoomExtensions { /// /// Creates and returns a fusion attribute. The join number will match the established Simpl /// standard of 50+, and will generate a 50+ join in the RVI. It calls /// FusionRoom.AddSig with join number - 49 /// /// The new attribute /// /// CreateOffsetBoolSig method /// public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) { Debug.LogDebug("Creating Offset Bool Sig: {0} at Join {1}", name, number); if (number < 50) { throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); } number -= 49; fr.AddSig(eSigType.Bool, number, name, mask); return fr.UserDefinedBooleanSigDetails[number]; } /// /// Creates and returns a fusion attribute. The join number will match the established Simpl /// standard of 50+, and will generate a 50+ join in the RVI. It calls /// FusionRoom.AddSig with join number - 49 /// /// The new attribute /// /// CreateOffsetUshortSig method /// public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) { Debug.LogDebug("Creating Offset UShort Sig: {0} at Join {1}", name, number); if (number < 50) { throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); } number -= 49; fr.AddSig(eSigType.UShort, number, name, mask); return fr.UserDefinedUShortSigDetails[number]; } /// /// Creates and returns a fusion attribute. The join number will match the established Simpl /// standard of 50+, and will generate a 50+ join in the RVI. It calls /// FusionRoom.AddSig with join number - 49 /// /// The new attribute /// /// CreateOffsetStringSig method /// public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) { Debug.LogDebug("Creating Offset String Sig: {0} at Join {1}", name, number); if (number < 50) { throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); } number -= 49; fr.AddSig(eSigType.String, number, name, mask); return fr.UserDefinedStringSigDetails[number]; } /// /// Creates and returns a static asset /// /// the new asset /// /// CreateStaticAsset method /// public static FusionStaticAsset CreateStaticAsset(this FusionRoom fr, uint number, string name, string type, string instanceId) { try { Debug.LogMessage(LogEventLevel.Information, "Adding Fusion Static Asset '{0}' to slot {1} with GUID: '{2}'", name, number, instanceId); fr.AddAsset(eAssetType.StaticAsset, number, name, type, instanceId); return fr.UserConfigurableAssetDetails[number].Asset as FusionStaticAsset; } catch (InvalidOperationException ex) { Debug.LogMessage(LogEventLevel.Information, "Error creating Static Asset for device: '{0}'. Check that multiple devices don't have missing or duplicate uid properties in configuration. /r/nError: {1}", name, ex); return null; } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, "Error creating Static Asset: {0}", e); return null; } } /// /// CreateOccupancySensorAsset method /// public static FusionOccupancySensor CreateOccupancySensorAsset(this FusionRoom fr, uint number, string name, string type, string instanceId) { try { Debug.LogMessage(LogEventLevel.Information, "Adding Fusion Occupancy Sensor Asset '{0}' to slot {1} with GUID: '{2}'", name, number, instanceId); fr.AddAsset(eAssetType.OccupancySensor, number, name, type, instanceId); return fr.UserConfigurableAssetDetails[number].Asset as FusionOccupancySensor; } catch (InvalidOperationException ex) { Debug.LogMessage(LogEventLevel.Information, "Error creating Static Asset for device: '{0}'. Check that multiple devices don't have missing or duplicate uid properties in configuration. Error: {1}", name, ex); return null; } catch (Exception e) { Debug.LogMessage(LogEventLevel.Error, "Error creating Static Asset: {0}", e); return null; } } } //************************************************************************************************ /// /// Extensions to enhance Fusion room, asset and signal creation. /// public static class FusionStaticAssetExtensions { /// /// Tries to set a Fusion asset with the make and model of a device. /// If the provided Device is IMakeModel, will set the corresponding parameters on the fusion static asset. /// Otherwise, does nothing. /// public static void TrySetMakeModel(this FusionStaticAsset asset, Device device) { if (device is IMakeModel mm) { asset.ParamMake.Value = mm.DeviceMake; asset.ParamModel.Value = mm.DeviceModel; } } /// /// Tries to attach the AssetError input on a Fusion asset to a Device's /// CommunicationMonitor.StatusChange event. Does nothing if the device is not /// IStatusMonitor /// /// /// public static void TryLinkAssetErrorToCommunication(this FusionStaticAsset asset, Device device) { if (device is ICommunicationMonitor) { var monitor = (device as ICommunicationMonitor).CommunicationMonitor; monitor.StatusChange += (o, a) => { // Link connected and error inputs on asset asset.Connected.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; asset.AssetError.InputSig.StringValue = a.Status.ToString(); }; // set current value asset.Connected.InputSig.BoolValue = monitor.Status == MonitorStatus.IsOk; asset.AssetError.InputSig.StringValue = monitor.Status.ToString(); } } } /// /// Represents a RoomInformation /// public class RoomInformation { /// /// Constructor /// public RoomInformation() { FusionCustomProperties = new List(); } /// /// Gets or sets the ID /// public string ID { get; set; } /// /// Gets or sets the Name /// public string Name { get; set; } /// /// Gets or sets the Location /// public string Location { get; set; } /// /// Gets or sets the Description /// public string Description { get; set; } /// /// Gets or sets the TimeZone /// public string TimeZone { get; set; } /// /// Gets or sets the WebcamURL /// public string WebcamURL { get; set; } /// /// Gets or sets the BacklogMsg /// public string BacklogMsg { get; set; } /// /// Gets or sets the SubErrorMsg /// public string SubErrorMsg { get; set; } /// /// Gets or sets the EmailInfo /// public string EmailInfo { get; set; } /// /// Gets or sets the FusionCustomProperties /// public List FusionCustomProperties { get; set; } } /// /// Represents a FusionCustomProperty /// public class FusionCustomProperty { /// /// Constructor /// public FusionCustomProperty() { } /// /// Constructor with id /// /// public FusionCustomProperty(string id) { ID = id; } /// /// Gets or sets the ID /// public string ID { get; set; } /// /// Gets or sets the CustomFieldName /// public string CustomFieldName { get; set; } /// /// Gets or sets the CustomFieldType /// public string CustomFieldType { get; set; } /// /// Gets or sets the CustomFieldValue /// public string CustomFieldValue { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Fusion; /// /// Factory for creating IEssentialsRoomFusionController devices /// public class IEssentialsRoomFusionControllerFactory : EssentialsDeviceFactory { /// /// Constructor /// public IEssentialsRoomFusionControllerFactory() { TypeNames = new List() { "fusionRoom" }; } /// /// Builds the device /// /// /// public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc) { Debug.LogDebug("Factory Attempting to create new IEssentialsRoomFusionController Device"); var properties = dc.Properties.ToObject(); return new IEssentialsRoomFusionController(dc.Key, dc.Name, properties); } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerPropertiesConfig.cs ================================================ using Newtonsoft.Json; using PepperDash.Core; /// /// Config properties for an IEssentialsRoomFusionController device /// public class IEssentialsRoomFusionControllerPropertiesConfig { /// /// Gets or sets the IP ID of the Fusion Room Controller /// [JsonProperty("ipId")] public string IpId { get; set; } /// /// Gets the IP ID as a UInt16 /// [JsonIgnore] public uint IpIdInt { get { // Try to parse the IpId string to UInt16 as hex if (ushort.TryParse(IpId, System.Globalization.NumberStyles.HexNumber, null, out ushort result)) { return result; } else { Debug.LogWarning("Failed to parse IpId '{0}' as UInt16", IpId); return 0; } } } /// /// Gets or sets the join map key /// [JsonProperty("joinMapKey")] public string JoinMapKey { get; set; } /// /// Gets or sets the room key associated with this Fusion Room Controller /// [JsonProperty("roomKey")] public string RoomKey { get; set; } /// /// Gets or sets whether to use the Fusion room name for this room /// /// Defaults to true to preserve current behavior. Set to false to skip updating the room name from Fusion [JsonProperty("useFusionRoomName")] public bool UseFusionRoomName { get; set; } = true; /// /// Gets or sets whether to use HTML format for help requests /// [JsonProperty("useHtmlFormatForHelpRequests")] public bool UseHtmlFormatForHelpRequests { get; set; } = false; /// /// Gets or sets whether to use 24-hour time format /// [JsonProperty("use24HourTimeFormat")] public bool Use24HourTimeFormat { get; set; } = false; /// /// Gets or sets whether to use a timeout for help requests /// [JsonProperty("useTimeoutForHelpRequests")] public bool UseTimeoutForHelpRequests { get; set; } = false; /// /// Gets or sets the timeout duration for help requests in milliseconds /// [JsonProperty("helpRequestTimeoutMs")] public int HelpRequestTimeoutMs { get; set; } = 30000; /// /// Gets or sets whether to enable schedule push notifications /// /// Defaults to false to skip getting schedule unless required [JsonProperty("enableSchedulePushNotifications")] public bool EnableSchedulePushNotifications { get; set; } = false; } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.Fusion { /// /// Represents Fusion Help Request functionality /// public interface IFusionHelpRequest { /// /// Feedback containing the response to a help request /// StringFeedback HelpRequestResponseFeedback { get; } /// /// Indicates whether a help request has been sent /// BoolFeedback HelpRequestSentFeedback { get; } /// /// Feedback containing the current status of the help request /// StringFeedback HelpRequestStatusFeedback { get; } /// /// Sends a help request /// void SendHelpRequest(); /// /// Clears the current help request status /// void CancelHelpRequest(); /// /// Toggles between sending and cancelling a help request /// void ToggleHelpRequest(); } } ================================================ FILE: src/PepperDash.Essentials.Core/Fusion/eFusionHelpResponse.cs ================================================ namespace PepperDash.Essentials.Core.Fusion { /// /// Enumeration of possible Fusion Help Responses based on the standard responses from Fusion /// public enum eFusionHelpResponse { /// /// No help response /// None, /// /// Help has been requested /// HelpRequested, /// /// Help is on the way /// HelpOnTheWay, /// /// Please call the helpdesk. /// CallHelpDesk, /// /// Rescheduling meeting. /// ReschedulingMeeting, /// /// Technician taking control. /// TakingControl, } } ================================================ FILE: src/PepperDash.Essentials.Core/Global/EthernetAdapterInfo.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Represents a EthernetAdapterInfo /// public class EthernetAdapterInfo { /// /// Gets or sets the Type /// public EthernetAdapterType Type { get; set; } /// /// Gets or sets the DhcpIsOn /// public bool DhcpIsOn { get; set; } /// /// Gets or sets the Hostname /// public string Hostname { get; set; } /// /// Gets or sets the MacAddress /// public string MacAddress { get; set; } /// /// Gets or sets the IpAddress /// public string IpAddress { get; set; } /// /// Gets or sets the Subnet /// public string Subnet { get; set; } /// /// Gets or sets the Gateway /// public string Gateway { get; set; } /// /// Gets or sets the Dns1 /// public string Dns1 { get; set; } /// /// Gets or sets the Dns2 /// public string Dns2 { get; set; } /// /// Gets or sets the Dns3 /// public string Dns3 { get; set; } /// /// Gets or sets the Domain /// public string Domain { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Global/Global.cs ================================================  using System; using System.Linq; using System.Text.RegularExpressions; using System.Globalization; using Crestron.SimplSharp; using System.Collections.Generic; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronDataStore; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DM; using PepperDash.Core; using PepperDash.Essentials.License; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Schema; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Global static class for Essentials /// public static class Global { /// /// Gets or sets the ControlSystem /// public static CrestronControlSystem ControlSystem { get; set; } /// /// Gets or sets the Platform /// public static eDevicePlatform Platform { get { return CrestronEnvironment.DevicePlatform; } } /// /// Gets the collection of Ethernet Adapter Info /// public static Dictionary EthernetAdapterInfoCollection { get; private set; } /// /// Gets or sets the LicenseManager /// public static LicenseManager LicenseManager { get; set; } /// /// Gets or sets the ProcessorSeries /// public static eCrestronSeries ProcessorSeries { get { return CrestronEnvironment.ProgramCompatibility; } } // TODO: consider making this configurable later /// /// The CultureInfo for formatting /// public static IFormatProvider Culture = CultureInfo.CreateSpecificCulture("en-US"); /// /// True when the processor type is a DMPS variant /// public static bool ControlSystemIsDmpsType { get { if(ControlSystem.SystemControl != null) { if(ControlSystem.SystemControl.SystemControlType > 0) { return true; } } return false; } } /// /// True when the processor type is a DMPS 4K variant /// public static bool ControlSystemIsDmps4kType { get { if(ControlSystem.SystemControl != null) { if(ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K150CSystemControl || ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K200CSystemControl || ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K250CSystemControl || ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K300CSystemControl || ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K350CSystemControl) { return true; } } return false; } } /// /// True when the processor type is a DMPS 4K 200/300/250/350 variant /// public static bool ControlSystemIsDmps4k3xxType { get { if(ControlSystem.SystemControl != null) { if(ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K200CSystemControl || ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K250CSystemControl || ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K300CSystemControl || ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K350CSystemControl) { return true; } } return false; } } /// /// Gets or sets the FilePathPrefix /// public static string FilePathPrefix { get; private set; } /// /// The file path prefix to the applciation directory /// public static string ApplicationDirectoryPathPrefix { get { return Crestron.SimplSharp.CrestronIO.Directory.GetApplicationDirectory(); } } /// /// Returns the directory separator character based on the running OS /// public static char DirectorySeparator { get { return System.IO.Path.DirectorySeparatorChar; } } /// /// Wildcarded config file name for global reference /// public const string ConfigFileName = "*configurationFile*.json"; /// /// Sets the file path prefix /// /// public static void SetFilePathPrefix(string prefix) { FilePathPrefix = prefix; Debug.LogMessage(LogEventLevel.Information, "File Path Prefix set to '{0}'", FilePathPrefix); } static string _AssemblyVersion; /// /// Gets the Assembly Version of Essentials /// /// The Assembly Version at Runtime public static string AssemblyVersion { get { return _AssemblyVersion; } private set { _AssemblyVersion = value; } } /// /// Sets the Assembly version to the version of the Essentials Library /// /// /// /// SetAssemblyVersion method /// public static void SetAssemblyVersion(string assemblyVersion) { AssemblyVersion = assemblyVersion; } /// /// Checks to see if the running version is in the list of development versions. If so, checks to see if it meets the minimum version requirement. /// If not in the list, returns false. For beta versions (0.xx.yy), will always return true. /// /// list of development versions /// minimum version /// public static bool IsRunningDevelopmentVersion(List developmentVersions, string minimumVersion) { if (Regex.Match(AssemblyVersion, @"^(\d*).(\d*).(\d*).*").Groups[1].Value == "0") { Debug.LogMessage(LogEventLevel.Verbose, "Running Local Build. Bypassing Dependency Check."); return true; } if (developmentVersions == null) { Debug.LogMessage(LogEventLevel.Information, "Development Plugin does not specify a list of versions. Loading plugin may not work as expected. Checking Minumum version"); return IsRunningMinimumVersionOrHigher(minimumVersion); } Debug.LogMessage(LogEventLevel.Verbose, "Comparing running version '{0}' to minimum versions '{1}'", AssemblyVersion, developmentVersions); var versionMatch = developmentVersions.FirstOrDefault(x => x == AssemblyVersion); if (String.IsNullOrEmpty(versionMatch)) { Debug.LogMessage(LogEventLevel.Information, "Essentials Build does not match any builds required for plugin load. Bypassing Plugin Load."); return false; } Debug.LogMessage(LogEventLevel.Verbose, "Essentials Build {0} matches list of development builds", AssemblyVersion); return IsRunningMinimumVersionOrHigher(minimumVersion); } /// /// Checks to see if the running version meets or exceed the minimum specified version. For beta versions (0.xx.yy), will always return true. /// /// Minimum specified version in format of xx.yy.zz /// Returns true if the running version meets or exceeds the minimum specified version public static bool IsRunningMinimumVersionOrHigher(string minimumVersion) { Debug.LogMessage(LogEventLevel.Verbose, "Comparing running version '{0}' to minimum version '{1}'", AssemblyVersion, minimumVersion); if (String.IsNullOrEmpty(minimumVersion)) { Debug.LogMessage(LogEventLevel.Information,"Plugin does not specify a minimum version. Loading plugin may not work as expected. Proceeding with loading plugin"); return true; } var runtimeVersion = Regex.Match(AssemblyVersion, @"^(\d*).(\d*).(\d*).*"); var runtimeVersionMajor = Int16.Parse(runtimeVersion.Groups[1].Value); var runtimeVersionMinor = Int16.Parse(runtimeVersion.Groups[2].Value); var runtimeVersionBuild = Int16.Parse(runtimeVersion.Groups[3].Value); var runtimeVer = new Version(runtimeVersionMajor, runtimeVersionMinor, runtimeVersionBuild); Version minimumVer; try { minimumVer = new Version(minimumVersion); } catch { Debug.LogMessage(LogEventLevel.Verbose, "unable to parse minimum version {0}. Bypassing plugin load.", minimumVersion); return false; } // Check for beta build version if (runtimeVer.Major != 0) { return runtimeVer.CompareTo(minimumVer) >= 0; } Debug.LogMessage(LogEventLevel.Verbose, "Running Local Build. Bypassing Dependency Check."); return true; /* var minVersion = Regex.Match(minimumVersion, @"^(\d*).(\d*).(\d*)$"); if(!minVersion.Success) { } var minVersionMajor = Int16.Parse(minVersion.Groups[1].Value); var minVersionMinor = Int16.Parse(minVersion.Groups[2].Value); var minVersionBuild = Int16.Parse(minVersion.Groups[3].Value); if (minVersionMajor > runtimeVersionMajor) return false; if (minVersionMinor > runtimeVersionMinor) return false; if (minVersionBuild > runtimeVersionBuild) return false; return true; */ } static Global() { // Fire up CrestronDataStoreStatic var err = CrestronDataStoreStatic.InitCrestronDataStore(); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) { CrestronConsole.PrintLine("Error starting CrestronDataStoreStatic: {0}", err); return; } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Global/JobTimer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Represents a JobTimer /// public static class JobTimer { static CTimer MinuteTimer; static List Items = new List(); /// /// AddAction method /// /// action to add public static void AddAction(Action act) { } /// /// AddJobTimerItem method /// /// JobTimerItem to add public static void AddJobTimerItem(JobTimerItem item) { var existing = Items.FirstOrDefault(i => i.Key == item.Key); if (existing != null) { Items.Remove(existing); } Items.Add(item); } static void CheckAndRunTimer() { if (Items.Count > 0 && MinuteTimer == null) { MinuteTimer = new CTimer(o => MinuteTimerCallback(), null, 60000, 60000); } } static void MinuteTimerCallback() { } } /// /// Represents a JobTimerItem /// public class JobTimerItem { /// /// Key property /// public string Key { get; private set; } /// /// JobAction property /// public Action JobAction { get; private set; } /// /// CycleType property /// public eJobTimerCycleTypes CycleType { get; private set; } /// /// RunNextAt property /// public DateTime RunNextAt { get; set; } /// /// Constructor /// /// item key /// cycle type /// action to run public JobTimerItem(string key, eJobTimerCycleTypes cycle, Action act) { } } /// /// JobTimerCycleTypes enum /// public enum eJobTimerCycleTypes { /// /// RunEveryDay property /// RunEveryDay, /// /// RunEveryHour property /// RunEveryHour, /// /// RunEveryHalfHour property /// RunEveryHalfHour, /// /// RunEveryMinute property /// RunEveryMinute } } ================================================ FILE: src/PepperDash.Essentials.Core/Global/Scheduler.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.Reflection; using Crestron.SimplSharp.Scheduler; using PepperDash.Core; using PepperDash.Essentials.Core.Fusion; using PepperDash.Essentials.Room.Config; using Serilog.Events; using Activator = System.Activator; namespace PepperDash.Essentials.Core { /// /// Global Scheduler for the system /// public static class Scheduler { private static readonly Dictionary EventGroups = new Dictionary(); static Scheduler() { CrestronConsole.AddNewConsoleCommand(DeleteEventGroup, "DeleteEventGroup", "Deletes the event group by key", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(ClearEventsFromGroup, "ClearAllEvents", "Clears all scheduled events for this group", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(ListAllEventGroups, "ListAllEventGroups", "Lists all the event groups by key", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(ListAllEventsForGroup, "ListEventsForGroup", "Lists all events for the given group", ConsoleAccessLevelEnum.AccessOperator); } static void DeleteEventGroup(string groupName) { if (EventGroups.ContainsKey(groupName)) { var group = EventGroups[groupName]; EventGroups.Remove(groupName); group.Dispose(); group = null; } } /// /// Clears (deletes) all events from a group /// /// static void ClearEventsFromGroup(string groupName) { if (!EventGroups.ContainsKey(groupName)) { Debug.LogMessage(LogEventLevel.Information, "[Scheduler]: Unable to delete events from group '{0}'. Group not found in EventGroups dictionary.", null, groupName); return; } var group = EventGroups[groupName]; if (group != null) { group.ClearAllEvents(); Debug.LogMessage(LogEventLevel.Information, "[Scheduler]: All events deleted from group '{0}'", null, groupName); } else Debug.LogMessage(LogEventLevel.Information, "[Scheduler]: Unable to delete events from group '{0}'. Group not found in EventGroups dictionary.", null, groupName); } static void ListAllEventGroups(string command) { CrestronConsole.ConsoleCommandResponse("Event Groups:"); foreach (var group in EventGroups) { CrestronConsole.ConsoleCommandResponse($"{group.Key}"); } } static void ListAllEventsForGroup(string args) { Debug.LogMessage(LogEventLevel.Information, "Getting events for group {0}...", null, args); ScheduledEventGroup group; if (!EventGroups.TryGetValue(args, out group)) { Debug.LogMessage(LogEventLevel.Information, "Unabled to get event group for key {0}", null, args); return; } foreach (var evt in group.ScheduledEvents) { CrestronConsole.ConsoleCommandResponse( $@" ****Event key {evt.Key}**** Event state: {evt.Value.EventState} Event date/time: {evt.Value.DateAndTime} Persistent: {evt.Value.Persistent} Acknowlegable: {evt.Value.Acknowledgeable} Recurrence: {evt.Value.Recurrence.Recurrence} Recurrence Days: {evt.Value.Recurrence.RecurrenceDays} ********************"); } } /// /// Adds the event group to the global list /// /// /// /// AddEventGroup method /// public static void AddEventGroup(ScheduledEventGroup eventGroup) { // Add this group to the global collection if (!EventGroups.ContainsKey(eventGroup.Name)) EventGroups.Add(eventGroup.Name, eventGroup); } /// /// Removes the event group from the global list /// /// /// /// RemoveEventGroup method /// public static void RemoveEventGroup(ScheduledEventGroup eventGroup) { if(!EventGroups.ContainsKey(eventGroup.Name)) EventGroups.Remove(eventGroup.Name); } /// /// Gets the event group by key /// /// key of the event group /// public static ScheduledEventGroup GetEventGroup(string key) { ScheduledEventGroup returnValue; return EventGroups.TryGetValue(key, out returnValue) ? returnValue : null; } } /// /// SchedulerUtilities class /// public static class SchedulerUtilities { /// /// Checks the day of week in eventTime to see if it matches the weekdays defined in the recurrence enum. /// /// /// /// /// /// CheckIfDayOfWeekMatchesRecurrenceDays method /// public static bool CheckIfDayOfWeekMatchesRecurrenceDays(DateTime eventTime, ScheduledEventCommon.eWeekDays recurrence) { bool isMatch = false; var dayOfWeek = eventTime.DayOfWeek; Debug.LogMessage(LogEventLevel.Debug, "[Scheduler]: eventTime day of week is: {0}",null, dayOfWeek); switch (dayOfWeek) { case DayOfWeek.Sunday: { if ((recurrence & ScheduledEventCommon.eWeekDays.Sunday) == ScheduledEventCommon.eWeekDays.Sunday) isMatch = true; break; } case DayOfWeek.Monday: { if ((recurrence & ScheduledEventCommon.eWeekDays.Monday) == ScheduledEventCommon.eWeekDays.Monday) isMatch = true; break; } case DayOfWeek.Tuesday: { if ((recurrence & ScheduledEventCommon.eWeekDays.Tuesday) == ScheduledEventCommon.eWeekDays.Tuesday) isMatch = true; break; } case DayOfWeek.Wednesday: { if ((recurrence & ScheduledEventCommon.eWeekDays.Wednesday) == ScheduledEventCommon.eWeekDays.Wednesday) isMatch = true; break; } case DayOfWeek.Thursday: { if ((recurrence & ScheduledEventCommon.eWeekDays.Thursday) == ScheduledEventCommon.eWeekDays.Thursday) isMatch = true; break; } case DayOfWeek.Friday: { if ((recurrence & ScheduledEventCommon.eWeekDays.Friday) == ScheduledEventCommon.eWeekDays.Friday) isMatch = true; break; } case DayOfWeek.Saturday: { if ((recurrence & ScheduledEventCommon.eWeekDays.Saturday) == ScheduledEventCommon.eWeekDays.Saturday) isMatch = true; break; } } Debug.LogMessage(LogEventLevel.Debug, "[Scheduler]: eventTime day of week matches recurrence days: {0}", isMatch); return isMatch; } /// /// CheckEventTimeForMatch method /// public static bool CheckEventTimeForMatch(ScheduledEvent evnt, DateTime time) { return evnt.DateAndTime.Hour == time.Hour && evnt.DateAndTime.Minute == time.Minute; } /// /// CheckEventRecurrenceForMatch method /// public static bool CheckEventRecurrenceForMatch(ScheduledEvent evnt, ScheduledEventCommon.eWeekDays days) { return evnt.Recurrence.RecurrenceDays == days; } /// /// CreateEventFromConfig method /// public static void CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group, ScheduledEvent.UserEventCallBack handler) { try { if (group == null) { Debug.LogMessage(LogEventLevel.Information, "Unable to create event. Group is null", null, null); return; } var scheduledEvent = new ScheduledEvent(config.Key, group) { Acknowledgeable = config.Acknowledgeable, Persistent = config.Persistent }; scheduledEvent.UserCallBack += handler; scheduledEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); var eventTime = DateTime.Parse(config.Time); if (DateTime.Now > eventTime) { eventTime = eventTime.AddDays(1); } Debug.LogMessage(LogEventLevel.Verbose, "[Scheduler] Current Date day of week: {0} recurrence days: {1}", null, eventTime.DayOfWeek, config.Days); var dayOfWeekConverted = ConvertDayOfWeek(eventTime); Debug.LogMessage(LogEventLevel.Debug, "[Scheduler] eventTime Day: {0}", null, dayOfWeekConverted); while (!dayOfWeekConverted.IsFlagSet(config.Days)) { eventTime = eventTime.AddDays(1); dayOfWeekConverted = ConvertDayOfWeek(eventTime); } scheduledEvent.DateAndTime.SetAbsoluteEventTime(eventTime); scheduledEvent.Recurrence.Weekly(config.Days); Debug.LogMessage(LogEventLevel.Verbose, $"[Scheduler] Event State: {scheduledEvent.EventState}", null, null); if (config.Enable && scheduledEvent.EventState != ScheduledEventCommon.eEventState.Enabled) { scheduledEvent.Enable(); } else if (!config.Enable && scheduledEvent.EventState != ScheduledEventCommon.eEventState.Disabled) { scheduledEvent.Disable(); } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Error, "Error creating scheduled event: {0}", null, e); } } private static ScheduledEventCommon.eWeekDays ConvertDayOfWeek(DateTime eventTime) { return (ScheduledEventCommon.eWeekDays) Enum.Parse(typeof(ScheduledEventCommon.eWeekDays), eventTime.DayOfWeek.ToString(), true); } private static bool IsFlagSet(this T value, T flag) where T : struct { CheckIsEnum(true); var lValue = Convert.ToInt64(value); var lFlag = Convert.ToInt64(flag); return (lValue & lFlag) != 0; } private static void CheckIsEnum(bool withFlags) { if (!typeof(T).IsEnum) throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName)); if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute))) throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName)); } } } ================================================ FILE: src/PepperDash.Essentials.Core/InUseTracking/IInUseTracking.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Defines a class that uses an InUseTracker /// public interface IInUseTracking { /// /// Gets the InUseTracker /// InUseTracking InUseTracker { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/InUseTracking/InUseTracking.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Provides in use tracking. Objects can register with this. InUseFeedback can provide /// events when usage changes. /// public class InUseTracking { /// /// Returns a copied list of all users of this tracker. /// public IEnumerable Users { get { return new List(_Users); } } List _Users = new List(); /// /// Feedback that changes when this goes in/out of use /// public BoolFeedback InUseFeedback { get; private set; } /// /// Gets or sets the InUseCountFeedback /// public IntFeedback InUseCountFeedback { get; private set; } /// /// Constructor /// public InUseTracking() { InUseFeedback = new BoolFeedback(() => _Users.Count > 0); InUseCountFeedback = new IntFeedback(() => _Users.Count); } /// /// Add a "user" object to this tracker. A user can be added to this tracker /// multiple times, provided that the label is different /// /// A label to identify the instance of the user. Treated like a "role", etc. /// The object to add public void AddUser(object objectToAdd, string label) { // check if an exact object/label pair exists and ignore if so. No double-registers. var check = _Users.FirstOrDefault(u => u.Label == label && u.User == objectToAdd); if (check != null) return; var prevCount = _Users.Count; _Users.Add(new InUseTrackingObject(objectToAdd, label)); // if this is the first add, fire an update if (prevCount == 0 && _Users.Count > 0) InUseFeedback.FireUpdate(); InUseCountFeedback.FireUpdate(); } /// /// RemoveUser method /// /// The label of the user to remove /// The object to remove public void RemoveUser(object objectToRemove, string label) { // Find the user object if exists and remove it var toRemove = _Users.FirstOrDefault(u => u.Label == label && u.User == objectToRemove); if (toRemove != null) { _Users.Remove(toRemove); if (_Users.Count == 0) InUseFeedback.FireUpdate(); InUseCountFeedback.FireUpdate(); } } } /// /// Represents a InUseTrackingObject /// public class InUseTrackingObject { /// /// The label of the user /// public string Label { get; private set; } /// /// The user object /// public object User { get; private set; } /// /// Constructor /// /// user using the object /// label for the object public InUseTrackingObject(object user, string label) { User = user; Label = label; } } //public class InUseEventArgs //{ // public int EventType { get; private set; } // public InUseTracking Tracker { get; private set; } // public InUseEventArgs(InUseTracking tracker, int eventType) // { // Tracker = tracker; // EventType = eventType; // } //} } ================================================ FILE: src/PepperDash.Essentials.Core/Interfaces/ILogStrings.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Essentials.Core.Interfaces { /// /// Defines the contract for ILogStrings /// [Obsolete("ILogStrings is no longer supported and will be removed in a future release.")] public interface ILogStrings : IKeyed { /// /// Defines a class that is capable of logging a string /// void SendToLog(IKeyed device, string logMessage); } } ================================================ FILE: src/PepperDash.Essentials.Core/Interfaces/ILogStringsWithLevel.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Essentials.Core.Interfaces { /// /// Defines the contract for ILogStringsWithLevel /// [Obsolete("ILogStringsWithLevel is no longer supported and will be removed in a future release.")] public interface ILogStringsWithLevel : IKeyed { /// /// Defines a class that is capable of logging a string with an int level /// void SendToLog(IKeyed device, Debug.ErrorLogLevel level, string logMessage); } } ================================================ FILE: src/PepperDash.Essentials.Core/JoinMaps/JoinMapBase.cs ================================================  using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Reflection; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// JoinMapHelper class /// public static class JoinMapHelper { /// /// Attempts to get the serialized join map from config /// /// /// /// /// GetSerializedJoinMapForDevice method /// public static string GetSerializedJoinMapForDevice(string joinMapKey) { if (string.IsNullOrEmpty(joinMapKey)) return null; var joinMap = ConfigReader.ConfigObject.JoinMaps[joinMapKey]; return joinMap.ToString(); } /// /// Attempts to get the serialized join map from config /// /// /// /// /// GetJoinMapForDevice method /// public static string GetJoinMapForDevice(string joinMapKey) { return GetSerializedJoinMapForDevice(joinMapKey); } /// /// Attempts to find a custom join map by key and returns it deserialized if found /// /// /// public static Dictionary TryGetJoinMapAdvancedForDevice(string joinMapKey) { try { if (string.IsNullOrEmpty(joinMapKey)) return null; if (!ConfigReader.ConfigObject.JoinMaps.ContainsKey(joinMapKey)) { Debug.LogMessage(LogEventLevel.Verbose, "No Join Map found in config with key: '{0}'", joinMapKey); return null; } Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load custom join map with key: {0}", joinMapKey); var joinMapJToken = ConfigReader.ConfigObject.JoinMaps[joinMapKey]; if (joinMapJToken == null) return null; var joinMapData = joinMapJToken.ToObject>(); return joinMapData; } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, "Error getting join map for key: '{0}'. Error: {1}", joinMapKey, e); return null; } } } /// /// Base class for join maps /// public abstract class JoinMapBaseAdvanced { /// /// The join offset /// protected uint JoinOffset; /// /// The collection of joins and associated metadata /// public Dictionary Joins { get; private set; } /// /// Constructor /// /// join start offset protected JoinMapBaseAdvanced(uint joinStart) { Joins = new Dictionary(); JoinOffset = joinStart - 1; } /// /// Constructor /// /// join start offset /// type of joinstart protected JoinMapBaseAdvanced(uint joinStart, Type type):this(joinStart) { AddJoins(type); } /// /// AddJoins method /// /// type of join to add protected void AddJoins(Type type) { var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance) .Where(f => f.IsDefined(typeof (JoinNameAttribute), true)).ToList(); Debug.LogMessage(LogEventLevel.Debug, "Got {fields} with JoinNameAttribute", fields.Count); foreach (var field in fields) { var childClass = Convert.ChangeType(this, type, null); //this here is JoinMapBaseAdvanced, not the child class. JoinMapBaseAdvanced has no fields. if (!(field.GetValue(childClass) is JoinDataComplete value)) { Debug.LogMessage(LogEventLevel.Information, "Unable to cast base class to {0}", type.Name); continue; } value.SetJoinOffset(JoinOffset); var joinName = value.GetNameAttribute(field); if (string.IsNullOrEmpty(joinName)) continue; Joins.Add(joinName, value); } if (Debug.Level > 0) { PrintJoinMapInfo(); } } /// /// PrintJoinMapInfo method /// public void PrintJoinMapInfo() { var sb = JoinmapStringBuilder(); CrestronConsole.ConsoleCommandResponse(sb.ToString()); } private StringBuilder JoinmapStringBuilder() { var sb = new StringBuilder(); var lineEnding = "\r\n"; var digitals = Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Digital)) .ToDictionary(j => j.Key, j => j.Value); var analogs = Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Analog)) .ToDictionary(j => j.Key, j => j.Value); var serials = Joins.Where(j => j.Value.Metadata.JoinType.HasFlag(eJoinType.Serial)) .ToDictionary(j => j.Key, j => j.Value); Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Digital join count {digitalCount} Analog join count {analogCount} Serial join count {serialCount}", null, digitals.Count, analogs.Count, serials.Count); // Get the joins of each type and print them sb.Append($"# {GetType().Name}\r\n"); sb.Append(lineEnding); sb.Append($"## Digitals{lineEnding}"); sb.Append(lineEnding); // Get the joins of each type and print them var digitalSb = AppendJoinList(GetSortedJoins(digitals)); digitalSb.Append($"## Analogs{lineEnding}"); digitalSb.Append(lineEnding); var analogSb = AppendJoinList(GetSortedJoins(analogs)); analogSb.Append($"## Serials{lineEnding}"); analogSb.Append(lineEnding); var serialSb = AppendJoinList(GetSortedJoins(serials)); sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length); sb.Append(digitalSb).Append(analogSb).Append(serialSb); return sb; } /// /// MarkdownJoinMapInfo method /// public void MarkdownJoinMapInfo(string deviceKey, string bridgeKey) { var pluginType = GetType().Name; CrestronConsole.ConsoleCommandResponse("{0}:\n", pluginType); WriteJoinmapMarkdown(JoinmapStringBuilder(), 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()); CrestronConsole.ConsoleCommandResponse("Joinmap Readme generated and written to {0}", fileName); } } /// /// Returns a sorted list by JoinNumber /// /// /// static List> GetSortedJoins(Dictionary joins) { var sortedJoins = joins.ToList(); sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber)); return sortedJoins; } static StringBuilder AppendJoinList(List> joins) { var sb = new StringBuilder(); const string stringFormatter = "| {0} | {1} | {2} | {3} | {4} |\r\n"; 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.Append(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.Append(string.Format(stringFormatter, new string('-', joinNumberLen), new string('-', joinSpanLen), new string('-', descriptionLen), new string('-', typeLen), new string('-', capabilitiesLen))); foreach (var join in joins) { sb.Append(join.Value.GetMarkdownFormattedData(stringFormatter, descriptionLen)); } sb.Append("\r\n"); return sb; } /// /// Attempts to find the matching key for the custom join and if found overwrites the default JoinData with the custom /// /// /// /// SetCustomJoinData method /// public void SetCustomJoinData(Dictionary joinData) { foreach (var customJoinData in joinData) { JoinDataComplete join; if (!Joins.TryGetValue(customJoinData.Key, out join)) { Debug.LogMessage(LogEventLevel.Verbose, "No matching key found in join map for: '{0}'", customJoinData.Key); continue; } if (join != null) { join.SetCustomJoinData(customJoinData.Value); } } PrintJoinMapInfo(); } // /// // /// Returns the join span for the join with the specified key // /// // /// // /// //public uint GetJoinSpanForKey(string key) //{ // return Joins.ContainsKey(key) ? Joins[key].JoinSpan : 0; //} } /// /// Read = Provides feedback to SIMPL /// Write = Responds to sig values from SIMPL /// [Flags] public enum eJoinCapabilities { /// /// No capabilities /// None = 0, /// /// To SIMPL /// ToSIMPL = 1, /// /// From SIMPL /// FromSIMPL = 2, /// /// To and From SIMPL /// ToFromSIMPL = ToSIMPL | FromSIMPL, /// /// To Fusion /// ToFusion = 4, /// /// From Fusion /// FromFusion = 8, /// /// To and From Fusion /// ToFromFusion = ToFusion | FromFusion, } /// /// Enumeration of eJoinType values /// [Flags] public enum eJoinType { /// /// No join type /// None = 0, /// /// Digital join /// Digital = 1, /// /// Analog join /// Analog = 2, /// /// Serial join /// Serial = 4, /// /// Digital and Analog join /// DigitalAnalog = Digital | Analog, /// /// Digital and Serial join /// DigitalSerial = Digital | Serial, /// /// Analog and Serial join /// AnalogSerial = Analog | Serial, /// /// Digital, Analog and Serial join /// DigitalAnalogSerial = Digital | Analog | Serial, } /// /// Represents a JoinMetadata /// public class JoinMetadata { private string _description; /// /// A description for the join to better describe its usage /// [JsonProperty("description")] public string Description { get { return _description; } set { _description = value; } } /// /// Gets or sets the JoinType /// [JsonProperty("joinType")] public eJoinType JoinType { get; set; } /// /// Gets or sets the JoinCapabilities /// [JsonProperty("joinCapabilities")] public eJoinCapabilities JoinCapabilities { get; set; } /// /// Gets or sets the ValidValues /// [JsonProperty("validValues")] public string[] ValidValues { get; set; } } /// /// Data describing the join. Can be overridden from configuratino /// public class JoinData { /// /// Join number (based on join offset value) /// [JsonProperty("joinNumber")] public uint JoinNumber { get; set; } /// /// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range /// [JsonProperty("joinSpan")] public uint JoinSpan { get; set; } /// /// Gets or sets the AttributeName /// [JsonProperty("attributeName")] public string AttributeName { get; set; } } /// /// A class to aggregate the JoinData and JoinMetadata for a join /// public class JoinDataComplete { private uint _joinOffset; private JoinData _data; /// /// Gets or sets the JoinMetadata /// public JoinMetadata Metadata { get; set; } /// /// To store some future information as you please /// public object UserObject { get; private set; } /// /// Constructor /// /// /// public JoinDataComplete(JoinData data, JoinMetadata metadata) { _data = data; Metadata = metadata; } /// /// GetMarkdownFormattedData method /// /// formatter to use /// length of the description /// 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) continue; errorKey = item.Key; break; } Debug.LogMessage(LogEventLevel.Information, "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 /// /// public void SetJoinOffset(uint joinOffset) { _joinOffset = joinOffset; } /// /// The join number (including the offset) /// public uint JoinNumber { get { return _data.JoinNumber+ _joinOffset; } set { _data.JoinNumber = value; } } /// /// The join span /// public uint JoinSpan { get { return _data.JoinSpan; } } /// /// The attribute name /// public string AttributeName { get { return _data.AttributeName; } } /// /// SetCustomJoinData method /// public void SetCustomJoinData(JoinData customJoinData) { _data = customJoinData; } /// /// GetNameAttribute method /// public string GetNameAttribute(MemberInfo memberInfo) { var name = string.Empty; var attribute = (JoinNameAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute)); if (attribute == null) return name; name = attribute.Name; Debug.LogMessage(LogEventLevel.Verbose, "JoinName Attribute value: {0}", name); return name; } } /// /// Represents a JoinNameAttribute /// [AttributeUsage(AttributeTargets.All)] public class JoinNameAttribute : Attribute { private string _Name; /// /// Constructor /// /// name of the attribute public JoinNameAttribute(string name) { Debug.LogMessage(LogEventLevel.Verbose, "Setting Attribute Name: {0}",null, name); _Name = name; } /// /// Gets the Name /// public string Name { get { return _Name; } } } } ================================================ FILE: src/PepperDash.Essentials.Core/License/EssentialsLicenseManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronDataStore; using PepperDash.Essentials.Core; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.License { /// /// Abstract base class for License Managers /// public abstract class LicenseManager { /// /// Gets or sets the LicenseIsValid /// public BoolFeedback LicenseIsValid { get; protected set; } /// /// Gets or sets the LicenseMessage /// public StringFeedback LicenseMessage { get; protected set; } /// /// Gets or sets the LicenseLog /// public StringFeedback LicenseLog { get; protected set; } /// /// Constructor /// protected LicenseManager() { CrestronConsole.AddNewConsoleCommand( s => CrestronConsole.ConsoleCommandResponse(GetStatusString()), "licensestatus", "shows license and related data", ConsoleAccessLevelEnum.AccessOperator); } /// /// Gets the status string for console command /// protected abstract string GetStatusString(); } /// /// Represents a MockEssentialsLicenseManager /// public class MockEssentialsLicenseManager : LicenseManager { /// /// Returns the singleton mock license manager for this app /// public static MockEssentialsLicenseManager Manager { get { if (_Manager == null) _Manager = new MockEssentialsLicenseManager(); return _Manager; } } static MockEssentialsLicenseManager _Manager; bool IsValid; MockEssentialsLicenseManager() : base() { LicenseIsValid = new BoolFeedback("LicenseIsValid", () => { return IsValid; }); CrestronConsole.AddNewConsoleCommand( s => SetFromConsole(s.Equals("true", StringComparison.OrdinalIgnoreCase)), "mocklicense", "true or false for testing", ConsoleAccessLevelEnum.AccessOperator); bool valid; var err = CrestronDataStoreStatic.GetGlobalBoolValue("MockLicense", out valid); if (err == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) SetIsValid(valid); else if (err == CrestronDataStore.CDS_ERROR.CDS_RECORD_NOT_FOUND) CrestronDataStoreStatic.SetGlobalBoolValue("MockLicense", false); else CrestronConsole.PrintLine("Error restoring Mock License setting: {0}", err); } void SetIsValid(bool isValid) { IsValid = isValid; CrestronDataStoreStatic.SetGlobalBoolValue("MockLicense", isValid); Debug.LogMessage(LogEventLevel.Information, "Mock License is{0} valid", IsValid ? "" : " not"); LicenseIsValid.FireUpdate(); } void SetFromConsole(bool isValid) { SetIsValid(isValid); } /// /// Gets the status string for console command /// /// license status valid or invalid protected override string GetStatusString() { return string.Format("License Status: {0}", IsValid ? "Valid" : "Not Valid"); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Lighting/Lighting Interfaces.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core.Lighting { /// /// Defines the contract for ILightingScenes /// public interface ILightingScenes { /// /// Fires when the lighting scene changes /// event EventHandler LightingSceneChange; /// /// Gets the list of LightingScenes /// List LightingScenes { get; } /// /// Selects the given LightingScene /// /// scene to select void SelectScene(LightingScene scene); /// /// Gets the currently selected LightingScene /// LightingScene CurrentLightingScene { get; } } /// /// Defines the contract for ILightingScenesDynamic /// public interface ILightingScenesDynamic : ILightingScenes { /// /// Fires when the lighting scenes are updated /// event EventHandler LightingScenesUpdated; } /// /// Defines the contract for ILightingMasterRaiseLower /// public interface ILightingMasterRaiseLower { /// /// Raises the master level /// void MasterRaise(); /// /// Lowers the master level /// void MasterLower(); /// /// Stops raising or lowering the master level /// void MasterRaiseLowerStop(); } /// /// Defines the contract for ILightingLoad /// public interface ILightingLoad { /// /// Sets the load level /// /// level to set void SetLoadLevel(int level); /// /// Raises the load level /// void Raise(); /// /// Lowers the load level /// void Lower(); /// /// feedback of the current load level /// IntFeedback LoadLevelFeedback { get; } /// /// feedback of whether the load is on /// BoolFeedback LoadIsOnFeedback { get; } } /// /// Represents a LightingSceneChangeEventArgs /// public class LightingSceneChangeEventArgs : EventArgs { /// /// Gets or sets the CurrentLightingScene /// public LightingScene CurrentLightingScene { get; private set; } /// /// Constructor for LightingSceneChangeEventArgs /// /// The lighting scene that changed public LightingSceneChangeEventArgs(LightingScene scene) { CurrentLightingScene = scene; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Lighting/LightingScene.cs ================================================  using System; using Newtonsoft.Json; namespace PepperDash.Essentials.Core.Lighting { /// /// Represents a LightingScene /// public class LightingScene { /// /// Gets or sets the Name /// [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } /// /// Gets or sets the ID /// [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public string ID { get; set; } bool _IsActive; /// /// Gets or sets whether the scene is active /// [JsonProperty("isActive", NullValueHandling = NullValueHandling.Ignore)] public bool IsActive { get { return _IsActive; } set { _IsActive = value; IsActiveFeedback.FireUpdate(); } } /// /// Gets or sets the SortOrder /// [JsonProperty("sortOrder", NullValueHandling = NullValueHandling.Ignore)] public int SortOrder { get; set; } /// /// Gets or sets the IsActiveFeedback /// [JsonIgnore] public BoolFeedback IsActiveFeedback { get; set; } /// /// Constructor for LightingScene /// public LightingScene() { IsActiveFeedback = new BoolFeedback(new Func(() => IsActive)); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.CrestronIO; using Serilog.Events; namespace PepperDash.Essentials.Core.Privacy { /// /// Used for applications where one or more microphones with momentary contact closure outputs are used to /// toggle the privacy state of the room. Privacy state feedback is represented /// public class MicrophonePrivacyController : EssentialsDevice { MicrophonePrivacyControllerConfig Config; bool initialized; /// /// Gets or sets whether LED control is enabled /// public bool EnableLeds { get { return _enableLeds; } set { _enableLeds = value; if (initialized) { if (value) { CheckPrivacyMode(); SetLedStates(); } else TurnOffAllLeds(); } } } bool _enableLeds; /// /// Gets or sets the Inputs /// public List Inputs { get; private set; } /// /// Gets or sets the RedLedRelay /// public GenericRelayDevice RedLedRelay { get; private set; } bool _redLedRelayState; /// /// Gets or sets the GreenLedRelay /// public GenericRelayDevice GreenLedRelay { get; private set; } bool _greenLedRelayState; /// /// Gets or sets the PrivacyDevice /// public IPrivacy PrivacyDevice { get; private set; } /// /// Constructor for MicrophonePrivacyController /// /// key of the controller device /// configuration for the controller device public MicrophonePrivacyController(string key, MicrophonePrivacyControllerConfig config) : base(key) { Config = config; Inputs = new List(); } /// /// CustomActivate method /// /// public override bool CustomActivate() { foreach (var i in Config.Inputs) { var input = DeviceManager.GetDeviceForKey(i.DeviceKey) as IDigitalInput; if(input != null) AddInput(input); } var greenLed = DeviceManager.GetDeviceForKey(Config.GreenLedRelay.DeviceKey) as GenericRelayDevice; if (greenLed != null) GreenLedRelay = greenLed; else Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Green LED device"); var redLed = DeviceManager.GetDeviceForKey(Config.RedLedRelay.DeviceKey) as GenericRelayDevice; if (redLed != null) RedLedRelay = redLed; else Debug.LogMessage(LogEventLevel.Information, this, "Unable to add Red LED device"); AddPostActivationAction(() => { PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange; PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; }); initialized = true; return base.CustomActivate(); } #region Overrides of Device /// /// Initialize method /// /// public override void Initialize() { CheckPrivacyMode(); } #endregion /// /// SetPrivacyDevice method /// public void SetPrivacyDevice(IPrivacy privacyDevice) { PrivacyDevice = privacyDevice; } void PrivacyModeIsOnFeedback_OutputChange(object sender, EventArgs e) { Debug.LogMessage(LogEventLevel.Debug, this, "Privacy mode change: {0}", sender as BoolFeedback); CheckPrivacyMode(); } void CheckPrivacyMode() { if (PrivacyDevice != null) { var privacyState = PrivacyDevice.PrivacyModeIsOnFeedback.BoolValue; if (privacyState) TurnOnRedLeds(); else TurnOnGreenLeds(); } } void AddInput(IDigitalInput input) { Inputs.Add(input); input.InputStateFeedback.OutputChange += InputStateFeedback_OutputChange; } void RemoveInput(IDigitalInput input) { var tempInput = Inputs.FirstOrDefault(i => i.Equals(input)); if (tempInput != null) tempInput.InputStateFeedback.OutputChange -= InputStateFeedback_OutputChange; Inputs.Remove(input); } void SetRedLedRelay(GenericRelayDevice relay) { RedLedRelay = relay; } void SetGreenLedRelay(GenericRelayDevice relay) { GreenLedRelay = relay; } /// /// Check the state of the input change and handle accordingly /// /// /// void InputStateFeedback_OutputChange(object sender, EventArgs e) { if ((sender as BoolFeedback).BoolValue == true) TogglePrivacyMute(); } /// /// Toggles the state of the privacy mute /// public void TogglePrivacyMute() { PrivacyDevice.PrivacyModeToggle(); } void TurnOnRedLeds() { _greenLedRelayState = false; _redLedRelayState = true; SetLedStates(); } void TurnOnGreenLeds() { _redLedRelayState = false; _greenLedRelayState = true; SetLedStates(); } /// /// If enabled, sets the actual state of the relays /// void SetLedStates() { if (_enableLeds) { SetRelayStates(); } else TurnOffAllLeds(); } /// /// Turns off all LEDs /// void TurnOffAllLeds() { _redLedRelayState = false; _greenLedRelayState = false; SetRelayStates(); } void SetRelayStates() { if (RedLedRelay != null) { if (_redLedRelayState) RedLedRelay.CloseRelay(); else RedLedRelay.OpenRelay(); } if(GreenLedRelay != null) { if (_greenLedRelayState) GreenLedRelay.CloseRelay(); else GreenLedRelay.OpenRelay(); } } } /// /// Represents a MicrophonePrivacyControllerFactory /// public class MicrophonePrivacyControllerFactory : EssentialsDeviceFactory { /// /// Constructor for MicrophonePrivacyControllerFactory /// public MicrophonePrivacyControllerFactory() { TypeNames = new List() { "microphoneprivacycontroller" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MIcrophonePrivacyController Device"); var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); return new Core.Privacy.MicrophonePrivacyController(dc.Key, props); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyControllerConfig.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core.CrestronIO; namespace PepperDash.Essentials.Core.Privacy { /// /// Represents a MicrophonePrivacyControllerConfig /// public class MicrophonePrivacyControllerConfig { /// /// Gets or sets the Inputs /// public List Inputs { get; set; } /// /// Gets or sets the GreenLedRelay /// public KeyedDevice GreenLedRelay { get; set; } /// /// Gets or sets the RedLedRelay /// public KeyedDevice RedLedRelay { get; set; } } /// /// Represents a KeyedDevice /// public class KeyedDevice { /// /// Gets or sets the DeviceKey /// public string DeviceKey { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Monitoring/CrestronGenericBaseCommunicationMonitor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using System.ComponentModel; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// /// public class CrestronGenericBaseCommunicationMonitor : StatusMonitorBase { GenericBase Device; /// /// Constructor for CrestronGenericBaseCommunicationMonitor /// /// parent device /// device to monitor /// time before warning status /// time before error status public CrestronGenericBaseCommunicationMonitor(IKeyed parent, GenericBase device, long warningTime, long errorTime) : base(parent, warningTime, errorTime) { Device = device; } /// /// Start method /// /// public override void Start() { Device.OnlineStatusChange -= Device_OnlineStatusChange; Device.OnlineStatusChange += Device_OnlineStatusChange; GetStatus(); } /// /// Stop method /// /// public override void Stop() { Device.OnlineStatusChange -= Device_OnlineStatusChange; } void Device_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) { GetStatus(); } void GetStatus() { if (Device.IsOnline) { Status = MonitorStatus.IsOk; StopErrorTimers(); } else StartErrorTimers(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Monitoring/GenericCommunicationMonitor.cs ================================================ using System; using PepperDash.Core; using System.Threading; using PepperDash.Core.Logging; namespace PepperDash.Essentials.Core { /// /// Used for monitoring comms that are IBasicCommunication. Will send a poll string and provide an event when /// statuses change. /// Default monitoring uses TextReceived event on Client. /// public class GenericCommunicationMonitor : StatusMonitorBase { /// /// Gets the Client being monitored /// public IBasicCommunication Client { get; private set; } /// /// Will monitor Client.BytesReceived if set to true. Otherwise the default is to monitor Client.TextReceived /// public bool MonitorBytesReceived { get; private set; } /// /// Return true if the Client is ISocketStatus /// public bool IsSocket => Client is ISocketStatus; private readonly string PollString; private readonly Action PollAction; private readonly long PollTime; private Timer PollTimer; private SemaphoreSlim semaphore = new SemaphoreSlim(1, 1); /// /// GenericCommunicationMonitor constructor /// /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected /// /// Parent device /// Communications Client /// Time in MS for polling /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning /// Error time in MS. If a message is not received before this elapsed time the status will be Error /// string to send for polling /// Poll time must be less than warning and error time public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, long warningTime, long errorTime, string pollString) : base(parent, warningTime, errorTime) { if (pollTime > warningTime || pollTime > errorTime) throw new ArgumentException("pollTime must be less than warning or errorTime"); Client = client; PollTime = pollTime; PollString = pollString; if (IsSocket) { (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; } } /// /// GenericCommunicationMonitor constructor with a bool to specify whether to monitor BytesReceived /// /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected /// /// Parent device /// Communications Client /// Time in MS for polling /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning /// Error time in MS. If a message is not received before this elapsed time the status will be Error /// string to send for polling /// Use bytesReceived event instead of textReceived when true public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, long warningTime, long errorTime, string pollString, bool monitorBytesReceived) : this(parent, client, pollTime, warningTime, errorTime, pollString) { MonitorBytesReceived = monitorBytesReceived; } /// /// GenericCommunicationMonitor constructor with a poll action instead of a poll string /// /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected /// /// Parent device /// Communications Client /// Time in MS for polling /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning /// Error time in MS. If a message is not received before this elapsed time the status will be Error /// Action to execute for polling /// Poll time must be less than warning and error time public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, long warningTime, long errorTime, Action pollAction) : base(parent, warningTime, errorTime) { if (pollTime > warningTime || pollTime > errorTime) throw new ArgumentException("pollTime must be less than warning or errorTime"); //if (pollTime < 5000) // throw new ArgumentException("pollTime cannot be less than 5000 ms"); Client = client; PollTime = pollTime; PollAction = pollAction; if (IsSocket) { (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; } } /// /// GenericCommunicationMonitor constructor with a poll action instead of a poll string and a bool to specify whether to monitor BytesReceived /// /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected /// /// Parent device /// Communications Client /// Time in MS for polling /// Warning time in MS. If a message is not received before this elapsed time the status will be Warning /// Error time in MS. If a message is not received before this elapsed time the status will be Error /// Action to execute for polling /// Use bytesReceived event instead of textReceived when true public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, long pollTime, long warningTime, long errorTime, Action pollAction, bool monitorBytesReceived) : this(parent, client, pollTime, warningTime, errorTime, pollAction) { MonitorBytesReceived = monitorBytesReceived; } /// /// GenericCommunicationMonitor constructor with a config object /// /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected /// /// Parent Device /// Communications Client /// Communication Monitor Config object public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, CommunicationMonitorConfig props) : this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) { if (IsSocket) { (Client as ISocketStatus).ConnectionChange += Socket_ConnectionChange; } } /// /// GenericCommunicationMonitor constructor with a config object and a bool to specify whether to monitor BytesReceived /// /// Note: If the client is a socket, the connection status will be monitored and the PollTimer will be started automatically when the client is connected /// /// Parent Device /// Communications Client /// Communication Monitor Config object /// Use bytesReceived event instead of textReceived when true public GenericCommunicationMonitor(IKeyed parent, IBasicCommunication client, CommunicationMonitorConfig props, bool monitorBytesReceived) : this(parent, client, props.PollInterval, props.TimeToWarning, props.TimeToError, props.PollString) { MonitorBytesReceived = monitorBytesReceived; } /// /// Start the poll cycle /// public override void Start() { if (MonitorBytesReceived) { Client.BytesReceived -= Client_BytesReceived; Client.BytesReceived += Client_BytesReceived; } else { Client.TextReceived -= Client_TextReceived; Client.TextReceived += Client_TextReceived; } BeginPolling(); } private void Socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) { if (!e.Client.IsConnected) { // Immediately stop polling and notify that device is offline Stop(); Status = MonitorStatus.InError; ResetErrorTimers(); } else { // Start polling and set status to unknow and let poll result update the status to IsOk when a response is received Status = MonitorStatus.StatusUnknown; Start(); } } private void BeginPolling() { try { semaphore.Wait(); { if (PollTimer != null) { return; } PollTimer = new Timer(o => Poll(), null, 0, PollTime); } } finally { semaphore.Release(); } } /// /// Stop method /// /// public override void Stop() { if(MonitorBytesReceived) { Client.BytesReceived -= Client_BytesReceived; } else { Client.TextReceived -= Client_TextReceived; } StopErrorTimers(); if (PollTimer == null) { return; } PollTimer.Dispose(); PollTimer = null; } private void Client_TextReceived(object sender, GenericCommMethodReceiveTextArgs e) { DataReceived(); } private void Client_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) { DataReceived(); } private void DataReceived() { Status = MonitorStatus.IsOk; ResetErrorTimers(); } private void Poll() { StartErrorTimers(); if (Client.IsConnected) { //Debug.LogMessage(LogEventLevel.Verbose, this, "Polling"); if(PollAction != null) PollAction.Invoke(); else Client.SendText(PollString); } else { this.LogVerbose("Comm not connected"); } } } /// /// Represents a CommunicationMonitorConfig /// public class CommunicationMonitorConfig { /// /// Gets or sets the PollInterval /// public int PollInterval { get; set; } /// /// Gets or sets the TimeToWarning /// public int TimeToWarning { get; set; } /// /// Gets or sets the TimeToError /// public int TimeToError { get; set; } /// /// Gets or sets the PollString /// public string PollString { get; set; } /// /// Default constructor. Sets pollInterval to 30s, TimeToWarning to 120s, and TimeToError to 300s /// public CommunicationMonitorConfig() { PollInterval = 30000; TimeToWarning = 120000; TimeToError = 300000; PollString = ""; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Monitoring/Interfaces.cs ================================================  using System; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IStatusMonitor /// public interface IStatusMonitor { /// /// Gets the Parent /// IKeyed Parent { get; } /// /// Fires when the status changes /// event EventHandler StatusChange; /// /// Gets the Status /// MonitorStatus Status { get; } /// /// Gets the Message /// string Message { get; } /// /// Gets or sets the IsOnlineFeedback /// BoolFeedback IsOnlineFeedback { get; set; } /// /// Start method /// void Start(); /// /// Stop method /// void Stop(); } /// /// Defines the contract for ICommunicationMonitor /// public interface ICommunicationMonitor { /// /// Gets the CommunicationMonitor /// StatusMonitorBase CommunicationMonitor { get; } } /// /// StatusUnknown = 0, IsOk = 1, InWarning = 2, InError = 3 /// public enum MonitorStatus { /// /// Status Unknown /// StatusUnknown = 0, /// /// Is Ok /// IsOk = 1, /// /// In Warning /// InWarning = 2, /// /// In Error /// InError = 3 } /// /// Represents a MonitorStatusChangeEventArgs /// public class MonitorStatusChangeEventArgs : EventArgs { /// /// Gets or sets the Status /// public MonitorStatus Status { get; private set; } /// /// Gets or sets the Message /// public string Message { get; private set; } /// /// Constructor for MonitorStatusChangeEventArgs /// /// monitor status public MonitorStatusChangeEventArgs(MonitorStatus status) { Status = status; Message = status == MonitorStatus.IsOk ? "" : status.ToString(); } /// /// Constructor for MonitorStatusChangeEventArgs /// /// monitor status /// status message public MonitorStatusChangeEventArgs(MonitorStatus status, string message) { Status = status; Message = message; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Monitoring/StatusMonitorBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using System.ComponentModel; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Base class for status monitors /// public abstract class StatusMonitorBase : IStatusMonitor, IKeyName { /// /// Event fired when status changes /// public event EventHandler StatusChange; /// /// Gets or sets the Key /// public string Key { get { return Parent.Key + "-comMonitor"; } } /// /// Gets or sets the Name /// public string Name { get { return "Comm. monitor"; } } /// /// Gets or sets the Parent /// public IKeyed Parent { get; private set; } /// /// Bool feedback for online status /// public BoolFeedback IsOnlineFeedback { get; set; } /// /// Indicates whether the monitored device is online /// public bool IsOnline; /// /// Current monitor status /// public MonitorStatus Status { get { return _Status; } protected set { if (value != _Status) { _Status = value; OnStatusChange(value); } } } MonitorStatus _Status; /// /// Current status message /// public string Message { get { return _Message; } set { if (value == _Message) return; _Message = value; OnStatusChange(Status, value); } } string _Message; long WarningTime; long ErrorTime; CTimer WarningTimer; CTimer ErrorTimer; /// /// Constructor /// /// parent device /// time in milliseconds before warning status /// time in milliseconds before error status public StatusMonitorBase(IKeyed parent, long warningTime, long errorTime) { Parent = parent; if (warningTime > errorTime) throw new ArgumentException("warningTime must be less than errorTime"); if (warningTime < 5000 || errorTime < 5000) throw new ArgumentException("time values cannot be less that 5000 ms"); IsOnlineFeedback = new BoolFeedback(() => { return IsOnline; }); Status = MonitorStatus.StatusUnknown; WarningTime = warningTime; ErrorTime = errorTime; } /// /// Starts the monitor /// public abstract void Start(); /// /// Stops the monitor /// public abstract void Stop(); /// /// Fires the StatusChange event /// /// monitor status protected void OnStatusChange(MonitorStatus status) { if (_Status == MonitorStatus.IsOk) IsOnline = true; else IsOnline = false; IsOnlineFeedback.FireUpdate(); var handler = StatusChange; if (handler != null) handler(this, new MonitorStatusChangeEventArgs(status)); } /// /// Fires the StatusChange event with message /// /// monitor status /// status message protected void OnStatusChange(MonitorStatus status, string message) { if (_Status == MonitorStatus.IsOk) IsOnline = true; else IsOnline = false; IsOnlineFeedback.FireUpdate(); var handler = StatusChange; if (handler != null) handler(this, new MonitorStatusChangeEventArgs(status, message)); } /// /// Starts the error timers /// protected void StartErrorTimers() { if (WarningTimer == null) WarningTimer = new CTimer(o => { Status = MonitorStatus.InWarning; }, WarningTime); if (ErrorTimer == null) ErrorTimer = new CTimer(o => { Status = MonitorStatus.InError; }, ErrorTime); } /// /// Stops the error timers /// protected void StopErrorTimers() { if (WarningTimer != null) WarningTimer.Stop(); if (ErrorTimer != null) ErrorTimer.Stop(); WarningTimer = null; ErrorTimer = null; } /// /// Resets the error timers /// protected void ResetErrorTimers() { if(WarningTimer != null) WarningTimer.Reset(WarningTime, WarningTime); if(ErrorTimer != null) ErrorTimer.Reset(ErrorTime, ErrorTime); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Monitoring/StatusMonitorCollection.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using System.ComponentModel; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Collection class for multiple status monitors /// public class StatusMonitorCollection : IStatusMonitor { /// /// Gets or sets the Parent /// public IKeyed Parent { get; private set; } List Monitors = new List(); #region IStatusMonitor Members /// /// Event fired when status changes /// public event EventHandler StatusChange; /// /// Gets or sets the Status /// public MonitorStatus Status { get; protected set; } /// /// Gets or sets the Message /// public string Message { get; private set; } /// /// Gets or sets the IsOnlineFeedback /// public BoolFeedback IsOnlineFeedback { get; set; } /// /// Constructor /// /// parent device public StatusMonitorCollection(IKeyed parent) { Parent = parent; } /// /// Start method /// public void Start() { foreach (var mon in Monitors) mon.StatusChange += mon_StatusChange; ProcessStatuses(); } void ProcessStatuses() { var InError = Monitors.Where(m => m.Status == MonitorStatus.InError).ToList(); var InWarning = Monitors.Where(m => m.Status == MonitorStatus.InWarning).ToList(); var IsOk = Monitors.Where(m => m.Status == MonitorStatus.IsOk).ToList(); MonitorStatus initialStatus; string prefix = "0:"; if (InError.Any()) { initialStatus = MonitorStatus.InError; prefix = "3:"; } else if (InWarning.Any()) { initialStatus = MonitorStatus.InWarning; prefix = "2:"; } else if (IsOk.Any()) initialStatus = MonitorStatus.IsOk; else initialStatus = MonitorStatus.StatusUnknown; // Build the error message string if (InError.Any() || InWarning.Any()) { var errorNames = InError .Select(mon => mon.Parent is IKeyName keyName ? keyName.Name : mon.Parent.Key) .ToList(); var warningNames = InWarning .Select(mon => mon.Parent is IKeyName keyName ? keyName.Name : mon.Parent.Key) .ToList(); var sb = new StringBuilder(prefix); if (errorNames.Count > 0) { sb.Append($"{errorNames.Count} Error{(errorNames.Count > 1 ? "s" : "")}: "); sb.Append(string.Join(", ", errorNames)); } if (warningNames.Count > 0) { if (errorNames.Count > 0) sb.Append("; "); sb.Append($"{warningNames.Count} Warning{(warningNames.Count > 1 ? "s" : "")}: "); sb.Append(string.Join(", ", warningNames)); } sb.Append(" Offline"); Message = sb.ToString(); } else { Message = "Room Ok."; } // Want to fire even if status doesn't change because the message may. Status = initialStatus; OnStatusChange(initialStatus, Message); } void mon_StatusChange(object sender, MonitorStatusChangeEventArgs e) { ProcessStatuses(); } /// /// Stop method /// public void Stop() { throw new NotImplementedException(); } #endregion /// /// AddMonitor method /// public void AddMonitor(IStatusMonitor monitor) { if (!Monitors.Contains(monitor)) Monitors.Add(monitor); } /// /// Fires the StatusChange event /// /// monitor status /// status message protected void OnStatusChange(MonitorStatus status, string message) { var handler = StatusChange; if (handler != null) handler(this, new MonitorStatusChangeEventArgs(status, message)); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.Diagnostics; using PepperDash.Core; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; namespace PepperDash.Essentials.Core.Monitoring { /// /// Wrapper for the static SystemMonitor class to extend functionality and provide external access /// to SystemMonitor via APIs /// public class SystemMonitorController : EssentialsBridgeableDevice { private const long UptimePollTime = 300000; private CTimer _uptimePollTimer; private string _uptime; private string _lastStart; /// /// Event fired when any SystemMonitor property changes /// public event EventHandler SystemMonitorPropertiesChanged; /// /// Gets or sets the ProgramStatusFeedbackCollection /// public Dictionary ProgramStatusFeedbackCollection; /// /// Gets or sets the EthernetStatusFeedbackCollection /// public Dictionary EthernetStatusFeedbackCollection; /// /// Gets or sets the TimeZoneFeedback /// public IntFeedback TimeZoneFeedback { get; protected set; } /// /// Gets or sets the TimeZoneTextFeedback /// public StringFeedback TimeZoneTextFeedback { get; protected set; } /// /// Gets or sets the IoControllerVersionFeedback /// public StringFeedback IoControllerVersionFeedback { get; protected set; } /// /// Gets or sets the SnmpVersionFeedback /// public StringFeedback SnmpVersionFeedback { get; protected set; } /// /// Gets or sets the BaCnetAppVersionFeedback /// public StringFeedback BaCnetAppVersionFeedback { get; protected set; } /// /// Gets or sets the ControllerVersionFeedback /// public StringFeedback ControllerVersionFeedback { get; protected set; } //new feedbacks. Issue #50 /// /// Gets or sets the SerialNumberFeedback /// public StringFeedback SerialNumberFeedback { get; protected set; } /// /// Gets or sets the ModelFeedback /// public StringFeedback ModelFeedback { get; set; } /// /// Gets or sets the UptimeFeedback /// public StringFeedback UptimeFeedback { get; set; } /// /// Gets or sets the LastStartFeedback /// public StringFeedback LastStartFeedback { get; set; } /// /// Gets or sets the IsApplianceFeedback /// public BoolFeedback IsApplianceFeedback { get; protected set; } private bool _isApplianceFb { get { return CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance; } } /// /// Gets or sets the IsServerFeedback /// public BoolFeedback IsServerFeedback { get; protected set; } private bool _isServerFb { get { return CrestronEnvironment.DevicePlatform == eDevicePlatform.Server; } } /// /// Constructor /// /// device key public SystemMonitorController(string key) : base(key) { Debug.LogMessage(LogEventLevel.Verbose, this, "Adding SystemMonitorController."); SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true; TimeZoneFeedback = new IntFeedback(() => SystemMonitor.TimeZoneInformation.TimeZoneNumber); TimeZoneTextFeedback = new StringFeedback(() => SystemMonitor.TimeZoneInformation.TimeZoneName); IoControllerVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.IOPVersion); SnmpVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.SNMPVersion); BaCnetAppVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.BACNetVersion); ControllerVersionFeedback = new StringFeedback(() => SystemMonitor.VersionInformation.ControlSystemVersion); SerialNumberFeedback = new StringFeedback(() => CrestronEnvironment.SystemInfo.SerialNumber); ModelFeedback = new StringFeedback(() => InitialParametersClass.ControllerPromptName); UptimeFeedback = new StringFeedback(() => _uptime); LastStartFeedback = new StringFeedback(()=> _lastStart); IsApplianceFeedback = new BoolFeedback(() => _isApplianceFb); IsServerFeedback = new BoolFeedback(() => _isServerFb); ProgramStatusFeedbackCollection = new Dictionary(); foreach (var prog in SystemMonitor.ProgramCollection) { var program = new ProgramStatusFeedbacks(prog); ProgramStatusFeedbackCollection.Add(prog.Number, program); } CreateEthernetStatusFeedbacks(); UpdateEthernetStatusFeeedbacks(); _uptimePollTimer = new CTimer(PollUptime,null,0, UptimePollTime); SystemMonitor.ProgramChange += SystemMonitor_ProgramChange; SystemMonitor.TimeZoneInformation.TimeZoneChange += TimeZoneInformation_TimeZoneChange; CrestronEnvironment.EthernetEventHandler += CrestronEnvironmentOnEthernetEventHandler; CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironmentOnProgramStatusEventHandler; } private void CrestronEnvironmentOnProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType != eProgramStatusEventType.Stopping) return; _uptimePollTimer.Stop(); _uptimePollTimer.Dispose(); _uptimePollTimer = null; } /// /// PollUptime method /// public void PollUptime(object obj) { var consoleResponse = string.Empty; CrestronConsole.SendControlSystemCommand("uptime", ref consoleResponse); ParseUptime(consoleResponse); UptimeFeedback.FireUpdate(); LastStartFeedback.FireUpdate(); } private void ParseUptime(string response) { var splitString = response.Trim().Split('\r', '\n'); var lastStartRaw = splitString.FirstOrDefault(o => o.Contains("started")); var uptimeRaw = splitString.FirstOrDefault(o => o.Contains("running")); if (!String.IsNullOrEmpty(lastStartRaw)) { var lastStartIndex = lastStartRaw.IndexOf(':'); _lastStart = lastStartRaw.Substring(lastStartIndex + 1).Trim(); } if (String.IsNullOrEmpty(uptimeRaw)) return; var forIndex = uptimeRaw.IndexOf("for", StringComparison.Ordinal); //4 => "for " to get what's on the right _uptime = uptimeRaw.Substring(forIndex + 4); } /// /// ProcessorReboot method /// public static void ProcessorReboot() { if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return; Debug.LogMessage(LogEventLevel.Information, "Rebooting..."); var response = string.Empty; CrestronConsole.SendControlSystemCommand("reboot", ref response); } /// /// ProgramReset method /// public static void ProgramReset(uint index) { if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return; Debug.LogMessage(LogEventLevel.Information, "Resetting Program {0}...", index); if (index <= 0 || index > 10) return; var cmd = string.Format("progreset -p:{0}", index); var response = string.Empty; CrestronConsole.SendControlSystemCommand(cmd, ref response); } private void CrestronEnvironmentOnEthernetEventHandler(EthernetEventArgs ethernetEventArgs) { if (ethernetEventArgs.EthernetEventType != eEthernetEventType.LinkUp) return; foreach (var fb in EthernetStatusFeedbackCollection) { fb.Value.UpdateEthernetStatus(); } } private void CreateEthernetStatusFeedbacks() { EthernetStatusFeedbackCollection = new Dictionary(); Debug.LogMessage(LogEventLevel.Verbose, "Creating {0} EthernetStatusFeedbacks", InitialParametersClass.NumberOfEthernetInterfaces); for (short i = 0; i < InitialParametersClass.NumberOfEthernetInterfaces; i++) { Debug.LogMessage(LogEventLevel.Verbose, "Creating EthernetStatusFeedback for Interface {0}", i); var ethernetInterface = new EthernetStatusFeedbacks(i); EthernetStatusFeedbackCollection.Add(i, ethernetInterface); } } private void UpdateEthernetStatusFeeedbacks() { foreach (var iface in EthernetStatusFeedbackCollection) { iface.Value.CurrentIpAddressFeedback.FireUpdate(); iface.Value.CurrentSubnetMaskFeedback.FireUpdate(); iface.Value.CurrentDefaultGatewayFeedback.FireUpdate(); iface.Value.StaticIpAddressFeedback.FireUpdate(); iface.Value.StaticSubnetMaskFeedback.FireUpdate(); iface.Value.StaticDefaultGatewayFeedback.FireUpdate(); iface.Value.HostNameFeedback.FireUpdate(); iface.Value.DnsServerFeedback.FireUpdate(); iface.Value.DomainFeedback.FireUpdate(); iface.Value.DhcpStatusFeedback.FireUpdate(); iface.Value.MacAddressFeedback.FireUpdate(); } } /// /// Gets data in separate thread /// private void RefreshSystemMonitorData() { // this takes a while, launch a new thread CrestronInvoke.BeginInvoke(UpdateFeedback); } private void UpdateFeedback(object o) { TimeZoneFeedback.FireUpdate(); TimeZoneTextFeedback.FireUpdate(); IoControllerVersionFeedback.FireUpdate(); SnmpVersionFeedback.FireUpdate(); BaCnetAppVersionFeedback.FireUpdate(); ControllerVersionFeedback.FireUpdate(); SerialNumberFeedback.FireUpdate(); ModelFeedback.FireUpdate(); IsApplianceFeedback.FireUpdate(); IsServerFeedback.FireUpdate(); OnSystemMonitorPropertiesChanged(); } private void OnSystemMonitorPropertiesChanged() { var handler = SystemMonitorPropertiesChanged; if (handler != null) { handler(this, new EventArgs()); } } /// /// CustomActivate method /// /// public override bool CustomActivate() { RefreshSystemMonitorData(); return base.CustomActivate(); } /// /// LinkToApi method /// /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new SystemMonitorJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); Debug.LogMessage(LogEventLevel.Verbose, this, "Linking API starting at join: {0}", joinStart); TimeZoneFeedback.LinkInputSig(trilist.UShortInput[joinMap.TimeZone.JoinNumber]); TimeZoneTextFeedback.LinkInputSig(trilist.StringInput[joinMap.TimeZoneName.JoinNumber]); IoControllerVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.IOControllerVersion.JoinNumber]); SnmpVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.SnmpAppVersion.JoinNumber]); BaCnetAppVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.BACnetAppVersion.JoinNumber]); ControllerVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.ControllerVersion.JoinNumber]); SerialNumberFeedback.LinkInputSig(trilist.StringInput[joinMap.SerialNumber.JoinNumber]); ModelFeedback.LinkInputSig(trilist.StringInput[joinMap.Model.JoinNumber]); UptimeFeedback.LinkInputSig(trilist.StringInput[joinMap.Uptime.JoinNumber]); LastStartFeedback.LinkInputSig(trilist.StringInput[joinMap.LastBoot.JoinNumber]); trilist.SetSigHeldAction(joinMap.ProcessorReboot.JoinNumber, 10000, ProcessorReboot); IsApplianceFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsAppliance.JoinNumber]); IsServerFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsServer.JoinNumber]); // iterate the program status feedback collection and map all the joins LinkProgramInfoJoins(this, trilist, joinMap); LinkEthernetInfoJoins(this, trilist, joinMap); } private static void LinkEthernetInfoJoins(SystemMonitorController systemMonitorController, BasicTriList trilist, SystemMonitorJoinMap joinMap) { uint ethernetSlotJoinStart = 0; foreach (var fb in systemMonitorController.EthernetStatusFeedbackCollection) { fb.Value.CurrentIpAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentIpAddress.JoinNumber]); fb.Value.CurrentSubnetMaskFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentSubnetMask.JoinNumber]); fb.Value.CurrentDefaultGatewayFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.CurrentDefaultGateway.JoinNumber]); fb.Value.StaticIpAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticIpAddress.JoinNumber]); fb.Value.StaticSubnetMaskFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticSubnetMask.JoinNumber]); fb.Value.StaticDefaultGatewayFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.StaticDefaultGateway.JoinNumber]); fb.Value.HostNameFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.HostName.JoinNumber]); fb.Value.MacAddressFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.MacAddress.JoinNumber]); fb.Value.DomainFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.Domain.JoinNumber]); fb.Value.DnsServerFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.DnsServer.JoinNumber]); fb.Value.DhcpStatusFeedback.LinkInputSig(trilist.StringInput[ethernetSlotJoinStart + joinMap.DhcpStatus.JoinNumber]); ethernetSlotJoinStart += joinMap.EthernetOffsetJoin.JoinNumber; } } private static void LinkProgramInfoJoins(SystemMonitorController systemMonitorController, BasicTriList trilist, SystemMonitorJoinMap joinMap) { uint programSlotJoinStart = 0; foreach (var p in systemMonitorController.ProgramStatusFeedbackCollection) { var programNumber = p.Value.Program.Number; trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramStart.JoinNumber, b => SystemMonitor.ProgramCollection[programNumber].OperatingState = eProgramOperatingState.Start); p.Value.ProgramStartedFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramStart.JoinNumber]); trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramStop.JoinNumber, b => SystemMonitor.ProgramCollection[programNumber].OperatingState = eProgramOperatingState.Stop); p.Value.ProgramStoppedFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramStop.JoinNumber]); trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramRegister.JoinNumber, b => SystemMonitor.ProgramCollection[programNumber].RegistrationState = eProgramRegistrationState.Register); p.Value.ProgramRegisteredFeedback.LinkInputSig( trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramRegister.JoinNumber]); trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramUnregister.JoinNumber, b => SystemMonitor.ProgramCollection[programNumber].RegistrationState = eProgramRegistrationState.Unregister); p.Value.ProgramUnregisteredFeedback.LinkInputSig( trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramUnregister.JoinNumber]); p.Value.ProgramNameFeedback.LinkInputSig(trilist.StringInput[programSlotJoinStart + joinMap.ProgramName.JoinNumber]); p.Value.ProgramCompileTimeFeedback.LinkInputSig( trilist.StringInput[programSlotJoinStart + joinMap.ProgramCompiledTime.JoinNumber]); p.Value.CrestronDataBaseVersionFeedback.LinkInputSig( trilist.StringInput[programSlotJoinStart + joinMap.ProgramCrestronDatabaseVersion.JoinNumber]); p.Value.EnvironmentVersionFeedback.LinkInputSig( trilist.StringInput[programSlotJoinStart + joinMap.ProgramEnvironmentVersion.JoinNumber]); p.Value.AggregatedProgramInfoFeedback.LinkInputSig( trilist.StringInput[programSlotJoinStart + joinMap.AggregatedProgramInfo.JoinNumber]); trilist.SetSigHeldAction(programSlotJoinStart + joinMap.ProgramReset.JoinNumber, 10000, () => ProgramReset(programNumber)); programSlotJoinStart = programSlotJoinStart + joinMap.ProgramOffsetJoin.JoinSpan; } } //// Sets the time zone //public void SetTimeZone(int timeZone) //{ // SystemMonitor.TimeZoneInformation.TimeZoneNumber = timeZone; //} /// /// Responds to program change events and triggers the appropriate feedbacks to update /// /// /// private void SystemMonitor_ProgramChange(Program sender, ProgramEventArgs args) { Debug.LogMessage(LogEventLevel.Verbose, this, "Program Change Detected for slot: {0}", sender.Number); Debug.LogMessage(LogEventLevel.Verbose, this, "Event Type: {0}", args.EventType); var program = ProgramStatusFeedbackCollection[sender.Number]; switch (args.EventType) { case eProgramChangeEventType.OperatingState: program.ProgramStartedFeedback.FireUpdate(); program.ProgramStoppedFeedback.FireUpdate(); program.ProgramInfo.OperatingState = args.OperatingState; if (args.OperatingState == eProgramOperatingState.Start) program.GetProgramInfo(); else { program.AggregatedProgramInfoFeedback.FireUpdate(); program.OnProgramInfoChanged(); } break; case eProgramChangeEventType.RegistrationState: program.ProgramRegisteredFeedback.FireUpdate(); program.ProgramUnregisteredFeedback.FireUpdate(); program.ProgramInfo.RegistrationState = args.RegistrationState; program.GetProgramInfo(); break; } } /// /// Responds to time zone changes and updates the appropriate feedbacks /// /// private void TimeZoneInformation_TimeZoneChange(TimeZoneEventArgs args) { Debug.LogMessage(LogEventLevel.Verbose, this, "Time Zone Change Detected."); TimeZoneFeedback.FireUpdate(); TimeZoneTextFeedback.FireUpdate(); OnSystemMonitorPropertiesChanged(); } /// /// Represents an EthernetStatusFeedbacks /// public class EthernetStatusFeedbacks { /// /// Gets or sets the HostNameFeedback /// public StringFeedback HostNameFeedback { get; protected set; } /// /// Gets or sets the DnsServerFeedback /// public StringFeedback DnsServerFeedback { get; protected set; } /// /// Gets or sets the DomainFeedback /// public StringFeedback DomainFeedback { get; protected set; } /// /// Gets or sets the MacAddressFeedback /// public StringFeedback MacAddressFeedback { get; protected set; } /// /// Gets or sets the DhcpStatusFeedback /// public StringFeedback DhcpStatusFeedback { get; protected set; } /// /// Gets or sets the CurrentIpAddressFeedback /// public StringFeedback CurrentIpAddressFeedback { get; protected set; } /// /// Gets or sets the CurrentSubnetMaskFeedback /// public StringFeedback CurrentSubnetMaskFeedback { get; protected set; } /// /// Gets or sets the CurrentDefaultGatewayFeedback /// public StringFeedback CurrentDefaultGatewayFeedback { get; protected set; } /// /// Gets or sets the StaticIpAddressFeedback /// public StringFeedback StaticIpAddressFeedback { get; protected set; } /// /// Gets or sets the StaticSubnetMaskFeedback /// public StringFeedback StaticSubnetMaskFeedback { get; protected set; } /// /// Gets or sets the StaticDefaultGatewayFeedback /// public StringFeedback StaticDefaultGatewayFeedback { get; protected set; } /// /// Constructor /// /// index of the ethernet addapter public EthernetStatusFeedbacks(short adapterIndex) { Debug.LogMessage(LogEventLevel.Verbose, "Ethernet Information for interface {0}", adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Hostname: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current IP Address: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current Subnet Mask: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Current Router: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static IP Address: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_IPADDRESS, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static Subnet Mask: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_IPMASK, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Static Router: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_STATIC_ROUTER, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} DNS Servers: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} DHCP State: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} Domain Name: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterIndex), adapterIndex); Debug.LogMessage(LogEventLevel.Verbose, "Adapter Index: {1} MAC Address: {0}", CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterIndex), adapterIndex); HostNameFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterIndex)); CurrentIpAddressFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex)); CurrentDefaultGatewayFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex)); CurrentSubnetMaskFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex)); StaticIpAddressFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterIndex)); StaticDefaultGatewayFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterIndex)); StaticSubnetMaskFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterIndex)); DomainFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterIndex)); DnsServerFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterIndex)); MacAddressFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterIndex)); DhcpStatusFeedback = new StringFeedback( () => CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterIndex)); } /// /// UpdateEthernetStatus method /// public void UpdateEthernetStatus() { HostNameFeedback.FireUpdate(); CurrentIpAddressFeedback.FireUpdate(); CurrentSubnetMaskFeedback.FireUpdate(); CurrentDefaultGatewayFeedback.FireUpdate(); StaticIpAddressFeedback.FireUpdate(); StaticSubnetMaskFeedback.FireUpdate(); StaticDefaultGatewayFeedback.FireUpdate(); DomainFeedback.FireUpdate(); DnsServerFeedback.FireUpdate(); MacAddressFeedback.FireUpdate(); DhcpStatusFeedback.FireUpdate(); } } /// /// Represents a ProgramStatusFeedbacks /// public class ProgramStatusFeedbacks { /// /// Event fired when ProgramInfo changes /// public event EventHandler ProgramInfoChanged; /// /// Gets or sets the Program /// public Program Program; /// /// Gets or sets the ProgramInfo /// public ProgramInfo ProgramInfo { get; set; } /// /// Gets or sets the ProgramStartedFeedback /// public BoolFeedback ProgramStartedFeedback; /// /// Gets or sets the ProgramStoppedFeedback /// public BoolFeedback ProgramStoppedFeedback; /// /// Gets or sets the ProgramRegisteredFeedback /// public BoolFeedback ProgramRegisteredFeedback; /// /// Gets or sets the ProgramUnregisteredFeedback /// public BoolFeedback ProgramUnregisteredFeedback; /// /// Gets or sets the ProgramNameFeedback /// public StringFeedback ProgramNameFeedback; /// /// Gets or sets the ProgramCompileTimeFeedback /// public StringFeedback ProgramCompileTimeFeedback; /// /// Gets or sets the CrestronDataBaseVersionFeedback /// public StringFeedback CrestronDataBaseVersionFeedback; // SIMPL windows version /// /// Gets or sets the EnvironmentVersionFeedback /// public StringFeedback EnvironmentVersionFeedback; /// /// Gets or sets the AggregatedProgramInfoFeedback /// public StringFeedback AggregatedProgramInfoFeedback; /// /// Constructor /// /// program to get status about public ProgramStatusFeedbacks(Program program) { ProgramInfo = new ProgramInfo(program.Number); Program = program; ProgramInfo.OperatingState = Program.OperatingState; ProgramInfo.RegistrationState = Program.RegistrationState; ProgramStartedFeedback = new BoolFeedback(() => Program.OperatingState == eProgramOperatingState.Start); ProgramStartedFeedback.FireUpdate(); ProgramStoppedFeedback = new BoolFeedback(() => Program.OperatingState == eProgramOperatingState.Stop); ProgramStoppedFeedback.FireUpdate(); ProgramRegisteredFeedback = new BoolFeedback(() => Program.RegistrationState == eProgramRegistrationState.Register); ProgramRegisteredFeedback.FireUpdate(); ProgramUnregisteredFeedback = new BoolFeedback(() => Program.RegistrationState == eProgramRegistrationState.Unregister); ProgramUnregisteredFeedback.FireUpdate(); ProgramNameFeedback = new StringFeedback(() => ProgramInfo.ProgramFile); CrestronDataBaseVersionFeedback = new StringFeedback(() => ProgramInfo.CrestronDb); EnvironmentVersionFeedback = new StringFeedback(() => ProgramInfo.Environment); ProgramCompileTimeFeedback = new StringFeedback(() => ProgramInfo.CompileTime); AggregatedProgramInfoFeedback = new StringFeedback(() => JsonConvert.SerializeObject(ProgramInfo)); GetProgramInfo(); } /// /// GetProgramInfo method /// public void GetProgramInfo() { CrestronInvoke.BeginInvoke(GetProgramInfo); } private void GetProgramInfo(object o) { Debug.LogMessage(LogEventLevel.Verbose, "Attempting to get program info for slot: {0}", Program.Number); string response = null; if (Program.RegistrationState == eProgramRegistrationState.Unregister || Program.OperatingState == eProgramOperatingState.Stop) { Debug.LogMessage(LogEventLevel.Verbose, "Program {0} not registered. Setting default values for program information.", Program.Number); ProgramInfo = new ProgramInfo(Program.Number) { OperatingState = Program.OperatingState, RegistrationState = Program.RegistrationState }; return; } var success = CrestronConsole.SendControlSystemCommand( string.Format("progcomments:{0}", Program.Number), ref response); if (!success) { Debug.LogMessage(LogEventLevel.Verbose, "Progcomments Attempt Unsuccessful for slot: {0}", Program.Number); UpdateFeedbacks(); return; } if (response.ToLower().Contains("bad or incomplete")) { Debug.LogMessage(LogEventLevel.Verbose, "Program in slot {0} not running. Setting default ProgramInfo for slot: {0}", Program.Number); // Assume no valid program info. Constructing a new object will wipe all properties ProgramInfo = new ProgramInfo(Program.Number) { OperatingState = Program.OperatingState, RegistrationState = Program.RegistrationState }; UpdateFeedbacks(); return; } // Shared properteis ProgramInfo.ProgramFile = ParseConsoleData(response, "Program File", ": ", "\n"); ProgramInfo.CompilerRevision = ParseConsoleData(response, "Compiler Rev", ": ", "\n"); ProgramInfo.CompileTime = ParseConsoleData(response, "Compiled On", ": ", "\n"); ProgramInfo.Include4Dat = ParseConsoleData(response, "Include4.dat", ": ", "\n"); if (ProgramInfo.ProgramFile.Contains(".dll")) { // SSP Program ProgramInfo.FriendlyName = ParseConsoleData(response, "Friendly Name", ": ", "\n"); ProgramInfo.ApplicationName = ParseConsoleData(response, "Application Name", ": ", "\n"); ProgramInfo.ProgramTool = ParseConsoleData(response, "Program Tool", ": ", "\n"); ProgramInfo.MinFirmwareVersion = ParseConsoleData(response, "Min Firmware Version", ": ", "\n"); ProgramInfo.PlugInVersion = ParseConsoleData(response, "PlugInVersion", ": ", "\n"); ProgramInfo.ProgramFile += string.Format(" {0}.{1}.{2}", ProgramInfo.CompilerRevisionInfo.Major, ProgramInfo.CompilerRevisionInfo.Minor, ProgramInfo.CompilerRevisionInfo.Build); ProgramInfo.Environment = ProgramInfo.ProgramTool; } else if (ProgramInfo.ProgramFile.Contains(".smw")) { // SIMPL Windows Program ProgramInfo.FriendlyName = ParseConsoleData(response, "Friendly Name", ":", "\n"); ProgramInfo.SystemName = ParseConsoleData(response, "System Name", ": ", "\n"); ProgramInfo.CrestronDb = ParseConsoleData(response, "CrestronDB", ": ", "\n"); ProgramInfo.Environment = ParseConsoleData(response, "Source Env", ": ", "\n"); ProgramInfo.Programmer = ParseConsoleData(response, "Programmer", ": ", "\n"); } Debug.LogMessage(LogEventLevel.Verbose, "Program info for slot {0} successfully updated", Program.Number); UpdateFeedbacks(); } private void UpdateFeedbacks() { ProgramNameFeedback.FireUpdate(); ProgramCompileTimeFeedback.FireUpdate(); CrestronDataBaseVersionFeedback.FireUpdate(); EnvironmentVersionFeedback.FireUpdate(); AggregatedProgramInfoFeedback.FireUpdate(); OnProgramInfoChanged(); } /// /// OnProgramInfoChanged method /// public void OnProgramInfoChanged() { //Debug.LogMessage(LogEventLevel.Debug, "Firing ProgramInfoChanged for slot: {0}", Program.Number); var handler = ProgramInfoChanged; if (handler != null) { handler(this, new ProgramInfoEventArgs(ProgramInfo)); } } private string ParseConsoleData(string data, string line, string startString, string endString) { var outputData = ""; if (data.Length <= 0) return outputData; if (!data.Contains(line)) { return outputData; } try { //Debug.LogMessage(LogEventLevel.Verbose, "ParseConsoleData Data: {0}, Line {1}, startStirng {2}, endString {3}", data, line, startString, endString); var linePosition = data.IndexOf(line, StringComparison.Ordinal); var startPosition = data.IndexOf(startString, linePosition, StringComparison.Ordinal) + startString.Length; var endPosition = data.IndexOf(endString, startPosition, StringComparison.Ordinal); outputData = data.Substring(startPosition, endPosition - startPosition).Trim(); //Debug.LogMessage(LogEventLevel.Verbose, "ParseConsoleData Return: {0}", outputData); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Error, "Error Parsing Console Data: {0}", e); Debug.LogMessage(LogEventLevel.Verbose, "Stack Trace: {stackTrace}", e.StackTrace); } return outputData; } } } /// /// Represents a ProgramInfo /// public class ProgramInfo { // Shared properties /// /// Gets the ProgramNumber /// [JsonProperty("programNumber")] public uint ProgramNumber { get; private set; } /// /// Gets or sets the OperatingState /// [JsonConverter(typeof (StringEnumConverter))] [JsonProperty("operatingState")] public eProgramOperatingState OperatingState { get; set; } /// /// Gets or sets the RegistrationState /// [JsonConverter(typeof (StringEnumConverter))] [JsonProperty("registrationState")] public eProgramRegistrationState RegistrationState { get; set; } /// /// Gets or sets the ProgramFile /// [JsonProperty("programFile")] public string ProgramFile { get; set; } /// /// Gets or sets the FriendlyName /// [JsonProperty("friendlyName")] public string FriendlyName { get; set; } /// /// Gets or sets the CompilerRevision /// [JsonProperty("compilerRevision")] public string CompilerRevision { get; set; } /// /// Gets the CompilerRevisionInfo /// [JsonIgnore] public Version CompilerRevisionInfo { get { return new Version(CompilerRevision); } } /// /// Gets or sets the CompileTime /// [JsonProperty("compileTime")] public string CompileTime { get; set; } /// /// Gets or sets the Include4Dat /// [JsonProperty("include4Dat")] public string Include4Dat { get; set; } // SIMPL Windows properties /// /// Gets or sets the SystemName /// [JsonProperty("systemName")] public string SystemName { get; set; } /// /// Gets or sets the CrestronDb /// [JsonProperty("crestronDb")] public string CrestronDb { get; set; } /// /// Gets or sets the Environment /// [JsonProperty("environment")] public string Environment { get; set; } /// /// Gets or sets the Programmer /// [JsonProperty("programmer")] public string Programmer { get; set; } // SSP Properties /// /// Gets or sets the ApplicationName /// [JsonProperty("applicationName")] public string ApplicationName { get; set; } /// /// Gets or sets the ProgramTool /// [JsonProperty("programTool")] public string ProgramTool { get; set; } /// /// Gets or sets the MinFirmwareVersion /// [JsonProperty("minFirmwareVersion")] public string MinFirmwareVersion { get; set; } /// /// Gets or sets the PlugInVersion /// [JsonProperty("plugInVersion")] public string PlugInVersion { get; set; } /// /// Constructor /// /// program slot to get info about public ProgramInfo(uint number) { ProgramNumber = number; ProgramFile = ""; FriendlyName = ""; CompilerRevision = ""; CompileTime = ""; Include4Dat = ""; SystemName = ""; CrestronDb = ""; Environment = ""; Programmer = ""; ApplicationName = ""; ProgramTool = ""; MinFirmwareVersion = ""; PlugInVersion = ""; } } /// /// Represents a ProgramInfoEventArgs /// public class ProgramInfoEventArgs : EventArgs { /// /// Gets or sets the ProgramInfo /// public ProgramInfo ProgramInfo; /// /// Constructor /// /// program info public ProgramInfoEventArgs(ProgramInfo progInfo) { ProgramInfo = progInfo; } } } ================================================ FILE: src/PepperDash.Essentials.Core/PartitionSensor/EssentialsPartitionController.cs ================================================ using PepperDash.Core; using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// /// Represents an abstract controller device for a partition dividing rooms that are combinable /// /// In Auto mode, it can use a partition sensor to automatically determine whether the partition is present. /// /// In Manual mode it accepts user input to tell it whether the partition is present. /// public class EssentialsPartitionController : IPartitionController { private IPartitionStateProvider _partitionSensor; /// /// Indicates whether the controller is in Auto mode or Manual mode /// public bool IsInAutoMode { get; private set; } private bool _partitionPresent; /// /// Gets or sets the PartitionPresent state /// public bool PartitionPresent { get { if (IsInAutoMode) { return _partitionSensor.PartitionPresentFeedback.BoolValue; } return _partitionPresent; } set { if (_partitionPresent == value) { return; } _partitionPresent = value; if (PartitionPresentFeedback != null) { PartitionPresentFeedback.FireUpdate(); } } } /// /// Constructor /// /// key for the partition controller /// name of the partition controller /// partition state provider sensor /// whether to default to manual mode /// list of adjacent room keys public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List adjacentRoomKeys) { Key = key; Name = name; AdjacentRoomKeys = adjacentRoomKeys; if (sensor != null) { _partitionSensor = sensor; if (!defaultToManualMode) { SetAutoMode(); } else { SetManualMode(); } } else { SetManualMode(); } PartitionPresentFeedback.FireUpdate(); } private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) { if (IsInAutoMode) { PartitionPresent = e.BoolValue; } } #region IPartitionController Members /// /// Gets or sets the AdjacentRoomKeys /// public List AdjacentRoomKeys { get; private set; } /// /// SetAutoMode method /// public void SetAutoMode() { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting {Key} to Auto Mode", this); IsInAutoMode = true; if (PartitionPresentFeedback != null) { PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue); } else { PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionPresentFeedback.BoolValue); } if (_partitionSensor != null) { _partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange; _partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; PartitionPresent = _partitionSensor.PartitionPresentFeedback.BoolValue; } PartitionPresentFeedback.FireUpdate(); } /// /// SetManualMode method /// public void SetManualMode() { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting {Key} to Manual Mode", this); IsInAutoMode = false; if (PartitionPresentFeedback != null) { PartitionPresentFeedback.SetValueFunc(() => _partitionPresent); } else { PartitionPresentFeedback = new BoolFeedback(() => _partitionPresent); } if (_partitionSensor != null) { _partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange; PartitionPresent = _partitionSensor.PartitionPresentFeedback.BoolValue; } PartitionPresentFeedback.FireUpdate(); } /// /// SetPartitionStatePresent method /// public void SetPartitionStatePresent() { if (!IsInAutoMode) { PartitionPresent = true; PartitionPresentFeedback.FireUpdate(); } } /// /// SetPartitionStateNotPresent method /// public void SetPartitionStateNotPresent() { if (!IsInAutoMode) { PartitionPresent = false; PartitionPresentFeedback.FireUpdate(); } } /// /// ToggglePartitionState method /// public void ToggglePartitionState() { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Toggling Partition State for {Key}", this); Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"IsInAutoMode: {IsInAutoMode}", this); if (!IsInAutoMode) { PartitionPresent = !PartitionPresent; PartitionPresentFeedback.FireUpdate(); } } #endregion #region IPartitionStateProvider Members /// /// Gets or sets the PartitionPresentFeedback /// public BoolFeedback PartitionPresentFeedback { get; private set; } #endregion #region IKeyName Members /// /// Gets or sets the Name /// public string Name { get; private set; } #endregion #region IKeyed Members /// /// Gets or sets the Key /// public string Key { get; private set; } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Core/PartitionSensor/IPartitionStateProvider.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IPartitionStateProvider /// public interface IPartitionStateProvider : IKeyName { /// /// Feedback indicating whether the partition is present /// [JsonIgnore] BoolFeedback PartitionPresentFeedback { get; } /// /// Indicates whether the partition is present /// [JsonProperty("partitionPresent")] bool PartitionPresent { get; } } /// /// Defines the contract for IPartitionController /// public interface IPartitionController : IPartitionStateProvider { /// /// List of adjacent room keys /// [JsonProperty("adjacentRoomKeys")] List AdjacentRoomKeys { get; } /// /// Indicates whether the controller is in Auto mode or Manual mode /// [JsonProperty("isInAutoMode")] bool IsInAutoMode { get; } /// /// Sets the PartitionPresent state /// void SetPartitionStatePresent(); /// /// Sets the PartitionPresent state to not present /// void SetPartitionStateNotPresent(); /// /// Toggles the PartitionPresent state /// void ToggglePartitionState(); /// /// Sets the controller to Manual mode /// void SetManualMode(); /// /// Sets the controller to Auto mode /// void SetAutoMode(); } } ================================================ FILE: src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj ================================================  Debug;Release;Debug 4.7.2 net472 true true bin\$(Configuration)\ PepperDash_Essentials_Core PepperDash.Essentials.Core PepperDash Essentials Core PepperDash.Essentials.Core $(Version) false full full pdbonly bin\$(Configuration)\PepperDash_Essentials_Core.xml ================================================ FILE: src/PepperDash.Essentials.Core/PepperDash_Essentials_Core.csproj.DotSettings ================================================  True False ================================================ FILE: src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// /// Defines a class that is capable of loading custom plugin device types /// public interface IPluginDeviceFactory : IDeviceFactory { /// /// Required to define the minimum version for Essentials in the format xx.yy.zz /// string MinimumEssentialsFrameworkVersion { get; } } /// /// Defines a class that is capable of loading custom plugin device types for development purposes /// [Obsolete("This interface is obsolete and will be removed in a future version." + " Use IPluginDeviceFactory instead and check Global.IsRunningDevelopmentVersion to determine if the Essentials framework is in development mode.")] public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory { /// /// Gets a list of all the development versions of the Essentials framework that are supported by this factory. /// List DevelopmentEssentialsFrameworkVersions { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using Crestron.SimplSharp; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; namespace PepperDash.Essentials { /// /// Deals with loading plugins at runtime /// public static class PluginLoader { /// /// The complete list of loaded assemblies. Includes Essentials Framework assemblies and plugins /// public static List LoadedAssemblies { get; private set; } /// /// The list of assemblies loaded from the plugins folder /// static List LoadedPluginFolderAssemblies; /// /// The assembly for the Essentials Framework /// public static LoadedAssembly EssentialsAssembly { get; private set; } /// /// The assembly for the PepperDash Core /// public static LoadedAssembly PepperDashCoreAssembly { get; private set; } /// /// The list of assemblies loaded from the Essentials plugins folder /// public static List EssentialsPluginAssemblies { get; private set; } /// /// The directory to look in for .cplz plugin packages /// static string _pluginDirectory => Global.FilePathPrefix + "plugins"; /// /// The directory where plugins will be moved to and loaded from /// static string _loadedPluginsDirectoryPath => _pluginDirectory + Global.DirectorySeparator + "loadedAssemblies"; // The temp directory where .cplz archives will be unzipped to static string _tempDirectory => _pluginDirectory + Global.DirectorySeparator + "temp"; static PluginLoader() { LoadedAssemblies = new List(); LoadedPluginFolderAssemblies = new List(); EssentialsPluginAssemblies = new List(); } /// /// AddProgramAssemblies method /// public static void AddProgramAssemblies() { Debug.LogMessage(LogEventLevel.Verbose, "Getting Assemblies loaded with Essentials"); // Get the loaded assembly filenames var appDi = new DirectoryInfo(Global.ApplicationDirectoryPathPrefix); var assemblyFiles = appDi.GetFiles("*.dll"); Debug.LogMessage(LogEventLevel.Verbose, "Found {0} Assemblies", assemblyFiles.Length); foreach (var fi in assemblyFiles.Where(fi => fi.Name.Contains("Essentials") || fi.Name.Contains("PepperDash"))) { string version = string.Empty; Assembly assembly = null; switch (fi.Name) { case ("PepperDashEssentials.dll"): { version = Global.AssemblyVersion; EssentialsAssembly = new LoadedAssembly(fi.Name, version, assembly); break; } case ("PepperDash_Essentials_Core.dll"): { version = Global.AssemblyVersion; break; } case ("Essentials Devices Common.dll"): { version = Global.AssemblyVersion; break; } case ("PepperDashCore.dll"): { Debug.LogMessage(LogEventLevel.Verbose, "Found PepperDash_Core.dll"); version = Debug.PepperDashCoreVersion; Debug.LogMessage(LogEventLevel.Verbose, "PepperDash_Core Version: {0}", version); PepperDashCoreAssembly = new LoadedAssembly(fi.Name, version, assembly); break; } } LoadedAssemblies.Add(new LoadedAssembly(fi.Name, version, assembly)); } if (Debug.Level > 1) { Debug.LogMessage(LogEventLevel.Verbose, "Loaded Assemblies:"); foreach (var assembly in LoadedAssemblies) { Debug.LogMessage(LogEventLevel.Verbose, "Assembly: {0}", assembly.Name); } } } /// /// SetEssentialsAssembly method /// public static void SetEssentialsAssembly(string name, Assembly assembly) { var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name)); if (loadedAssembly != null) { loadedAssembly.SetAssembly(assembly); } } /// /// Loads an assembly via Reflection and adds it to the list of loaded assemblies /// /// static LoadedAssembly LoadAssembly(string filePath) { try { //Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load {0}", filePath); var assembly = Assembly.LoadFrom(filePath); if (assembly != null) { var assyVersion = GetAssemblyVersion(assembly); var loadedAssembly = new LoadedAssembly(assembly.GetName().Name, assyVersion, assembly); LoadedAssemblies.Add(loadedAssembly); Debug.LogMessage(LogEventLevel.Information, "Loaded assembly '{0}', version {1}", loadedAssembly.Name, loadedAssembly.Version); return loadedAssembly; } else { Debug.LogMessage(LogEventLevel.Information, "Unable to load assembly: '{0}'", filePath); } return null; } catch (Exception ex) { Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath); return null; } } /// /// Attempts to get the assembly informational version and if not possible gets the version /// /// /// public static string GetAssemblyVersion(Assembly assembly) { var ver = assembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); if (ver != null && ver.Length > 0) { // Get the AssemblyInformationalVersion AssemblyInformationalVersionAttribute verAttribute = ver[0] as AssemblyInformationalVersionAttribute; return verAttribute.InformationalVersion; } else { // Get the AssemblyVersion var version = assembly.GetName().Version; var verStr = string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, version.Build, version.Revision); return verStr; } } /// /// Checks if the filename matches an already loaded assembly file's name /// /// name of loaded assembly /// True if file already matches loaded assembly file. public static bool CheckIfAssemblyLoaded(string name) { Debug.LogMessage(LogEventLevel.Verbose, "Checking if assembly: {0} is loaded...", name); var loadedAssembly = LoadedAssemblies.FirstOrDefault(s => s.Name.Equals(name)); if (loadedAssembly != null) { Debug.LogMessage(LogEventLevel.Verbose, "Assembly already loaded."); return true; } else { Debug.LogMessage(LogEventLevel.Verbose, "Assembly not loaded."); return false; } } /// /// Associates the specified assembly with the given name in the loaded assemblies collection. /// /// If an assembly with the specified name already exists in the loaded assemblies collection, /// this method updates its associated assembly. If no matching name is found, the method does nothing. /// The name used to identify the assembly. This value is case-sensitive and must not be null or empty. /// The assembly to associate with the specified name. This value must not be null. public static void AddLoadedAssembly(string name, Assembly assembly) { var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name)); loadedAssembly?.SetAssembly(assembly); } /// /// Used by console command to report the currently loaded assemblies and versions /// /// public static void ReportAssemblyVersions(string command) { CrestronConsole.ConsoleCommandResponse("Essentials Version: {0}" + CrestronEnvironment.NewLine, Global.AssemblyVersion); CrestronConsole.ConsoleCommandResponse("PepperDash Core Version: {0}" + CrestronEnvironment.NewLine, PepperDashCoreAssembly.Version); CrestronConsole.ConsoleCommandResponse("Essentials Plugin Versions:" + CrestronEnvironment.NewLine); foreach (var assembly in EssentialsPluginAssemblies) { CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version); } //CrestronConsole.ConsoleCommandResponse("Loaded Assemblies:" + CrestronEnvironment.NewLine); //foreach (var assembly in LoadedAssemblies) //{ // CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version); //} } /// /// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder /// static void MoveDllAssemblies() { Debug.LogMessage(LogEventLevel.Information, "Looking for .dll assemblies from plugins folder..."); var pluginDi = new DirectoryInfo(_pluginDirectory); var pluginFiles = pluginDi.GetFiles("*.dll"); if (pluginFiles.Length > 0) { if (!Directory.Exists(_loadedPluginsDirectoryPath)) { Directory.CreateDirectory(_loadedPluginsDirectoryPath); } } foreach (var pluginFile in pluginFiles) { try { Debug.LogMessage(LogEventLevel.Information, "Found .dll: {0}", pluginFile.Name); if (!CheckIfAssemblyLoaded(pluginFile.Name)) { string filePath = string.Empty; filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + pluginFile.Name; // Check if there is a previous file in the loadedPlugins directory and delete if (File.Exists(filePath)) { Debug.LogMessage(LogEventLevel.Information, "Found existing file in loadedPlugins: {0} Deleting and moving new file to replace it", filePath); File.Delete(filePath); } // Move the file File.Move(pluginFile.FullName, filePath); Debug.LogMessage(LogEventLevel.Verbose, "Moved {0} to {1}", pluginFile.FullName, filePath); } else { Debug.LogMessage(LogEventLevel.Information, "Skipping assembly: {0}. There is already an assembly with that name loaded.", pluginFile.FullName); } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, "Error with plugin file {0} . Exception: {1}", pluginFile.FullName, e); continue; //catching any load issues and continuing. There will be exceptions loading Crestron .dlls from the cplz Probably should do something different here } } Debug.LogMessage(LogEventLevel.Information, "Done with .dll assemblies"); } /// /// Unzips each .cplz archive into the temp directory and moves any unloaded files into loadedPlugins /// static void UnzipAndMoveCplzArchives() { Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from user folder..."); //var di = new DirectoryInfo(_pluginDirectory); //var zFiles = di.GetFiles("*.cplz"); //// Find cplz files at the root of the user folder. Makes development/testing easier for VC-4, and helps with mistakes by end users //var userDi = new DirectoryInfo(Global.FilePathPrefix); //var userZFiles = userDi.GetFiles("*.cplz"); Debug.LogInformation("Checking {folder} for .cplz files", Global.FilePathPrefix); var cplzFiles = Directory.GetFiles(Global.FilePathPrefix, "*.cplz", SearchOption.AllDirectories) .Select(f => new FileInfo(f)) .ToArray(); if (cplzFiles.Length > 0) { if (!Directory.Exists(_loadedPluginsDirectoryPath)) { Directory.CreateDirectory(_loadedPluginsDirectoryPath); } } foreach (var zfi in cplzFiles) { Directory.CreateDirectory(_tempDirectory); var tempDi = new DirectoryInfo(_tempDirectory); Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.FullName); var result = CrestronZIP.Unzip(zfi.FullName, tempDi.FullName); Debug.LogMessage(LogEventLevel.Information, "UnZip Result: {0}", result.ToString()); var tempFiles = tempDi.GetFiles("*.dll"); foreach (var tempFile in tempFiles) { try { if (!CheckIfAssemblyLoaded(tempFile.Name)) { string filePath = string.Empty; filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + tempFile.Name; // Check if there is a previous file in the loadedPlugins directory and delete if (File.Exists(filePath)) { Debug.LogMessage(LogEventLevel.Information, "Found existing file in loadedPlugins: {0} Deleting and moving new file to replace it", filePath); File.Delete(filePath); } // Move the file File.Move(tempFile.FullName, filePath); Debug.LogMessage(LogEventLevel.Verbose, "Moved {0} to {1}", tempFile.FullName, filePath); } else { Debug.LogMessage(LogEventLevel.Information, "Skipping assembly: {0}. There is already an assembly with that name loaded.", tempFile.FullName); } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, "Assembly {0} is not a custom assembly. Exception: {1}", tempFile.FullName, e); continue; //catching any load issues and continuing. There will be exceptions loading Crestron .dlls from the cplz Probably should do something different here } } // Delete the .cplz and the temp directory Directory.Delete(_tempDirectory, true); zfi.Delete(); } Debug.LogMessage(LogEventLevel.Information, "Done with .cplz archives"); } /// /// Attempts to load the assemblies from the loadedPlugins folder /// static void LoadPluginAssemblies() { Debug.LogMessage(LogEventLevel.Information, "Loading assemblies from loadedPlugins folder..."); var pluginDi = new DirectoryInfo(_loadedPluginsDirectoryPath); var pluginFiles = pluginDi.GetFiles("*.dll"); Debug.LogMessage(LogEventLevel.Verbose, "Found {0} plugin assemblies to load", pluginFiles.Length); foreach (var pluginFile in pluginFiles) { var loadedAssembly = LoadAssembly(pluginFile.FullName); LoadedPluginFolderAssemblies.Add(loadedAssembly); } Debug.LogMessage(LogEventLevel.Information, "All Plugins Loaded."); } /// /// Iterate the loaded assemblies and try to call the LoadPlugin method /// static void LoadCustomPluginTypes() { Debug.LogMessage(LogEventLevel.Information, "Loading Custom Plugin Types..."); foreach (var loadedAssembly in LoadedPluginFolderAssemblies) { // iteratate this assembly's classes, looking for "LoadPlugin()" methods try { var assy = loadedAssembly.Assembly; Type[] types = { }; try { types = assy.GetTypes(); Debug.LogMessage(LogEventLevel.Debug, $"Got types for assembly {assy.GetName().Name}"); } catch (TypeLoadException e) { Debug.LogMessage(LogEventLevel.Error, "Unable to get types for assembly {0}: {1}", loadedAssembly.Name, e.Message); Debug.LogMessage(LogEventLevel.Verbose, e.StackTrace); continue; } foreach (var type in types) { try { if (typeof(IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract) { var plugin = (IPluginDeviceFactory)Activator.CreateInstance(type); LoadCustomPlugin(plugin, loadedAssembly); } } catch (NotSupportedException) { //this happens for dlls that aren't PD dlls, like ports of Mono classes into S#. Swallowing. } catch (Exception e) { Debug.LogMessage(LogEventLevel.Error, "Load Plugin not found. {0}.{2} is not a plugin factory. Exception: {1}", loadedAssembly.Name, e.Message, type.Name); continue; } } } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Error Loading assembly {0}: {1}", loadedAssembly.Name, e.Message); Debug.LogMessage(LogEventLevel.Verbose, "{0}", e.StackTrace); continue; } } // plugin dll will be loaded. Any classes in plugin should have a static constructor // that registers that class with the Core.DeviceFactory Debug.LogMessage(LogEventLevel.Information, "Done Loading Custom Plugin Types."); } /// /// Loads a custom plugin and performs a dependency check to ensure compatibility with the required Essentials /// framework version. /// /// This method verifies that the plugin meets the minimum required Essentials framework version /// before loading it. If the plugin fails the dependency check, it is skipped, and a log message is generated. If /// the plugin passes the check, it is loaded, and its type factories are initialized. /// The plugin to be loaded, implementing the interface. If the plugin also /// implements , additional checks for development versions are /// performed. /// The assembly associated with the plugin being loaded. This is used for logging and tracking purposes. static void LoadCustomPlugin(IPluginDeviceFactory pluginDeviceFactory, LoadedAssembly loadedAssembly) { var passed = pluginDeviceFactory is IPluginDevelopmentDeviceFactory developmentPlugin ? Global.IsRunningDevelopmentVersion (developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion) : Global.IsRunningMinimumVersionOrHigher(pluginDeviceFactory.MinimumEssentialsFrameworkVersion); if (!passed) { Debug.LogMessage(LogEventLevel.Information, "\r\n********************\r\n\tPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n********************", pluginDeviceFactory.MinimumEssentialsFrameworkVersion, loadedAssembly.Name); return; } else { Debug.LogMessage(LogEventLevel.Information, "Passed plugin passed dependency check (required version {0})", pluginDeviceFactory.MinimumEssentialsFrameworkVersion); } Debug.LogMessage(LogEventLevel.Information, "Loading plugin factory: {0}", loadedAssembly.Name); LoadDeviceFactories(pluginDeviceFactory); if (!EssentialsPluginAssemblies.Contains(loadedAssembly)) EssentialsPluginAssemblies.Add(loadedAssembly); } /// /// Loads device factories from the specified plugin device factory and registers them for use. /// /// This method retrieves metadata from the provided , including /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type /// names are converted to lowercase for registration. /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered. private static void LoadDeviceFactories(IPluginDeviceFactory deviceFactory) { foreach (var typeName in deviceFactory.TypeNames) { string description = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0 ? descriptionAttribute[0].Description : "No description available"; DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice); } } /// /// LoadPlugins method /// public static void LoadPlugins() { Debug.LogMessage(LogEventLevel.Information, "Attempting to Load Plugins from {_pluginDirectory}", _pluginDirectory); if (Directory.Exists(_pluginDirectory)) { Debug.LogMessage(LogEventLevel.Information, "Plugins directory found, checking for plugins"); // Deal with any .dll files MoveDllAssemblies(); // Deal with any .cplz files UnzipAndMoveCplzArchives(); if (Directory.Exists(_loadedPluginsDirectoryPath)) { // Load the assemblies from the loadedPlugins folder into the AppDomain LoadPluginAssemblies(); // Load the types from any custom plugin assemblies LoadCustomPluginTypes(); } } } } /// /// Represents a LoadedAssembly /// public class LoadedAssembly { /// /// Gets the name of the assembly /// [JsonProperty("name")] public string Name { get; private set; } /// /// Gets the version of the assembly /// [JsonProperty("version")] public string Version { get; private set; } /// /// Gets the assembly /// [JsonIgnore] public Assembly Assembly { get; private set; } /// /// Initializes a new instance of the LoadedAssembly class /// /// The name of the assembly /// The version of the assembly /// The assembly public LoadedAssembly(string name, string version, Assembly assembly) { Name = name; Version = version; Assembly = assembly; } /// /// SetAssembly method /// public void SetAssembly(Assembly assembly) { Assembly = assembly; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Presets/DevicePresets.cs ================================================  using System; using System.Collections.Generic; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; using PepperDash.Core; //using SSMono.IO; using PepperDash.Core.WebApi.Presets; using Serilog.Events; namespace PepperDash.Essentials.Core.Presets { /// /// Class that represents the model behind presets display /// public class DevicePresetsModel : Device { /// /// Delegate for preset recalled event /// /// device that recalled a preset /// channel that was recalled public delegate void PresetRecalledCallback(ISetTopBoxNumericKeypad device, string channel); /// /// Delegate for presets saved event /// /// list of presets that were saved public delegate void PresetsSavedCallback(List presets); private readonly CCriticalSection _fileOps = new CCriticalSection(); private readonly bool _initSuccess; private readonly ISetTopBoxNumericKeypad _setTopBox; /// /// The methods on the STB device to call when dialing /// private Dictionary> _dialFunctions; private bool _dialIsRunning; private Action _enterFunction; private string _filePath; /// /// Constructor /// /// key for the device /// set top box device /// file name for presets public DevicePresetsModel(string key, ISetTopBoxNumericKeypad setTopBox, string fileName) : this(key, fileName) { try { _setTopBox = setTopBox; // Grab the digit functions from the device // If any fail, the whole thing fails peacefully _dialFunctions = new Dictionary>(10) { {'1', setTopBox.Digit1}, {'2', setTopBox.Digit2}, {'3', setTopBox.Digit3}, {'4', setTopBox.Digit4}, {'5', setTopBox.Digit5}, {'6', setTopBox.Digit6}, {'7', setTopBox.Digit7}, {'8', setTopBox.Digit8}, {'9', setTopBox.Digit9}, {'0', setTopBox.Digit0}, {'-', setTopBox.Dash} }; } catch { Debug.LogMessage(LogEventLevel.Information, "DevicePresets '{0}', not attached to INumericKeypad device. Ignoring", key); _dialFunctions = null; return; } _enterFunction = setTopBox.KeypadEnter; } /// /// Constructor /// /// key for the device /// file name for presets public DevicePresetsModel(string key, string fileName) : base(key) { PulseTime = 150; DigitSpacingMs = 150; UseLocalImageStorage = true; ImagesLocalHostPrefix = "http://" + CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); ImagesPathPrefix = @"/presets/images.zip/"; ListPathPrefix = @"/html/presets/lists/"; SetFileName(fileName); _initSuccess = true; } /// /// Event fired when a preset is recalled /// public event PresetRecalledCallback PresetRecalled; /// /// Event fired when presets are saved /// public event PresetsSavedCallback PresetsSaved; /// /// Gets or sets the PulseTime /// public int PulseTime { get; set; } /// /// Gets or sets the DigitSpacingMs /// public int DigitSpacingMs { get; set; } /// /// Gets or sets the PresetsAreLoaded /// public bool PresetsAreLoaded { get; private set; } /// /// Gets or sets the PresetsList /// public List PresetsList { get; private set; } /// /// Gets the Count of presets /// public int Count { get { return PresetsList != null ? PresetsList.Count : 0; } } /// /// Gets or sets the UseLocalImageStorage /// public bool UseLocalImageStorage { get; set; } /// /// Gets or sets the ImagesLocalHostPrefix /// public string ImagesLocalHostPrefix { get; set; } /// /// Gets or sets the ImagesPathPrefix /// public string ImagesPathPrefix { get; set; } /// /// Gets or sets the ListPathPrefix /// public string ListPathPrefix { get; set; } /// /// Event fired when presets are loaded /// public event EventHandler PresetsLoaded; /// /// SetFileName method /// public void SetFileName(string path) { _filePath = ListPathPrefix + path; Debug.LogMessage(LogEventLevel.Verbose, this, "Setting presets file path to {0}", _filePath); LoadChannels(); } /// /// LoadChannels method /// public void LoadChannels() { try { _fileOps.Enter(); Debug.LogMessage(LogEventLevel.Verbose, this, "Loading presets from {0}", _filePath); PresetsAreLoaded = false; try { var pl = JsonConvert.DeserializeObject(File.ReadToEnd(_filePath, Encoding.ASCII)); Name = pl.Name; PresetsList = pl.Channels; Debug.LogMessage(LogEventLevel.Verbose, this, "Loaded {0} presets", PresetsList.Count); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, this, "LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}", _filePath, e.Message); // Just save a default empty list PresetsList = new List(); } PresetsAreLoaded = true; var handler = PresetsLoaded; if (handler != null) { handler(this, EventArgs.Empty); } } finally { _fileOps.Leave(); } } /// /// Dial method /// public void Dial(int presetNum) { if (presetNum <= PresetsList.Count) { Dial(PresetsList[presetNum - 1].Channel); } } /// /// Dial method /// public void Dial(string chanNum) { if (_dialIsRunning || !_initSuccess) { return; } if (_dialFunctions == null) { Debug.LogMessage(LogEventLevel.Debug, "DevicePresets '{0}', not attached to keypad device. Ignoring channel", Key); return; } _dialIsRunning = true; CrestronInvoke.BeginInvoke(o => { foreach (var c in chanNum.ToCharArray()) { if (_dialFunctions.ContainsKey(c)) { Pulse(_dialFunctions[c]); } CrestronEnvironment.Sleep(DigitSpacingMs); } if (_enterFunction != null) { Pulse(_enterFunction); } _dialIsRunning = false; }); if (_setTopBox == null) return; OnPresetRecalled(_setTopBox, chanNum); } /// /// Dial method /// public void Dial(int presetNum, ISetTopBoxNumericKeypad setTopBox) { if (presetNum <= PresetsList.Count) { Dial(PresetsList[presetNum - 1].Channel, setTopBox); } } /// /// Dial method /// public void Dial(string chanNum, ISetTopBoxNumericKeypad setTopBox) { _dialFunctions = new Dictionary>(10) { {'1', setTopBox.Digit1}, {'2', setTopBox.Digit2}, {'3', setTopBox.Digit3}, {'4', setTopBox.Digit4}, {'5', setTopBox.Digit5}, {'6', setTopBox.Digit6}, {'7', setTopBox.Digit7}, {'8', setTopBox.Digit8}, {'9', setTopBox.Digit9}, {'0', setTopBox.Digit0}, {'-', setTopBox.Dash} }; _enterFunction = setTopBox.KeypadEnter; OnPresetRecalled(setTopBox, chanNum); Dial(chanNum); } private void OnPresetRecalled(ISetTopBoxNumericKeypad setTopBox, string channel) { var handler = PresetRecalled; if (handler == null) { return; } handler(setTopBox, channel); } /// /// UpdatePreset method /// public void UpdatePreset(int index, PresetChannel preset) { if (index >= PresetsList.Count) { return; } PresetsList[index] = preset; SavePresets(); OnPresetsSaved(); } /// /// UpdatePresets method /// public void UpdatePresets(List presets) { PresetsList = presets; SavePresets(); OnPresetsSaved(); } private void SavePresets() { try { _fileOps.Enter(); var pl = new PresetsList {Channels = PresetsList, Name = Name}; var json = JsonConvert.SerializeObject(pl, Formatting.Indented); using (var file = File.Open(_filePath, FileMode.Truncate)) { file.Write(json, Encoding.UTF8); } } finally { _fileOps.Leave(); } } private void OnPresetsSaved() { var handler = PresetsSaved; if (handler == null) return; handler(PresetsList); } private void Pulse(Action act) { act(true); CrestronEnvironment.Sleep(PulseTime); act(false); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Presets/DevicePresetsView.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core.Presets { /// /// Represents a DevicePresetsView /// public class DevicePresetsView { /// /// Gets or sets the ShowNumbers /// public bool ShowNumbers { get; set; } /// /// Gets or sets the ShowName /// public bool ShowName { get; set; } /// /// Gets or sets the ShowIcon /// public bool ShowIcon { get; set; } /// /// Gets or sets the SRL /// public SubpageReferenceList SRL { get; private set; } /// /// Gets or sets the Model /// public DevicePresetsModel Model { get; private set; } /// /// Constructor /// /// trilst /// device presets model /// public DevicePresetsView(BasicTriListWithSmartObject tl, DevicePresetsModel model) { if (model == null) { throw new ArgumentNullException("model", "DevicePresetsView Cannot be instantiated with null model"); } ShowIcon = true; ShowName = true; Model = model; SRL = new SubpageReferenceList(tl, 10012, 3, 0, 4); Model.PresetsLoaded += new EventHandler(Model_PresetsLoaded); } /// /// Attach method /// public void Attach() { if (Model.PresetsAreLoaded) { uint index = 1; foreach (var p in Model.PresetsList) { SRL.AddItem(new PresetsListSubpageReferenceListItem(p, index, SRL, this)); index++; } SRL.Count = (ushort)Model.PresetsList.Count; } } /// /// Detach method /// public void Detach() { SRL.Clear(); } void Model_PresetsLoaded(object sender, EventArgs e) { Detach(); Attach(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Presets/Interfaces.cs ================================================ //using System; //using System.Collections.Generic; //using System.Linq; //using System.Text; //using Crestron.SimplSharp; //namespace PepperDash.Essentials.Core //{ // public interface IPresetsFileChanged : IKeyed // { // public event EventHandler PresetsFileChanged; // } // public class PresetsFileChangeEventArgs : EventArgs // { // public string FilePath { get; private set; } // public PresetsFileChangeEventArgs(string filePath) // { // FilePath = filePath; // } // } //} ================================================ FILE: src/PepperDash.Essentials.Core/Presets/PresetBase.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; namespace PepperDash.Essentials.Core.Presets { /// /// Represents a PresetBase /// public class PresetBase { /// /// Gets or sets the ID /// [JsonProperty("id")] public int ID { get; set; } /// /// Gets or sets the Description /// [JsonProperty("description")] public string Description { get; set; } /// /// Gets or sets Defined /// [JsonProperty("defined")] public bool Defined { get; set; } /// /// Gets or sets the IsDefinable /// [JsonProperty("isDefinable")] public bool IsDefinable { get; set; } /// /// Constructor /// /// id of the preset /// description of the preset /// whether the preset is defined /// whether the preset is definable public PresetBase(int id, string description, bool def, bool isDef) { ID = id; Description = description; Defined = def; IsDefinable = isDef; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Presets/PresetChannel.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; namespace PepperDash.Essentials.Core.Presets { /// /// Represents a PresetChannel /// public class PresetChannel { /// /// Gets or sets the Name /// [JsonProperty(Required = Required.Always,PropertyName = "name")] public string Name { get; set; } /// /// Gets or sets the IconUrl /// [JsonProperty(Required = Required.Always, PropertyName = "iconUrl")] public string IconUrl { get; set; } /// /// Gets or sets the Channel /// [JsonProperty(Required = Required.Always, PropertyName = "channel")] public string Channel { get; set; } } /// /// Represents a PresetsList /// public class PresetsList { /// /// Gets or sets the Name /// [JsonProperty(Required=Required.Always,PropertyName = "name")] public string Name { get; set; } /// /// Gets or sets the Channels /// [JsonProperty(Required = Required.Always, PropertyName = "channels")] public List Channels { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Presets/PresetsListSubpageReferenceListItem.cs ================================================ 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 Serilog.Events; namespace PepperDash.Essentials.Core.Presets { /// /// Represents a PresetsListSubpageReferenceListItem /// public class PresetsListSubpageReferenceListItem : SubpageReferenceListItem { DevicePresetsView View; PresetChannel Channel; /// /// Constructor /// /// preset channel /// index of the preset /// owner of the subpage reference list item /// device presets view public PresetsListSubpageReferenceListItem(PresetChannel chan, uint index, SubpageReferenceList owner, DevicePresetsView view) : base(index, owner) { View = view; Channel = chan; owner.GetBoolFeedbackSig(index, 1).UserObject = new Action(b => { if (!b) view.Model.Dial((int)index); }); Refresh(); } /// /// Clear method /// /// public override void Clear() { Owner.GetBoolFeedbackSig(Index, 1).UserObject = null; Owner.StringInputSig(Index, 1).StringValue = ""; Owner.StringInputSig(Index, 2).StringValue = ""; Owner.StringInputSig(Index, 3).StringValue = ""; } /// /// Refresh method /// /// public override void Refresh() { var name = View.ShowName ? Channel.Name : ""; Owner.StringInputSig(Index, 1).StringValue = name; var chan = View.ShowNumbers ? Channel.Channel : ""; Owner.StringInputSig(Index, 2).StringValue = chan; var url = View.Model.ImagesLocalHostPrefix + View.Model.ImagesPathPrefix + Channel.IconUrl; Debug.LogMessage(LogEventLevel.Verbose, "icon url={0}", url); var icon = View.ShowIcon ? url : ""; Owner.StringInputSig(Index, 3).StringValue = icon; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Properties/ControlSystem.cfg ================================================ ================================================ FILE: src/PepperDash.Essentials.Core/Queues/ComsMessage.cs ================================================ using System; using PepperDash.Core; namespace PepperDash.Essentials.Core.Queues { /// /// Represents a ComsMessage /// public class ComsMessage : IQueueMessage { private readonly byte[] _bytes; private readonly IBasicCommunication _coms; private readonly string _string; private readonly bool _isByteMessage; /// /// Constructor for a string message /// /// IBasicCommunication to send the message /// Message to send public ComsMessage(IBasicCommunication coms, string message) { Validate(coms, message); _coms = coms; _string = message; } /// /// Constructor for a byte message /// /// IBasicCommunication to send the message /// Message to send public ComsMessage(IBasicCommunication coms, byte[] message) { Validate(coms, message); _coms = coms; _bytes = message; _isByteMessage = true; } private void Validate(IBasicCommunication coms, object message) { if (coms == null) throw new ArgumentNullException("coms"); if (message == null) throw new ArgumentNullException("message"); } /// /// Dispatch method /// public void Dispatch() { if (_isByteMessage) { _coms.SendBytes(_bytes); } else { _coms.SendText(_string); } } /// /// ToString method /// /// public override string ToString() { return _bytes != null ? _bytes.ToString() : _string; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Queues/GenericQueue.cs ================================================ using System; using System.Collections.Concurrent; using System.Threading; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; using Thread = Crestron.SimplSharpPro.CrestronThread.Thread; namespace PepperDash.Essentials.Core.Queues { /// /// Threadsafe processing of queued items with pacing if required /// public class GenericQueue : IQueue { private readonly string _key; /// /// The internal queue /// protected readonly ConcurrentQueue _queue; /// /// The worker thread /// protected readonly Thread _worker; /// /// The wait handle for the queue /// protected readonly CEvent _waitHandle = new CEvent(); private bool _delayEnabled; private int _delayTime; private const Thread.eThreadPriority _defaultPriority = Thread.eThreadPriority.MediumPriority; /// /// Gets or sets the Disposed /// public bool Disposed { get; private set; } /// /// Returns the capacity of the CrestronQueue (fixed Size property) /// public int QueueCapacity { get { return int.MaxValue; } } /// /// Returns the number of elements currently in the CrestronQueue /// public int QueueCount { get { return _queue.Count; } } /// /// Constructor with no thread priority /// /// public GenericQueue(string key) : this(key, _defaultPriority, 0, 0) { } /// /// Constructor with queue size /// /// /// Fixed size for the queue to hold public GenericQueue(string key, int capacity) : this(key, _defaultPriority, capacity, 0) { } /// /// Constructor for generic queue with no pacing /// /// Key /// Pacing in ms between actions public GenericQueue(int pacing, string key) : this(key, _defaultPriority, 0, pacing) { } /// /// Constructor with pacing and capacity /// /// /// /// public GenericQueue(string key, int pacing, int capacity) : this(key, _defaultPriority, capacity, pacing) { } /// /// Constructor with pacing and priority /// /// /// /// public GenericQueue(string key, int pacing, Thread.eThreadPriority priority) : this(key, priority, 0, pacing) { } /// /// Constructor with pacing, priority and capacity /// /// /// /// public GenericQueue(string key, Thread.eThreadPriority priority, int capacity) : this(key, priority, capacity, 0) { } /// /// Constructor with pacing, priority and capacity /// /// /// /// /// public GenericQueue(string key, int pacing, Thread.eThreadPriority priority, int capacity) : this(key, priority, capacity, pacing) { } /// /// Constructor for generic queue with no pacing /// /// Key /// /// /// protected GenericQueue(string key, Thread.eThreadPriority priority, int capacity, int pacing) { _key = key; int cap = 25; // sets default if (capacity > 0) { cap = capacity; // overrides default } _queue = new ConcurrentQueue(); _worker = new Thread(ProcessQueue, null, Thread.eThreadStartOptions.Running) { Priority = priority, Name = _key }; SetDelayValues(pacing); } private void SetDelayValues(int pacing) { _delayEnabled = pacing > 0; _delayTime = pacing; CrestronEnvironment.ProgramStatusEventHandler += programEvent => { if (programEvent != eProgramStatusEventType.Stopping) return; Dispose(true); }; } /// /// Thread callback /// /// The action used to process dequeued items /// Null when the thread is exited private object ProcessQueue(object obj) { while (true) { if (_queue.TryDequeue(out var item) && item == null) break; if (item != null) { try { //Debug.LogMessage(LogEventLevel.Verbose, this, "Processing queue item: '{0}'", item.ToString()); item.Dispatch(); if (_delayEnabled) Thread.Sleep(_delayTime); } catch (ThreadAbortException) { //swallowing this exception, as it should only happen on shut down } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Information, this, "Caught an exception in the Queue: {1}:{0}", ex.Message, ex); Debug.LogMessage(LogEventLevel.Verbose, this, "Stack Trace: {0}", ex.StackTrace); if (ex.InnerException != null) { Debug.LogMessage(LogEventLevel.Information, this, "---\r\n{0}", ex.InnerException.Message); Debug.LogMessage(LogEventLevel.Verbose, this, "Stack Trace: {0}", ex.InnerException.StackTrace); } } } else _waitHandle.Wait(); } return null; } /// /// Enqueue method /// public void Enqueue(IQueueMessage item) { if (Disposed) { Debug.LogMessage(LogEventLevel.Debug, this, "Queue has been disposed. Enqueuing messages not allowed while program is stopping."); return; } _queue.Enqueue(item); _waitHandle.Set(); } /// /// Dispose method /// public void Dispose() { Dispose(true); CrestronEnvironment.GC.SuppressFinalize(this); } /// /// Actually does the disposing. If you override this method, be sure to either call the base implementation /// or clean up all the resources yourself. /// /// set to true unless called from finalizer protected void Dispose(bool disposing) { if (Disposed) return; if (disposing) { using (_waitHandle) { Debug.LogMessage(LogEventLevel.Verbose, this, "Disposing..."); _queue.Enqueue(null); _waitHandle.Set(); _worker.Join(); } } Disposed = true; } /// /// Finalizer /// ~GenericQueue() { Dispose(true); } /// /// Key /// public string Key { get { return _key; } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Queues/IQueue.cs ================================================ using System; using PepperDash.Core; namespace PepperDash.Essentials.Core.Queues { /// /// Defines the contract for IQueue /// public interface IQueue : IKeyed, IDisposable where T : class { /// /// Enqueues an item /// /// item to be queued void Enqueue(T item); /// /// gets the disposed status of the queue /// bool Disposed { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Queues/IQueueMessage.cs ================================================ using System; namespace PepperDash.Essentials.Core.Queues { /// /// Defines the contract for IQueueMessage /// public interface IQueueMessage { /// /// Dispatches the message /// void Dispatch(); } } ================================================ FILE: src/PepperDash.Essentials.Core/Queues/ProcessStringMessage.cs ================================================ using System; namespace PepperDash.Essentials.Core.Queues { /// /// Represents a ProcessStringMessage /// public class ProcessStringMessage : IQueueMessage { private readonly Action _action; private readonly string _message; /// /// Constructor /// /// Message to be processed /// Action to invoke on the message public ProcessStringMessage(string message, Action action) { _message = message; _action = action; } /// /// Processes the string with the given action /// public void Dispatch() { if (_action == null || String.IsNullOrEmpty(_message)) return; _action(_message); } /// /// To string /// /// The current message /// /// ToString method /// /// public override string ToString() { return _message ?? String.Empty; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Queues/StringResponseProcessor.cs ================================================ using System; using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Essentials.Core.Queues { /// /// Processes string responses from a communication port or gather using a queue to ensure thread safety /// public sealed class StringResponseProcessor : IKeyed, IDisposable { private readonly Action _processStringAction; private readonly IQueue _queue; private readonly IBasicCommunication _coms; private readonly CommunicationGather _gather; private StringResponseProcessor(string key, Action processStringAction) { _processStringAction = processStringAction; _queue = new GenericQueue(key); CrestronEnvironment.ProgramStatusEventHandler += programEvent => { if (programEvent != eProgramStatusEventType.Stopping) return; Dispose(); }; } /// /// Constructor that builds an instance and subscribes to coms TextReceived for processing /// /// Com port to process strings from /// Action to process the incoming strings public StringResponseProcessor(IBasicCommunication coms, Action processStringAction) : this(coms.Key, processStringAction) { _coms = coms; coms.TextReceived += OnResponseReceived; } /// /// Constructor that builds an instance and subscribes to gather Line Received for processing /// /// Gather to process strings from /// Action to process the incoming strings public StringResponseProcessor(CommunicationGather gather, Action processStringAction) : this(gather.Port.Key, processStringAction) { _gather = gather; gather.LineReceived += OnResponseReceived; } private void OnResponseReceived(object sender, GenericCommMethodReceiveTextArgs args) { _queue.Enqueue(new ProcessStringMessage(args.Text, _processStringAction)); } /// /// Key /// public string Key { get { return _queue.Key; } } /// /// Disposes the instance and cleans up resources. /// public void Dispose() { Dispose(true); CrestronEnvironment.GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (Disposed) return; if (disposing) { if (_coms != null) _coms.TextReceived -= OnResponseReceived; if (_gather != null) { _gather.LineReceived -= OnResponseReceived; _gather.Stop(); } _queue.Dispose(); } Disposed = true; } /// /// Gets or sets the Disposed /// public bool Disposed { get; private set; } /// /// Finalizer /// ~StringResponseProcessor() { Dispose(false); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Ramps and Increments/ActionIncrementer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// An incrementer that can use the values of some other object/primitive value to do its thing. /// It uses an Action to set the value and a Func to get the value from whatever this is /// attached to. /// public class ActionIncrementer { /// /// The amount to change the value by each increment /// public int ChangeAmount { get; set; } /// /// The maximum value for the incrementer /// public int MaxValue { get; set; } /// /// The minimum value for the incrementer /// public int MinValue { get; set; } /// /// The delay before repeating starts /// public uint RepeatDelay { get; set; } /// /// The time between repeats /// public uint RepeatTime { get; set; } Action SetAction; Func GetFunc; CTimer Timer; /// /// /// /// /// /// /// /// /// Action that will be called when this needs to set the destination value /// Func that is called to get the current value public ActionIncrementer(int changeAmount, int minValue, int maxValue, uint repeatDelay, uint repeatTime, Action setAction, Func getFunc) { SetAction = setAction; GetFunc = getFunc; ChangeAmount = changeAmount; MaxValue = maxValue; MinValue = minValue; RepeatDelay = repeatDelay; RepeatTime = repeatTime; } /// /// StartUp method /// public void StartUp() { if (Timer != null) return; Go(ChangeAmount); } /// /// Starts decrementing cycle /// public void StartDown() { if (Timer != null) return; Go(-ChangeAmount); } /// /// Stops the repeat /// public void Stop() { if (Timer != null) Timer.Stop(); Timer = null; } /// /// Helper that does the work of setting new level, and starting repeat loop, checking against bounds first. /// /// void Go(int change) { int currentLevel = GetFunc(); // Fire once then pause int newLevel = currentLevel + change; bool atLimit = CheckLevel(newLevel, out newLevel); SetAction(newLevel); if (atLimit) // Don't go past end Stop(); else if (Timer == null) // Only enter the timer if it's not already running Timer = new CTimer(o => { Go(change); }, null, RepeatDelay, RepeatTime); } /// /// Helper to check a new level against min/max. Returns revised level if new level /// will go out of bounds /// /// The level to check against bounds /// Revised level if bounds are exceeded. Min or max /// true if new level is at or past bounds bool CheckLevel(int levelIn, out int levelOut) { bool isAtLimit = false; if (levelIn > MaxValue) { levelOut = MaxValue; isAtLimit = true; } else if (levelIn < MinValue) { levelOut = MinValue; isAtLimit = true; } else levelOut = levelIn; return isAtLimit; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Ramps and Increments/NumericalHelpers.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Represents a NumericalHelpers /// public class NumericalHelpers { /// /// Scales a value /// /// /// /// /// /// /// public static double Scale(double input, double inMin, double inMax, double outMin, double outMax) { //Debug.LogMessage(LogEventLevel.Verbose, this, "Scaling (double) input '{0}' with min '{1}'/max '{2}' to output range min '{3}'/max '{4}'", input, inMin, inMax, outMin, outMax); double inputRange = inMax - inMin; if (inputRange <= 0) { throw new ArithmeticException(string.Format("Invalid Input Range '{0}' for Scaling. Min '{1}' Max '{2}'.", inputRange, inMin, inMax)); } double outputRange = outMax - outMin; var output = (((input - inMin) * outputRange) / inputRange) + outMin; // Debug.LogMessage(LogEventLevel.Verbose, this, "Scaled output '{0}'", output); return output; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Ramps and Increments/UshortSigIncrementer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Attaches to UShortInputSig and does incremental ramping of the signal /// public class UshortSigIncrementer { UShortInputSig TheSig; /// /// The amount to change the value by each increment /// public ushort ChangeAmount { get; set; } /// /// The maximum value for the incrementer /// public int MaxValue { get; set; } /// /// The minimum value for the incrementer /// public int MinValue { get; set; } /// /// The delay before repeating starts /// public uint RepeatDelay { get; set; } /// /// The time between repeats /// public uint RepeatTime { get; set; } bool SignedMode; CTimer Timer; /// /// Constructor /// /// the signal toi be incremented /// the amount to increment by /// the minimum value of the signal /// the maximum value of the signal /// the delay before repeating starts /// the time between repeats public UshortSigIncrementer(UShortInputSig sig, ushort changeAmount, int minValue, int maxValue, uint repeatDelay, uint repeatTime) { TheSig = sig; ChangeAmount = changeAmount; MaxValue = maxValue; MinValue = minValue; if (MinValue < 0 || MaxValue < 0) SignedMode = true; RepeatDelay = repeatDelay; RepeatTime = repeatTime; if (SignedMode && (MinValue < -32768 || MaxValue > 32767)) Debug.LogMessage(LogEventLevel.Debug, "UshortSigIncrementer has signed values that exceed range of -32768, 32767"); } /// /// StartUp method /// public void StartUp() { if (Timer != null) return; Go(ChangeAmount); } /// /// StartDown method /// public void StartDown() { if (Timer != null) return; Go(-ChangeAmount); } void Go(int change) { int level; if (SignedMode) level = TheSig.ShortValue; else level = TheSig.UShortValue; // Fire once then pause int newLevel = level + change; bool atLimit = CheckLevel(newLevel, out newLevel); SetValue((ushort)newLevel); if (atLimit) // Don't go past end Stop(); else if (Timer == null) // Only enter the timer if it's not already running Timer = new CTimer(o => { Go(change); }, null, RepeatDelay, RepeatTime); } bool CheckLevel(int levelIn, out int levelOut) { bool IsAtLimit = false; if (levelIn > MaxValue) { levelOut = MaxValue; IsAtLimit = true; } else if (levelIn < MinValue) { levelOut = MinValue; IsAtLimit = true; } else levelOut = levelIn; return IsAtLimit; } /// /// Stop method /// public void Stop() { if (Timer != null) Timer.Stop(); Timer = null; } void SetValue(ushort value) { //CrestronConsole.PrintLine("Increment level:{0} / {1}", value, (short)value); TheSig.UShortValue = value; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.Scheduler; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// A device that when linked to a room can power the room on when enabled during scheduled hours. /// public class RoomOnToDefaultSourceWhenOccupied : ReconfigurableDevice { RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig; /// /// Gets or sets the FeatureEnabled /// public bool FeatureEnabled { get; private set; } /// /// Gets or sets the FeatureEnabledTime /// public DateTime FeatureEnabledTime { get; private set; } ScheduledEvent FeatureEnableEvent; const string FeatureEnableEventName = "EnableRoomOnToDefaultSourceWhenOccupied"; /// /// Gets or sets the FeatureDisabledTime /// public DateTime FeatureDisabledTime { get; private set; } ScheduledEvent FeatureDisableEvent; const string FeatureDisableEventName = "DisableRoomOnToDefaultSourceWhenOccupied"; ScheduledEventGroup FeatureEventGroup; /// /// Gets or sets the Room /// public IRoomOccupancy Room { get; private set; } private Fusion.IEssentialsRoomFusionController FusionRoom; /// /// Constructor for RoomOnToDefaultSourceWhenOccupied /// /// config of the device public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) : base (config) { PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); FeatureEventGroup = new ScheduledEventGroup(this.Key); FeatureEventGroup.RetrieveAllEvents(); // Add to the global class for tracking Scheduler.AddEventGroup(FeatureEventGroup); AddPostActivationAction(() => { // Subscribe to room event to know when RoomOccupancy is set and ready to be subscribed to if (Room != null) Room.RoomOccupancyIsSet += new EventHandler(RoomOccupancyIsSet); else Debug.LogMessage(LogEventLevel.Debug, this, "Room has no RoomOccupancy object set"); var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion"; FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Core.Fusion.IEssentialsRoomFusionController; if (FusionRoom == null) Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey); }); } /// /// CustomActivate method /// /// public override bool CustomActivate() { SetUpDevice(); return base.CustomActivate(); } /// /// Sets up device based on config values /// void SetUpDevice() { Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as IRoomOccupancy; if (Room != null) { try { FeatureEnabledTime = DateTime.Parse(PropertiesConfig.OccupancyStartTime); if (FeatureEnabledTime != null) { Debug.LogMessage(LogEventLevel.Debug, this, "Enabled Time: {0}", FeatureEnabledTime.ToString()); } else Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyStartTime); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e); } try { FeatureDisabledTime = DateTime.Parse(PropertiesConfig.OccupancyEndTime); if (FeatureDisabledTime != null) { Debug.LogMessage(LogEventLevel.Debug, this, "Disabled Time: {0}", FeatureDisabledTime.ToString()); } else Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyEndTime); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Debug, this, "Unable to parse a DateTime config value \n Error: {1}", e); } if (!PropertiesConfig.EnableRoomOnWhenOccupied) FeatureEventGroup.ClearAllEvents(); else { AddEnableEventToGroup(); AddDisableEventToGroup(); FeatureEventGroup.UserGroupCallBack += new ScheduledEventGroup.UserEventGroupCallBack(FeatureEventGroup_UserGroupCallBack); FeatureEventGroup.EnableAllEvents(); } FeatureEnabled = CheckIfFeatureShouldBeEnabled(); } else Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get room from Device Manager with key: {0}", PropertiesConfig.RoomKey); } /// /// CustomSetConfig method /// /// config of the device protected override void CustomSetConfig(DeviceConfig config) { var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); if(newPropertiesConfig != null) PropertiesConfig = newPropertiesConfig; ConfigWriter.UpdateDeviceConfig(config); SetUpDevice(); } /// /// Subscribe to feedback from RoomIsOccupiedFeedback on Room /// /// /// void RoomOccupancyIsSet(object sender, EventArgs e) { if (Room.RoomOccupancy != null) { Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += new EventHandler(RoomIsOccupiedFeedback_OutputChange); Debug.LogMessage(LogEventLevel.Debug, this, "Subscribed to RoomOccupancy status from: '{0}'", Room.Key); } } void FeatureEventGroup_UserGroupCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) { Debug.LogMessage(LogEventLevel.Debug, this, "{0}:{1} @ {2}", SchEvent.Name, type, DateTime.Now); if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) { SchEvent.Acknowledge(); if (SchEvent.Name == FeatureEnableEventName) { if (PropertiesConfig.EnableRoomOnWhenOccupied) FeatureEnabled = true; Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Enabled by event.*****"); } else if (SchEvent.Name == FeatureDisableEventName) { FeatureEnabled = false; Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Disabled by event.*****"); } } } /// /// Checks if the feature should be currently enabled. Used on startup if processor starts after start time but before end time /// /// bool CheckIfFeatureShouldBeEnabled() { bool enabled = false; if(PropertiesConfig.EnableRoomOnWhenOccupied) { Debug.LogMessage(LogEventLevel.Debug, this, "Current Time: {0} \n FeatureEnabledTime: {1} \n FeatureDisabledTime: {2}", DateTime.Now, FeatureEnabledTime, FeatureDisabledTime); if (DateTime.Now.TimeOfDay.CompareTo(FeatureEnabledTime.TimeOfDay) >= 0 && FeatureDisabledTime.TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0) { if (SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(DateTime.Now, CalculateDaysOfWeekRecurrence())) { enabled = true; } } } if(enabled) Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Enabled*****"); else Debug.LogMessage(LogEventLevel.Debug, this, "*****Feature Disabled*****"); return enabled; } /// /// Respond to Occupancy status event /// /// /// void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) { Debug.LogMessage(LogEventLevel.Debug, this, "RoomIsOccupiedFeeback.OutputChange event fired. e.BoolValue: {0}", e.BoolValue); if(e.BoolValue) { // Occupancy detected if (FeatureEnabled) { var essentialsRoom = Room as IEssentialsRoom; if (essentialsRoom != null) { if (!essentialsRoom.OnFeedback.BoolValue) { Debug.LogMessage(LogEventLevel.Debug, this, "Powering Room on to default source"); var defaultRouteRoom = Room as IRunDefaultPresentRoute; if (defaultRouteRoom != null) { defaultRouteRoom.RunDefaultPresentRoute(); } } } // Check room power state first } } } void CreateEvent(ScheduledEvent schEvent, string name) { Debug.LogMessage(LogEventLevel.Debug, this, "Adding Event: '{0}'", name); // Create the event if (schEvent == null) schEvent = new ScheduledEvent(name, FeatureEventGroup); // Set up its initial properties schEvent.Acknowledgeable = false; if(!schEvent.Persistent) schEvent.Persistent = true; schEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); // Set config driven properties if (schEvent.Name == FeatureEnableEventName) { schEvent.Description = "Enables the RoomOnToDefaultSourceWhenOccupiedFeature"; var eventRecurrennce = CalculateDaysOfWeekRecurrence(); var eventTime = new DateTime(); // Check to make sure the date for this event is in the future if (DateTime.Now.CompareTo(FeatureEnabledTime) > 0) eventTime = FeatureEnabledTime.AddDays(1); else eventTime = FeatureEnabledTime; Debug.LogMessage(LogEventLevel.Debug, this, "eventTime (before recurrence check): {0}", eventTime); // Check day of week against recurrence days and move date ahead as necessary to avoid throwing an exception by trying to set the event // start date on a day of the week that doesn't match teh recurrence values while(!SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(eventTime, eventRecurrennce)) { eventTime = eventTime.AddDays(1); Debug.LogMessage(LogEventLevel.Debug, this, "eventTime does not fall on a recurrence weekday. eventTime: {0}", eventTime); } schEvent.DateAndTime.SetAbsoluteEventTime(eventTime); Debug.LogMessage(LogEventLevel.Debug, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); //CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureEnabledTime, FeatureDisabledTime); schEvent.Recurrence.Weekly(eventRecurrennce); } else if (schEvent.Name == FeatureDisableEventName) { schEvent.Description = "Disables the RoomOnToDefaultSourceWhenOccupiedFeature"; // Check to make sure the date for this event is in the future if (DateTime.Now.CompareTo(FeatureDisabledTime) > 0) schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime.AddDays(1)); else schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime); Debug.LogMessage(LogEventLevel.Debug, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureDisabledTime, FeatureEnabledTime); schEvent.Recurrence.Daily(); } } void CalculateAndSetAcknowledgeExpirationTimeout(ScheduledEvent schEvent, DateTime time1, DateTime time2) { Debug.LogMessage(LogEventLevel.Debug, this, "time1.Hour = {0}", time1.Hour); Debug.LogMessage(LogEventLevel.Debug, this, "time2.Hour = {0}", time2.Hour); Debug.LogMessage(LogEventLevel.Debug, this, "time1.Minute = {0}", time1.Minute); Debug.LogMessage(LogEventLevel.Debug, this, "time2.Minute = {0}", time2.Minute); // Calculate the Acknowledge Expiration timer to be the time between the enable and dispable events, less one minute var ackHours = time2.Hour - time1.Hour; if(ackHours < 0) ackHours = ackHours + 24; var ackMinutes = time2.Minute - time1.Minute; Debug.LogMessage(LogEventLevel.Debug, this, "ackHours = {0}, ackMinutes = {1}", ackHours, ackMinutes); var ackTotalMinutes = ((ackHours * 60) + ackMinutes) - 1; var ackExpHour = ackTotalMinutes / 60; var ackExpMinutes = ackTotalMinutes % 60; Debug.LogMessage(LogEventLevel.Debug, this, "Acknowledge Expiration Timeout: {0} hours, {1} minutes", ackExpHour, ackExpMinutes); schEvent.AcknowledgeExpirationTimeout.Hour = (ushort)(ackHours); schEvent.AcknowledgeExpirationTimeout.Minute = (ushort)(ackExpMinutes); } /// /// Checks existing event to see if it matches the execution time /// /// event we are checking /// time we are checking against /// bool CheckExistingEventTimeForMatch(ScheduledEvent existingEvent, DateTime newTime) { bool isMatch = true; // Check to see if hour and minute match if (existingEvent.DateAndTime.Hour != newTime.Hour || existingEvent.DateAndTime.Minute != newTime.Minute) return false; return isMatch; } /// /// Checks existing event to see if it matches the recurrence days /// /// /// /// bool CheckExistingEventRecurrenceForMatch(ScheduledEvent existingEvent, ScheduledEventCommon.eWeekDays eWeekdays) { bool isMatch = true; // Check to see if recurrence matches if (eWeekdays != existingEvent.Recurrence.RecurrenceDays) return false; return isMatch; } /// /// Adds the Enable event to the local event group and sets its properties based on config /// void AddEnableEventToGroup() { if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureEnableEventName)) { CreateEvent(FeatureEnableEvent, FeatureEnableEventName); } else { // Check if existing event has same time and recurrence as config values FeatureEnableEvent = FeatureEventGroup.ScheduledEvents[FeatureEnableEventName]; Debug.LogMessage(LogEventLevel.Debug, this, "Enable event already found in group"); // Check config times and days against DateAndTime of existing event. If different, delete existing event and create new event if(!CheckExistingEventTimeForMatch(FeatureEnableEvent, FeatureEnabledTime) || !CheckExistingEventRecurrenceForMatch(FeatureEnableEvent, CalculateDaysOfWeekRecurrence())) { Debug.LogMessage(LogEventLevel.Debug, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureEnableEvent.Name); FeatureEventGroup.DeleteEvent(FeatureEnableEvent); FeatureEnableEvent = null; CreateEvent(FeatureEnableEvent, FeatureEnableEventName); } } } /// /// Adds the Enable event to the local event group and sets its properties based on config /// void AddDisableEventToGroup() { if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureDisableEventName)) { CreateEvent(FeatureDisableEvent, FeatureDisableEventName); } else { FeatureDisableEvent = FeatureEventGroup.ScheduledEvents[FeatureDisableEventName]; Debug.LogMessage(LogEventLevel.Debug, this, "Disable event already found in group"); // Check config times against DateAndTime of existing event. If different, delete existing event and create new event if(!CheckExistingEventTimeForMatch(FeatureDisableEvent, FeatureDisabledTime)) { Debug.LogMessage(LogEventLevel.Debug, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureDisableEvent.Name); FeatureEventGroup.DeleteEvent(FeatureDisableEvent); FeatureDisableEvent = null; CreateEvent(FeatureDisableEvent, FeatureDisableEventName); } } } /// /// Calculates the correct bitfield enum value for the event recurrence based on the config values /// /// ScheduledEventCommon.eWeekDays CalculateDaysOfWeekRecurrence() { ScheduledEventCommon.eWeekDays value = new ScheduledEventCommon.eWeekDays(); if (PropertiesConfig.EnableSunday) value = value | ScheduledEventCommon.eWeekDays.Sunday; if (PropertiesConfig.EnableMonday) value = value | ScheduledEventCommon.eWeekDays.Monday; if (PropertiesConfig.EnableTuesday) value = value | ScheduledEventCommon.eWeekDays.Tuesday; if (PropertiesConfig.EnableWednesday) value = value | ScheduledEventCommon.eWeekDays.Wednesday; if (PropertiesConfig.EnableThursday) value = value | ScheduledEventCommon.eWeekDays.Thursday; if (PropertiesConfig.EnableFriday) value = value | ScheduledEventCommon.eWeekDays.Friday; if (PropertiesConfig.EnableSaturday) value = value | ScheduledEventCommon.eWeekDays.Saturday; return value; } /// /// Callback for event that enables feature. Enables feature if config property is true /// /// /// void FeatureEnableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) { if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) { if(PropertiesConfig.EnableRoomOnWhenOccupied) FeatureEnabled = true; Debug.LogMessage(LogEventLevel.Debug, this, "RoomOnToDefaultSourceWhenOccupied Feature Enabled."); } } /// /// Callback for event that enables feature. Disables feature /// /// /// void FeatureDisableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) { if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) { FeatureEnabled = false; Debug.LogMessage(LogEventLevel.Debug, this, "RoomOnToDefaultSourceWhenOccupied Feature Disabled."); } } } /// /// Represents a RoomOnToDefaultSourceWhenOccupiedConfig /// public class RoomOnToDefaultSourceWhenOccupiedConfig { /// /// Gets or sets the RoomKey /// [JsonProperty("roomKey")] public string RoomKey { get; set; } /// /// Gets or sets the EnableRoomOnWhenOccupied /// [JsonProperty("enableRoomOnWhenOccupied")] public bool EnableRoomOnWhenOccupied { get; set; } /// /// Gets or sets the OccupancyStartTime /// [JsonProperty("occupancyStartTime")] public string OccupancyStartTime { get; set; } /// /// Gets or sets the OccupancyEndTime /// [JsonProperty("occupancyEndTime")] public string OccupancyEndTime { get; set; } /// /// Gets or sets the EnableSunday /// [JsonProperty("enableSunday")] public bool EnableSunday { get; set; } /// /// Gets or sets the EnableMonday /// [JsonProperty("enableMonday")] public bool EnableMonday { get; set; } /// /// Gets or sets the EnableTuesday /// [JsonProperty("enableWednesday")] public bool EnableTuesday { get; set; } /// /// Gets or sets the EnableWednesday /// [JsonProperty("enableWednesday")] public bool EnableWednesday { get; set; } /// /// Gets or sets the EnableThursday /// [JsonProperty("enableThursday")] public bool EnableThursday { get; set; } /// /// Gets or sets the EnableFriday /// [JsonProperty("enableFriday")] public bool EnableFriday { get; set; } /// /// Gets or sets the EnableSaturday /// [JsonProperty("enableSaturday")] public bool EnableSaturday { get; set; } } /// /// Represents a RoomOnToDefaultSourceWhenOccupiedFactory /// public class RoomOnToDefaultSourceWhenOccupiedFactory : EssentialsDeviceFactory { /// /// Constructor for RoomOnToDefaultSourceWhenOccupiedFactory /// public RoomOnToDefaultSourceWhenOccupiedFactory() { TypeNames = new List() { "roomonwhenoccupancydetectedfeature" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RoomOnToDefaultSourceWhenOccupied Device"); return new RoomOnToDefaultSourceWhenOccupied(dc); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombiner.cs ================================================ using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Core.Logging; using Serilog.Events; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace PepperDash.Essentials.Core { /// /// Represents a device that manages room combinations by controlling partitions and scenarios. /// /// The allows for dynamic configuration of room /// combinations based on partition states and predefined scenarios. It supports both automatic and manual modes /// for managing room combinations. In automatic mode, the device determines the current room combination scenario /// based on partition sensor states. In manual mode, scenarios can be set explicitly by the user. public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner { private EssentialsRoomCombinerPropertiesConfig _propertiesConfig; private IRoomCombinationScenario _currentScenario; private List _rooms; /// /// Gets a list of rooms represented as key-name pairs. /// public List Rooms { get { return _rooms.Cast().ToList(); } } private bool _isInAutoMode; /// /// Gets or sets a value indicating whether the system is operating in automatic mode. /// /// Changing this property triggers an update event via /// IsInAutoModeFeedback.FireUpdate(). Ensure that any event listeners are properly configured to handle /// this update. public bool IsInAutoMode { get { return _isInAutoMode; } set { if (value == _isInAutoMode) { return; } _isInAutoMode = value; IsInAutoModeFeedback.FireUpdate(); } } /// /// Gets a value indicating whether automatic mode is disabled. /// public bool DisableAutoMode { get { return _propertiesConfig.DisableAutoMode; } } private CTimer _scenarioChangeDebounceTimer; private int _scenarioChangeDebounceTimeSeconds = 10; // default to 10s private Mutex _scenarioChange = new Mutex(); /// /// Initializes a new instance of the class, which manages room combination /// scenarios and partition states. /// /// The class is designed to handle dynamic room /// combination scenarios based on partition states. It supports both automatic and manual modes for managing /// room combinations. By default, the instance starts in automatic mode unless the /// specifies otherwise. After activation, the room combiner initializes partition state providers and sets up /// the initial room configuration. Additionally, it subscribes to the event to ensure proper initialization of dependent devices /// before determining or setting the room combination scenario. /// The unique identifier for the room combiner instance. /// The configuration properties for the room combiner, including default settings and debounce times. public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props) : base(key) { _propertiesConfig = props; Partitions = new List(); RoomCombinationScenarios = new List(); if (_propertiesConfig.ScenarioChangeDebounceTimeSeconds > 0) { _scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds; } IsInAutoModeFeedback = new BoolFeedback(() => _isInAutoMode); // default to auto mode IsInAutoMode = true; if (_propertiesConfig.defaultToManualMode) { IsInAutoMode = false; } IsInAutoModeFeedback.FireUpdate(); CreateScenarios(); AddPostActivationAction(() => { SetupPartitionStateProviders(); SetRooms(); }); // Subscribe to the AllDevicesInitialized event // We need to wait until all devices are initialized in case // any actions are dependent on 3rd party devices already being // connected and initialized DeviceManager.AllDevicesInitialized += (o, a) => { if (IsInAutoMode) { DetermineRoomCombinationScenario(); } else { SetRoomCombinationScenario(_propertiesConfig.defaultScenarioKey); } }; } private void CreateScenarios() { foreach (var scenarioConfig in _propertiesConfig.Scenarios) { var scenario = new RoomCombinationScenario(scenarioConfig); RoomCombinationScenarios.Add(scenario); } } private void SetRooms() { _rooms = new List(); foreach (var roomKey in _propertiesConfig.RoomKeys) { var room = DeviceManager.GetDeviceForKey(roomKey); if (DeviceManager.GetDeviceForKey(roomKey) is IEssentialsRoom essentialsRoom) { _rooms.Add(essentialsRoom); } } var rooms = DeviceManager.AllDevices.OfType().Cast(); foreach (var room in rooms) { room.Deactivate(); } } private void SetupPartitionStateProviders() { foreach (var pConfig in _propertiesConfig.Partitions) { var sensor = DeviceManager.GetDeviceForKey(pConfig.DeviceKey) as IPartitionStateProvider; var partition = new EssentialsPartitionController(pConfig.Key, pConfig.Name, sensor, _propertiesConfig.defaultToManualMode, pConfig.AdjacentRoomKeys); partition.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; Partitions.Add(partition); } } private void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) { StartDebounceTimer(); } private void StartDebounceTimer() { // default to 500ms for manual mode var time = 500; // if in auto mode, debounce the scenario change if (IsInAutoMode) time = _scenarioChangeDebounceTimeSeconds * 1000; if (_scenarioChangeDebounceTimer == null) { _scenarioChangeDebounceTimer = new CTimer((o) => DetermineRoomCombinationScenario(), time); } else { _scenarioChangeDebounceTimer.Reset(time); } } /// /// Determines the current room combination scenario based on the state of the partition sensors /// private void DetermineRoomCombinationScenario() { if (_scenarioChangeDebounceTimer != null) { _scenarioChangeDebounceTimer.Dispose(); _scenarioChangeDebounceTimer = null; } this.LogInformation("Determining Combination Scenario"); var currentScenario = RoomCombinationScenarios.FirstOrDefault((s) => { this.LogDebug("Checking scenario {scenarioKey}", s.Key); // iterate the partition states foreach (var partitionState in s.PartitionStates) { this.LogDebug("checking PartitionState {partitionStateKey}", partitionState.PartitionKey); // get the partition by key var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); this.LogDebug("Expected State: {partitionPresent} Actual State: {partitionState}", partitionState.PartitionPresent, partition.PartitionPresentFeedback.BoolValue); if (partition != null && partitionState.PartitionPresent != partition.PartitionPresentFeedback.BoolValue) { // the partition can't be found or the state doesn't match return false; } } // if it hasn't returned false by now we have the matching scenario return true; }); if (currentScenario != null) { this.LogInformation("Found combination Scenario {scenarioKey}", currentScenario.Key); ChangeScenario(currentScenario); } } private async Task ChangeScenario(IRoomCombinationScenario newScenario) { if (newScenario == _currentScenario) { return; } // Deactivate the old scenario first if (_currentScenario != null) { Debug.LogMessage(LogEventLevel.Information, "Deactivating scenario {currentScenario}", this, _currentScenario.Name); await _currentScenario.Deactivate(); } _currentScenario = newScenario; // Activate the new scenario if (_currentScenario != null) { Debug.LogMessage(LogEventLevel.Debug, $"Current Scenario: {_currentScenario.Name}", this); await _currentScenario.Activate(); } RoomCombinationScenarioChanged?.Invoke(this, new EventArgs()); } #region IEssentialsRoomCombiner Members /// /// Occurs when the room combination scenario changes. /// /// This event is triggered whenever the configuration or state of the room combination /// changes. Subscribers can use this event to update their logic or UI based on the new scenario. public event EventHandler RoomCombinationScenarioChanged; /// /// Gets the current room combination scenario. /// public IRoomCombinationScenario CurrentScenario { get { return _currentScenario; } } /// /// Gets or sets the IsInAutoModeFeedback /// public BoolFeedback IsInAutoModeFeedback { get; private set; } /// /// Enables auto mode for the room combiner and its partitions, allowing automatic room combination scenarios to /// be determined. /// /// Auto mode allows the room combiner to automatically adjust its configuration based on /// the state of its partitions. If auto mode is disabled in the configuration, this method logs a warning and /// does not enable auto mode. public void SetAutoMode() { if(_propertiesConfig.DisableAutoMode) { this.LogWarning("Auto mode is disabled for this room combiner. Cannot set to auto mode."); return; } IsInAutoMode = true; foreach (var partition in Partitions) { partition.SetAutoMode(); } DetermineRoomCombinationScenario(); } /// /// Switches the system to manual mode, disabling automatic operations. /// /// This method sets the system to manual mode by updating the mode state and propagates /// the change to all partitions. Once in manual mode, automatic operations are disabled for the system and its /// partitions. /// /// SetManualMode method /// public void SetManualMode() { IsInAutoMode = false; foreach (var partition in Partitions) { partition.SetManualMode(); } } /// /// Toggles the current mode between automatic and manual. /// /// If the current mode is automatic, this method switches to manual mode. If the /// current mode is manual, it switches to automatic mode. /// /// ToggleMode method /// public void ToggleMode() { if (IsInAutoMode) { SetManualMode(); } else { SetAutoMode(); } } /// /// Gets or sets the RoomCombinationScenarios /// public List RoomCombinationScenarios { get; private set; } /// /// Gets the collection of partition controllers managed by this instance. /// public List Partitions { get; private set; } /// /// Toggles the state of the partition identified by the specified partition key. /// /// If no partition with the specified key exists, the method performs no /// action. /// The key of the partition whose state is to be toggled. This value cannot be null or empty. public void TogglePartitionState(string partitionKey) { var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)); if (partition != null) { partition.ToggglePartitionState(); } } /// /// Sets the room combination scenario based on the specified scenario key. /// /// This method manually adjusts the partition states according to the specified /// scenario. If the application is in auto mode, the operation will not proceed, and a log message will be /// generated indicating that the mode must be set to manual first. If the specified scenario key does not /// match any existing scenario, a debug log message will be generated. For each partition state in the /// scenario, the corresponding partition will be updated to either "Present" or "Not Present" based on the /// scenario's configuration. If a partition key in the scenario cannot be found, a debug log message will be /// generated. /// The key identifying the room combination scenario to apply. This must match the key of an existing scenario. public void SetRoomCombinationScenario(string scenarioKey) { if (IsInAutoMode) { Debug.LogMessage(LogEventLevel.Information, this, "Cannot set room combination scenario when in auto mode. Set to auto mode first."); return; } // Get the scenario var scenario = RoomCombinationScenarios.FirstOrDefault((s) => s.Key.Equals(scenarioKey)); // Set the parition states from the scenario manually if (scenario != null) { Debug.LogMessage(LogEventLevel.Information, this, "Manually setting scenario to '{0}'", scenario.Key); foreach (var partitionState in scenario.PartitionStates) { var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); if (partition != null) { if (partitionState.PartitionPresent) { Debug.LogMessage(LogEventLevel.Information, this, "Manually setting state to Present for: '{0}'", partition.Key); partition.SetPartitionStatePresent(); } else { Debug.LogMessage(LogEventLevel.Information, this, "Manually setting state to Not Present for: '{0}'", partition.Key); partition.SetPartitionStateNotPresent(); } } else { Debug.LogMessage(LogEventLevel.Debug, this, "Unable to find partition with key: '{0}'", partitionState.PartitionKey); } } } else { Debug.LogMessage(LogEventLevel.Debug, this, "Unable to find scenario with key: '{0}'", scenarioKey); } } #endregion } /// /// Provides a factory for creating instances of devices. /// /// This factory is responsible for constructing devices /// based on the provided configuration. It supports the type name "essentialsroomcombiner" for device /// creation. /// /// Represents a EssentialsRoomCombinerFactory /// public class EssentialsRoomCombinerFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the class. /// /// This factory is used to create instances of room combiners with the specified type /// names. By default, the factory includes the type name "essentialsroomcombiner". public EssentialsRoomCombinerFactory() { TypeNames = new List { "essentialsroomcombiner" }; } /// /// Creates and initializes a new instance of the device. /// /// This method uses the provided device configuration to extract the properties and /// create an device. Ensure that the configuration contains valid /// properties for the device to be created successfully. /// The device configuration containing the key and properties required to build the device. /// A new instance of initialized with the specified configuration. public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EssentialsRoomCombiner Device"); var props = dc.Properties.ToObject(); return new EssentialsRoomCombiner(dc.Key, props); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using Newtonsoft.Json; namespace PepperDash.Essentials.Core { /// /// Config properties for an EssentialsRoomCombiner device /// public class EssentialsRoomCombinerPropertiesConfig { /// /// Gets or sets a value indicating whether the system operates in automatic mode. /// Some systems don't have partitions sensors, and show shouldn't allow auto mode to be turned on. When this is true in the configuration, /// auto mode won't be allowed to be turned on. /// [JsonProperty("disableAutoMode")] public bool DisableAutoMode { get; set; } /// /// The list of partitions that device the rooms /// [JsonProperty("partitions")] public List Partitions {get; set;} /// /// The list of combinations scenarios for the rooms /// [JsonProperty("scenarios")] public List Scenarios { get; set; } /// /// The list of rooms keys that can be combined /// [JsonProperty("roomKeys")] public List RoomKeys {get; set;} /// /// Set to true to default to manual mode /// [JsonProperty("defaultToManualMode")] public bool defaultToManualMode { get; set; } /// /// The key of the scenario to default to at system startup if in manual mode /// [JsonProperty("defaultScenarioKey")] public string defaultScenarioKey { get; set; } /// /// Gets or sets the debounce time, in seconds, for scenario changes. /// [JsonProperty("scenarioChangeDebounceTimeSeconds")] public int ScenarioChangeDebounceTimeSeconds { get; set; } } /// /// Config properties for a partition that separates rooms /// public class PartitionConfig : IKeyName { /// /// Gets or sets the unique key associated with the object. /// [JsonProperty("key")] public string Key { get; set; } /// /// Gets or sets the name associated with the object. /// [JsonProperty("name")] public string Name { get; set; } /// /// Key of the device that implements IPartitionStateProvider to provide the state of the partition /// [JsonProperty("deviceKey")] public string DeviceKey { get; set; } /// /// Keys of the rooms that this partion would be located between /// [JsonProperty("adjacentRoomKeys")] public List AdjacentRoomKeys { get; set; } } /// /// Config propeties for a room combination scenario /// public class RoomCombinationScenarioConfig : IKeyName { /// /// Gets or sets the key associated with the object. /// [JsonProperty("key")] public string Key { get; set; } /// /// Gets or sets the name associated with the object. /// [JsonProperty("name")] public string Name { get; set; } /// /// Gets or sets a value indicating whether to hide this scenario in the UI. /// [JsonProperty("hideInUi", NullValueHandling = NullValueHandling.Ignore)] public bool HideInUi { get; set; } /// /// Gets or sets the collection of partition states. /// [JsonProperty("partitionStates")] public List PartitionStates { get; set; } /// /// Determines which UI devices get mapped to which room in this scenario. The Key should be the key of the UI device and the Value should be the key of the room to map to /// [JsonProperty("uiMap")] public Dictionary UiMap { get; set; } /// /// Gets or sets the list of actions to be performed during device activation. /// [JsonProperty("activationActions")] public List ActivationActions { get; set; } /// /// Gets or sets the list of actions to be performed when a device is deactivated. /// [JsonProperty("deactivationActions")] public List DeactivationActions { get; set; } } /// /// Config properties to represent the state of a partition sensor in a RoomCombinationScenario /// public class PartitionState { /// /// Gets or sets the partition key used to group and organize data within a storage system. /// [JsonProperty("partitionKey")] public string PartitionKey { get; set; } /// /// Gets or sets a value indicating whether a partition is currently present. /// [JsonProperty("partitionSensedState")] public bool PartitionPresent { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs ================================================ using System; using System.Collections.Generic; using System.Threading.Tasks; using Newtonsoft.Json; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Describes the functionality for an EssentailsRoomCombiner device /// public interface IEssentialsRoomCombiner : IKeyed { /// /// Indicates that the room combination scenario has changed /// event EventHandler RoomCombinationScenarioChanged; /// /// The current room combination scenario /// [JsonProperty("currentScenario")] IRoomCombinationScenario CurrentScenario { get; } /// /// When true, indicates the current mode is auto mode /// [JsonIgnore] BoolFeedback IsInAutoModeFeedback {get;} /// /// Gets a value indicating whether the automatic mode is disabled. /// [JsonProperty("disableAutoMode")] bool DisableAutoMode { get; } /// /// Gets a value indicating whether the system is operating in automatic mode. /// [JsonProperty("isInAutoMode")] bool IsInAutoMode { get; } /// /// Gets the collection of rooms associated with the current object. /// [JsonProperty("rooms")] List Rooms { get; } /// /// Sets auto mode /// void SetAutoMode(); /// /// Sets manual mode /// void SetManualMode(); /// /// Toggles the current mode between auto and manual /// void ToggleMode(); /// /// The available room combinatino scenarios /// [JsonProperty("roomCombinationScenarios")] List RoomCombinationScenarios { get; } /// /// The partition /// [JsonProperty("partitions")] List Partitions { get; } /// /// Toggles the state of a manual partition sensor /// /// void TogglePartitionState(string partitionKey); /// /// Sets the room combination scenario (if in manual mode) /// /// void SetRoomCombinationScenario(string scenarioKey); } /// /// Represents a scenario for combining rooms, including activation, deactivation, and associated state. /// /// This interface defines the behavior for managing room combination scenarios, including /// activation and deactivation, tracking the active state, and managing related partition states and UI mappings. /// Implementations of this interface are expected to handle the logic for room combinations based on the provided /// partition states and UI mappings. /// /// Defines the contract for IRoomCombinationScenario /// public interface IRoomCombinationScenario : IKeyName { /// /// When true, indicates that this room combination scenario is active /// [JsonIgnore] BoolFeedback IsActiveFeedback { get; } /// /// Gets a value indicating whether the entity is active. /// [JsonProperty("isActive")] bool IsActive { get; } /// /// Gets a value indicating whether this scenario should be hidden in the UI. /// [JsonProperty("hideInUi")] bool HideInUi { get; } /// /// Activates this room combination scenario /// Task Activate(); /// /// Deactivates this room combination scenario /// Task Deactivate(); /// /// The state of the partitions that would activate this scenario /// [JsonProperty("partitionStates")] List PartitionStates { get; } /// /// The mapping of UIs by key to rooms by key /// [JsonProperty("uiMap")] Dictionary UiMap { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs ================================================ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using Serilog.Events; using System.Collections.Generic; using System.Threading.Tasks; namespace PepperDash.Essentials.Core { /// /// Represents a room combination scenario /// public class RoomCombinationScenario : IRoomCombinationScenario, IKeyName { private RoomCombinationScenarioConfig _config; /// /// Gets or sets the key associated with the object. /// [JsonProperty("key")] public string Key { get; set; } /// /// Gets or sets the name associated with the object. /// [JsonProperty("name")] public string Name { get; set; } /// /// Gets a value indicating whether to hide this scenario in the UI. /// /// [JsonProperty("hideInUi")] public bool HideInUi { get { return _config.HideInUi; } } /// /// Gets or sets the PartitionStates /// /// [JsonProperty("partitionStates")] public List PartitionStates { get; private set; } /// /// Determines which UI devices get mapped to which room in this scenario. The Key should be the key of the UI device and the Value should be the key of the room to map to /// [JsonProperty("uiMap")] public Dictionary UiMap { get; set; } private bool _isActive; /// /// Gets or sets IsActive /// [JsonProperty("isActive")] public bool IsActive { get { return _isActive; } set { if (value == _isActive) { return; } _isActive = value; IsActiveFeedback.FireUpdate(); } } /// /// Gets or sets the IsActiveFeedback /// [JsonIgnore] public BoolFeedback IsActiveFeedback { get; private set; } private List activationActions; private List deactivationActions; /// /// Constructor for RoomCombinationScenario /// /// config of the room combine scenario public RoomCombinationScenario(RoomCombinationScenarioConfig config) { Key = config.Key; Name = config.Name; PartitionStates = config.PartitionStates; UiMap = config.UiMap; activationActions = config.ActivationActions; deactivationActions = config.DeactivationActions; _config = config; IsActiveFeedback = new BoolFeedback(() => _isActive); } /// /// Activates the scenario /// /// public async Task Activate() { this.LogInformation("Activating Scenario {name} with {activationActionCount} action(s) defined", Name, activationActions.Count); List tasks = new List(); if (activationActions != null) { foreach (var action in activationActions) { this.LogInformation("Running Activation action {@action}", action); await DeviceJsonApi.DoDeviceActionAsync(action); } } IsActive = true; } /// /// Deactivates the scenario /// /// public async Task Deactivate() { this.LogInformation("Deactivating Scenario {name} with {deactivationActionCount} action(s) defined", Name, deactivationActions.Count); List tasks = new List(); if (deactivationActions != null) { foreach (var action in deactivationActions) { this.LogInformation("Running deactivation action {actionDeviceKey}:{actionMethod}", action.DeviceKey, action.MethodName); await DeviceJsonApi.DoDeviceActionAsync(action); } } IsActive = false; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs ================================================  namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsDualDisplayRoomPropertiesConfig /// public class EssentialsDualDisplayRoomPropertiesConfig : EssentialsNDisplayRoomPropertiesConfig { } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleRoomPropertiesConfig.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsHuddleRoomPropertiesConfig /// public class EssentialsHuddleRoomPropertiesConfig : EssentialsRoomPropertiesConfig { /// /// The key of the default display device /// [JsonProperty("defaultDisplayKey")] public string DefaultDisplayKey { get; set; } /// /// The key of the default audio device /// [JsonProperty("defaultAudioKey")] public string DefaultAudioKey { get; set; } /// /// The key of the source list for the room /// [JsonProperty("sourceListKey")] public string SourceListKey { get; set; } /// /// The key of the default source item from the source list /// [JsonProperty("defaultSourceItem")] public string DefaultSourceItem { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs ================================================  using Newtonsoft.Json; namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsHuddleVtc1PropertiesConfig /// public class EssentialsHuddleVtc1PropertiesConfig : EssentialsConferenceRoomPropertiesConfig { /// /// Gets or sets the DefaultDisplayKey /// [JsonProperty("defaultDisplayKey")] public string DefaultDisplayKey { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs ================================================  using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.Config { /// /// /// public class EssentialsNDisplayRoomPropertiesConfig : EssentialsConferenceRoomPropertiesConfig { /// /// Gets or sets the DefaultAudioBehavior /// [JsonProperty("defaultAudioBehavior")] public string DefaultAudioBehavior { get; set; } /// /// Gets or sets the DefaultVideoBehavior /// [JsonProperty("defaultVideoBehavior")] public string DefaultVideoBehavior { get; set; } /// /// Gets or sets the Displays /// [JsonProperty("displays")] public Dictionary Displays { get; set; } /// /// Constructor /// public EssentialsNDisplayRoomPropertiesConfig() { Displays = new Dictionary(); } } /// /// Represents a DisplayItem /// public class DisplayItem : IKeyName { /// /// Gets or sets the Key /// public string Key { get; set; } /// /// Gets or sets the Name /// public string Name { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsPresentationPropertiesConfig.cs ================================================ using System.Collections.Generic; namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsPresentationRoomPropertiesConfig /// public class EssentialsPresentationRoomPropertiesConfig : EssentialsRoomPropertiesConfig { /// /// Gets or sets the DefaultAudioBehavior /// public string DefaultAudioBehavior { get; set; } /// /// Gets or sets the DefaultAudioKey /// public string DefaultAudioKey { get; set; } /// /// Gets or sets the DefaultVideoBehavior /// public string DefaultVideoBehavior { get; set; } /// /// Gets or sets the DisplayKeys /// public List DisplayKeys { get; set; } /// /// Gets or sets the SourceListKey /// public string SourceListKey { get; set; } /// /// Gets or sets a value indicating whether the room has a DSP /// public bool HasDsp { get; set; } /// /// Constructor /// public EssentialsPresentationRoomPropertiesConfig() { DisplayKeys = new List(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Privacy; using Serilog.Events; namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsRoomConfigHelper /// public class EssentialsRoomConfigHelper { /// /// GetEmergency method /// public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, IEssentialsRoom room) { // This emergency var emergency = props.Emergency; if (emergency != null) { //switch on emergency type here. Right now only contact and shutdown var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room); DeviceManager.AddDevice(e); return e; } return null; } /// /// /// /// /// /// /// /// GetMicrophonePrivacy method /// public static MicrophonePrivacyController GetMicrophonePrivacy( EssentialsRoomPropertiesConfig props, IPrivacy room) { var microphonePrivacy = props.MicrophonePrivacy; if (microphonePrivacy == null) { Debug.LogMessage(LogEventLevel.Information, "Cannot create microphone privacy with null properties"); return null; } // Get the MicrophonePrivacy device from the device manager var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as MicrophonePrivacyController); // Set this room as the IPrivacy device if (mP == null) { Debug.LogMessage(LogEventLevel.Information, "ERROR: Selected device {0} is not MicrophonePrivacyController", props.MicrophonePrivacy.DeviceKey); return null; } mP.SetPrivacyDevice(room); var behaviour = props.MicrophonePrivacy.Behaviour.ToLower(); if (behaviour == null) { Debug.LogMessage(LogEventLevel.Information, "WARNING: No behaviour defined for MicrophonePrivacyController"); return null; } if (behaviour == "trackroomstate") { // Tie LED enable to room power state var essRoom = room as IEssentialsRoom; essRoom.OnFeedback.OutputChange += (o, a) => { if (essRoom.OnFeedback.BoolValue) mP.EnableLeds = true; else mP.EnableLeds = false; }; mP.EnableLeds = essRoom.OnFeedback.BoolValue; } else if (behaviour == "trackcallstate") { // Tie LED enable to room power state var inCallRoom = room as IHasInCallFeedback; inCallRoom.InCallFeedback.OutputChange += (o, a) => { if (inCallRoom.InCallFeedback.BoolValue) mP.EnableLeds = true; else mP.EnableLeds = false; }; mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue; } return mP; } } /// /// Represents a EssentialsRoomPropertiesConfig /// public class EssentialsRoomPropertiesConfig { /// /// Gets or sets the Addresses /// [JsonProperty("addresses")] public EssentialsRoomAddressPropertiesConfig Addresses { get; set; } /// /// Gets or sets the Description /// [JsonProperty("description")] public string Description { get; set; } /// /// Gets or sets the Emergency /// [JsonProperty("emergency")] public EssentialsRoomEmergencyConfig Emergency { get; set; } /// /// Gets or sets the Help /// [JsonProperty("help")] public EssentialsHelpPropertiesConfig Help { get; set; } /// /// Gets or sets the HelpMessage /// [JsonProperty("helpMessage")] public string HelpMessage { get; set; } /// /// Read this value to get the help message. It checks for the old and new config format. /// public string HelpMessageForDisplay { get { if (Help != null && !string.IsNullOrEmpty(Help.Message)) { return Help.Message; } else { return HelpMessage; } } } /// /// Gets or sets the Environment /// [JsonProperty("environment")] public EssentialsEnvironmentPropertiesConfig Environment { get; set; } /// /// Gets or sets the LogoLight /// [JsonProperty("logo")] public EssentialsLogoPropertiesConfig LogoLight { get; set; } /// /// Gets or sets the LogoDark /// [JsonProperty("logoDark")] public EssentialsLogoPropertiesConfig LogoDark { get; set; } /// /// Gets or sets the MicrophonePrivacy /// [JsonProperty("microphonePrivacy")] public EssentialsRoomMicrophonePrivacyConfig MicrophonePrivacy { get; set; } /// /// Gets or sets the Occupancy /// [JsonProperty("occupancy")] public EssentialsRoomOccSensorConfig Occupancy { get; set; } /// /// Gets or sets the OneButtonMeeting /// [JsonProperty("oneButtonMeeting")] public EssentialsOneButtonMeetingPropertiesConfig OneButtonMeeting { get; set; } /// /// Gets or sets the ShutdownVacancySeconds /// [JsonProperty("shutdownVacancySeconds")] public int ShutdownVacancySeconds { get; set; } /// /// Gets or sets the ShutdownPromptSeconds /// [JsonProperty("shutdownPromptSeconds")] public int ShutdownPromptSeconds { get; set; } /// /// Gets or sets the Tech /// [JsonProperty("tech")] public EssentialsRoomTechConfig Tech { get; set; } /// /// Gets or sets the Volumes /// [JsonProperty("volumes")] public EssentialsRoomVolumesConfig Volumes { get; set; } /// /// Gets or sets the Fusion /// [JsonProperty("fusion")] public EssentialsRoomFusionConfig Fusion { get; set; } /// /// Gets or sets the UiBehavior /// [JsonProperty("essentialsRoomUiBehaviorConfig", NullValueHandling = NullValueHandling.Ignore)] public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } /// /// Gets or sets the ZeroVolumeWhenSwtichingVolumeDevices /// [JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")] public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; } /// /// Indicates if this room represents a combination of other rooms /// [JsonProperty("isRoomCombinationScenario")] public bool IsRoomCombinationScenario { get; set; } /// /// Constructor /// public EssentialsRoomPropertiesConfig() { LogoLight = new EssentialsLogoPropertiesConfig(); LogoDark = new EssentialsLogoPropertiesConfig(); } } /// /// Represents a EssentialsRoomUiBehaviorConfig /// public class EssentialsRoomUiBehaviorConfig { /// /// Gets or sets the DisableActivityButtonsWhileWarmingCooling /// [JsonProperty("disableActivityButtonsWhileWarmingCooling")] public bool DisableActivityButtonsWhileWarmingCooling { get; set; } } /// /// Represents a EssentialsAvRoomPropertiesConfig /// public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig { /// /// Gets or sets the DefaultAudioKey /// [JsonProperty("defaultAudioKey")] public string DefaultAudioKey { get; set; } /// /// Gets or sets the DefaultOnDspPresetKey /// [JsonProperty("defaultOnDspPresetKey")] public string DefaultOnDspPresetKey { get; set; } /// /// Gets or sets the DefaultOffDspPresetKey /// [JsonProperty("defaultOffDspPresetKey")] public string DefaultOffDspPresetKey { get; set; } /// /// Gets or sets the SourceListKey /// [JsonProperty("sourceListKey")] public string SourceListKey { get; set; } /// /// Gets or sets the DestinationListKey /// [JsonProperty("destinationListKey")] public string DestinationListKey { get; set; } /// /// Gets or sets the AudioControlPointListKey /// [JsonProperty("audioControlPointListKey")] public string AudioControlPointListKey { get; set; } /// /// Gets or sets the CameraListKey /// [JsonProperty("cameraListKey")] public string CameraListKey { get; set; } /// /// Gets or sets the DefaultSourceItem /// [JsonProperty("defaultSourceItem")] public string DefaultSourceItem { get; set; } /// /// Indicates if the room supports advanced sharing /// [JsonProperty("supportsAdvancedSharing")] public bool SupportsAdvancedSharing { get; set; } /// /// Indicates if non-tech users can change the share mode /// [JsonProperty("userCanChangeShareMode")] public bool UserCanChangeShareMode { get; set; } /// /// Gets or sets the MatrixRoutingKey /// [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] public string MatrixRoutingKey { get; set; } } /// /// Represents a EssentialsConferenceRoomPropertiesConfig /// public class EssentialsConferenceRoomPropertiesConfig : EssentialsAvRoomPropertiesConfig { /// /// Gets or sets the VideoCodecKey /// [JsonProperty("videoCodecKey")] public string VideoCodecKey { get; set; } /// /// Gets or sets the AudioCodecKey /// [JsonProperty("audioCodecKey")] public string AudioCodecKey { get; set; } } /// /// Represents a EssentialsEnvironmentPropertiesConfig /// public class EssentialsEnvironmentPropertiesConfig { /// /// Gets or sets the Enabled /// public bool Enabled { get; set; } /// /// Gets or sets the DeviceKeys /// [JsonProperty("deviceKeys")] public List DeviceKeys { get; set; } /// /// Constructor /// public EssentialsEnvironmentPropertiesConfig() { DeviceKeys = new List(); } } /// /// Represents a EssentialsRoomFusionConfig /// public class EssentialsRoomFusionConfig { /// /// Gets the the IpId as a UInt16 /// public uint IpIdInt { get { try { return Convert.ToUInt32(IpId, 16); } catch (Exception) { throw new FormatException(string.Format("ERROR:Unable to convert IP ID: {0} to hex. Error:\n{1}", IpId)); } } } /// /// Gets or sets the IpId /// [JsonProperty("ipId")] public string IpId { get; set; } /// /// Gets or sets the JoinMapKey /// [JsonProperty("joinMapKey")] public string JoinMapKey { get; set; } } /// /// Represents a EssentialsRoomMicrophonePrivacyConfig /// public class EssentialsRoomMicrophonePrivacyConfig { /// /// Gets or sets the DeviceKey /// [JsonProperty("deviceKey")] public string DeviceKey { get; set; } /// /// Gets or sets the Behaviour /// [JsonProperty("behaviour")] public string Behaviour { get; set; } } /// /// Represents a EssentialsHelpPropertiesConfig /// public class EssentialsHelpPropertiesConfig { /// /// Gets or sets the Message /// [JsonProperty("message")] public string Message { get; set; } /// /// Gets or sets the ShowCallButton /// [JsonProperty("showCallButton")] public bool ShowCallButton { get; set; } /// /// Defaults to "Call Help Desk" /// [JsonProperty("callButtonText")] public string CallButtonText { get; set; } /// /// Constructor /// public EssentialsHelpPropertiesConfig() { CallButtonText = "Call Help Desk"; } } /// /// Represents a EssentialsOneButtonMeetingPropertiesConfig /// public class EssentialsOneButtonMeetingPropertiesConfig { /// /// Gets or sets the Enable /// [JsonProperty("enable")] public bool Enable { get; set; } } /// /// Represents a EssentialsRoomAddressPropertiesConfig /// public class EssentialsRoomAddressPropertiesConfig { /// /// Gets or sets the PhoneNumber /// [JsonProperty("phoneNumber")] public string PhoneNumber { get; set; } /// /// Gets or sets the SipAddress /// [JsonProperty("sipAddress")] public string SipAddress { get; set; } } /// /// Represents a EssentialsLogoPropertiesConfig /// public class EssentialsLogoPropertiesConfig { /// /// Gets or sets the Type /// [JsonProperty("type")] public string Type { get; set; } /// /// Gets or sets the Url /// [JsonProperty("url")] public string Url { get; set; } /// /// GetLogoUrlLight method /// public string GetLogoUrlLight() { if (Type == "url") return Url; if (Type == "system") return string.Format("http://{0}:8080/logo.png", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)); return null; } /// /// GetLogoUrlDark method /// public string GetLogoUrlDark() { if (Type == "url") return Url; if (Type == "system") return string.Format("http://{0}:8080/logo-dark.png", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)); return null; } } /// /// Represents a EssentialsRoomOccSensorConfig /// public class EssentialsRoomOccSensorConfig { /// /// Gets or sets the DeviceKey /// [JsonProperty("deviceKey")] public string DeviceKey { get; set; } /// /// Gets or sets the TimeoutMinutes /// [JsonProperty("timeoutMinutes")] public int TimeoutMinutes { get; set; } } /// /// Represents a EssentialsRoomTechConfig /// public class EssentialsRoomTechConfig { /// /// Gets or sets the Password /// [JsonProperty("password")] public string Password { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs ================================================ namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsRoomEmergencyConfig /// public class EssentialsRoomEmergencyConfig { /// /// Gets or sets the Trigger /// public EssentialsRoomEmergencyTriggerConfig Trigger { get; set; } /// /// Gets or sets the Behavior /// public string Behavior { get; set; } } /// /// Represents a EssentialsRoomEmergencyTriggerConfig /// public class EssentialsRoomEmergencyTriggerConfig { /// /// contact,versiport /// public string Type { get; set; } /// /// Input number if contact /// public int Number { get; set; } /// /// TriggerOnClose indicates if the trigger is on close /// public bool TriggerOnClose { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomScheduledEventsConfig.cs ================================================  using System.Collections.Generic; using Crestron.SimplSharp.Scheduler; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsRoomScheduledEventsConfig /// public class EssentialsRoomScheduledEventsConfig { /// /// Gets or sets the ScheduledEvents /// [JsonProperty("scheduledEvents")] public List ScheduledEvents; } /// /// Represents a ScheduledEventConfig /// public class ScheduledEventConfig { /// /// Gets or sets the Key /// [JsonProperty("key")] public string Key; /// /// Gets or sets the Name /// [JsonProperty("name")] public string Name; /// /// Gets or sets the Days /// [JsonProperty("days")] public ScheduledEventCommon.eWeekDays Days; /// /// Gets or sets the Time /// [JsonProperty("time")] public string Time; /// /// Gets or sets the Actions /// [JsonProperty("actions")] public List Actions; /// /// Gets or sets the Persistent /// [JsonProperty("persistent")] public bool Persistent; /// /// Gets or sets the Acknowledgeable /// [JsonProperty("acknowledgeable")] public bool Acknowledgeable; /// /// Gets or sets the Enable /// [JsonProperty("enable")] public bool Enable; } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsTechRoomConfig.cs ================================================  using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsTechRoomConfig /// public class EssentialsTechRoomConfig { /// /// The key of the dummy device used to enable routing /// [JsonProperty("dummySourceKey")] public string DummySourceKey { get; set; } /// /// The keys of the displays assigned to this room /// [JsonProperty("displays")] public List Displays { get; set; } /// /// The keys of the tuners assigned to this room /// [JsonProperty("tuners")] public List Tuners { get; set; } /// /// PIN to access the room as a normal user /// [JsonProperty("userPin")] public string UserPin { get; set; } /// /// PIN to access the room as a tech user /// [JsonProperty("techPin")] public string TechPin { get; set; } /// /// Name of the presets file. Path prefix is assumed to be /html/presets/lists/ /// [JsonProperty("presetsFileName")] public string PresetsFileName { get; set; } /// /// Gets or sets the ScheduledEvents /// [JsonProperty("scheduledEvents")] public List ScheduledEvents { get; set; } /// /// Indicates that the room is the primary when true /// [JsonProperty("isPrimary")] public bool IsPrimary { get; set; } /// /// Indicates which tuners should mirror preset recall when two rooms are configured in a primary->secondary scenario /// [JsonProperty("mirroredTuners")] public Dictionary MirroredTuners { get; set; } /// /// Gets or sets the HelpMessage /// [JsonProperty("helpMessage")] public string HelpMessage { get; set; } /// /// Gets or sets the IsTvPresetsProvider /// [JsonProperty("isTvPresetsProvider")] public bool IsTvPresetsProvider; /// /// Constructor /// public EssentialsTechRoomConfig() { Displays = new List(); Tuners = new List(); ScheduledEvents = new List(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/EssentialsVolumeLevelConfig.cs ================================================ using System; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.Config { /// /// Represents a EssentialsRoomVolumesConfig /// public class EssentialsRoomVolumesConfig { /// /// Gets or sets the Master /// public EssentialsVolumeLevelConfig Master { get; set; } /// /// Gets or sets the Program /// public EssentialsVolumeLevelConfig Program { get; set; } /// /// Gets or sets the AudioCallRx /// public EssentialsVolumeLevelConfig AudioCallRx { get; set; } /// /// Gets or sets the AudioCallTx /// public EssentialsVolumeLevelConfig AudioCallTx { get; set; } } /// /// Represents a EssentialsVolumeLevelConfig /// public class EssentialsVolumeLevelConfig { /// /// Gets or sets the DeviceKey /// public string DeviceKey { get; set; } /// /// Gets or sets the Label /// public string Label { get; set; } /// /// Gets or sets the Level /// public int Level { get; set; } /// /// Helper to get the device associated with key - one timer. /// public IBasicVolumeWithFeedback GetDevice() { throw new NotImplementedException("This method references DM CHASSIS Directly"); /* // DM output card format: deviceKey--output~number, dm8x8-1--output~4 var match = Regex.Match(DeviceKey, @"([-_\w]+)--(\w+)~(\d+)"); if (match.Success) { var devKey = match.Groups[1].Value; var chassis = DeviceManager.GetDeviceForKey(devKey) as DmChassisController; if (chassis != null) { var outputNum = Convert.ToUInt32(match.Groups[3].Value); if (chassis.VolumeControls.ContainsKey(outputNum)) // should always... return chassis.VolumeControls[outputNum]; } // No volume for some reason. We have failed as developers return null; } // DSP/DMPS format: deviceKey--levelName, biampTesira-1--master match = Regex.Match(DeviceKey, @"([-_\w]+)--(.+)"); if (match.Success) { var devKey = match.Groups[1].Value; var dsp = DeviceManager.GetDeviceForKey(devKey) as BiampTesiraForteDsp; if (dsp != null) { var levelTag = match.Groups[2].Value; if (dsp.LevelControlPoints.ContainsKey(levelTag)) // should always... return dsp.LevelControlPoints[levelTag]; } var dmps = DeviceManager.GetDeviceForKey(devKey) as DmpsAudioOutputController; if (dmps != null) { var levelTag = match.Groups[2].Value; switch (levelTag) { case "master": return dmps.MasterVolumeLevel; case "source": return dmps.SourceVolumeLevel; case "micsmaster": return dmps.MicsMasterVolumeLevel; case "codec1": return dmps.Codec1VolumeLevel; case "codec2": return dmps.Codec2VolumeLevel; default: return dmps.MasterVolumeLevel; } } // No volume for some reason. We have failed as developers return null; } return null; } * */ } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Config/SimplRoomPropertiesConfig.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; namespace PepperDash.Essentials.Room.Config { /// /// Represents a SimplRoomPropertiesConfig /// public class SimplRoomPropertiesConfig : EssentialsHuddleVtc1PropertiesConfig { /// /// Gets or sets the RoomPhoneNumber /// [JsonProperty("roomPhoneNumber")] public string RoomPhoneNumber { get; set; } /// /// Gets or sets the RoomURI /// [JsonProperty("roomURI")] public string RoomURI { get; set; } /// /// Gets or sets the SpeedDials /// [JsonProperty("speedDials")] public List SpeedDials { get; set; } /// /// Gets or sets the VolumeSliderNames /// [JsonProperty("volumeSliderNames")] public List VolumeSliderNames { get; set; } } /// /// Represents a SimplSpeedDial /// public class SimplSpeedDial { /// /// Gets or sets the Name /// [JsonProperty("name")] public string Name { get; set; } /// /// Gets or sets the Number /// [JsonProperty("number")] public string Number { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs ================================================ using System; using Crestron.SimplSharpPro; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Core { /// /// Represents a EssentialsRoomEmergencyContactClosure /// public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase, IEssentialsRoomEmergency { /// /// Event fired when emergency state changes /// public event EventHandler EmergencyStateChange; IEssentialsRoom Room; string Behavior; bool TriggerOnClose; /// /// Gets or sets the InEmergency /// public bool InEmergency { get; private set; } /// /// Constructor for EssentialsRoomEmergencyContactClosure /// /// device key /// emergency device config /// the room associated with this emergency contact closure public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, IEssentialsRoom room) : base(key) { Room = room; var cs = Global.ControlSystem; if (config.Trigger.Type.Equals("contact", StringComparison.OrdinalIgnoreCase)) { var portNum = (uint)config.Trigger.Number; if (portNum <= cs.NumberOfDigitalInputPorts) { cs.DigitalInputPorts[portNum].Register(); cs.DigitalInputPorts[portNum].StateChange += EsentialsRoomEmergencyContactClosure_StateChange; } } else if (config.Trigger.Type.Equals("versiport", StringComparison.OrdinalIgnoreCase)) { var portNum = (uint)config.Trigger.Number; if (portNum <= cs.NumberOfVersiPorts) { cs.VersiPorts[portNum].Register(); cs.VersiPorts[portNum].SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); cs.VersiPorts[portNum].DisablePullUpResistor = true; cs.VersiPorts[portNum].VersiportChange += EssentialsRoomEmergencyContactClosure_VersiportChange; } } Behavior = config.Behavior; TriggerOnClose = config.Trigger.TriggerOnClose; } private void EssentialsRoomEmergencyContactClosure_VersiportChange(Versiport port, VersiportEventArgs args) { if (args.Event == eVersiportEvent.DigitalInChange) { ContactClosure_StateChange(port.DigitalIn); } } void EsentialsRoomEmergencyContactClosure_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args) { ContactClosure_StateChange(args.State); } void ContactClosure_StateChange(bool portState) { if (portState && TriggerOnClose || !portState && !TriggerOnClose) { InEmergency = true; if (EmergencyStateChange != null) EmergencyStateChange(this, new EventArgs()); RunEmergencyBehavior(); } else { InEmergency = false; if (EmergencyStateChange != null) EmergencyStateChange(this, new EventArgs()); } } /// /// RunEmergencyBehavior method /// public void RunEmergencyBehavior() { if (Behavior.Equals("shutdown")) Room.Shutdown(); } } /// /// Defines the contract for IEssentialsRoomEmergency /// public interface IEssentialsRoomEmergency { /// /// Event fired when emergency state changes /// event EventHandler EmergencyStateChange; /// /// Gets or sets the InEmergency /// bool InEmergency { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.Scheduler; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// /// public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom { /// /// /// public BoolFeedback OnFeedback { get; private set; } /// /// Fires when the RoomOccupancy object is set /// public event EventHandler RoomOccupancyIsSet; /// /// Gets or sets the IsWarmingUpFeedback /// public BoolFeedback IsWarmingUpFeedback { get; private set; } /// /// Gets or sets the IsCoolingDownFeedback /// public BoolFeedback IsCoolingDownFeedback { get; private set; } /// /// Gets or sets the RoomOccupancy /// public IOccupancyStatusProvider RoomOccupancy { get; protected set; } /// /// Gets or sets the OccupancyStatusProviderIsRemote /// public bool OccupancyStatusProviderIsRemote { get; private set; } /// /// Gets or sets the EnvironmentalControlDevices /// public List EnvironmentalControlDevices { get; protected set; } /// /// Indicates if the room has any environmental control devices /// public bool HasEnvironmentalControlDevices { get { return EnvironmentalControlDevices != null && EnvironmentalControlDevices.Count > 0; } } /// /// Gets or sets the IsWarmingFeedbackFunc /// protected abstract Func IsWarmingFeedbackFunc { get; } /// /// Gets or sets the IsCoolingFeedbackFunc /// protected abstract Func IsCoolingFeedbackFunc { get; } /// /// Gets or sets the IsMobileControlEnabled /// public bool IsMobileControlEnabled { get; private set; } /// /// Gets or sets the MobileControlRoomBridge /// public IMobileControlRoomMessenger MobileControlRoomBridge { get; private set; } /// /// The config name of the default source list /// protected const string _defaultListKey = "default"; /// /// The config name of the source list /// /// private string _sourceListKey; /// /// Gets or sets the SourceListKey /// public string SourceListKey { get { if(string.IsNullOrEmpty(_sourceListKey)) { return _defaultListKey; } else { return _sourceListKey; } } protected set { if (value != _sourceListKey) { _sourceListKey = value; } } } private string _destinationListKey; /// /// Gets or sets the DestinationListKey /// public string DestinationListKey { get { if (string.IsNullOrEmpty(_destinationListKey)) { return _defaultListKey; } else { return _destinationListKey; } } protected set { if (value != _destinationListKey) { _destinationListKey = value; } } } private string _audioControlPointListKey; /// /// Gets or sets the AudioControlPointListKey /// public string AudioControlPointListKey { get { if (string.IsNullOrEmpty(_audioControlPointListKey)) { return _defaultListKey; } else { return _destinationListKey; } } protected set { if (value != _audioControlPointListKey) { _audioControlPointListKey = value; } } } private string _cameraListKey; /// /// Gets or sets the CameraListKey /// public string CameraListKey { get { if (string.IsNullOrEmpty(_cameraListKey)) { return _defaultListKey; } else { return _cameraListKey; } } protected set { if (value != _cameraListKey) { _cameraListKey = value; } } } /// /// Gets or sets the ShutdownPromptTimer /// public SecondsCountdownTimer ShutdownPromptTimer { get; private set; } /// /// Gets or sets the ShutdownPromptSeconds /// public int ShutdownPromptSeconds { get; set; } /// /// Gets or sets the ShutdownVacancySeconds /// public int ShutdownVacancySeconds { get; set; } /// /// Gets or sets the ShutdownType /// public eShutdownType ShutdownType { get; private set; } /// /// Gets or sets the Emergency /// public EssentialsRoomEmergencyBase Emergency { get; set; } /// /// Gets or sets the MicrophonePrivacy /// public Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; } /// /// Gets or sets the LogoUrlLightBkgnd /// public string LogoUrlLightBkgnd { get; set; } /// /// Gets or sets the LogoUrlDarkBkgnd /// public string LogoUrlDarkBkgnd { get; set; } /// /// Gets or sets the RoomVacancyShutdownTimer /// protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; } /// /// Gets or sets the VacancyMode /// public eVacancyMode VacancyMode { get; private set; } /// /// Seconds after vacancy prompt is displayed until shutdown /// protected int RoomVacancyShutdownSeconds; /// /// Seconds after vacancy detected until prompt is displayed /// protected int RoomVacancyShutdownPromptSeconds; /// /// /// protected abstract Func OnFeedbackFunc { get; } /// /// Gets or sets the SavedVolumeLevels /// protected Dictionary SavedVolumeLevels = new Dictionary(); /// /// When volume control devices change, should we zero the one that we are leaving? /// public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; } /// /// Constructor for EssentialsRoomBase /// /// config of the device public EssentialsRoomBase(DeviceConfig config) : base(config) { EnvironmentalControlDevices = new List(); // Setup the ShutdownPromptTimer ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => { if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue) ShutdownType = eShutdownType.None; }; ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered ShutdownPromptSeconds = 60; ShutdownVacancySeconds = 120; ShutdownType = eShutdownType.None; RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer"); //RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) => //{ // if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue) // ShutdownType = ShutdownType.Vacancy; //}; RoomVacancyShutdownTimer.HasFinished += new EventHandler(RoomVacancyShutdownPromptTimer_HasFinished); // Shutdown is triggered RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt VacancyMode = eVacancyMode.None; OnFeedback = new BoolFeedback(OnFeedbackFunc); IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc); IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc); AddPostActivationAction(() => { if (RoomOccupancy != null) OnRoomOccupancyIsSet(); }); } /// /// CustomActivate method /// /// public override bool CustomActivate() { SetUpMobileControl(); return base.CustomActivate(); } /// /// Sets the SourceListKey property to the passed in value or the default if no value passed in /// /// protected void SetSourceListKey(string sourceListKey) { if (!string.IsNullOrEmpty(sourceListKey)) { SourceListKey = sourceListKey; } else { sourceListKey = _defaultListKey; } } /// /// Sets the DestinationListKey property to the passed in value or the default if no value passed in /// /// key of the destination list object protected void SetDestinationListKey(string destinationListKey) { if (!string.IsNullOrEmpty(destinationListKey)) { DestinationListKey = destinationListKey; } } /// /// If mobile control is enabled, sets the appropriate properties /// void SetUpMobileControl() { var mcBridgeKey = string.Format("mobileControlBridge-{0}", Key); var mcBridge = DeviceManager.GetDeviceForKey(mcBridgeKey); if (mcBridge == null) { Debug.LogMessage(LogEventLevel.Debug, this, "*********************Mobile Control Bridge Not found for this room."); IsMobileControlEnabled = false; return; } else { MobileControlRoomBridge = mcBridge as IMobileControlRoomMessenger; Debug.LogMessage(LogEventLevel.Debug, this, "*********************Mobile Control Bridge found and enabled for this room"); IsMobileControlEnabled = true; } } void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e) { switch (VacancyMode) { case eVacancyMode.None: StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); break; case eVacancyMode.InInitialVacancy: StartRoomVacancyTimer(eVacancyMode.InShutdownWarning); break; case eVacancyMode.InShutdownWarning: { StartShutdown(eShutdownType.Vacancy); Debug.LogMessage(LogEventLevel.Information, this, "Shutting Down due to vacancy."); break; } default: break; } } /// /// /// /// /// /// StartShutdown method /// public void StartShutdown(eShutdownType type) { // Check for shutdowns running. Manual should override other shutdowns if (type == eShutdownType.Manual) ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds; else if (type == eShutdownType.Vacancy) ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds; ShutdownType = type; ShutdownPromptTimer.Start(); Debug.LogMessage(LogEventLevel.Information, this, "ShutdownPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount); } /// /// StartRoomVacancyTimer method /// public void StartRoomVacancyTimer(eVacancyMode mode) { if (mode == eVacancyMode.None) RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds; else if (mode == eVacancyMode.InInitialVacancy) RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds; else if (mode == eVacancyMode.InShutdownWarning) RoomVacancyShutdownTimer.SecondsToCount = 60; VacancyMode = mode; RoomVacancyShutdownTimer.Start(); Debug.LogMessage(LogEventLevel.Information, this, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount); } /// /// Shutdown method /// public void Shutdown() { VacancyMode = eVacancyMode.None; EndShutdown(); } /// /// This method is for the derived class to define it's specific shutdown /// requirements but should not be called directly. It is called by Shutdown() /// protected abstract void EndShutdown(); /// /// Override this to implement a default volume level(s) method /// public abstract void SetDefaultLevels(); /// /// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device /// /// /// public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes) { if (statusProvider == null) { Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Occupancy sensor device is null"); return; } Debug.LogMessage(LogEventLevel.Information, this, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key); Debug.LogMessage(LogEventLevel.Information, this, "Timeout Minutes from Config is: {0}", timeoutMinutes); // If status provider is fusion, set flag to remote if (statusProvider is Core.Fusion.IEssentialsRoomFusionController) OccupancyStatusProviderIsRemote = true; if(timeoutMinutes > 0) RoomVacancyShutdownSeconds = timeoutMinutes * 60; Debug.LogMessage(LogEventLevel.Information, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); RoomOccupancy = statusProvider; RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; OnRoomOccupancyIsSet(); } void OnRoomOccupancyIsSet() { var handler = RoomOccupancyIsSet; if (handler != null) handler(this, new EventArgs()); } /// /// To allow base class to power room on to last source /// public abstract void PowerOnToDefaultOrLastSource(); /// /// To allow base class to power room on to default source /// /// public abstract bool RunDefaultPresentRoute(); void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e) { if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false && AllowVacancyTimerToStart()) { Debug.LogMessage(LogEventLevel.Debug, this, "Notice: Vacancy Detected"); // Trigger the timer when the room is vacant StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); } else { Debug.LogMessage(LogEventLevel.Debug, this, "Notice: Occupancy Detected"); // Reset the timer when the room is occupied RoomVacancyShutdownTimer.Cancel(); } } /// /// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed /// /// public abstract void RoomVacatedForTimeoutPeriod(object o); /// /// Allow the vacancy event from an occupancy sensor to turn the room off. /// /// If the timer should be allowed. Defaults to true protected virtual bool AllowVacancyTimerToStart() { return true; } } /// /// To describe the various ways a room may be shutting down /// public enum eShutdownType { /// /// No shutdown in progress /// None = 0, /// /// Manual shutdown initiated /// External, /// /// Vacancy based shutdown /// Manual, /// /// Shutdown due to room vacancy /// Vacancy } /// /// Enumeration of eVacancyMode values /// public enum eVacancyMode { /// /// No vacancy detected /// None = 0, /// /// InInitialVacancy - countdown to warning /// InInitialVacancy, /// /// InShutdownWarning - countdown to shutdown /// InShutdownWarning } /// /// Enumeration of eWarmingCoolingMode values /// public enum eWarmingCoolingMode { /// /// None /// None, /// /// Warming /// Warming, /// /// Cooling /// Cooling } /// /// Base class for room emergency implementations /// public abstract class EssentialsRoomEmergencyBase : IKeyed { /// /// Key of the room /// public string Key { get; private set; } /// /// Constructor for EssentialsRoomEmergencyBase /// /// key of the room public EssentialsRoomEmergencyBase(string key) { Key = key; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/IEssentialsRoom.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Room.Config; using PepperDash.Essentials.Core.Devices; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Describes the basic functionality of an EssentialsRoom /// public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute, IEnvironmentalControls { /// /// Gets the PowerFeedback /// BoolFeedback OnFeedback { get; } /// /// Gets the IsOccupiedFeedback /// BoolFeedback IsWarmingUpFeedback { get; } /// /// Gets the IsCoolingDownFeedback /// BoolFeedback IsCoolingDownFeedback { get; } /// /// Gets a value indicating whether mobile control is enabled for this room /// bool IsMobileControlEnabled { get; } /// /// Gets the MobileControlRoomBridge /// IMobileControlRoomMessenger MobileControlRoomBridge { get; } /// /// Gets the SourceListKey /// string SourceListKey { get; } /// /// Gets the DestinationListKey /// string DestinationListKey { get; } /// /// Gets the AudioControlPointListKey /// string AudioControlPointListKey { get; } /// /// Gets the CameraListKey /// string CameraListKey { get; } /// /// Gets the ShutdownPromptTimer /// SecondsCountdownTimer ShutdownPromptTimer { get; } /// /// Gets the ShutdownVacancyTimer /// int ShutdownPromptSeconds { get; } /// /// Gets the ShutdownVacancySeconds /// int ShutdownVacancySeconds { get; } /// /// Gets the ShutdownType /// eShutdownType ShutdownType { get; } /// /// Gets the LogoUrlLightBkgnd /// string LogoUrlLightBkgnd { get; } /// /// Gets the LogoUrlDarkBkgnd /// string LogoUrlDarkBkgnd { get; } /// /// Starts the shutdown process /// /// type of shutdown event void StartShutdown(eShutdownType type); /// /// Shuts down the room /// void Shutdown(); /// /// Powers on the room to either the default source or the last source used /// void PowerOnToDefaultOrLastSource(); } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/IRoomEventSchedule.cs ================================================ using PepperDash.Essentials.Room.Config; using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoomEventSchedule /// public interface IRoomEventSchedule { /// /// Adds or updates a scheduled event /// /// void AddOrUpdateScheduledEvent(ScheduledEventConfig eventConfig); /// /// Removes a scheduled event by its key /// /// List GetScheduledEvents(); /// /// Removes a scheduled event by its key /// event EventHandler ScheduledEventsChanged; } /// /// Represents a ScheduledEventEventArgs /// public class ScheduledEventEventArgs : EventArgs { /// /// Gets or sets the ScheduledEvents /// public List ScheduledEvents; } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Interfaces.cs ================================================ using System; using System.Collections.Generic; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// For rooms with in call feedback /// public interface IHasInCallFeedback { /// /// Gets the InCallFeedback /// BoolFeedback InCallFeedback { get; } } /// /// For rooms with a single display /// public interface IHasDefaultDisplay { /// /// Gets the DefaultDisplay /// IRoutingSink DefaultDisplay { get; } } /// /// For rooms with multiple displays /// [Obsolete("Will be removed in a future version")] public interface IHasMultipleDisplays { /// /// Gets the Displays dictionary /// Dictionary Displays { get; } } /// /// For rooms with routing /// public interface IRunRouteAction { /// /// Runs a route action /// /// /// void RunRouteAction(string routeKey, string sourceListKey); /// /// Runs a route action with a success callback /// /// /// /// void RunRouteAction(string routeKey, string sourceListKey, Action successCallback); } /// /// Defines the contract for IRunDirectRouteAction /// public interface IRunDirectRouteAction { /// /// Runs a direct route /// /// /// /// void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo); } /// /// Describes a room with matrix routing /// public interface IHasMatrixRouting { /// /// Gets the MatrixRoutingDeviceKey /// string MatrixRoutingDeviceKey { get; } /// /// Gets the EndpointKeys /// List EndpointKeys { get; } } /// /// Defines the contract for IHasRoutingEndpoints /// public interface IHasRoutingEndpoints { /// /// Gets the EndpointKeys /// List EndpointKeys { get; } } /// /// Describes a room with a shutdown prompt timer /// public interface IShutdownPromptTimer { /// /// Gets the ShutdownPromptTimer /// SecondsCountdownTimer ShutdownPromptTimer { get; } /// /// Gets the ShutdownPromptSeconds /// /// number of seconds to set void SetShutdownPromptSeconds(int seconds); /// /// Starts the shutdown process /// /// type of shutdown event void StartShutdown(eShutdownType type); } /// /// Defines the contract for ITechPassword /// public interface ITechPassword { /// /// Event fired when tech password validation result is available /// event EventHandler TechPasswordValidateResult; /// /// Event fired when tech password is changed /// event EventHandler TechPasswordChanged; /// /// Gets the TechPasswordLength /// int TechPasswordLength { get; } /// /// Validates the tech password /// /// The tech password to validate void ValidateTechPassword(string password); /// /// Sets the tech password /// /// The current tech password /// The new tech password to set void SetTechPassword(string oldPassword, string newPassword); } /// /// Represents a TechPasswordEventArgs /// public class TechPasswordEventArgs : EventArgs { /// /// Gets or sets the IsValid /// public bool IsValid { get; private set; } /// /// Constructor for TechPasswordEventArgs /// /// public TechPasswordEventArgs(bool isValid) { IsValid = isValid; } } /// /// Defines the contract for IRunDefaultPresentRoute /// public interface IRunDefaultPresentRoute { /// /// Runs the default present route /// /// bool RunDefaultPresentRoute(); } /// /// For rooms that have default presentation and calling routes /// public interface IRunDefaultCallRoute : IRunDefaultPresentRoute { /// /// Runs the default call route /// /// bool RunDefaultCallRoute(); } /// /// Describes environmental controls available on a room such as lighting, shades, temperature, etc. /// public interface IEnvironmentalControls { /// /// Gets the EnvironmentalControlDevices /// List EnvironmentalControlDevices { get; } /// /// Gets a value indicating whether the room has environmental control devices /// bool HasEnvironmentalControlDevices { get; } } /// /// Defines the contract for IRoomOccupancy /// public interface IRoomOccupancy : IKeyed { /// /// Gets the RoomOccupancy /// IOccupancyStatusProvider RoomOccupancy { get; } /// /// Gets a value indicating whether the OccupancyStatusProviderIsRemote /// bool OccupancyStatusProviderIsRemote { get; } /// /// Sets the room occupancy /// /// /// void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes); /// /// Called when the room has been vacated for the timeout period /// /// void RoomVacatedForTimeoutPeriod(object o); /// /// Starts the room vacancy timer /// /// vacancy mode void StartRoomVacancyTimer(eVacancyMode mode); /// /// Gets the VacancyMode /// eVacancyMode VacancyMode { get; } /// /// Event fired when room occupancy is set /// event EventHandler RoomOccupancyIsSet; } /// /// Defines the contract for IEmergency /// public interface IEmergency { /// /// Gets the Emergency /// EssentialsRoomEmergencyBase Emergency { get; } } /// /// Defines the contract for IMicrophonePrivacy /// public interface IMicrophonePrivacy { /// /// Gets the MicrophonePrivacy /// Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; } } /// /// Defines the contract for IHasAccessoryDevices /// public interface IHasAccessoryDevices : IKeyName { /// /// Gets the AccessoryDeviceKeys /// List AccessoryDeviceKeys { get; } } /// /// Defines the contract for IHasCiscoNavigatorTouchpanel /// public interface IHasCiscoNavigatorTouchpanel { /// /// Gets the CiscoNavigatorTouchpanelKey /// string CiscoNavigatorTouchpanelKey { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/Room.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using PepperDash.Core; namespace PepperDash.Essentials.Core { //*************************************************************************************************** /// /// Abstract base class for Room /// public abstract class Room : Device, IHasFeedback { /// /// Gets or sets the RoomIsOnFeedback /// public abstract BoolFeedback RoomIsOnFeedback { get; protected set; } /// /// Gets or sets the IsCoolingDownFeedback /// public abstract BoolFeedback IsCoolingDownFeedback { get; protected set; } /// /// Gets or sets the IsWarmingUpFeedback /// public abstract BoolFeedback IsWarmingUpFeedback { get; protected set; } // In concrete classes, these should be computed from the relevant devices /// /// Gets or sets the CooldownTime /// /// public virtual uint CooldownTime { get { return 10000; } } /// /// Gets or sets the WarmupTime /// /// public virtual uint WarmupTime { get { return 5000; } } /// /// Gets or sets the Description /// public string Description { get; set; } /// /// Gets or sets the HelpMessage /// public string HelpMessage { get; set; } /// /// Room Constructor /// /// room key /// room name public Room(string key, string name) : base(key, name) { Description = ""; HelpMessage = ""; } /// /// RoomOn method /// /// public virtual void RoomOn() { } /// /// RoomOff method /// public virtual void RoomOff() { } #region IDeviceWithOutputs Members /// /// Gets the Feedbacks /// public virtual FeedbackCollection Feedbacks { get { return new FeedbackCollection { RoomIsOnFeedback, IsCoolingDownFeedback, IsWarmingUpFeedback }; } } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Core/Room/iOccupancyStatusProvider.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IOccupancyStatusProvider /// public interface IOccupancyStatusProvider { /// /// Gets the RoomIsOccupiedFeedback /// BoolFeedback RoomIsOccupiedFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/DummyRoutingInputsDevice.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; namespace PepperDash.Essentials.Core.Routing { /// /// Represents a DummyRoutingInputsDevice /// public class DummyRoutingInputsDevice : Device, IRoutingSource, IRoutingOutputs { /// /// Gets or sets the AudioVideoOutputPort /// public RoutingOutputPort AudioVideoOutputPort { get; private set; } /// /// contains the output port /// public RoutingPortCollection OutputPorts { get { return new RoutingPortCollection() { AudioVideoOutputPort }; } } /// /// constructor /// /// key for special device public DummyRoutingInputsDevice(string key) : base(key) { AudioVideoOutputPort = new RoutingOutputPort("internal", eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.BackplaneOnly, null, this, true); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/Extensions.cs ================================================ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using PepperDash.Essentials.Core.Queues; using PepperDash.Essentials.Core.Routing; using Debug = PepperDash.Core.Debug; namespace PepperDash.Essentials.Core { /// /// Extensions added to any IRoutingInputs classes to provide discovery-based routing /// on those destinations. /// public static class Extensions { /// /// A collection of RouteDescriptors for each signal type. /// public static readonly Dictionary RouteDescriptors = new Dictionary() { { eRoutingSignalType.Audio, new RouteDescriptorCollection() }, { eRoutingSignalType.Video, new RouteDescriptorCollection() }, { eRoutingSignalType.SecondaryAudio, new RouteDescriptorCollection() }, { eRoutingSignalType.AudioVideo, new RouteDescriptorCollection() }, { eRoutingSignalType.UsbInput, new RouteDescriptorCollection() }, { eRoutingSignalType.UsbOutput, new RouteDescriptorCollection() } }; /// /// Stores pending route requests, keyed by the destination device key. /// Used primarily to handle routing requests while a device is cooling down. /// private static readonly Dictionary RouteRequests = new Dictionary(); /// /// A queue to process route requests and releases sequentially. /// private static readonly GenericQueue routeRequestQueue = new GenericQueue("routingQueue"); /// /// Indexed lookup of TieLines by destination device key for faster queries. /// private static Dictionary> _tieLinesByDestination; /// /// Indexed lookup of TieLines by source device key for faster queries. /// private static Dictionary> _tieLinesBySource; /// /// Cache of failed route attempts to avoid re-checking impossible paths. /// Format: "sourceKey|destKey|signalType" /// Uses ConcurrentDictionary as a thread-safe set (byte value is unused). /// private static readonly ConcurrentDictionary _impossibleRoutes = new ConcurrentDictionary(); /// /// Indexes all TieLines by source and destination device keys for faster lookups. /// Should be called once at system startup after all TieLines are created. /// public static void IndexTieLines() { try { Debug.LogInformation("Indexing TieLines for faster route discovery"); _tieLinesByDestination = TieLineCollection.Default .GroupBy(t => t.DestinationPort.ParentDevice.Key) .ToDictionary(g => g.Key, g => g.ToList()); _tieLinesBySource = TieLineCollection.Default .GroupBy(t => t.SourcePort.ParentDevice.Key) .ToDictionary(g => g.Key, g => g.ToList()); Debug.LogInformation("TieLine indexing complete. {0} destination keys, {1} source keys", _tieLinesByDestination.Count, _tieLinesBySource.Count); } catch (Exception ex) { Debug.LogError("Exception indexing TieLines: {exception}", ex.Message); Debug.LogDebug(ex, "Stack Trace: "); } } /// /// Gets TieLines connected to a destination device. /// Uses indexed lookup if available, otherwise falls back to LINQ query. /// /// The destination device key /// List of TieLines connected to the destination private static IEnumerable GetTieLinesForDestination(string destinationKey) { if (_tieLinesByDestination != null && _tieLinesByDestination.TryGetValue(destinationKey, out List tieLines)) { return tieLines; } // Fallback to LINQ if index not available return TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destinationKey); } /// /// Gets TieLines connected to a source device. /// Uses indexed lookup if available, otherwise falls back to LINQ query. /// /// The source device key /// List of TieLines connected to the source private static IEnumerable GetTieLinesForSource(string sourceKey) { if (_tieLinesBySource != null && _tieLinesBySource.TryGetValue(sourceKey, out List tieLines)) { return tieLines; } // Fallback to LINQ if index not available return TieLineCollection.Default.Where(t => t.SourcePort.ParentDevice.Key == sourceKey); } /// /// Creates a cache key for route impossibility tracking. /// /// Source device key /// Destination device key /// Source port key /// Destination port key /// Signal type /// Cache key string private static string GetRouteKey(string sourceKey, string destKey, string sourcePortKey, string destinationPortKey, eRoutingSignalType type) { return $"{sourceKey}|{destKey}|{sourcePortKey}|{destinationPortKey}|{type}"; } /// /// Clears the impossible routes cache. Should be called if TieLines are added/removed at runtime. /// public static void ClearImpossibleRoutesCache() { _impossibleRoutes.Clear(); Debug.LogInformation("Impossible routes cache cleared"); } /// /// 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 IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, string destinationPortKey = "", string sourcePortKey = "") { // Remove this line before committing!!!!! var frame = new StackFrame(1, true); Debug.LogInformation("ReleaseAndMakeRoute Called from {method} with params {destinationKey}:{sourceKey}:{signalType}:{destinationPortKey}:{sourcePortKey}", frame.GetMethod().Name, destination.Key, source.Key, signalType.ToString(), destinationPortKey, sourcePortKey); var inputPort = string.IsNullOrEmpty(destinationPortKey) ? null : destination.InputPorts.FirstOrDefault(p => p.Key == destinationPortKey); var outputPort = string.IsNullOrEmpty(sourcePortKey) ? null : source.OutputPorts.FirstOrDefault(p => p.Key == sourcePortKey); ReleaseAndMakeRoute(destination, source, signalType, inputPort, outputPort); } /// /// Will release the existing route to the destination, if a route is found. This does not CLEAR the route, only stop counting usage time on any output ports that have a usage tracker set. /// /// destination to clear public static void ReleaseRoute(this IRoutingInputs destination) { routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, string.Empty, false)); } /// /// Will release the existing route to the destination, if a route is found. This does not CLEAR the route, only stop counting usage time on any output ports that have a usage tracker set /// /// destination to clear /// Input to use to find existing route /// /// ReleaseRoute method /// public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey) { routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, inputPortKey, false)); } /// /// Clears the route on the destination. This will remove any routes that are currently in use /// /// Destination public static void ClearRoute(this IRoutingInputs destination) { routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, string.Empty, true)); } /// /// Clears the route on the destination. This will remove any routes that are currently in use /// /// destination /// input to use to find existing route /// /// ClearRoute method /// public static void ClearRoute(this IRoutingInputs destination, string inputPortKey) { routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, inputPortKey, true)); } /// /// Removes the route request for the destination. This will remove any routes that are currently in use /// /// destination device key public static void RemoveRouteRequestForDestination(string destinationKey) { Debug.LogInformation("Removing route request for {destination}", destinationKey); var result = RouteRequests.Remove(destinationKey); var messageTemplate = result ? "Route Request for {destination} removed" : "Route Request for {destination} not found"; Debug.LogInformation(messageTemplate, destinationKey); } /// /// 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, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) { // if it's a single signal type, find the route if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) && !(signalType.HasFlag(eRoutingSignalType.Video) && signalType.HasFlag(eRoutingSignalType.SecondaryAudio))) { var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, signalType); Debug.LogDebug(destination, "Attempting to build source route from {sourceKey} of type {type}", source.Key, signalType); if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort)) singleTypeRouteDescriptor = null; var routes = singleTypeRouteDescriptor?.Routes ?? new List(); foreach (var route in routes) { Debug.LogVerbose(destination, "Route for device: {route}", route.ToString()); } return (singleTypeRouteDescriptor, null); } // otherwise, audioVideo needs to be handled as two steps. Debug.LogDebug(destination, "Attempting to build source route from {destinationKey} to {sourceKey} of type {type}", source.Key, signalType); RouteDescriptor audioRouteDescriptor; if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio)) { audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, eRoutingSignalType.SecondaryAudio); } else { audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, eRoutingSignalType.Audio); } var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort); if (!audioSuccess) Debug.LogDebug(destination, "Cannot find audio route to {0}", source.Key); var videoRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, sourcePort, eRoutingSignalType.Video); var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort); if (!videoSuccess) Debug.LogDebug(destination, "Cannot find video route to {0}", source.Key); foreach (var route in audioRouteDescriptor.Routes) { Debug.LogVerbose(destination, "Audio route for device: {route}", route.ToString()); } foreach (var route in videoRouteDescriptor.Routes) { Debug.LogVerbose(destination, "Video route for device: {route}", route.ToString()); } if (!audioSuccess && !videoSuccess) return (null, null); // Return null for descriptors that have no routes return (audioSuccess && audioRouteDescriptor.Routes.Count > 0 ? audioRouteDescriptor : null, videoSuccess && videoRouteDescriptor.Routes.Count > 0 ? videoRouteDescriptor : null); } /// /// Internal method to handle the logic for releasing an existing route and making a new one. /// Handles devices with cooling states by queueing the request. /// /// The destination device. /// The source device. /// The type of signal to route. /// The specific destination input port (optional). /// The specific source output port (optional). private static void ReleaseAndMakeRoute(IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort = null, RoutingOutputPort sourcePort = null) { if (destination == null) throw new ArgumentNullException(nameof(destination)); if (source == null) throw new ArgumentNullException(nameof(source)); if (destinationPort == null) Debug.LogDebug("Destination port is null"); if (sourcePort == null) Debug.LogDebug("Source port is null"); var routeRequest = new RouteRequest { Destination = destination, DestinationPort = destinationPort, Source = source, SourcePort = sourcePort, SignalType = signalType }; var coolingDevice = destination as IWarmingCooling; //We already have a route request for this device, and it's a cooling device and is cooling if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) { coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown; coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; RouteRequests[destination.Key] = routeRequest; Debug.LogInformation("Device: {destination} is cooling down and already has a routing request stored. Storing new route request to route to source key: {sourceKey}", destination.Key, routeRequest.Source.Key); return; } //New Request if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true) { coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown; RouteRequests.Add(destination.Key, routeRequest); Debug.LogInformation("Device: {destination} is cooling down. Storing route request to route to source key: {sourceKey}", destination.Key, routeRequest.Source.Key); return; } if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false) { var handledRequest = RouteRequests[destination.Key]; coolingDevice.IsCoolingDownFeedback.OutputChange -= handledRequest.HandleCooldown; RouteRequests.Remove(destination.Key); Debug.LogInformation("Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", destination.Key, routeRequest.Source.Key); } routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, destinationPort?.Key ?? string.Empty, false)); routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest)); } /// /// Maps destination input ports to source output ports for all routing devices. /// public static void MapDestinationsToSources() { try { // Index TieLines before mapping if not already done if (_tieLinesByDestination == null || _tieLinesBySource == null) { IndexTieLines(); } var sinks = DeviceManager.AllDevices.OfType().Where(d => !(d is IRoutingInputsOutputs)); var sources = DeviceManager.AllDevices.OfType().Where(d => !(d is IRoutingInputsOutputs)); foreach (var sink in sinks) { foreach (var source in sources) { foreach (var inputPort in sink.InputPorts) { foreach (var outputPort in source.OutputPorts) { var (audioOrSingleRoute, videoRoute) = sink.GetRouteToSource(source, inputPort.Type, inputPort, outputPort); if (audioOrSingleRoute == null && videoRoute == null) { continue; } if (audioOrSingleRoute != null) { // Only add routes that have actual switching steps if (audioOrSingleRoute.Routes == null || audioOrSingleRoute.Routes.Count == 0) { continue; } // Add to the appropriate collection(s) based on signal type // Note: A single route descriptor with combined flags (e.g., AudioVideo) will be added once per matching signal type if (audioOrSingleRoute.SignalType.HasFlag(eRoutingSignalType.Audio)) { RouteDescriptors[eRoutingSignalType.Audio].AddRouteDescriptor(audioOrSingleRoute); } if (audioOrSingleRoute.SignalType.HasFlag(eRoutingSignalType.Video)) { RouteDescriptors[eRoutingSignalType.Video].AddRouteDescriptor(audioOrSingleRoute); } if (audioOrSingleRoute.SignalType.HasFlag(eRoutingSignalType.SecondaryAudio)) { RouteDescriptors[eRoutingSignalType.SecondaryAudio].AddRouteDescriptor(audioOrSingleRoute); } if (audioOrSingleRoute.SignalType.HasFlag(eRoutingSignalType.UsbInput)) { RouteDescriptors[eRoutingSignalType.UsbInput].AddRouteDescriptor(audioOrSingleRoute); } if (audioOrSingleRoute.SignalType.HasFlag(eRoutingSignalType.UsbOutput)) { RouteDescriptors[eRoutingSignalType.UsbOutput].AddRouteDescriptor(audioOrSingleRoute); } } if (videoRoute != null) { // Only add routes that have actual switching steps if (videoRoute.Routes == null || videoRoute.Routes.Count == 0) { continue; } RouteDescriptors[eRoutingSignalType.Video].AddRouteDescriptor(videoRoute); } } } } } } catch (Exception ex) { Debug.LogError("Exception mapping routes: {exception}", ex.Message); Debug.LogDebug(ex, "Stack Trace: "); } } /// /// Executes the actual routing based on a . /// Finds the route path, adds it to the collection, and executes the switches. /// /// The route request details. private static void RunRouteRequest(RouteRequest request) { try { if (request.Source == null) return; RouteDescriptor audioOrSingleRoute = null; RouteDescriptor videoRoute = null; // Try to use pre-loaded route descriptors first if (request.SignalType.HasFlag(eRoutingSignalType.AudioVideo)) { // For AudioVideo routes, check both Audio and Video collections if (RouteDescriptors.TryGetValue(eRoutingSignalType.Audio, out RouteDescriptorCollection audioCollection)) { audioOrSingleRoute = audioCollection.Descriptors.FirstOrDefault(d => d.Source.Key == request.Source.Key && d.Destination.Key == request.Destination.Key && (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) && (request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key)); } if (RouteDescriptors.TryGetValue(eRoutingSignalType.Video, out RouteDescriptorCollection videoCollection)) { videoRoute = videoCollection.Descriptors.FirstOrDefault(d => d.Source.Key == request.Source.Key && d.Destination.Key == request.Destination.Key && (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) && (request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key)); } } else { // For single signal type routes var signalTypeToCheck = request.SignalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : request.SignalType; if (RouteDescriptors.TryGetValue(signalTypeToCheck, out RouteDescriptorCollection collection)) { audioOrSingleRoute = collection.Descriptors.FirstOrDefault(d => d.Source.Key == request.Source.Key && d.Destination.Key == request.Destination.Key && (request.DestinationPort == null || d.InputPort?.Key == request.DestinationPort.Key) && (request.SourcePort == null || d.OutputPort?.Key == request.SourcePort.Key)); } } // If no pre-loaded route found, build it dynamically if (audioOrSingleRoute == null && videoRoute == null) { Debug.LogDebug(request.Destination, "No pre-loaded route found, building dynamically"); (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort); } if (audioOrSingleRoute == null && videoRoute == null) return; RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute); if (videoRoute != null) { RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute); } Debug.LogVerbose(request.Destination, "Executing full route"); audioOrSingleRoute.ExecuteRoutes(); videoRoute?.ExecuteRoutes(); } catch (Exception ex) { Debug.LogError("Exception Running Route Request {request}: {exception}", request, ex.Message); Debug.LogDebug(ex, "Stack Trace: "); } } /// /// Will release the existing route on the destination, if it is found in RouteDescriptorCollection.DefaultCollection /// /// /// The input port key to use to find the route. If empty, will use the first available input port /// If true, will clear the route on the destination. This will remove any routes that are currently in use private static void ReleaseRouteInternal(IRoutingInputs destination, string inputPortKey, bool clearRoute) { try { Debug.LogInformation(destination, "Release route for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling) { var coolingDevice = destination as IWarmingCooling; coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; } RouteRequests.Remove(destination.Key); var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey); if (current != null) { Debug.LogInformation(destination, "Releasing current route: {0}", current.Source.Key); current.ReleaseRoutes(clearRoute); } } catch (Exception ex) { Debug.LogError("Exception releasing route for '{destination}':'{inputPortKey}': {exception}", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey, ex.Message); Debug.LogDebug(ex, "Stack Trace: "); } } /// /// 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 /// The RoutingOutputPort whose link is being checked for a route /// The source output port (optional) /// true if source is hit private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, RoutingOutputPort outputPortToUse, List alreadyCheckedDevices, eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable, RoutingInputPort destinationPort, RoutingOutputPort sourcePort) { cycle++; // Check if this route has already been determined to be impossible var routeKey = GetRouteKey(source.Key, destination.Key, sourcePort?.Key ?? "auto", destinationPort?.Key ?? "auto", signalType); if (_impossibleRoutes.ContainsKey(routeKey)) { Debug.LogVerbose("Route {0} is cached as impossible, skipping", routeKey); return false; } Debug.LogVerbose("GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString()); RoutingInputPort goodInputPort = null; // Use indexed lookup instead of LINQ query var allDestinationTieLines = GetTieLinesForDestination(destination.Key); IEnumerable destinationTieLines; TieLine directTie = null; if (destinationPort == null) { destinationTieLines = allDestinationTieLines.Where(t => t.Type.HasFlag(signalType) || signalType == eRoutingSignalType.AudioVideo); } else { destinationTieLines = allDestinationTieLines.Where(t => t.DestinationPort.Key == destinationPort.Key && t.Type.HasFlag(signalType)); } // find the TieLine without a port if (destinationPort == null && sourcePort == null) { directTie = destinationTieLines.FirstOrDefault(t => t.SourcePort.ParentDevice.Key == source.Key); } // find a tieLine to a specific destination port without a specific source port else if (destinationPort != null && sourcePort == null) { directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key); } // find a tieline to a specific source port without a specific destination port else if (destinationPort == null & sourcePort != null) { directTie = destinationTieLines.FirstOrDefault(t => t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key); } // find a tieline to a specific source port and destination port else if (destinationPort != null && sourcePort != null) { directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key); } if (directTie != null) // Found a tie directly to the source { goodInputPort = directTie.DestinationPort; } else // no direct-connect. Walk back devices. { Debug.LogVerbose(destination, "is not directly connected to {sourceKey}. 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 midpointTieLines = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs); //Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration if (alreadyCheckedDevices == null) alreadyCheckedDevices = new List(); alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs); foreach (var tieLine in midpointTieLines) { var midpointDevice = tieLine.SourcePort.ParentDevice as IRoutingInputsOutputs; // Check if this previous device has already been walked if (alreadyCheckedDevices.Contains(midpointDevice)) { Debug.LogVerbose(destination, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", midpointDevice.Key, destination.Key); continue; } var midpointOutputPort = tieLine.SourcePort; Debug.LogVerbose(destination, "Trying to find route on {midpointDeviceKey}", midpointDevice.Key); // haven't seen this device yet. Do it. Pass the output port to the next // level to enable switching on success var upstreamRoutingSuccess = midpointDevice.GetRouteToSource(source, midpointOutputPort, alreadyCheckedDevices, signalType, cycle, routeTable, null, sourcePort); if (upstreamRoutingSuccess) { Debug.LogVerbose(destination, "Upstream device route found"); Debug.LogVerbose(destination, "Route found on {midpointDeviceKey}", midpointDevice.Key); Debug.LogVerbose(destination, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", tieLine.SourcePort, tieLine.DestinationPort); goodInputPort = tieLine.DestinationPort; break; // Stop looping the inputs in this cycle } } } if (goodInputPort == null) { Debug.LogVerbose(destination, "No route found to {0}", source.Key); // Cache this as an impossible route _impossibleRoutes.TryAdd(routeKey, 0); return false; } // we have a route on corresponding inputPort. *** Do the route *** if (destination is IRoutingSink) { // it's a sink device routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort)); } else if (destination is IRouting) { routeTable.Routes.Add(new RouteSwitchDescriptor(outputPortToUse, goodInputPort)); } else // device is merely IRoutingInputOutputs Debug.LogVerbose(destination, "No routing. Passthrough device"); return true; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/ICardPortsDevice.cs ================================================ //using System; //using System.Collections.Generic; //using System.Linq; //using System.Text; //using Crestron.SimplSharp; //using PepperDash.Core; //namespace PepperDash.Essentials.Core //{ // /// // /// Defines a class that has cards, like a DM chassis controller, where // /// we need to access ports on those cards // /// // public interface ICardPortsDevice : IKeyed // { // RoutingInputPort GetChildInputPort(string card, string port); // RoutingOutputPort GetChildOutputPort(string card, string port); // } //} ================================================ FILE: src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core.Routing { /// /// The current sources for the room, keyed by eRoutingSignalType. /// This allows for multiple sources to be tracked, such as audio and video. /// /// /// This interface is used to provide access to the current sources in a room, /// allowing for more complex routing scenarios where multiple signal types are involved. /// public interface ICurrentSources { /// /// Gets the current sources for the room, keyed by eRoutingSignalType. /// This dictionary contains the current source for each signal type, such as audio, video, and control signals. /// Dictionary CurrentSources { get; } /// /// Gets the current source keys for the room, keyed by eRoutingSignalType. /// This dictionary contains the keys for the current source for each signal type, such as audio, video, and control signals. /// Dictionary CurrentSourceKeys { get; } /// /// Event raised when the current sources change. /// event EventHandler CurrentSourcesChanged; /// /// Sets the current source for a specific signal type. /// This method updates the current source for the specified signal type and notifies any subscribers of the change. /// /// The signal type to update. /// The key for the source list. /// The source list item to set as the current source. void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem); } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs ================================================ /* Unmerged change from project 'PepperDash.Essentials.Core (net6)' Before: namespace PepperDash.Essentials.Core.Routing.Interfaces After: using PepperDash; using PepperDash.Essentials; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing.Interfaces */ using System; namespace PepperDash.Essentials.Core { /// /// Delegate for SourceInfoChangeHandler /// public delegate void SourceInfoChangeHandler(SourceListItem info, ChangeType type); //******************************************************************************************* // Interfaces /// /// For rooms with a single presentation source, change event /// [Obsolete("Use ICurrentSources instead")] public interface IHasCurrentSourceInfoChange { /// /// The key for the current source info, used to look up the source in the SourceList /// string CurrentSourceInfoKey { get; set; } /// /// The current source info for the room, used to look up the source in the SourceList /// SourceListItem CurrentSourceInfo { get; set; } /// /// Event that is raised when the current source info changes. /// This is used to notify the system of changes to the current source info. /// The event handler receives the new source info and the type of change that occurred. /// event SourceInfoChangeHandler CurrentSourceChange; } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IInputSync.cs ================================================ using PepperDash.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.Routing { /// /// Defines the contract for IVideoSync /// public interface IVideoSync : IKeyed { /// /// Gets whether or not video sync is detected /// bool VideoSyncDetected { get; } /// /// Event raised when video sync changes /// event EventHandler VideoSyncChanged; } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IMatrixRouting.cs ================================================ using System.Collections.Generic; namespace PepperDash.Essentials.Core.Routing { /// /// Defines the contract for IMatrixRouting /// public interface IMatrixRouting { /// /// Gets the input slots /// Dictionary InputSlots { get; } /// /// Gets the output slots /// Dictionary OutputSlots { get; } /// /// Routes the specified input slot to the specified output slot for the specified signal type /// /// key of the input slot /// key of the output slot /// signal type void Route(string inputSlotKey, string outputSlotKey, eRoutingSignalType type); } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRmcRouting.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRmcRouting /// public interface IRmcRouting : IRoutingNumeric { /// /// Feedback for the current Audio/Video source as a number /// IntFeedback AudioVideoSourceNumericFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRmcRoutingWithFeedback.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRmcRoutingWithFeedback /// public interface IRmcRoutingWithFeedback : IRmcRouting { } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRouting.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// /// Defines a midpoint device as have internal routing. Any devices in the middle of the /// signal chain, that do switching, must implement this for routing to work otherwise /// the routing algorithm will treat the IRoutingInputsOutputs device as a passthrough /// device. /// public interface IRouting : IRoutingInputsOutputs { /// /// Executes a switch on the device /// /// input selector /// output selector /// type of signal void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType); } /*public interface IRouting : IRoutingInputsOutputs { void ExecuteSwitch(TInputSelector inputSelector, TOutputSelector outputSelector, eRoutingSignalType signalType); }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingFeedback.cs ================================================ using System; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingFeedback /// public interface IRoutingFeedback : IKeyName { /// /// Event raised when a numeric switch changes /// event EventHandler NumericSwitchChange; //void OnSwitchChange(RoutingNumericEventArgs e); } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingHasVideoInputSyncFeedbacks.cs ================================================ 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 { /// /// Defines the contract for IRoutingHasVideoInputSyncFeedbacks /// public interface IRoutingHasVideoInputSyncFeedbacks { /// /// Video Input Sync Feedbacks /// FeedbackCollection VideoInputSyncFeedbacks { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingInputSlot.cs ================================================ namespace PepperDash.Essentials.Core.Routing { /// /// Defines the contract for IRoutingInputSlot /// public interface IRoutingInputSlot: IRoutingSlot, IOnline, IVideoSync { /// /// Gets the Tx device key /// string TxDeviceKey { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingInputs.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingInputs /// public interface IRoutingInputs : IKeyed { /// /// Collection of Input Ports /// RoutingPortCollection InputPorts { get; } } /* public interface IRoutingInputs : IKeyed { RoutingPortCollection, TSelector> InputPorts { get; } }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingInputsOutputs.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingInputsOutputs /// public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs { } /* /// /// For devices like RMCs, baluns, other devices with no switching. /// public interface IRoutingInputsOutputs : IRoutingInputs, IRoutingOutputs { }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingNumeric.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingNumeric /// public interface IRoutingNumeric : IRouting { /// /// Executes a numeric switch on the device /// /// input selector /// output selector /// type of signal void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type); } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingNumericWithFeedback.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingNumericWithFeedback /// public interface IRoutingNumericWithFeedback : IRoutingNumeric, IRoutingFeedback { } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingOutputSlot.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core.Routing { /// /// Defines the contract for IRoutingOutputSlot /// public interface IRoutingOutputSlot : IRoutingSlot { /// /// Event raised when output slot changes /// event EventHandler OutputSlotChanged; /// /// Gets the Rx device key /// string RxDeviceKey { get; } /// /// Gets the current routes /// Dictionary CurrentRoutes { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingOutputs.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingOutputs /// public interface IRoutingOutputs : IKeyed { /// /// Collection of Output Ports /// RoutingPortCollection OutputPorts { get; } } /* public interface IRoutingOutputs : IKeyed { RoutingPortCollection, TSelector> OutputPorts { get; } }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs ================================================ using PepperDash.Essentials.Core.Routing; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingSink /// public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange { } /// /// For fixed-source endpoint devices with an input port /// public interface IRoutingSinkWithInputPort : IRoutingSink { /// /// Gets the current input port for this routing sink. /// RoutingInputPort CurrentInputPort { get; } } /// /// Interface for routing sinks that have access to the current source information. /// public interface IRoutingSinkWithCurrentSources : IRoutingSink, ICurrentSources { } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithFeedback.cs ================================================ using PepperDash.Essentials.Core.Routing; using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingSinkWithFeedback /// public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching { } /* /// /// For fixed-source endpoint devices /// public interface IRoutingSinkWithFeedback : IRoutingSinkWithSwitching { RouteSwitchDescriptor CurrentRoute { get; } event EventHandler InputChanged; }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingSinkWithSwitching.cs ================================================ using System; namespace PepperDash.Essentials.Core { /// /// Delegate for InputChangedEventHandler /// public delegate void InputChangedEventHandler(IRoutingSinkWithSwitching destination, RoutingInputPort currentPort); /// /// Defines the contract for IRoutingSinkWithSwitching /// public interface IRoutingSinkWithSwitching : IRoutingSink { /// /// Executes a switch on the device /// /// input selector void ExecuteSwitch(object inputSelector); } /// /// Defines the contract for IRoutingSinkWithSwitchingWithInputPort /// public interface IRoutingSinkWithSwitchingWithInputPort:IRoutingSinkWithSwitching, IRoutingSinkWithInputPort { /// /// Event raised when the input changes /// event InputChangedEventHandler InputChanged; } /* /// /// Endpoint device like a display, that selects inputs /// /// /// Defines the contract for IRoutingSinkWithSwitching /// public interface IRoutingSinkWithSwitching : IRoutingSink { void ExecuteSwitch(TSelector inputSelector); }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingSlot.cs ================================================ using PepperDash.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.Routing { /// /// Defines the contract for IRoutingSlot /// public interface IRoutingSlot:IKeyName { /// /// Gets the slot number /// int SlotNumber { get; } /// /// Gets the supported signal types /// eRoutingSignalType SupportedSignalTypes { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingSource.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingSource /// public interface IRoutingSource : IRoutingOutputs { } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingWithClear.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for IRoutingWithClear /// public interface IRoutingWithClear : IRouting { /// /// Clears a route to an output, however a device needs to do that /// /// Output to clear /// signal type to clear void ClearRoute(object outputSelector, eRoutingSignalType signalType); } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/IRoutingWithFeedback.cs ================================================ using System.Collections.Generic; using System; namespace PepperDash.Essentials.Core { /// /// Delegate for handling route change events on devices implementing . /// /// The routing device where the change occurred. /// A descriptor of the new route that was established. /// /// Delegate for RouteChangedEventHandler /// public delegate void RouteChangedEventHandler(IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute); /// /// Defines a routing device () that provides feedback about its current routes. /// public interface IRoutingWithFeedback : IRouting { /// /// Gets a list describing the currently active routes on this device. /// List CurrentRoutes { get; } /// /// Event triggered when a route changes on this device. /// event RouteChangedEventHandler RouteChanged; } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/ITxRouting.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for ITxRouting /// public interface ITxRouting : IRoutingNumeric { /// /// Feedback indicating the currently routed video source by its numeric identifier. /// IntFeedback VideoSourceNumericFeedback { get; } /// /// Feedback indicating the currently routed audio source by its numeric identifier. /// IntFeedback AudioSourceNumericFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/ITxRoutingWithFeedback.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Defines the contract for ITxRoutingWithFeedback /// public interface ITxRoutingWithFeedback : ITxRouting { } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RouteDescriptor.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharpPro; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Represents a collection of individual route steps between a Source and a Destination device for a specific signal type. /// public class RouteDescriptor { /// /// The destination device (sink or midpoint) for the route. /// public IRoutingInputs Destination { get; private set; } /// /// The InputPort on the destination device for this route, if applicable. May be null if the route is not for a specific input port. /// public RoutingInputPort InputPort { get; private set; } /// /// Gets the source device (sink or midpoint) for the route. /// public IRoutingOutputs Source { get; private set; } /// /// Gets the OutputPort on the source device for this route, if applicable. May be null if the route is not for a specific output port. /// public RoutingOutputPort OutputPort { get; private set; } /// /// Gets the signal type for this route. /// public eRoutingSignalType SignalType { get; private set; } /// /// Gets the collection of route switch descriptors for this route. /// public List Routes { get; private set; } /// /// Initializes a new instance of the class for a route without a specific destination input port. /// /// The source device. /// The destination device. /// The type of signal being routed. public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType) : this(source, destination, null, signalType) { } /// /// Initializes a new instance of the class for a route with a specific destination input port. /// /// The source device. /// The destination device. /// The destination input port (optional). /// The signal type for this route. public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, eRoutingSignalType signalType) : this(source, destination, inputPort, null, signalType) { } /// /// Initializes a new instance of the class for a route with specific destination input and source output ports. /// /// /// /// /// /// public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, RoutingInputPort inputPort, RoutingOutputPort outputPort, eRoutingSignalType signalType) { Destination = destination; InputPort = inputPort; Source = source; OutputPort = outputPort; SignalType = signalType; Routes = new List(); } /// /// ExecuteRoutes method /// public void ExecuteRoutes() { foreach (var route in Routes) { Debug.LogVerbose("ExecuteRoutes: {0}", route.ToString()); if (route.SwitchingDevice is IRoutingSinkWithSwitching sink) { sink.ExecuteSwitch(route.InputPort.Selector); continue; } if (route.SwitchingDevice is IRouting switchingDevice) { switchingDevice.ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType); route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType); Debug.LogVerbose("Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); } } } /// /// Releases the usage tracking for the route and optionally clears the route on the switching devices. /// /// If true, attempts to clear the route on the switching devices (e.g., set input to null/0). public void ReleaseRoutes(bool clearRoute = false) { foreach (var route in Routes.Where(r => r.SwitchingDevice is IRouting)) { if (route.SwitchingDevice is IRouting switchingDevice) { if (clearRoute) { try { switchingDevice.ExecuteSwitch(null, route.OutputPort.Selector, SignalType); } catch (Exception e) { Debug.LogError("Error executing switch: {exception}", e.Message); Debug.LogDebug(e, "Stack Trace: "); } } if (route.OutputPort == null) { continue; } if (route.OutputPort.InUseTracker != null) { route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType); Debug.LogVerbose("Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue); } else { Debug.LogVerbose("InUseTracker is null for OutputPort {0}", route.OutputPort.Key); } } } } /// /// Returns a string representation of the route descriptor, including source, destination, and individual route steps. /// /// A string describing the route. public override string ToString() { var routesText = Routes.Select(r => r.ToString()).ToArray(); return $"Route table from {Source.Key} to {Destination.Key} for {SignalType}:\r\n {string.Join("\r\n ", routesText)}"; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs ================================================ using System.Collections.Generic; using System.Linq; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// A collection of RouteDescriptors - typically the static DefaultCollection is used /// public class RouteDescriptorCollection { /// /// Gets the default collection of RouteDescriptors. /// public static RouteDescriptorCollection DefaultCollection { get { if (_DefaultCollection == null) _DefaultCollection = new RouteDescriptorCollection(); return _DefaultCollection; } } private static RouteDescriptorCollection _DefaultCollection; private readonly List RouteDescriptors = new List(); /// /// Gets an enumerable collection of all RouteDescriptors in this collection. /// public IEnumerable Descriptors => RouteDescriptors.AsReadOnly(); /// /// 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 (descriptor == null) { return; } // Check if a route already exists with the same source, destination, input port, AND signal type var existingRoute = RouteDescriptors.FirstOrDefault(t => t.Source == descriptor.Source && t.Destination == descriptor.Destination && t.SignalType == descriptor.SignalType && ((t.InputPort == null && descriptor.InputPort == null) || (t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key)) && ((t.OutputPort == null && descriptor.OutputPort == null) || (t.OutputPort != null && descriptor.OutputPort != null && t.OutputPort.Key == descriptor.OutputPort.Key))); if (existingRoute != null) { Debug.LogInformation(descriptor.Destination, "Route from {source}:{outputPort} to {destination}:{inputPort} ({signalType}) already exists in this collection", descriptor?.Source?.Key, descriptor?.OutputPort?.Key ?? "auto", descriptor?.Destination?.Key, descriptor?.InputPort?.Key ?? "auto", descriptor?.SignalType ); return; } Debug.LogVerbose("Adding route descriptor: {source}:{outputPort} -> {destination}:{inputPort} ({signalType})", descriptor?.Source?.Key, descriptor?.OutputPort?.Key ?? "auto", descriptor?.Destination?.Key, descriptor?.InputPort?.Key ?? "auto", descriptor?.SignalType); RouteDescriptors.Add(descriptor); } /// /// Gets the RouteDescriptor for a destination. Returns null if no RouteDescriptor for a destination exists. /// public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) { Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}'", destination?.Key ?? null); return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); } /// /// Gets the route descriptor for a specific destination and input port /// /// The destination device /// The input port key /// The matching RouteDescriptor or null if not found public RouteDescriptor GetRouteDescriptorForDestinationAndInputPort(IRoutingInputs destination, string inputPortKey) { Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination && rd.InputPort != null && rd.InputPort.Key == inputPortKey); } /// /// Removes a RouteDescriptor from the collection based on the specified destination and input port key. /// /// The destination for which the route descriptor is to be removed. /// The key of the input port associated with the route descriptor. If empty, the method will attempt to remove a descriptor based solely on the destination. /// The removed RouteDescriptor object if a matching descriptor was found; otherwise, null. public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination, string inputPortKey = "") { Debug.LogMessage(LogEventLevel.Information, "Removing route descriptor for '{destination}':'{inputPortKey}'", destination.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); var descr = string.IsNullOrEmpty(inputPortKey) ? GetRouteDescriptorForDestination(destination) : GetRouteDescriptorForDestinationAndInputPort(destination, inputPortKey); if (descr != null) RouteDescriptors.Remove(descr); Debug.LogMessage(LogEventLevel.Information, "Found route descriptor {routeDescriptor}", destination, descr); return descr; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RouteRequest.cs ================================================ using PepperDash.Core; using Serilog.Events; using System; namespace PepperDash.Essentials.Core { /// /// Represents a RouteRequest /// public class RouteRequest { /// /// The specific input port on the destination device to use for the route. Can be null if the port should be automatically determined or is not applicable. /// public RoutingInputPort DestinationPort { get; set; } /// /// Gets or sets the SourcePort /// public RoutingOutputPort SourcePort { get; set; } /// /// Gets or sets the Destination /// public IRoutingInputs Destination { get; set; } /// /// Gets or sets the Source /// public IRoutingOutputs Source { get; set; } /// /// Gets or sets the SignalType /// public eRoutingSignalType SignalType { get; set; } /// /// Handles the route request after a device's cooldown period has finished. /// This method is typically subscribed to the IsCoolingDownFeedback.OutputChange event. /// /// The object that triggered the event (usually the cooling device). /// Event arguments indicating the cooldown state change. public void HandleCooldown(object sender, FeedbackEventArgs args) { try { Debug.LogMessage(LogEventLevel.Information, "Handling cooldown route request: {destination}:{destinationPort} -> {source}:{sourcePort} {type}", null, Destination?.Key ?? "empty destination", DestinationPort?.Key ?? "no destination port", Source?.Key ?? "empty source", SourcePort?.Key ?? "empty source port", SignalType.ToString()); if (args.BoolValue == true) { return; } Debug.LogMessage(LogEventLevel.Information, "Cooldown complete. Making route from {destination} to {source}", Destination?.Key, Source?.Key); Destination.ReleaseAndMakeRoute(Source, SignalType, DestinationPort?.Key ?? string.Empty, SourcePort?.Key ?? string.Empty); if (sender is IWarmingCooling coolingDevice) { Debug.LogMessage(LogEventLevel.Debug, "Unsubscribing from cooling feedback for {destination}", null, Destination.Key); coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown; } } catch(Exception ex) { Debug.LogMessage(ex, "Exception handling cooldown", Destination); } } /// /// Returns a string representation of the route request. /// /// A string describing the source and destination of the route request. public override string ToString() { return $"Route {Source?.Key ?? "No Source Device"}:{SourcePort?.Key ?? "auto"} to {Destination?.Key ?? "No Destination Device"}:{DestinationPort?.Key ?? "auto"}"; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RouteRequestQueueItem.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.Core.Queues; using System; using Serilog.Events; namespace PepperDash.Essentials.Core.Routing { /// /// Represents a RouteRequestQueueItem /// public class RouteRequestQueueItem : IQueueMessage { /// /// The action to perform for the route request. /// private readonly Action action; /// /// The route request data. /// private readonly RouteRequest routeRequest; /// /// Initializes a new instance of the class. /// /// The action to perform. /// The route request data. public RouteRequestQueueItem(Action routeAction, RouteRequest request) { action = routeAction; routeRequest = request; } /// /// Dispatches the route request action. /// public void Dispatch() { Debug.LogMessage(LogEventLevel.Information, "Dispatching route request {routeRequest}", null, routeRequest); action(routeRequest); } } /// /// Represents a ReleaseRouteQueueItem /// public class ReleaseRouteQueueItem : IQueueMessage { /// /// The action to perform for releasing the route. /// private readonly Action action; /// /// The destination device whose route is being released. /// private readonly IRoutingInputs destination; /// /// The specific input port key on the destination to release, or null/empty for any/default. /// private readonly string inputPortKey; /// /// Indicates whether to clear the route (send null) or just release the usage tracking. /// private readonly bool clearRoute; /// /// Initializes a new instance of the class. /// /// The action to perform. /// The destination device. /// The input port key. /// True to clear the route, false to just release. public ReleaseRouteQueueItem(Action action, IRoutingInputs destination, string inputPortKey, bool clearRoute) { this.action = action; this.destination = destination; this.inputPortKey = inputPortKey; this.clearRoute = clearRoute; } /// /// Dispatch method /// public void Dispatch() { Debug.LogMessage(LogEventLevel.Information, "Dispatching release route request for {destination}:{inputPortKey}", null, destination?.Key ?? "no destination", string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); action(destination, inputPortKey, clearRoute); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RouteSwitchDescriptor.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Represents a RouteSwitchDescriptor /// public class RouteSwitchDescriptor { /// /// Gets or sets the SwitchingDevice /// public IRoutingInputs SwitchingDevice { get { return InputPort?.ParentDevice; } } /// /// The output port being switched from (relevant for matrix switchers). Null for sink devices. /// public RoutingOutputPort OutputPort { get; set; } /// /// The input port being switched to. /// public RoutingInputPort InputPort { get; set; } /// /// Initializes a new instance of the class for sink devices (no output port). /// /// The input port being switched to. public RouteSwitchDescriptor(RoutingInputPort inputPort) { InputPort = inputPort; } /// /// Initializes a new instance of the class for matrix switchers. /// /// The output port being switched from. /// The input port being switched to. public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort) { InputPort = inputPort; OutputPort = outputPort; } /// /// Returns a string representation of the route switch descriptor. /// /// A string describing the switch operation. /// public override string ToString() { if (SwitchingDevice is IRouting) return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches output {(OutputPort != null ? OutputPort.Key : "No output port")} to input {(InputPort != null ? InputPort.Key : "No input port")}"; else return $"{(SwitchingDevice != null ? SwitchingDevice.Key : "No Device")} switches to input {(InputPort != null ? InputPort.Key : "No input port")}"; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RoutingFeedbackManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Timers; using PepperDash.Core; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core.Routing { /// /// Manages routing feedback by subscribing to route changes on midpoint and sink devices, /// tracing the route back to the original source, and updating the CurrentSourceInfo on sink devices. /// public class RoutingFeedbackManager : EssentialsDevice { /// /// Maps midpoint device keys to the set of sink device keys that are downstream /// private Dictionary> midpointToSinksMap; /// /// Debounce timers for each sink device to prevent rapid successive updates /// private readonly Dictionary updateTimers = new Dictionary(); /// /// Lock object protecting all access to . /// private readonly object _timerLock = new object(); /// /// Debounce delay in milliseconds /// private const long DEBOUNCE_MS = 500; /// /// Initializes a new instance of the class. /// /// The unique key for this manager device. /// The name of this manager device. public RoutingFeedbackManager(string key, string name) : base(key, name) { AddPreActivationAction(BuildMidpointSinkMap); AddPreActivationAction(SubscribeForMidpointFeedback); AddPreActivationAction(SubscribeForSinkFeedback); } /// /// Builds a map of which sink devices are downstream of each midpoint device /// for performance optimization in HandleMidpointUpdate /// private void BuildMidpointSinkMap() { midpointToSinksMap = new Dictionary>(); var sinks = DeviceManager.AllDevices.OfType(); foreach (var sink in sinks) { if (sink.CurrentInputPort == null) continue; // Find all upstream midpoints for this sink var upstreamMidpoints = GetUpstreamMidpoints(sink); foreach (var midpointKey in upstreamMidpoints) { if (!midpointToSinksMap.ContainsKey(midpointKey)) midpointToSinksMap[midpointKey] = new HashSet(); midpointToSinksMap[midpointKey].Add(sink.Key); } } Debug.LogMessage( Serilog.Events.LogEventLevel.Information, "Built midpoint-to-sink map with {count} midpoints", this, midpointToSinksMap.Count ); } /// /// Gets all upstream midpoint device keys for a given sink /// private HashSet GetUpstreamMidpoints(IRoutingSinkWithSwitchingWithInputPort sink) { var result = new HashSet(); var visited = new HashSet(); if (sink.CurrentInputPort == null) return result; var tieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == sink.CurrentInputPort.Key && tl.DestinationPort.ParentDevice.Key == sink.CurrentInputPort.ParentDevice.Key); if (tieLine == null) return result; TraceUpstreamMidpoints(tieLine, result, visited); return result; } /// /// Recursively traces upstream to find all midpoint devices /// private void TraceUpstreamMidpoints(TieLine tieLine, HashSet midpoints, HashSet visited) { if (tieLine == null || visited.Contains(tieLine.SourcePort.ParentDevice.Key)) return; visited.Add(tieLine.SourcePort.ParentDevice.Key); if (tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) { midpoints.Add(midpoint.Key); // Find upstream TieLines connected to this midpoint's inputs var midpointInputs = (midpoint as IRoutingInputs)?.InputPorts; if (midpointInputs != null) { foreach (var inputPort in midpointInputs) { var upstreamTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key); if (upstreamTieLine != null) TraceUpstreamMidpoints(upstreamTieLine, midpoints, visited); } } } } /// /// Subscribes to the RouteChanged event on all devices implementing . /// private void SubscribeForMidpointFeedback() { var midpointDevices = DeviceManager.AllDevices.OfType(); foreach (var device in midpointDevices) { device.RouteChanged += HandleMidpointUpdate; } } /// /// Subscribes to the InputChanged event on all devices implementing . /// private void SubscribeForSinkFeedback() { var sinkDevices = DeviceManager.AllDevices.OfType(); foreach (var device in sinkDevices) { device.InputChanged += HandleSinkUpdate; } } /// /// Handles the RouteChanged event from a midpoint device. /// Only triggers updates for sink devices that are downstream of this midpoint. /// /// The midpoint device that reported a route change. /// The descriptor of the new route. private void HandleMidpointUpdate( IRoutingWithFeedback midpoint, RouteSwitchDescriptor newRoute ) { try { // Only update affected sinks (performance optimization) if (midpointToSinksMap != null && midpointToSinksMap.TryGetValue(midpoint.Key, out var affectedSinkKeys)) { Debug.LogMessage( Serilog.Events.LogEventLevel.Debug, "Midpoint {midpoint} changed, updating {count} downstream sinks", this, midpoint.Key, affectedSinkKeys.Count ); foreach (var sinkKey in affectedSinkKeys) { if (DeviceManager.GetDeviceForKey(sinkKey) is IRoutingSinkWithSwitchingWithInputPort sink) { UpdateDestination(sink, sink.CurrentInputPort); } } } else { Debug.LogMessage( Serilog.Events.LogEventLevel.Debug, "Midpoint {midpoint} changed but has no downstream sinks in map", this, midpoint.Key ); } } catch (Exception ex) { Debug.LogMessage( ex, "Error handling midpoint update from {midpointKey}:{Exception}", this, midpoint.Key, ex ); } } /// /// Removes a sink from every midpoint set in the map and re-adds it based on its /// current input port. Call this whenever a sink's selected input changes so that /// HandleMidpointUpdate always sees an up-to-date downstream set. /// private void RebuildMapForSink(IRoutingSinkWithSwitchingWithInputPort sink) { if (midpointToSinksMap == null) return; // Remove this sink from all existing midpoint sets foreach (var set in midpointToSinksMap.Values) set.Remove(sink.Key); // Drop any midpoint entries that are now empty var emptyKeys = midpointToSinksMap .Where(kvp => kvp.Value.Count == 0) .Select(kvp => kvp.Key) .ToList(); foreach (var k in emptyKeys) midpointToSinksMap.Remove(k); // Re-add the sink under every midpoint that is upstream of its new input if (sink.CurrentInputPort == null) return; var upstreamMidpoints = GetUpstreamMidpoints(sink); foreach (var midpointKey in upstreamMidpoints) { if (!midpointToSinksMap.ContainsKey(midpointKey)) midpointToSinksMap[midpointKey] = new HashSet(); midpointToSinksMap[midpointKey].Add(sink.Key); } } /// /// Handles the InputChanged event from a sink device. /// Updates the midpoint-to-sink map for the new input path, then triggers /// a source-info update for the sink. /// /// The sink device that reported an input change. /// The new input port selected on the sink device. private void HandleSinkUpdate( IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort ) { try { // Keep the map current so HandleMidpointUpdate can find this sink if (sender is IRoutingSinkWithSwitchingWithInputPort sinkWithInputPort) RebuildMapForSink(sinkWithInputPort); UpdateDestination(sender, currentInputPort); } catch (Exception ex) { Debug.LogMessage( ex, "Error handling Sink update from {senderKey}:{Exception}", this, sender.Key, ex ); } } /// /// Updates the CurrentSourceInfo and CurrentSourceInfoKey properties on a destination (sink) device /// based on its currently selected input port by tracing the route back through tie lines. /// Uses debouncing to prevent rapid successive updates. /// /// The destination sink device to update. /// The currently selected input port on the destination device. private void UpdateDestination( IRoutingSinkWithSwitching destination, RoutingInputPort inputPort ) { if (destination == null) return; var key = destination.Key; // Cancel and replace any existing timer under the lock so no callback // can race with us while we swap the entry. Timer timerToDispose = null; Timer newTimer = null; newTimer = new Timer(DEBOUNCE_MS) { AutoReset = false }; newTimer.Elapsed += (s, e) => { try { UpdateDestinationImmediate(destination, inputPort); } catch (Exception ex) { Debug.LogMessage( ex, "Error in debounced update for destination {destinationKey}: {message}", this, destination.Key, ex.Message ); } finally { // Remove the entry first so a concurrent UpdateDestination call // cannot re-dispose whatever timer we're about to dispose. Timer selfTimer = null; lock (_timerLock) { if (updateTimers.TryGetValue(key, out var current) && ReferenceEquals(current, newTimer)) { selfTimer = current; updateTimers.Remove(key); } } selfTimer?.Dispose(); } }; lock (_timerLock) { if (updateTimers.TryGetValue(key, out var existingTimer)) timerToDispose = existingTimer; updateTimers[key] = newTimer; } // Dispose the old timer outside the lock to avoid holding the lock during disposal. // Dispose implicitly stops the timer, preventing its Elapsed event from firing. timerToDispose?.Dispose(); // Start after the lock is released so the Elapsed callback cannot deadlock // trying to acquire _timerLock while we still hold it. newTimer.Start(); } /// /// Immediately updates the CurrentSourceInfo for a destination device. /// Called after debounce delay. /// private void UpdateDestinationImmediate( IRoutingSinkWithSwitching destination, RoutingInputPort inputPort ) { Debug.LogMessage( Serilog.Events.LogEventLevel.Debug, "Updating destination {destination} with inputPort {inputPort}", this, destination?.Key, inputPort?.Key ); if (inputPort == null) { Debug.LogMessage( Serilog.Events.LogEventLevel.Debug, "Destination {destination} has not reported an input port yet", this, destination.Key ); return; } TieLine firstTieLine; try { var tieLines = TieLineCollection.Default; firstTieLine = tieLines.FirstOrDefault(tl => tl.DestinationPort.Key == inputPort.Key && tl.DestinationPort.ParentDevice.Key == inputPort.ParentDevice.Key ); if (firstTieLine == null) { Debug.LogMessage( Serilog.Events.LogEventLevel.Debug, "No tieline found for inputPort {inputPort}. Clearing current source", this, inputPort ); var tempSourceListItem = new SourceListItem { SourceKey = "$transient", Name = inputPort.Key, }; destination.CurrentSourceInfo = tempSourceListItem; ; destination.CurrentSourceInfoKey = "$transient"; return; } } catch (Exception ex) { Debug.LogMessage(ex, "Error getting first tieline: {Exception}", this, ex); return; } // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine); TieLine sourceTieLine; try { sourceTieLine = GetRootTieLine(firstTieLine); if (sourceTieLine == null) { Debug.LogMessage( Serilog.Events.LogEventLevel.Debug, "No route found to source for inputPort {inputPort}. Clearing current source", this, inputPort ); var tempSourceListItem = new SourceListItem { SourceKey = "$transient", Name = "None", }; destination.CurrentSourceInfo = tempSourceListItem; destination.CurrentSourceInfoKey = string.Empty; return; } } catch (Exception ex) { Debug.LogError(this, "Error getting sourceTieLine: {message}", ex.Message); Debug.LogDebug(ex, "StackTrace: "); return; } // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine); // Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet. var room = DeviceManager .AllDevices.OfType() .FirstOrDefault( (r) => { if (r is IHasMultipleDisplays roomMultipleDisplays) { return roomMultipleDisplays.Displays.Any(d => d.Value.Key == destination.Key ); } if (r is IHasDefaultDisplay roomDefaultDisplay) { return roomDefaultDisplay.DefaultDisplay.Key == destination.Key; } if (ConfigReader.ConfigObject.GetDestinationListForKey(r.DestinationListKey)?.FirstOrDefault(d => d.Value.SinkKey == destination.Key) != null) { return true; } return false; } ); if (room == null) { Debug.LogMessage( Serilog.Events.LogEventLevel.Debug, "No room found for display {destination}", this, destination.Key ); return; } // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found room {room} for destination {destination}", this, room.Key, destination.Key); var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); if (sourceList == null) { Debug.LogDebug(this, "No source list found for source list key {key}. Unable to find source for tieLine {sourceTieLine}", room.SourceListKey, sourceTieLine ); return; } // Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found sourceList for room {room}", this, room.Key); var sourceListItem = sourceList.FirstOrDefault(sli => { //// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, // "SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}", // this, // sli.Key, // sli.Value.SourceKey, // sourceTieLine.SourcePort.ParentDevice.Key); return sli.Value.SourceKey.Equals( sourceTieLine.SourcePort.ParentDevice.Key, StringComparison.InvariantCultureIgnoreCase ); }); var source = sourceListItem.Value; var sourceKey = sourceListItem.Key; if (source == null) { Debug.LogDebug(this, "No source found for device {key}. Creating transient source for {destination}", sourceTieLine.SourcePort.ParentDevice.Key, destination ); var tempSourceListItem = new SourceListItem { SourceKey = "$transient", Name = sourceTieLine.SourcePort.Key, }; destination.CurrentSourceInfoKey = "$transient"; destination.CurrentSourceInfo = tempSourceListItem; return; } //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {@source} with key {sourceKey}", this, source, sourceKey); destination.CurrentSourceInfoKey = sourceKey; destination.CurrentSourceInfo = source; } /// /// Traces a route back from a given tie line to find the root source tie line. /// Leverages the existing Extensions.GetRouteToSource method with loop protection. /// /// The starting tie line (typically connected to a sink or midpoint). /// The connected to the original source device, or null if the source cannot be determined. private TieLine GetRootTieLine(TieLine tieLine) { try { if (!(tieLine.DestinationPort.ParentDevice is IRoutingInputs sink)) { Debug.LogDebug(this, "TieLine destination {device} is not IRoutingInputs", tieLine.DestinationPort.ParentDevice.Key ); return null; } // Get all potential sources (devices that only have outputs, not inputs+outputs) var sources = DeviceManager.AllDevices .OfType() .Where(s => !(s is IRoutingInputsOutputs)); // Try each signal type that this TieLine supports var signalTypes = new[] { eRoutingSignalType.Audio, eRoutingSignalType.Video, eRoutingSignalType.AudioVideo, eRoutingSignalType.SecondaryAudio, eRoutingSignalType.UsbInput, eRoutingSignalType.UsbOutput }; foreach (var signalType in signalTypes) { if (!tieLine.Type.HasFlag(signalType)) continue; foreach (var source in sources) { // Use the optimized route discovery with loop protection var (route, _) = sink.GetRouteToSource( source, signalType, tieLine.DestinationPort, null ); if (route != null && route.Routes != null && route.Routes.Count > 0) { // Routes[0] is the hop nearest the source: its InputPort is the // port on the first switching device that receives the signal from // the source side. The TieLine whose DestinationPort matches that // port is the exact tie that was traversed, giving us the precise // source output port via SourcePort — regardless of how many output // ports the source device has. var firstHop = route.Routes[0]; var sourceTieLine = TieLineCollection.Default.FirstOrDefault(tl => tl.DestinationPort.Key == firstHop.InputPort.Key && tl.DestinationPort.ParentDevice.Key == firstHop.InputPort.ParentDevice.Key); if (sourceTieLine != null) { Debug.LogDebug(this, "Found route from {source} to {sink} with {count} hops", source.Key, sink.Key, route.Routes.Count ); return sourceTieLine; } } } } Debug.LogDebug(this, "No route found to any source from {sink}", sink.Key); return null; } catch (Exception ex) { Debug.LogError(this, "Error getting root tieLine: {message}", ex.Message); Debug.LogDebug(ex, "StackTrace: "); return null; } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RoutingInputPort.cs ================================================ using Newtonsoft.Json; using System; namespace PepperDash.Essentials.Core { /// /// Represents a RoutingInputPort /// public class RoutingInputPort : RoutingPort { /// /// The IRoutingInputs object this lives on /// [JsonIgnore] public IRoutingInputs ParentDevice { get; private set; } /// /// Constructor for a basic RoutingInputPort /// /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. /// May be string, number, whatever /// The IRoutingInputs object this lives on /// key of the port /// type of the routing signal /// connection type of the port public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, IRoutingInputs parent) : this (key, type, connType, selector, parent, false) { } /// /// Constructor for a virtual routing input port that lives inside a device. For example /// the ports that link a DM card to a DM matrix bus /// /// true for internal ports /// key of the port /// type of the routing signal /// connection type of the port /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. /// May be string, number, whatever /// The IRoutingInputs object this lives on public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, IRoutingInputs parent, bool isInternal) : base(key, type, connType, selector, isInternal) { if (parent == null) throw new ArgumentNullException(nameof(parent)); ParentDevice = parent; } /// /// Returns a string representation of the input port. /// /// A string in the format "ParentDeviceKey|PortKey|SignalType|ConnectionType". /// public override string ToString() { return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; } } /*/// /// Basic RoutingInput with no statuses. /// public class RoutingInputPort : RoutingPort { /// /// Gets or sets the ParentDevice /// public IRoutingInputs ParentDevice { get; private set; } /// /// Constructor for a basic RoutingInputPort /// /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. /// May be string, number, whatever /// The IRoutingInputs object this lives on public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, IRoutingInputs parent) : this(key, type, connType, selector, parent, false) { } /// /// Constructor for a virtual routing input port that lives inside a device. For example /// the ports that link a DM card to a DM matrix bus /// /// true for internal ports public RoutingInputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, IRoutingInputs parent, bool isInternal) : base(key, type, connType, selector, isInternal) { ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); } }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RoutingInputPortWithVideoStatuses.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Represents a RoutingInputPortWithVideoStatuses /// public class RoutingInputPortWithVideoStatuses : RoutingInputPort { /// /// Provides feedback outputs for video statuses associated with this port. /// public VideoStatusOutputs VideoStatus { get; private set; } /// /// Initializes a new instance of the class. /// /// The unique key for this port. /// The signal type supported by this port. /// The physical connection type of this port. /// An object used to refer to this port in the parent device's ExecuteSwitch method. /// The device this port belongs to. /// A containing delegates to retrieve video status values. public RoutingInputPortWithVideoStatuses(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, IRoutingInputs parent, VideoStatusFuncsWrapper funcs) : base(key, type, connType, selector, parent) { VideoStatus = new VideoStatusOutputs(funcs); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RoutingNumericEventArgs.cs ================================================ using System; namespace PepperDash.Essentials.Core { /// /// Represents a RoutingNumericEventArgs /// public class RoutingNumericEventArgs : EventArgs { /// /// The numeric representation of the output, if applicable. /// public uint? Output { get; set; } /// /// The numeric representation of the input, if applicable. /// public uint? Input { get; set; } /// /// The type of signal involved in the routing change. /// public eRoutingSignalType SigType { get; set; } /// /// The input port involved in the routing change, if applicable. /// public RoutingInputPort InputPort { get; set; } /// /// The output port involved in the routing change, if applicable. /// public RoutingOutputPort OutputPort { get; set; } /// /// Initializes a new instance of the class using numeric identifiers. /// /// The numeric output identifier. /// The numeric input identifier. /// The signal type. public RoutingNumericEventArgs(uint output, uint input, eRoutingSignalType sigType) : this(output, input, null, null, sigType) { } /// /// Initializes a new instance of the class using port objects. /// /// The output port object. /// The input port object. /// The signal type. public RoutingNumericEventArgs(RoutingOutputPort outputPort, RoutingInputPort inputPort, eRoutingSignalType sigType) : this(null, null, outputPort, inputPort, sigType) { } /// /// Initializes a new instance of the class with default values. /// public RoutingNumericEventArgs() : this(null, null, null, null, 0) { } /// /// Initializes a new instance of the class with potentially mixed identifiers. /// /// The numeric output identifier (optional). /// The numeric input identifier (optional). /// The output port object (optional). /// The input port object (optional). /// The signal type. public RoutingNumericEventArgs(uint? output, uint? input, RoutingOutputPort outputPort, RoutingInputPort inputPort, eRoutingSignalType sigType) { OutputPort = outputPort; InputPort = inputPort; Output = output; Input = input; SigType = sigType; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RoutingOutputPort.cs ================================================ using Newtonsoft.Json; using System; namespace PepperDash.Essentials.Core { /// /// Represents a RoutingOutputPort /// public class RoutingOutputPort : RoutingPort { /// /// The IRoutingOutputs object this port lives on. /// [JsonIgnore] public IRoutingOutputs ParentDevice { get; private set; } /// /// Tracks which destinations are currently using this output port. /// public InUseTracking InUseTracker { get; private set; } /// /// Initializes a new instance of the class. /// /// The unique key for this port. /// The signal type supported by this port. /// The physical connection type of this port. /// An object used to refer to this port in the parent device's ExecuteSwitch method. /// The device this port belongs to. public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, IRoutingOutputs parent) : this(key, type, connType, selector, parent, false) { } /// /// Initializes a new instance of the class, potentially marking it as internal. /// /// The unique key for this port. /// The signal type supported by this port. /// The physical connection type of this port. /// An object used to refer to this port in the parent device's ExecuteSwitch method. /// The device this port belongs to. /// True if this port represents an internal connection within a device (e.g., card to backplane). public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, IRoutingOutputs parent, bool isInternal) : base(key, type, connType, selector, isInternal) { ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); InUseTracker = new InUseTracking(); } /// /// Returns a string representation of the output port. /// /// A string in the format "ParentDeviceKey|PortKey|SignalType|ConnectionType". public override string ToString() { return $"{ParentDevice.Key}|{Key}|{Type}|{ConnectionType}"; } } /*public class RoutingOutputPort : RoutingPort { /// /// Gets or sets the ParentDevice /// public IRoutingOutputs ParentDevice { get; private set; } /// /// Gets or sets the InUseTracker /// public InUseTracking InUseTracker { get; private set; } /// /// /// An object used to refer to this port in the IRouting device's ExecuteSwitch method. /// May be string, number, whatever /// The IRoutingOutputs object this port lives on public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, IRoutingOutputs parent) : this(key, type, connType, selector, parent, false) { } public RoutingOutputPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, IRoutingOutputs parent, bool isInternal) : base(key, type, connType, selector, isInternal) { ParentDevice = parent ?? throw new ArgumentNullException(nameof(parent)); InUseTracker = new InUseTracking(); } /// /// ToString method /// /// public override string ToString() { return ParentDevice.Key + ":" + Key; } }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RoutingPort.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Base class for and . /// public abstract class RoutingPort : IKeyed { /// /// The unique key identifying this port within its parent device. /// public string Key { get; private set; } /// /// The type of signal this port handles (e.g., Audio, Video, AudioVideo). /// public eRoutingSignalType Type { get; private set; } /// /// The physical connection type of this port (e.g., Hdmi, Rca, Dm). /// public eRoutingPortConnectionType ConnectionType { get; private set; } /// /// An object (often a number or string) used by the parent routing device to select this port during switching. /// public readonly object Selector; /// /// Indicates if this port represents an internal connection within a device (e.g., card to backplane). /// public bool IsInternal { get; private set; } /// /// An object used to match feedback values to this port, if applicable. /// public object FeedbackMatchObject { get; set; } /// /// A reference to the underlying hardware port object (e.g., SimplSharpPro Port), if applicable. /// public object Port { get; set; } /// /// Initializes a new instance of the class. /// /// The unique key for this port. /// The signal type supported by this port. /// The physical connection type of this port. /// The selector object for switching. /// True if this port is internal. public RoutingPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, object selector, bool isInternal) { Key = key; Type = type; ConnectionType = connType; Selector = selector; IsInternal = isInternal; } } /*public abstract class RoutingPort:IKeyed { /// /// Gets or sets the Key /// public string Key { get; private set; } /// /// Gets or sets the Type /// public eRoutingSignalType Type { get; private set; } /// /// Gets or sets the ConnectionType /// public eRoutingPortConnectionType ConnectionType { get; private set; } public readonly TSelector Selector; /// /// Gets or sets the IsInternal /// public bool IsInternal { get; private set; } /// /// Gets or sets the FeedbackMatchObject /// public object FeedbackMatchObject { get; set; } /// /// Gets or sets the Port /// public object Port { get; set; } public RoutingPort(string key, eRoutingSignalType type, eRoutingPortConnectionType connType, TSelector selector, bool isInternal) { Key = key; Type = type; ConnectionType = connType; Selector = selector; IsInternal = isInternal; } }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RoutingPortCollection.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace PepperDash.Essentials.Core { /// /// Represents a RoutingPortCollection, which is essentially a List with an indexer for case-insensitive lookup of ports by their key names. /// public class RoutingPortCollection : List where T: RoutingPort { /// /// Case-insensitive port lookup linked to ports' keys /// public T this[string key] { get { return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); } } } /* /// /// Basically a List , with an indexer to find ports by key name /// public class RoutingPortCollection : List where T : RoutingPort { /// /// Case-insensitive port lookup linked to ports' keys /// public T this[string key] { get { return this.FirstOrDefault(i => i.Key.Equals(key, StringComparison.OrdinalIgnoreCase)); } } }*/ } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/RoutingPortNames.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Defines constant string values for common routing port keys. /// These should correspond directly with the portNames var in the config tool. /// public class RoutingPortNames { /// /// antennaIn /// public const string AntennaIn = "antennaIn"; /// /// anyAudioIn /// public const string AnyAudioIn = "anyAudioIn"; /// /// anyAudioOut /// public const string AnyAudioOut = "anyAudioOut"; /// /// anyOut /// public const string AnyOut = "anyOut"; /// /// anyVideoIn /// public const string AnyVideoIn = "anyVideoIn"; /// /// anyVideoOut /// public const string AnyVideoOut = "anyVideoOut"; /// /// balancedAudioOut /// public const string BalancedAudioOut = "balancedAudioOut"; /// /// codecOsd /// public const string CodecOsd = "codecOsd"; /// /// componentIn /// public const string ComponentIn = "componentIn"; /// /// componentOut /// public const string ComponentOut = "componentOut"; /// /// compositeIn /// public const string CompositeIn = "compositeIn"; /// /// compositeOut /// public const string CompositeOut = "compositeOut"; /// /// displayPortIn /// public const string DisplayPortIn = "displayPortIn"; /// /// displayPortIn1 /// public const string DisplayPortIn1 = "displayPortIn1"; /// /// displayPortIn2 /// public const string DisplayPortIn2 = "displayPortIn2"; /// /// displayPortIn3 /// public const string DisplayPortIn3 = "displayPortIn3"; /// /// displayPortOut /// public const string DisplayPortOut = "displayPortOut"; /// /// dmIn /// public const string DmIn = "dmIn"; /// /// dmOut /// public const string DmOut = "dmOut"; /// /// dviIn /// public const string DviIn = "dviIn"; /// /// dviIn1 /// public const string DviIn1 = "dviIn1"; /// /// dviOut /// public const string DviOut = "dviOut"; /// /// hdmiIn /// public const string HdmiIn = "hdmiIn"; /// /// hdmiIn1 /// public const string HdmiIn1 = "hdmiIn1"; /// /// hdmiIn1PC /// public const string HdmiIn1PC = "hdmiIn1PC"; /// /// hdmiIn2 /// public const string HdmiIn2 = "hdmiIn2"; /// /// hdmiIn2PC /// public const string HdmiIn2PC = "hdmiIn2PC"; /// /// hdmiIn3 /// public const string HdmiIn3 = "hdmiIn3"; /// /// hdmiIn4 /// public const string HdmiIn4 = "hdmiIn4"; /// /// hdmiIn5 /// public const string HdmiIn5 = "hdmiIn5"; /// /// hdmiIn6 /// public const string HdmiIn6 = "hdmiIn6"; /// /// hdmiOut /// public const string HdmiOut = "hdmiOut"; /// /// hdmiOut1 /// public const string HdmiOut1 = "hdmiOut1"; /// /// hdmiOut2 /// public const string HdmiOut2 = "hdmiOut2"; /// /// hdmiOut3 /// public const string HdmiOut3 = "hdmiOut3"; /// /// hdmiOut4 /// public const string HdmiOut4 = "hdmiOut4"; /// /// hdmiOut5 /// public const string HdmiOut5 = "hdmiOut5"; /// /// hdmiOut6 /// public const string HdmiOut6 = "hdmiOut6"; /// /// none /// public const string None = "none"; /// /// rgbIn /// public const string RgbIn = "rgbIn"; /// /// rgbIn1 /// public const string RgbIn1 = "rgbIn1"; /// /// rgbIn2 /// public const string RgbIn2 = "rgbIn2"; /// /// vgaIn /// public const string VgaIn = "vgaIn"; /// /// vgaIn1 /// public const string VgaIn1 = "vgaIn1"; /// /// vgaOut /// public const string VgaOut = "vgaOut"; /// /// IPC/OPS /// public const string IpcOps = "ipcOps"; /// /// MediaPlayer /// public const string MediaPlayer = "mediaPlayer"; /// /// UsbCIn /// public const string UsbCIn = "usbCIn"; /// /// UsbCIn1 /// public const string UsbCIn1 = "usbCIn1"; /// /// UsbCIn2 /// public const string UsbCIn2 = "usbCIn2"; /// /// UsbCIn3 /// public const string UsbCIn3 = "usbCIn3"; /// /// UsbCOut /// public const string UsbCOut = "usbCOut"; /// /// UsbCOut1 /// public const string UsbCOut1 = "usbCOut1"; /// /// UsbCOut2 /// public const string UsbCOut2 = "usbCOut2"; /// /// UsbCOut3 /// public const string UsbCOut3 = "usbCOut3"; /// /// HdBaseTIn /// public const string HdBaseTIn = "hdBaseTIn"; /// /// HdBaseTOut /// public const string HdBaseTOut = "hdBaseTOut"; /// /// SdiIn /// public const string SdiIn = "sdiIn"; /// /// SdiOut /// public const string SdiOut = "sdiOut"; } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/TieLine.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; namespace PepperDash.Essentials.Core { /// /// Represents a connection between routing ports, linking a source output port to a destination input port. /// This class is used to define signal paths for routing algorithms, including signal type overrides and internal connections. /// public class TieLine { /// /// The source output port of the tie line. /// public RoutingOutputPort SourcePort { get; private set; } /// /// The destination input port of the tie line. /// public RoutingInputPort DestinationPort { get; private set; } //public int InUseCount { get { return DestinationUsingThis.Count; } } /// /// Gets the type of this tie line. Returns the intersection of signal types supported by both /// the source and destination ports (what signals can actually travel through this tie line), /// or the OverrideType when it is set. /// public eRoutingSignalType Type { get { if (OverrideType.HasValue) return OverrideType.Value; return SourcePort.Type & DestinationPort.Type; } } /// /// Use this to override the Type property. For example, when both ports support AudioVideo /// but the physical cable only carries Audio or Video, setting this will limit the signal /// paths available to the routing algorithm without affecting the actual port types. /// When set, this value is used instead of the calculated intersection of source and destination types. /// public eRoutingSignalType? OverrideType { get; set; } //List DestinationUsingThis = new List(); /// /// Gets a value indicating whether this tie line represents an internal connection within a device (both source and destination ports are internal). /// public bool IsInternal { get { return SourcePort.IsInternal && DestinationPort.IsInternal; } } /// /// Gets a value indicating whether the signal types of the source and destination ports differ. /// public bool TypeMismatch { get { return SourcePort.Type != DestinationPort.Type; } } /// /// Gets a value indicating whether the connection types of the source and destination ports differ. /// public bool ConnectionTypeMismatch { get { return SourcePort.ConnectionType != DestinationPort.ConnectionType; } } /// /// A descriptive note about any type mismatch, if applicable. /// public string TypeMismatchNote { get; set; } /// /// Initializes a new instance of the class. /// /// The source output port. /// The destination input port. public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort) { if (sourcePort == null || destinationPort == null) throw new ArgumentNullException("source or destination port"); SourcePort = sourcePort; DestinationPort = destinationPort; } /// /// Creates a tie line with an overriding Type. See help for OverrideType property for info. /// /// The source output port. /// The destination input port. /// The signal type to limit the link to. Overrides the calculated intersection of port types for routing calculations. public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType? overrideType) : this(sourcePort, destinationPort) { OverrideType = overrideType; } /// /// Creates a tie line with an overriding Type. See help for OverrideType property for info. /// /// The source output port. /// The destination input port. /// The signal type to limit the link to. Overrides the calculated intersection of port types for routing calculations. public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType overrideType) : this(sourcePort, destinationPort) { OverrideType = overrideType; } /// /// Will link up video status from supporting inputs to connected outputs. /// public void Activate() { // Now does nothing } /// /// Deactivates the tie line. /// public void Deactivate() { // Now does nothing } /// /// Returns a string representation of the tie line. /// /// A string describing the source, destination, and type of the tie line. public override string ToString() { return string.Format("Tie line: {0}:{1} --> {2}:{3} {4}", SourcePort.ParentDevice.Key, SourcePort.Key, DestinationPort.ParentDevice.Key, DestinationPort.Key, Type.ToString()); } } //******************************************************************************** /// /// Represents a collection of objects, which define signal paths for routing algorithms. /// This class provides functionality for managing tie lines and includes a singleton instance for global access. /// public class TieLineCollection : List { /// /// Gets the default singleton instance of the . /// public static TieLineCollection Default { get { if (_Default == null) _Default = new TieLineCollection(); return _Default; } } /// /// Backing field for the singleton instance. /// [JsonIgnore] private static TieLineCollection _Default; } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; namespace PepperDash.Essentials.Core.Config { /// /// Represents the configuration data for a single tie line between two routing ports. /// public class TieLineConfig { /// /// The key of the source device. /// public string SourceKey { get; set; } /// /// The key of the source card (if applicable, e.g., in a modular chassis). /// public string SourceCard { get; set; } /// /// The key of the source output port, used for routing configurations. /// public string SourcePort { get; set; } /// /// Gets or sets the DestinationKey /// public string DestinationKey { get; set; } /// /// Gets or sets the DestinationCard /// public string DestinationCard { get; set; } /// /// Gets or sets the DestinationPort /// public string DestinationPort { get; set; } /// /// Optional override for the signal type of the tie line. If set, this overrides the calculated /// intersection of source and destination port types for routing calculations. Useful when the /// physical cable supports fewer signal types than both ports are capable of. /// [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public eRoutingSignalType? OverrideType { get; set; } /// /// Returns the appropriate tie line for either a card-based device or /// regular device with ports on-device. /// /// null if config data does not match ports, cards or devices public TieLine GetTieLine() { Debug.LogInformation("Build TieLine: {config}", ToString()); // Get the source device if (!(DeviceManager.GetDeviceForKey(SourceKey) is IRoutingOutputs sourceDev)) { LogError("Routable source not found"); return null; } // Get the destination device if (!(DeviceManager.GetDeviceForKey(DestinationKey) is IRoutingInputs destDev)) { LogError("Routable destination not found"); return null; } //Get the source port var sourceOutputPort = sourceDev.OutputPorts[SourcePort]; if (sourceOutputPort == null) { LogError("Source does not contain port"); return null; } //Get the Destination port var destinationInputPort = destDev.InputPorts[DestinationPort]; if (destinationInputPort == null) { LogError("Destination does not contain port"); return null; } // Validate signal type compatibility if (OverrideType.HasValue) { // When override type is specified, both ports must support it if (!sourceOutputPort.Type.HasFlag(OverrideType.Value)) { LogError($"Override type '{OverrideType.Value}' is not supported by source port '{SourcePort}' (type: {sourceOutputPort.Type})"); return null; } if (!destinationInputPort.Type.HasFlag(OverrideType.Value)) { LogError($"Override type '{OverrideType.Value}' is not supported by destination port '{DestinationPort}' (type: {destinationInputPort.Type})"); return null; } } else { // Without override type, ports must have at least one common signal type flag if ((sourceOutputPort.Type & destinationInputPort.Type) == 0) { LogError($"Incompatible signal types: source port '{SourcePort}' (type: {sourceOutputPort.Type}) has no common signal types with destination port '{DestinationPort}' (type: {destinationInputPort.Type})"); return null; } } return new TieLine(sourceOutputPort, destinationInputPort, OverrideType); } /// /// Logs an error message related to creating this tie line configuration. /// /// The specific error message. private void LogError(string msg) { Debug.LogError("Cannot create tie line: {message}", msg); } /// /// Returns a string representation of the tie line configuration. /// /// A string describing the source and destination of the configured tie line. public override string ToString() { return $"{SourceKey}.{SourceCard}.{SourcePort} --> {DestinationKey}.{DestinationCard}.{DestinationPort}"; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/eRoutingPortConnectionType.cs ================================================ namespace PepperDash.Essentials.Core { /// /// Enumeration of eRoutingPortConnectionType values /// public enum eRoutingPortConnectionType { /// /// No connection type /// None, /// /// Backplane only connection /// BackplaneOnly, /// /// Connection via cable /// DisplayPort, /// /// DVI connection /// Dvi, /// /// HDMI connection /// Hdmi, /// /// RGB connection /// Rgb, /// /// VGA connection /// Vga, /// /// Line audio connection /// LineAudio, /// /// Digital audio connection /// DigitalAudio, /// /// SDI connection /// Sdi, /// /// Composite connection /// Composite, /// /// Component connection /// Component, /// /// DM CAT connection /// DmCat, /// /// DM MM Fiber connection /// DmMmFiber, /// /// DM SM Fiber connection /// DmSmFiber, /// /// Speaker connection /// Speaker, /// /// Microphone connection /// Streaming, /// /// USB-C connection /// UsbC, /// /// HDBaseT connection /// HdBaseT } } ================================================ FILE: src/PepperDash.Essentials.Core/Routing/eRoutingSignalType.cs ================================================ using System; namespace PepperDash.Essentials.Core { /// /// Enumeration of eRoutingSignalType values /// [Flags] public enum eRoutingSignalType { /// /// Audio signal type /// Audio = 1, /// /// Video signal type /// Video = 2, /// /// AudioVideo signal type /// AudioVideo = Audio | Video, /// /// Control signal type /// [Obsolete("UsbOutput is no longer supported and will be removed in a future release.")] UsbOutput = 8, /// /// Control signal type /// [Obsolete("UsbInput is no longer supported and will be removed in a future release.")] UsbInput = 16, /// /// Secondary audio signal type /// [Obsolete("SecondaryAudio is no longer supported and will be removed in a future release.")] SecondaryAudio = 32 } } ================================================ FILE: src/PepperDash.Essentials.Core/Secrets/CrestronGlobalSecretsProvider.cs ================================================ using System; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronDataStore; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Represents a CrestronGlobalSecretsProvider /// public class CrestronGlobalSecretsProvider : ISecretProvider { /// /// Gets or sets the Key /// public string Key { get; set; } //Added for reference /// /// Gets or sets the Description /// public string Description { get; private set; } /// /// Constructor for CrestronGlobalSecretsProvider /// /// The key for the secret provider public CrestronGlobalSecretsProvider(string key) { Key = key; Description = String.Format("Default secret provider serving all local applications"); } static CrestronGlobalSecretsProvider() { //Added for future encrypted reference var secureSupported = CrestronSecureStorage.Supported; CrestronDataStoreStatic.InitCrestronDataStore(); if (secureSupported) { //doThingsFuture } } /// /// Set secret for item in the CrestronSecretsProvider /// /// Secret Key /// Secret Value public bool SetSecret(string key, object value) { var secret = value as string; CrestronDataStore.CDS_ERROR returnCode; if (String.IsNullOrEmpty(secret)) { returnCode = CrestronDataStoreStatic.clearGlobal(key); if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) { Debug.LogMessage(LogEventLevel.Information, this, "Successfully removed secret \"{0}\"", secret); return true; } } else { returnCode = CrestronDataStoreStatic.SetGlobalStringValue(key, secret); if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) { Debug.LogMessage(LogEventLevel.Information, this, "Successfully set secret \"{0}\"", secret); return true; } } Debug.LogMessage(LogEventLevel.Information, this, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString()); return false; } /// /// Retrieve secret for item in the CrestronSecretsProvider /// /// Secret Key /// ISecret Object containing key, provider, and value public ISecret GetSecret(string key) { string mySecret; var getErrorCode = CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret); switch (getErrorCode) { case CrestronDataStore.CDS_ERROR.CDS_SUCCESS: Debug.LogMessage(LogEventLevel.Verbose, this, "Secret Successfully retrieved for {0}:{1}", Key, key); return new CrestronSecret(key, mySecret, this); default: Debug.LogMessage(LogEventLevel.Information, this, "Unable to retrieve secret for {0}:{1} - {2}", Key, key, getErrorCode.ToString()); return null; } } /// /// Determine if a secret is present within the provider without retrieving it /// /// Secret Key /// bool if present public bool TestSecret(string key) { string mySecret; return CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Secrets/CrestronLocalSecretsProvider.cs ================================================ using System; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronDataStore; using PepperDash.Core; using Crestron.SimplSharpPro; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Represents a CrestronLocalSecretsProvider /// public class CrestronLocalSecretsProvider : ISecretProvider { /// /// Gets or sets the Key /// public string Key { get; set; } //Added for reference /// /// Gets or sets the Description /// public string Description { get; private set; } /// /// Constructor for CrestronLocalSecretsProvider /// /// The key for the secret provider public CrestronLocalSecretsProvider(string key) { Key = key; Description = String.Format("Default secret provider serving Essentials Application {0}", InitialParametersClass.ApplicationNumber); } static CrestronLocalSecretsProvider() { //Added for future encrypted reference var secureSupported = CrestronSecureStorage.Supported; CrestronDataStoreStatic.InitCrestronDataStore(); if (secureSupported) { //doThingsFuture } } /// /// Set secret for item in the CrestronSecretsProvider /// /// Secret Key /// Secret Value public bool SetSecret(string key, object value) { var secret = value as string; CrestronDataStore.CDS_ERROR returnCode; if (String.IsNullOrEmpty(secret)) { returnCode = CrestronDataStoreStatic.clearLocal(key); if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) { Debug.LogMessage(LogEventLevel.Information, this, "Successfully removed secret \"{0}\"", secret); return true; } } else { returnCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret); if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS) { Debug.LogMessage(LogEventLevel.Information, this, "Successfully set secret \"{0}\"", secret); return true; } } Debug.LogMessage(LogEventLevel.Information, this, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString()); return false; } /// /// Retrieve secret for item in the CrestronSecretsProvider /// /// Secret Key /// ISecret Object containing key, provider, and value /// /// GetSecret method /// public ISecret GetSecret(string key) { string mySecret; var getErrorCode = CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret); switch (getErrorCode) { case CrestronDataStore.CDS_ERROR.CDS_SUCCESS: Debug.LogMessage(LogEventLevel.Verbose, this, "Secret Successfully retrieved for {0}:{1}", Key, key); return new CrestronSecret(key, mySecret, this); default: Debug.LogMessage(LogEventLevel.Information, this, "Unable to retrieve secret for {0}:{1} - {2}", Key, key, getErrorCode.ToString()); return null; } } /// /// Determine if a secret is present within the provider without retrieving it /// /// Secret Key /// bool if present /// /// TestSecret method /// public bool TestSecret(string key) { string mySecret; return CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Secrets/CrestronSecret.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core { /// /// Special container class for CrestronSecret provider /// public class CrestronSecret : ISecret { /// /// Gets the Provider /// public ISecretProvider Provider { get; private set; } /// /// Gets the Key /// public string Key { get; private set; } /// /// Gets the Value /// public object Value { get; private set; } /// /// Constructor for CrestronSecret /// /// key for the secret /// value of the secret /// provider of the secret public CrestronSecret(string key, string value, ISecretProvider provider) { Key = key; Value = value; Provider = provider; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Secrets/Interfaces.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Defines the contract for ISecretProvider /// public interface ISecretProvider : IKeyed { /// /// Set secret value for provider by key /// /// key of secret to set /// value to set secret to /// bool SetSecret(string key, object value); /// /// Return object containing secret from provider /// /// key of secret to retrieve /// ISecret GetSecret(string key); /// /// Verifies presence of secret /// /// key of secret to chek /// bool TestSecret(string key); /// /// Description of the secrets provider /// string Description { get; } } /// /// interface for delivering secrets in Essentials. /// public interface ISecret { /// /// Instance of ISecretProvider that the secret belongs to /// ISecretProvider Provider { get; } /// /// Key of the secret in the provider /// string Key { get; } /// /// Value of the secret /// object Value { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Secrets/SecretsManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// SecretsManager static class /// public static class SecretsManager { /// /// Gets the Secrets dictionary /// public static Dictionary Secrets { get; private set; } /// /// Initialize method /// public static void Initialize() { AddSecretProvider("default", new CrestronLocalSecretsProvider("default")); AddSecretProvider("CrestronGlobalSecrets", new CrestronGlobalSecretsProvider("CrestronGlobalSecrets")); CrestronConsole.AddNewConsoleCommand(SetSecretProcess, "setsecret", "Adds secret to secrets provider", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(UpdateSecretProcess, "updatesecret", "Updates secret in secrets provider", ConsoleAccessLevelEnum.AccessAdministrator); CrestronConsole.AddNewConsoleCommand(DeleteSecretProcess, "deletesecret", "Deletes secret from secrest provider", ConsoleAccessLevelEnum.AccessAdministrator); CrestronConsole.AddNewConsoleCommand(ListProviders, "secretproviderlist", "Return list of all valid secrets providers", ConsoleAccessLevelEnum.AccessAdministrator); CrestronConsole.AddNewConsoleCommand(GetProviderInfo, "secretproviderinfo", "Return data about secrets provider", ConsoleAccessLevelEnum.AccessAdministrator); } static SecretsManager() { Secrets = new Dictionary(); } /// /// Get Secret Provider from dictionary by key /// /// Dictionary Key for provider /// ISecretProvider /// /// GetSecretProviderByKey method /// public static ISecretProvider GetSecretProviderByKey(string key) { ISecretProvider secret; Secrets.TryGetValue(key, out secret); if (secret == null) { Debug.LogMessage(LogEventLevel.Debug, "SecretsManager unable to retrieve SecretProvider with the key '{0}'", key); } return secret; } /// /// GetProviderInfo method /// public static void GetProviderInfo(string cmd) { string response; var args = cmd.Split(' '); if (cmd.Length == 0 || (args.Length == 1 && args[0] == "?")) { response = "Returns data about secrets provider. Format 'secretproviderinfo '"; CrestronConsole.ConsoleCommandResponse(response); return; } if (args.Length == 1) { var provider = GetSecretProviderByKey(args[0]); if (provider == null) { response = "Invalid secrets provider key"; CrestronConsole.ConsoleCommandResponse(response); return; } response = String.Format("{0} : {1}", provider.Key, provider.Description); CrestronConsole.ConsoleCommandResponse(response); return; } response = "Improper number of arguments"; CrestronConsole.ConsoleCommandResponse(response); } /// /// Console Command that returns all valid secrets in the essentials program. /// /// /// /// ListProviders method /// public static void ListProviders(string cmd) { var response = String.Empty; var args = cmd.Split(' '); if (cmd.Length == 0) { if (Secrets != null && Secrets.Count > 0) { response = Secrets.Aggregate(response, (current, secretProvider) => current + (secretProvider.Key + "\n\r")); } else { response = "No Secrets Providers Available"; } CrestronConsole.ConsoleCommandResponse(response); return; } if (args.Length == 1 && args[0] == "?") { response = "Reports all valid and preset Secret providers"; CrestronConsole.ConsoleCommandResponse(response); return; } response = "Improper number of arguments"; CrestronConsole.ConsoleCommandResponse(response); } /// /// Add secret provider to secrets dictionary /// /// Key of new entry /// New Provider Entry /// /// AddSecretProvider method /// public static void AddSecretProvider(string key, ISecretProvider provider) { if (!Secrets.ContainsKey(key)) { Secrets.Add(key, provider); Debug.LogMessage(LogEventLevel.Debug, "Secrets provider '{0}' added to SecretsManager", key); return; } Debug.LogMessage(LogEventLevel.Information, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key ); } /// /// Add secret provider to secrets dictionary, with optional overwrite parameter /// /// Key of new entry /// New provider entry /// true to overwrite any existing providers in the dictionary /// /// AddSecretProvider method /// public static void AddSecretProvider(string key, ISecretProvider provider, bool overwrite) { if (!Secrets.ContainsKey(key)) { Secrets.Add(key, provider); Debug.LogMessage(LogEventLevel.Debug, "Secrets provider '{0}' added to SecretsManager", key); return; } if (overwrite) { Secrets.Add(key, provider); Debug.LogMessage(LogEventLevel.Debug, "Provider with the key '{0}' already exists in secrets. Overwriting with new secrets provider.", key); return; } Debug.LogMessage(LogEventLevel.Information, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key); } private static void SetSecretProcess(string cmd) { string response; var args = cmd.Split(' '); if (args.Length == 0) { //some Instructional Text response = "Adds secrets to secret provider. Format 'setsecret '"; CrestronConsole.ConsoleCommandResponse(response); return; } if (args.Length == 1 && args[0] == "?") { response = "Adds secrets to secret provider. Format 'setsecret '"; CrestronConsole.ConsoleCommandResponse(response); return; } if (args.Length < 3) { response = "Improper number of arguments"; CrestronConsole.ConsoleCommandResponse(response); return; } var provider = GetSecretProviderByKey(args[0]); if (provider == null) { //someFail response = "Provider key invalid"; CrestronConsole.ConsoleCommandResponse(response); return; } var key = args[1]; var secret = args[2]; CrestronConsole.ConsoleCommandResponse(SetSecret(provider, key, secret)); } private static void UpdateSecretProcess(string cmd) { string response; var args = cmd.Split(' '); if (args.Length == 0) { //some Instructional Text response = "Updates secrets in secret provider. Format 'updatesecret '"; CrestronConsole.ConsoleCommandResponse(response); return; } if (args.Length == 1 && args[0] == "?") { response = "Updates secrets in secret provider. Format 'updatesecret '"; CrestronConsole.ConsoleCommandResponse(response); return; } if (args.Length < 3) { //someFail response = "Improper number of arguments"; CrestronConsole.ConsoleCommandResponse(response); return; } var provider = GetSecretProviderByKey(args[0]); if (provider == null) { //someFail response = "Provider key invalid"; CrestronConsole.ConsoleCommandResponse(response); return; } var key = args[1]; var secret = args[2]; CrestronConsole.ConsoleCommandResponse(UpdateSecret(provider, key, secret)); } private static string UpdateSecret(ISecretProvider provider, string key, string secret) { var secretPresent = provider.TestSecret(key); Debug.LogMessage(LogEventLevel.Verbose, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key); if (!secretPresent) return String.Format( "Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to modify it"); var response = provider.SetSecret(key, secret) ? String.Format( "Secret successfully set for {0}:{1}", provider.Key, key) : String.Format( "Unable to set secret for {0}:{1}", provider.Key, key); return response; } private static string SetSecret(ISecretProvider provider, string key, string secret) { var secretPresent = provider.TestSecret(key); Debug.LogMessage(LogEventLevel.Verbose, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key); if (secretPresent) return String.Format( "Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it"); var response = provider.SetSecret(key, secret) ? String.Format( "Secret successfully set for {0}:{1}", provider.Key, key) : String.Format( "Unable to set secret for {0}:{1}", provider.Key, key); return response; } private static void DeleteSecretProcess(string cmd) { string response; var args = cmd.Split(' '); if (args.Length == 0) { //some Instructional Text response = "Deletes secrets in secret provider. Format 'deletesecret '"; CrestronConsole.ConsoleCommandResponse(response); return; } if (args.Length == 1 && args[0] == "?") { response = "Deletes secrets in secret provider. Format 'deletesecret '"; CrestronConsole.ConsoleCommandResponse(response); return; } if (args.Length < 2) { //someFail response = "Improper number of arguments"; CrestronConsole.ConsoleCommandResponse(response); return; } var provider = GetSecretProviderByKey(args[0]); if (provider == null) { //someFail response = "Provider key invalid"; CrestronConsole.ConsoleCommandResponse(response); return; } var key = args[1]; provider.SetSecret(key, ""); response = provider.SetSecret(key, "") ? String.Format( "Secret successfully deleted for {0}:{1}", provider.Key, key) : String.Format( "Unable to delete secret for {0}:{1}", provider.Key, key); CrestronConsole.ConsoleCommandResponse(response); return; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Secrets/SecretsPropertiesConfig.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Newtonsoft.Json; namespace PepperDash.Essentials.Core { /// /// Provide a way to easily deserialize into a secret object from config /// public class SecretsPropertiesConfig { /// /// Gets or sets the Provider /// [JsonProperty("provider")] public string Provider { get; set; } /// /// Gets or sets the Key /// [JsonProperty("key")] public string Key { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Shades/Shade Interfaces.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Core.Shades { /// /// Defines the contract for IShades /// public interface IShades { /// /// List of shades controlled by this device /// List Shades { get; } } /// /// Requirements for a device that implements basic Open/Close/Stop shade control (Uses 3 relays) /// public interface IShadesOpenCloseStop { /// /// Opens the shade /// void Open(); /// /// Closes the shade /// void Close(); /// /// Stops the shade /// void Stop(); } /// /// Requirements for a device that implements Open/Close/Stop shade control with presets /// public interface IShadesOpenClosePreset : IShadesOpenCloseStop { /// /// Recalls the preset /// /// preset number to recall void RecallPreset(uint presetNumber); /// /// Saves the preset /// /// preset number to save void SavePreset(uint presetNumber); /// /// Label for the preset button /// string StopOrPresetButtonLabel { get; } /// /// Event raised when a preset is recalled /// event EventHandler PresetSaved; } /// /// Defines the contract for IShadesRaiseLowerFeedback /// public interface IShadesRaiseLowerFeedback { /// /// Feedback to indicate if the shade is lowering /// BoolFeedback ShadeIsLoweringFeedback { get; } /// /// Feedback to indicate if the shade is raising /// BoolFeedback ShadeIsRaisingFeedback { get; } } /// /// Requirements for a shade/scene that is open or closed /// public interface IShadesOpenClosedFeedback: IShadesOpenCloseStop { /// /// Feedback to indicate if the shade is open /// BoolFeedback ShadeIsOpenFeedback { get; } /// /// Feedback to indicate if the shade is closed /// BoolFeedback ShadeIsClosedFeedback { get; } } /// /// Used to implement raise/stop/lower/stop from single button /// public interface IShadesStopOrMove { /// /// Raises the shade or stops it if it's already moving /// void OpenOrStop(); /// /// Lowers the shade or stops it if it's already moving /// void CloseOrStop(); /// /// Opens, closes, or stops the shade depending on current state /// void OpenCloseOrStop(); } /// /// Defines the contract for IShadesStopFeedback /// public interface IShadesStopFeedback : IShadesOpenCloseStop { /// /// Feedback to indicate if the shade is stopped /// BoolFeedback IsStoppedFeedback { get; } } /// /// Requirements for position /// public interface IShadesPosition { /// /// Gets the current position of the shade /// /// value of the position to set void SetPosition(ushort value); } /// /// Basic feedback for shades position /// public interface IShadesFeedback: IShadesPosition, IShadesStopFeedback { /// /// Feedback to indicate the current position of the shade /// IntFeedback PositionFeedback { get; } } /// /// Feedback for scenes /// public interface ISceneFeedback { /// /// Runs the scene /// void Run(); /// /// Feedback to indicate if all shades are at the scene position /// BoolFeedback AllAreAtSceneFeedback { get; } } /// /// Combines basic shade interfaces for Crestron Basic shades /// public interface ICrestronBasicShade : IShadesOpenClosedFeedback, IShadesStopOrMove, IShadesFeedback, IShadesRaiseLowerFeedback { } } ================================================ FILE: src/PepperDash.Essentials.Core/Shades/ShadeBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; namespace PepperDash.Essentials.Core.Shades { /// /// Base class for shades /// [Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")] public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop { /// /// Constructor /// /// key of the shade device /// name of the shade device public ShadeBase(string key, string name) : base(key, name) { } #region iShadesOpenClose Members /// /// Opens the shade /// public abstract void Open(); /// /// Stops the shade /// public abstract void Stop(); /// /// Closes the shade /// public abstract void Close(); #endregion } } ================================================ FILE: src/PepperDash.Essentials.Core/SigHelper.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using PepperDash.Core; namespace PepperDash.Essentials.Core { /// /// Helper class for various Sig events /// public class SigHelper { /// /// Runs action when Sig is pressed /// /// signal pressed /// action to run public static void Pressed(Sig sig, Action act) { if (sig.BoolValue) act(); } /// /// Runs action when Sig is released /// public static void Released(Sig sig, Action act) { if (!sig.BoolValue) act(); } /// /// SetBoolOutAction method /// public static void SetBoolOutAction(BoolOutputSig sig, Action a) { if (sig != null) sig.UserObject = a; } /// /// Safely clears action of non-null sig. /// public static void ClearBoolOutAction(BoolOutputSig sig) { if (sig != null) sig.UserObject = null; } /// /// Does a timed ramp, where the time is scaled proportional to the /// remaining range to cover /// /// Ushort sig to scale /// Level to go to /// In ms (not hundredths like Crestron Sig ramp function) /// /// RampTimeScaled method /// public static void RampTimeScaled(Sig sig, ushort newLevel, uint time) { ushort level = sig.UShortValue; int diff = Math.Abs(level - newLevel); uint scaledTime = (uint)(diff * time / 65535); Ramp(sig, newLevel, scaledTime); } /// /// Ramps signal /// /// /// /// In ms (not hundredths like Crestron Sig ramp function) /// /// Ramp method /// public static void Ramp(Sig sig, ushort level, uint time) { sig.CreateRamp(level, time / 10); } } } ================================================ FILE: src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDPad.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core.SmartObjects { /// /// Represents a SmartObjectDPad /// public class SmartObjectDPad : SmartObjectHelperBase { /// /// Gets or sets the SigUp /// public BoolOutputSig SigUp { get { return GetBoolOutputNamed("Up"); } } /// /// Gets or sets the SigDown /// public BoolOutputSig SigDown { get { return GetBoolOutputNamed("Down"); } } /// /// Gets or sets the SigLeft /// public BoolOutputSig SigLeft { get { return GetBoolOutputNamed("Left"); } } /// /// Gets or sets the SigRight /// public BoolOutputSig SigRight { get { return GetBoolOutputNamed("Right"); } } /// /// Gets or sets the SigCenter /// public BoolOutputSig SigCenter { get { return GetBoolOutputNamed("Center"); } } /// /// Constructor /// /// smart object /// use user object handler if true public SmartObjectDPad(SmartObject so, bool useUserObjectHandler) : base(so, useUserObjectHandler) { } } } ================================================ FILE: src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs ================================================ 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 Serilog.Events; namespace PepperDash.Essentials.Core.SmartObjects { /// /// Represents a SmartObjectDynamicList /// public class SmartObjectDynamicList : SmartObjectHelperBase { /// /// Sig name for Scroll To Item /// public const string SigNameScrollToItem = "Scroll To Item"; /// /// Sig name for Set Number of Items /// public const string SigNameSetNumberOfItems = "Set Number of Items"; /// /// Gets or sets the NameSigOffset /// public uint NameSigOffset { get; private set; } /// /// Gets or sets the Count /// public ushort Count { get { return SmartObject.UShortInput[SigNameSetNumberOfItems].UShortValue; } set { SmartObject.UShortInput[SigNameSetNumberOfItems].UShortValue = value; } } /// /// Gets or sets the MaxCount /// public int MaxCount { get; private set; } /// /// Wrapper for smart object /// /// /// True if the standard user object action handler will be used /// The starting join of the string sigs for the button labels public SmartObjectDynamicList(SmartObject so, bool useUserObjectHandler, uint nameSigOffset) : base(so, useUserObjectHandler) { try { // Just try to touch the count signal to make sure this is indeed a dynamic list var c = Count; NameSigOffset = nameSigOffset; MaxCount = SmartObject.BooleanOutput.Count(s => s.Name.EndsWith("Pressed")); //Debug.LogMessage(LogEventLevel.Verbose, "Smart object {0} has {1} max", so.ID, MaxCount); } catch { var msg = string.Format("SmartObjectDynamicList: Smart Object {0:X2}-{1} is not a dynamic list. Ignoring", so.Device.ID, so.ID); Debug.LogMessage(LogEventLevel.Information, msg); } } /// /// SetItem method /// public void SetItem(uint index, string mainText, string iconName, Action action) { SetItemMainText(index, mainText); SetItemIcon(index, iconName); SetItemButtonAction(index, action); //try //{ // SetMainButtonText(index, text); // SetIcon(index, iconName); // SetButtonAction(index, action); //} //catch(Exception e) //{ // Debug.LogMessage(LogEventLevel.Debug, "Cannot set Dynamic List item {0} on smart object {1}", index, SmartObject.ID); // ErrorLog.Warn(e.ToString()); //} } /// /// SetItemMainText method /// public void SetItemMainText(uint index, string text) { if (index > MaxCount) return; // The list item template defines CIPS tags that refer to standard joins (SmartObject.Device as BasicTriList).StringInput[NameSigOffset + index].StringValue = text; } /// /// SetItemIcon method /// public void SetItemIcon(uint index, string iconName) { if (index > MaxCount) return; SmartObject.StringInput[string.Format("Set Item {0} Icon Serial", index)].StringValue = iconName; } /// /// SetItemButtonAction method /// public void SetItemButtonAction(uint index, Action action) { if (index > MaxCount) return; SmartObject.BooleanOutput[string.Format("Item {0} Pressed", index)].UserObject = action; } /// /// SetFeedback method /// public void SetFeedback(uint index, bool interlocked) { if (interlocked) ClearFeedbacks(); SmartObject.BooleanInput[string.Format("Item {0} Selected", index)].BoolValue = true; } /// /// ClearFeedbacks method /// public void ClearFeedbacks() { for(int i = 1; i<= Count; i++) SmartObject.BooleanInput[string.Format("Item {0} Selected", i)].BoolValue = false; } /// /// Removes Action object from all buttons /// public void ClearActions() { Debug.LogMessage(LogEventLevel.Verbose, "SO CLEAR"); for(ushort i = 1; i <= MaxCount; i++) SmartObject.BooleanOutput[string.Format("Item {0} Pressed", i)].UserObject = null; } } } ================================================ FILE: src/PepperDash.Essentials.Core/SmartObjects/SmartObjectHelperBase.cs ================================================ 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 Serilog.Events; namespace PepperDash.Essentials.Core.SmartObjects { /// /// Represents a SmartObjectHelperBase /// public class SmartObjectHelperBase { /// /// Gets or sets the SmartObject /// public SmartObject SmartObject { get; private set; } /// /// Gets or sets the Validated /// public bool Validated { get; protected set; } /// /// Constructor /// /// smart object /// use the user object hadnler if true public SmartObjectHelperBase(SmartObject so, bool useUserObjectHandler) { SmartObject = so; if (useUserObjectHandler) { // Prevent this from double-registering SmartObject.SigChange -= this.SmartObject_SigChange; SmartObject.SigChange += this.SmartObject_SigChange; } } /// /// Destructor /// ~SmartObjectHelperBase() { SmartObject.SigChange -= this.SmartObject_SigChange; } /// /// Helper to get a sig name with debugging when fail /// /// /// public BoolOutputSig GetBoolOutputNamed(string name) { if (SmartObject.BooleanOutput.Contains(name)) return SmartObject.BooleanOutput[name]; else Debug.LogMessage(LogEventLevel.Information, "WARNING: Cannot get signal. Smart object {0} on trilist {1:x2} does not contain signal '{2}'", SmartObject.ID, SmartObject.Device.ID, name); return null; } /// /// Sets action on signal after checking for existence. /// /// /// /// /// SetBoolAction method /// public void SetBoolAction(string name, Action a) { if (SmartObject.BooleanOutput.Contains(name)) SmartObject.BooleanOutput[name].UserObject = a; else { Debug.LogMessage(LogEventLevel.Information, "WARNING: Cannot set action. Smart object {0} on trilist {1:x2} does not contain signal '{2}'", SmartObject.ID, SmartObject.Device.ID, name); } } /// /// Standard Action listener /// /// /// void SmartObject_SigChange(GenericBase currentDevice, SmartObjectEventArgs args) { var uo = args.Sig.UserObject; if (uo is Action) (uo as Action)(args.Sig.BoolValue); else if (uo is Action) (uo as Action)(args.Sig.UShortValue); else if (uo is Action) (uo as Action)(args.Sig.StringValue); } } } ================================================ FILE: src/PepperDash.Essentials.Core/SmartObjects/SmartObjectNumeric.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core.SmartObjects { /// /// Represents a SmartObjectNumeric /// public class SmartObjectNumeric : SmartObjectHelperBase { /// /// Gets or sets the Misc1SigName /// public string Misc1SigName { get; set; } /// /// Gets or sets the Misc2SigName /// public string Misc2SigName { get; set; } /// /// Gets or sets the Digit1 /// public BoolOutputSig Digit1 { get { return GetBoolOutputNamed("1"); } } /// /// Gets or sets the Digit2 /// public BoolOutputSig Digit2 { get { return GetBoolOutputNamed("2"); } } /// /// Gets or sets the Digit3 /// public BoolOutputSig Digit3 { get { return GetBoolOutputNamed("3"); } } /// /// Gets or sets the Digit4 /// public BoolOutputSig Digit4 { get { return GetBoolOutputNamed("4"); } } /// /// Gets or sets the Digit5 /// public BoolOutputSig Digit5 { get { return GetBoolOutputNamed("5"); } } /// /// Gets or sets the Digit6 /// public BoolOutputSig Digit6 { get { return GetBoolOutputNamed("6"); } } /// /// Gets or sets the Digit7 /// public BoolOutputSig Digit7 { get { return GetBoolOutputNamed("7"); } } /// /// Gets or sets the Digit8 /// public BoolOutputSig Digit8 { get { return GetBoolOutputNamed("8"); } } /// /// Gets or sets the Digit9 /// public BoolOutputSig Digit9 { get { return GetBoolOutputNamed("9"); } } /// /// Gets or sets the Digit0 /// public BoolOutputSig Digit0 { get { return GetBoolOutputNamed("0"); } } /// /// Gets or sets the Misc1 /// public BoolOutputSig Misc1 { get { return GetBoolOutputNamed(Misc1SigName); } } /// /// Gets or sets the Misc2 /// public BoolOutputSig Misc2 { get { return GetBoolOutputNamed(Misc2SigName); } } /// /// Constructor /// /// smart object /// use user handler if true public SmartObjectNumeric(SmartObject so, bool useUserObjectHandler) : base(so, useUserObjectHandler) { Misc1SigName = "Misc_1"; Misc2SigName = "Misc_2"; } } } ================================================ FILE: src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SourceListSubpageReferenceList.cs ================================================  //using System; //using System.Collections.Generic; //using System.Linq; //using System.Text; //using Crestron.SimplSharp; //using Crestron.SimplSharpPro; //using Crestron.SimplSharpPro.DeviceSupport; //using Crestron.SimplSharpPro.UI; //using PepperDash.Core; //namespace PepperDash.Essentials.Core //{ // //***************************************************************************** // /// // /// Wrapper class for subpage reference list. Contains helpful methods to get at the various signal groupings // /// and to get individual signals using an index and a join. // /// // public class SourceListSubpageReferenceList : SubpageReferenceList // { // public const uint SmartObjectJoin = 3801; // Action SourceSelectCallback; // EssentialsRoom CurrentRoom; // public SourceListSubpageReferenceList(BasicTriListWithSmartObject tl, // Action sourceSelectCallback) // : base(tl, SmartObjectJoin, 3, 1, 3) // { // SourceSelectCallback = sourceSelectCallback; // } // void SetSourceList(Dictionary dict) // { // // Iterate all positions, including ones missing from the dict. // var max = dict.Keys.Max(); // for (uint i = 1; i <= max; i++) // { // // Add the source if it's in the dict // if (dict.ContainsKey(i)) // { // Items.Add(new SourceListSubpageReferenceListItem(i, dict[i], this, SourceSelectCallback)); // // Plug the callback function into the buttons // } // // Blank the line // else // Items.Add(new SourceListSubpageReferenceListItem(i, null, // this, SourceSelectCallback)); // } // Count = (ushort)max; // } // /// // /// Links the SRL to the Room's PresentationSourceChange event for updating of the UI // /// // /// // public void AttachToRoom(EssentialsRoom room) // { // CurrentRoom = room; // SetSourceList(room.Sources); // CurrentRoom.PresentationSourceChange -= CurrentRoom_PresentationSourceChange; // CurrentRoom.PresentationSourceChange += CurrentRoom_PresentationSourceChange; // SetPresentationSourceFb(CurrentRoom.CurrentPresentationSource); // } // /// // /// Disconnects the SRL from a Room's PresentationSourceChange // /// // public void DetachFromCurrentRoom() // { // ClearPresentationSourceFb(CurrentRoom.CurrentPresentationSource); // if(CurrentRoom != null) // CurrentRoom.PresentationSourceChange -= CurrentRoom_PresentationSourceChange; // CurrentRoom = null; // } // // Handler to route source changes into list feedback // void CurrentRoom_PresentationSourceChange(object sender, EssentialsRoomSourceChangeEventArgs args) // { // Debug.LogMessage(LogEventLevel.Verbose, "SRL received source change"); // ClearPresentationSourceFb(args.OldSource); // SetPresentationSourceFb(args.NewSource); // } // void ClearPresentationSourceFb(IPresentationSource source) // { // if (source == null) return; // var oldSourceItem = (SourceListSubpageReferenceListItem)Items.FirstOrDefault( // i => ((SourceListSubpageReferenceListItem)i).SourceDevice == source); // if (oldSourceItem != null) // oldSourceItem.ClearFeedback(); // } // void SetPresentationSourceFb(IPresentationSource source) // { // if (source == null) return; // // Now set the new source to light up // var newSourceItem = (SourceListSubpageReferenceListItem)Items.FirstOrDefault( // i => ((SourceListSubpageReferenceListItem)i).SourceDevice == source); // if (newSourceItem != null) // newSourceItem.SetFeedback(); // } // } // public class SourceListSubpageReferenceListItem : SubpageReferenceListItem // { // public readonly IPresentationSource SourceDevice; // public const uint ButtonPressJoin = 1; // public const uint SelectedFeedbackJoin = 2; // public const uint ButtonTextJoin = 1; // public const uint IconNameJoin = 2; // public SourceListSubpageReferenceListItem(uint index, // IPresentationSource srcDevice, SubpageReferenceList owner, Action sourceSelectCallback) // : base(index, owner) // { // if (srcDevice == null) throw new ArgumentNullException("srcDevice"); // if (owner == null) throw new ArgumentNullException("owner"); // if (sourceSelectCallback == null) throw new ArgumentNullException("sourceSelectCallback"); // SourceDevice = srcDevice; // var nameSig = owner.StringInputSig(index, ButtonTextJoin); // // Should be able to see if there is not enough buttons right here // if (nameSig == null) // { // Debug.LogMessage(LogEventLevel.Information, "ERROR: Item {0} does not exist on source list SRL", index); // return; // } // nameSig.StringValue = srcDevice.Name; // owner.StringInputSig(index, IconNameJoin).StringValue = srcDevice.IconName; // // Assign a source selection action to the appropriate button's UserObject - on release // owner.GetBoolFeedbackSig(index, ButtonPressJoin).UserObject = new Action(b => // { if (!b) sourceSelectCallback(index); }); // // hook up the video icon // var videoDev = srcDevice as IAttachVideoStatus; // if (videoDev != null) // { // var status = videoDev.GetVideoStatuses(); // if (status != null) // { // Debug.LogMessage(LogEventLevel.Debug, "Linking {0} video status to SRL", videoDev.Key); // videoDev.GetVideoStatuses().VideoSyncFeedback.LinkInputSig(owner.BoolInputSig(index, 3)); // } // } // } // public void SetFeedback() // { // Owner.BoolInputSig(Index, SelectedFeedbackJoin).BoolValue = true; // } // public void ClearFeedback() // { // Owner.BoolInputSig(Index, SelectedFeedbackJoin).BoolValue = false; // } // } //} ================================================ FILE: src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.UI; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { ////***************************************************************************** ///// ///// Base class for all subpage reference list controllers ///// //public class SubpageReferenceListController //{ // public SubpageReferenceList TheList { get; protected set; } //} //***************************************************************************** /// /// Wrapper class for subpage reference list. Contains helpful methods to get at the various signal groupings /// and to get individual signals using an index and a join. /// public class SubpageReferenceList { /// /// Gets or sets the Count /// public ushort Count { get { return SetNumberOfItemsSig.UShortValue; } set { SetNumberOfItemsSig.UShortValue = value; } } /// /// Gets or sets the MaxDefinedItems /// public ushort MaxDefinedItems { get; private set; } /// /// Gets or sets the ScrollToItemSig /// public UShortInputSig ScrollToItemSig { get; private set; } UShortInputSig SetNumberOfItemsSig; /// /// Gets or sets the BoolIncrement /// public uint BoolIncrement { get; protected set; } /// /// Gets or sets the UShortIncrement /// public uint UShortIncrement { get; protected set; } /// /// Gets or sets the StringIncrement /// public uint StringIncrement { get; protected set; } /// /// Gets or sets the SRL /// protected readonly SmartObject SRL; /// /// Gets the list of items in the SRL /// protected readonly List Items = new List(); /// /// Constructor /// /// trilist for the smart object /// smart object ID /// /// /// public SubpageReferenceList(BasicTriListWithSmartObject triList, uint smartObjectId, uint boolIncrement, uint ushortIncrement, uint stringIncrement) { SmartObject obj; // Fail cleanly if not defined if (triList.SmartObjects == null || triList.SmartObjects.Count == 0) { Debug.LogMessage(LogEventLevel.Information, "TriList {0:X2} Smart objects have not been loaded", triList.ID, smartObjectId); return; } if (triList.SmartObjects.TryGetValue(smartObjectId, out obj)) { SRL = triList.SmartObjects[smartObjectId]; ScrollToItemSig = SRL.UShortInput["Scroll To Item"]; SetNumberOfItemsSig = SRL.UShortInput["Set Number of Items"]; BoolIncrement = boolIncrement; UShortIncrement = ushortIncrement; StringIncrement = stringIncrement; // Count the enable lines to see what max items is MaxDefinedItems = (ushort)SRL.BooleanInput .Where(s => s.Name.Contains("Enable")).Count(); Debug.LogMessage(LogEventLevel.Verbose, "SRL {0} contains max {1} items", SRL.ID, MaxDefinedItems); SRL.SigChange -= new SmartObjectSigChangeEventHandler(SRL_SigChange); SRL.SigChange += new SmartObjectSigChangeEventHandler(SRL_SigChange); } else Debug.LogMessage(LogEventLevel.Information, "ERROR: TriList 0x{0:X2} Cannot load smart object {1}. Verify correct SGD file is loaded", triList.ID, smartObjectId); } /// /// Adds item to saved list of displayed items (not necessarily in order) /// DOES NOT adjust Count /// /// /// /// AddItem method /// public void AddItem(SubpageReferenceListItem item) { Items.Add(item); } /// /// Clear method /// public void Clear() { // If a line item needs to disconnect an CueActionPair or do something to release RAM foreach (var item in Items) item.Clear(); // Empty the list Items.Clear(); // Clean up the SRL Count = 1; ScrollToItemSig.UShortValue = 1; } /// /// Refresh method /// public void Refresh() { foreach (var item in Items) item.Refresh(); } // Helpers to get sigs by their weird SO names /// /// Returns the Sig associated with a given SRL line index /// and the join number of the object on the SRL subpage. /// Note: If the join number exceeds the increment range, or the count of Sigs on the /// list object, this will return null /// /// The line or item position on the SRL /// The join number of the item on the SRL subpage /// A Sig or null if the numbers are out of range public BoolOutputSig GetBoolFeedbackSig(uint index, uint sigNum) { if (sigNum > BoolIncrement) return null; return SRL.BooleanOutput.FirstOrDefault(s => s.Name.Equals(GetBoolFeedbackSigName(index, sigNum))); } /// /// Returns the Sig associated with a given SRL line index /// and the join number of the object on the SRL subpage. /// Note: If the join number exceeds the increment range, or the count of Sigs on the /// list object, this will return null /// /// The line or item position on the SRL /// The join number of the item on the SRL subpage /// A Sig or null if the numbers are out of range public UShortOutputSig GetUShortOutputSig(uint index, uint sigNum) { if (sigNum > UShortIncrement) return null; return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetUShortOutputSigName(index, sigNum))); } /// /// Returns the Sig associated with a given SRL line index /// and the join number of the object on the SRL subpage. /// Note: If the join number exceeds the increment range, or the count of Sigs on the /// list object, this will return null /// /// The line or item position on the SRL /// The join number of the item on the SRL subpage /// A Sig or null if the numbers are out of range public StringOutputSig GetStringOutputSig(uint index, uint sigNum) { if (sigNum > StringIncrement) return null; return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetStringOutputSigName(index, sigNum))); } /// /// Returns the Sig associated with a given SRL line index /// and the join number of the object on the SRL subpage. /// Note: If the join number exceeds the increment range, or the count of Sigs on the /// list object, this will return null /// /// The line on the SRL /// The join number of the item on the SRL subpage /// A Sig or null if the numbers are out of range public BoolInputSig BoolInputSig(uint index, uint sigNum) { if (sigNum > BoolIncrement) return null; return SRL.BooleanInput.FirstOrDefault(s => s.Name.Equals(GetBoolInputSigName(index, sigNum))); } /// /// Returns the Sig associated with a given SRL line index /// and the join number of the object on the SRL subpage. /// Note: If the join number exceeds the increment range, or the count of Sigs on the /// list object, this will return null /// /// The line on the SRL /// The join number of the item on the SRL subpage /// A Sig or null if the numbers are out of range public UShortInputSig UShortInputSig(uint index, uint sigNum) { if (sigNum > UShortIncrement) return null; return SRL.UShortInput.FirstOrDefault(s => s.Name.Equals(GetUShortInputSigName(index, sigNum))); } /// /// Returns the Sig associated with a given SRL line index /// and the join number of the object on the SRL subpage. /// Note: If the join number exceeds the increment range, or the count of Sigs on the /// list object, this will return null /// /// The line on the SRL /// The join number of the item on the SRL subpage /// A Sig or null if the numbers are out of range public StringInputSig StringInputSig(uint index, uint sigNum) { if (sigNum > StringIncrement) return null; return SRL.StringInput.FirstOrDefault(s => s.Name.Equals(GetStringInputSigName(index, sigNum))); } // Helpers to get signal names string GetBoolFeedbackSigName(uint index, uint sigNum) { var num = (index - 1) * BoolIncrement + sigNum; return String.Format("press{0}", num); } string GetUShortOutputSigName(uint index, uint sigNum) { var num = (index - 1) * UShortIncrement + sigNum; return String.Format("an_act{0}", num); } string GetStringOutputSigName(uint index, uint sigNum) { var num = (index - 1) * StringIncrement + sigNum; return String.Format("text-i{0}", num); } string GetBoolInputSigName(uint index, uint sigNum) { var num = (index - 1) * BoolIncrement + sigNum; return String.Format("fb{0}", num); } string GetUShortInputSigName(uint index, uint sigNum) { var num = (index - 1) * UShortIncrement + sigNum; return String.Format("an_fb{0}", num); } string GetStringInputSigName(uint index, uint sigNum) { var num = (index - 1) * StringIncrement + sigNum; return String.Format("text-o{0}", num); } /// /// Stock SigChange handler /// /// /// /// /// SRL_SigChange method /// public static void SRL_SigChange(GenericBase currentDevice, SmartObjectEventArgs args) { var uo = args.Sig.UserObject; if (uo is Action) (uo as Action)(args.Sig.BoolValue); else if (uo is Action) (uo as Action)(args.Sig.UShortValue); else if (uo is Action) (uo as Action)(args.Sig.StringValue); } } } ================================================ FILE: src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceListItem.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.UI; namespace PepperDash.Essentials.Core { /// /// Represents a SubpageReferenceListItem /// public class SubpageReferenceListItem { /// /// The list that this lives in /// protected SubpageReferenceList Owner; /// /// The index of this item /// protected uint Index; /// /// Constructor /// /// index of the item /// owner of the item public SubpageReferenceListItem(uint index, SubpageReferenceList owner) { Index = index; Owner = owner; } /// /// Clear method /// /// public virtual void Clear() { } /// /// Refresh method /// public virtual void Refresh() { } } } ================================================ FILE: src/PepperDash.Essentials.Core/Timers/CountdownTimer.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Represents a SecondsCountdownTimer /// public class SecondsCountdownTimer: IKeyed { /// /// Event fired when the timer starts /// public event EventHandler HasStarted; /// /// Event fired when the timer finishes /// public event EventHandler HasFinished; /// /// Event fired when the timer is cancelled /// public event EventHandler WasCancelled; /// /// Gets or sets the Key /// public string Key { get; private set; } /// /// Gets or sets the IsRunningFeedback /// public BoolFeedback IsRunningFeedback { get; private set; } bool _isRunning; /// /// Gets or sets the PercentFeedback /// public IntFeedback PercentFeedback { get; private set; } /// /// Gets or sets the TimeRemainingFeedback /// public StringFeedback TimeRemainingFeedback { get; private set; } /// /// Gets or sets the SecondsRemainingFeedback /// public IntFeedback SecondsRemainingFeedback { get; private set; } /// /// Gets or sets the CountsDown /// public bool CountsDown { get; set; } /// /// Gets or sets the SecondsToCount /// public int SecondsToCount { get; set; } /// /// Gets or sets the StartTime /// public DateTime StartTime { get; private set; } /// /// Gets or sets the FinishTime /// public DateTime FinishTime { get; private set; } private CTimer _secondTimer; /// /// Constructor /// /// public SecondsCountdownTimer(string key) { Key = key; IsRunningFeedback = new BoolFeedback(() => _isRunning); TimeRemainingFeedback = new StringFeedback(() => { // Need to handle up and down here. var timeSpan = FinishTime - DateTime.Now; Debug.LogMessage(LogEventLevel.Verbose, "timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}", this, timeSpan.Minutes, timeSpan.Seconds, timeSpan.TotalSeconds); if (Math.Floor(timeSpan.TotalSeconds) < 60 && Math.Floor(timeSpan.TotalSeconds) >= 0) //ignore milliseconds { return String.Format("{0:00}", timeSpan.Seconds); } return Math.Floor(timeSpan.TotalSeconds) < 0 ? "00" : String.Format("{0:00}:{1:00}", timeSpan.Minutes, timeSpan.Seconds); }); SecondsRemainingFeedback = new IntFeedback(() => (int)(FinishTime - DateTime.Now).TotalSeconds); PercentFeedback = new IntFeedback( () => (int) (Math.Floor((FinishTime - DateTime.Now).TotalSeconds)/ Math.Floor((FinishTime - StartTime).TotalSeconds)*100)); } /// /// Start method /// public void Start() { if (_isRunning) return; StartTime = DateTime.Now; FinishTime = StartTime + TimeSpan.FromSeconds(SecondsToCount); if (_secondTimer != null) _secondTimer.Stop(); _secondTimer = new CTimer(SecondElapsedTimerCallback, null, 0, 1000); _isRunning = true; IsRunningFeedback.FireUpdate(); var handler = HasStarted; if (handler != null) handler(this, new EventArgs()); } /// /// Reset method /// public void Reset() { _isRunning = false; IsRunningFeedback.FireUpdate(); Start(); } /// /// Cancel method /// public void Cancel() { StopHelper(); var handler = WasCancelled; if (handler != null) handler(this, new EventArgs()); } /// /// Finish method /// public void Finish() { StopHelper(); var handler = HasFinished; if (handler != null) handler(this, new EventArgs()); } void StopHelper() { if (_secondTimer != null) { _secondTimer.Stop(); _secondTimer = null; } _isRunning = false; IsRunningFeedback.FireUpdate(); } void SecondElapsedTimerCallback(object o) { if (DateTime.Now >= FinishTime) { Finish(); return; } PercentFeedback.FireUpdate(); TimeRemainingFeedback.FireUpdate(); SecondsRemainingFeedback.FireUpdate(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Timers/RetriggerableTimer.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Serilog.Events; namespace PepperDash.Essentials.Core.Timers { /// /// A device that runs a retriggerable timer and can execute actions specified in config /// [Description("A retriggerable timer device")] public class RetriggerableTimer : EssentialsDevice { private RetriggerableTimerPropertiesConfig _propertiesConfig; private CTimer _timer; private long _timerIntervalMs; /// /// Constructor /// /// key of the timer /// configuration for the timer public RetriggerableTimer(string key, DeviceConfig config) : base(key, config.Name) { var props = config.Properties.ToObject(); _propertiesConfig = props; if (_propertiesConfig != null) { _timerIntervalMs = _propertiesConfig.TimerIntervalMs; } } /// /// CustomActivate method /// /// public override bool CustomActivate() { if (_propertiesConfig.StartTimerOnActivation) { StartTimer(); } return base.CustomActivate(); } private void CleanUpTimer() { if (_timer != null) { _timer.Stop(); _timer.Dispose(); } _timer = null; } /// /// StartTimer method /// public void StartTimer() { CleanUpTimer(); Debug.LogMessage(LogEventLevel.Information, this, "Starting Timer"); _timer = new CTimer(TimerElapsedCallback, GetActionFromConfig(eRetriggerableTimerEvents.Elapsed), _timerIntervalMs, _timerIntervalMs); } /// /// StopTimer method /// public void StopTimer() { Debug.LogMessage(LogEventLevel.Information, this, "Stopping Timer"); _timer.Stop(); ExecuteAction(GetActionFromConfig(eRetriggerableTimerEvents.Stopped)); } private DeviceActionWrapper GetActionFromConfig(eRetriggerableTimerEvents eventType) { var action = _propertiesConfig.Events[eRetriggerableTimerEvents.Elapsed]; if (action != null) return action; else return null; } /// /// Executes the Elapsed action from confing when the timer elapses /// /// action to be executed private void TimerElapsedCallback(object action) { Debug.LogMessage(LogEventLevel.Debug, this, "Timer Elapsed. Executing Action"); if (action == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Timer elapsed but unable to execute action. Action is null."); return; } var devAction = action as DeviceActionWrapper; if (devAction != null) ExecuteAction(devAction); else { Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to cast action as DeviceActionWrapper. Cannot Execute"); } } private void ExecuteAction(DeviceActionWrapper action) { if (action == null) return; try { DeviceJsonApi.DoDeviceAction(action); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, this, "Error Executing Action: {0}", e); } //finally // Not sure this is needed //{ // _Timer.Reset(0, _TimerIntervalMs); //} } } /// /// Configuration Properties for RetriggerableTimer /// public class RetriggerableTimerPropertiesConfig { /// /// Start the timer on device activation /// [JsonProperty("startTimerOnActivation")] public bool StartTimerOnActivation { get; set; } /// /// Timer interval in milliseconds /// [JsonProperty("timerIntervalMs")] public long TimerIntervalMs { get; set; } /// /// Events and their associated actions /// [JsonProperty("events")] public Dictionary Events { get; set; } /// /// Constructor /// public RetriggerableTimerPropertiesConfig() { Events = new Dictionary(); } } /// /// Enumeration of eRetriggerableTimerEvents values /// public enum eRetriggerableTimerEvents { /// /// Elapsed event /// Elapsed, /// /// Stopped event /// Stopped, } /// /// Factory class /// public class RetriggerableTimerFactory : EssentialsDeviceFactory { /// /// Constructor /// public RetriggerableTimerFactory() { TypeNames = new List() { "retriggerabletimer" }; } /// /// BuildDevice method /// /// device config /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new RetriggerableTimer Device"); return new RetriggerableTimer(dc.Key, dc); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Touchpanels/CrestronTouchpanelPropertiesConfig.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Core { /// /// Represents a CrestronTouchpanelPropertiesConfig /// public class CrestronTouchpanelPropertiesConfig { /// /// Gets or sets the ControlProperties /// [JsonProperty("control")] public EssentialsControlPropertiesConfig ControlProperties { get; set; } /// /// Gets or sets the IpId /// [JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)] public string IpId { get; set; } /// /// Gets or sets the DefaultRoomKey /// [JsonProperty("defaultRoomKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultRoomKey { get; set; } /// /// Gets or sets the RoomListKey /// [JsonProperty("roomListKey", NullValueHandling = NullValueHandling.Ignore)] public string RoomListKey { get; set; } /// /// Gets or sets the SgdFile /// [JsonProperty("sgdFile", NullValueHandling = NullValueHandling.Ignore)] public string SgdFile { get; set; } /// /// Gets or sets the ProjectName /// [JsonProperty("projectName", NullValueHandling = NullValueHandling.Ignore)] public string ProjectName { get; set; } /// /// Gets or sets the ShowVolumeGauge /// [JsonProperty("showVolumeGauge", NullValueHandling = NullValueHandling.Ignore)] public bool? ShowVolumeGauge { get; set; } /// /// Gets or sets the UsesSplashPage /// [JsonProperty("usesSplashPage", NullValueHandling = NullValueHandling.Ignore)] public bool? UsesSplashPage { get; set; } /// /// Gets or sets the ShowDate /// [JsonProperty("showDate", NullValueHandling = NullValueHandling.Ignore)] public bool? ShowDate { get; set; } /// /// Gets or sets the ShowTime /// [JsonProperty("showTime", NullValueHandling = NullValueHandling.Ignore)] public bool? ShowTime { get; set; } /// /// Gets or sets the Setup /// [JsonProperty("setup", NullValueHandling = NullValueHandling.Ignore)] public UiSetupPropertiesConfig Setup { get; set; } /// /// Gets or sets the HeaderStyle /// [JsonProperty("headerStyle", NullValueHandling = NullValueHandling.Ignore)] public string HeaderStyle { get; set; } /// /// Gets or sets the IncludeInFusionRoomHealth /// [JsonProperty("includeInFusionRoomHealth", NullValueHandling = NullValueHandling.Ignore)] public bool? IncludeInFusionRoomHealth { get; set; } /// /// Gets or sets the ScreenSaverTimeoutMin /// [JsonProperty("screenSaverTimeoutMin", NullValueHandling = NullValueHandling.Ignore)] public uint? ScreenSaverTimeoutMin { get; set; } /// /// Gets or sets the ScreenSaverMovePositionIntervalMs /// [JsonProperty("screenSaverMovePositionIntervalMs", NullValueHandling = NullValueHandling.Ignore)] public uint? ScreenSaverMovePositionIntervalMs { get; set; } /// /// The count of sources that will trigger the "additional" arrows to show on the SRL. /// Defaults to 5 /// [JsonProperty("sourcesOverflowCount", NullValueHandling = NullValueHandling.Ignore)] public int? SourcesOverflowCount { get; set; } /// /// Constructor /// public CrestronTouchpanelPropertiesConfig() : this(false) { } /// /// Constructor /// /// set values to default if true public CrestronTouchpanelPropertiesConfig(bool setDefaultValues = false) { if(!setDefaultValues) { return; } SourcesOverflowCount = 5; HeaderStyle = Habanero; // Default values ScreenSaverTimeoutMin = 5; ScreenSaverMovePositionIntervalMs = 15000; } /// /// "habanero" /// public const string Habanero = "habanero"; /// /// "verbose" /// public const string Verbose = "verbose"; } /// /// Represents a UiSetupPropertiesConfig /// public class UiSetupPropertiesConfig { /// /// Gets or sets the IsVisible /// [JsonProperty("isVisible", NullValueHandling = NullValueHandling.Ignore)] public bool IsVisible { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core { /// /// Defines the contract for IHasBasicTriListWithSmartObject /// public interface IHasBasicTriListWithSmartObject { /// /// Gets the Panel /// BasicTriListWithSmartObject Panel { get; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Touchpanels/Keyboards/HabaneroKeyboardController.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core.Touchpanels.Keyboards { /// /// Represents a HabaneroKeyboardController /// public class HabaneroKeyboardController { /// /// Single-key press events, rather than using a built-up text string on the OutputFeedback /// public event EventHandler KeyPress; /// /// Gets or sets the TriList /// public BasicTriList TriList { get; private set; } /// /// Gets or sets the OutputFeedback /// public StringFeedback OutputFeedback { get; private set; } /// /// Gets or sets the IsVisible /// public bool IsVisible { get; private set; } /// /// Gets or sets the DotComButtonString /// public string DotComButtonString { get; set; } /// /// Gets or sets the GoButtonText /// public string GoButtonText { get; set; } /// /// Gets or sets the SecondaryButtonText /// public string SecondaryButtonText { get; set; } /// /// Gets or sets the GoButtonVisible /// public bool GoButtonVisible { get; set; } /// /// Gets or sets the SecondaryButtonVisible /// public bool SecondaryButtonVisible { get; set; } int ShiftMode = 0; StringBuilder Output; /// /// Gets or sets the HideAction /// public Action HideAction { get; set; } CTimer BackspaceTimer; /// /// /// /// public HabaneroKeyboardController(BasicTriList trilist) { TriList = trilist; Output = new StringBuilder(); OutputFeedback = new StringFeedback(() => Output.ToString()); DotComButtonString = ".com"; } /// /// Show method /// public void Show() { if (IsVisible) return; TriList.SetSigTrueAction(ClosePressJoin, Hide); TriList.SetSigTrueAction(GoButtonPressJoin, () => OnKeyPress(KeyboardSpecialKey.GoButton)); TriList.SetSigTrueAction(SecondaryButtonPressJoin, () => OnKeyPress(KeyboardSpecialKey.SecondaryButton)); TriList.SetSigTrueAction(2921, () => Press(A(ShiftMode))); TriList.SetSigTrueAction(2922, () => Press(B(ShiftMode))); TriList.SetSigTrueAction(2923, () => Press(C(ShiftMode))); TriList.SetSigTrueAction(2924, () => Press(D(ShiftMode))); TriList.SetSigTrueAction(2925, () => Press(E(ShiftMode))); TriList.SetSigTrueAction(2926, () => Press(F(ShiftMode))); TriList.SetSigTrueAction(2927, () => Press(G(ShiftMode))); TriList.SetSigTrueAction(2928, () => Press(H(ShiftMode))); TriList.SetSigTrueAction(2929, () => Press(I(ShiftMode))); TriList.SetSigTrueAction(2930, () => Press(J(ShiftMode))); TriList.SetSigTrueAction(2931, () => Press(K(ShiftMode))); TriList.SetSigTrueAction(2932, () => Press(L(ShiftMode))); TriList.SetSigTrueAction(2933, () => Press(M(ShiftMode))); TriList.SetSigTrueAction(2934, () => Press(N(ShiftMode))); TriList.SetSigTrueAction(2935, () => Press(O(ShiftMode))); TriList.SetSigTrueAction(2936, () => Press(P(ShiftMode))); TriList.SetSigTrueAction(2937, () => Press(Q(ShiftMode))); TriList.SetSigTrueAction(2938, () => Press(R(ShiftMode))); TriList.SetSigTrueAction(2939, () => Press(S(ShiftMode))); TriList.SetSigTrueAction(2940, () => Press(T(ShiftMode))); TriList.SetSigTrueAction(2941, () => Press(U(ShiftMode))); TriList.SetSigTrueAction(2942, () => Press(V(ShiftMode))); TriList.SetSigTrueAction(2943, () => Press(W(ShiftMode))); TriList.SetSigTrueAction(2944, () => Press(X(ShiftMode))); TriList.SetSigTrueAction(2945, () => Press(Y(ShiftMode))); TriList.SetSigTrueAction(2946, () => Press(Z(ShiftMode))); TriList.SetSigTrueAction(2947, () => Press('.')); TriList.SetSigTrueAction(2948, () => Press('@')); TriList.SetSigTrueAction(2949, () => Press(' ')); TriList.SetSigHeldAction(2950, 500, StartBackspaceRepeat, StopBackspaceRepeat, Backspace); //TriList.SetSigTrueAction(2950, Backspace); TriList.SetSigTrueAction(2951, Shift); TriList.SetSigTrueAction(2952, NumShift); TriList.SetSigTrueAction(2953, Clear); TriList.SetSigTrueAction(2954, () => Press(DotComButtonString)); TriList.SetBool(GoButtonVisibleJoin, GoButtonVisible); TriList.SetString(GoButtonTextJoin, GoButtonText); TriList.SetBool(SecondaryButtonVisibleJoin, SecondaryButtonVisible); TriList.SetString(SecondaryButtonTextJoin, SecondaryButtonText); TriList.SetBool(KeyboardVisible, true); ShowKeys(); IsVisible = true; } /// /// Hide method /// public void Hide() { if (!IsVisible) return; for (uint i = 2901; i < 2970; i++) TriList.ClearBoolSigAction(i); // run attached actions if(HideAction != null) HideAction(); TriList.SetBool(KeyboardVisible, false); IsVisible = false; } /// /// /// /// /// /// Press method /// public void Press(char c) { OnKeyPress(c.ToString()); Output.Append(c); OutputFeedback.FireUpdate(); ResetShift(); } /// /// /// /// /// /// Press method /// public void Press(string s) { OnKeyPress(s); Output.Append(s); OutputFeedback.FireUpdate(); ResetShift(); } /// /// EnableGoButton method /// public void EnableGoButton() { TriList.SetBool(GoButtonEnableJoin, true); } /// /// /// public void DisableGoButton() { TriList.SetBool(GoButtonEnableJoin, false); } void ResetShift() { if (ShiftMode == 1) { ShiftMode = 0; ShowKeys(); } else if (ShiftMode == 3) { ShiftMode = 2; ShowKeys(); } } char A(int i) { return new char[] { 'a', 'A', '?', '?' }[i]; } char B(int i) { return new char[] { 'b', 'B', ':', ':' }[i]; } char C(int i) { return new char[] { 'c', 'C', '>', '>' }[i]; } char D(int i) { return new char[] { 'd', 'D', '_', '_' }[i]; } char E(int i) { return new char[] { 'e', 'E', '3', '#' }[i]; } char F(int i) { return new char[] { 'f', 'F', '=', '=' }[i]; } char G(int i) { return new char[] { 'g', 'G', '+', '+' }[i]; } char H(int i) { return new char[] { 'h', 'H', '[', '[' }[i]; } char I(int i) { return new char[] { 'i', 'I', '8', '*' }[i]; } char J(int i) { return new char[] { 'j', 'J', ']', ']' }[i]; } char K(int i) { return new char[] { 'k', 'K', '/', '/' }[i]; } char L(int i) { return new char[] { 'l', 'L', '\\', '\\' }[i]; } char M(int i) { return new char[] { 'm', 'M', '"', '"' }[i]; } char N(int i) { return new char[] { 'n', 'N', '\'', '\'' }[i]; } char O(int i) { return new char[] { 'o', 'O', '9', '(' }[i]; } char P(int i) { return new char[] { 'p', 'P', '0', ')' }[i]; } char Q(int i) { return new char[] { 'q', 'Q', '1', '!' }[i]; } char R(int i) { return new char[] { 'r', 'R', '4', '$' }[i]; } char S(int i) { return new char[] { 's', 'S', '-', '-' }[i]; } char T(int i) { return new char[] { 't', 'T', '5', '%' }[i]; } char U(int i) { return new char[] { 'u', 'U', '7', '&' }[i]; } char V(int i) { return new char[] { 'v', 'V', ';', ';' }[i]; } char W(int i) { return new char[] { 'w', 'W', '2', '@' }[i]; } char X(int i) { return new char[] { 'x', 'X', '<', '<' }[i]; } char Y(int i) { return new char[] { 'y', 'Y', '6', '^' }[i]; } char Z(int i) { return new char[] { 'z', 'Z', ',', ',' }[i]; } /// /// Does what it says /// void StartBackspaceRepeat() { if (BackspaceTimer == null) { BackspaceTimer = new CTimer(o => Backspace(), null, 0, 175); } } /// /// Does what it says /// void StopBackspaceRepeat() { if (BackspaceTimer != null) { BackspaceTimer.Stop(); BackspaceTimer = null; } } void Backspace() { OnKeyPress(KeyboardSpecialKey.Backspace); if (Output.Length > 0) { Output.Remove(Output.Length - 1, 1); OutputFeedback.FireUpdate(); } } void Clear() { OnKeyPress(KeyboardSpecialKey.Clear); Output.Remove(0, Output.Length); OutputFeedback.FireUpdate(); } /* When in mode 0 (lowercase): * shift button: up arrow 0 * numShift button: 123/#$@#$ 0 * * - shift --> mode 1 * - double-tap shift --> caps lock * - numShift --> mode 2 * * mode 1 (uppercase) * shift button: down arrow 1 * numShift button: 123/##$# 0 * * - shift --> mode 0 * - numShift --> mode 2 * * - Tapping any key will go back to mode 0 * * mode 2 (numbers-sym) * Shift button: #$#$#$ 2 * numShift: ABC 1 * * - shift --> mode 3 * - double-tap shift --> caps lock * - numShift --> mode 0 * * mode 3 (sym) * Shift button: 123 3 * numShift: ABC 1 * * - shift --> mode 2 * - numShift --> mode 0 * * - Tapping any key will go back to mode 2 */ void Shift() { if (ShiftMode == 0) ShiftMode = 1; else if (ShiftMode == 1) ShiftMode = 0; else if (ShiftMode == 2) ShiftMode = 3; else ShiftMode = 2; ShowKeys(); } void NumShift() { if (ShiftMode == 0 || ShiftMode == 1) ShiftMode = 2; else if (ShiftMode == 2 || ShiftMode == 3) ShiftMode = 0; ShowKeys(); } void ShowKeys() { TriList.SetString(2921, A(ShiftMode).ToString()); TriList.SetString(2922, B(ShiftMode).ToString()); TriList.SetString(2923, C(ShiftMode).ToString()); TriList.SetString(2924, D(ShiftMode).ToString()); TriList.SetString(2925, E(ShiftMode).ToString()); TriList.SetString(2926, F(ShiftMode).ToString()); TriList.SetString(2927, G(ShiftMode).ToString()); TriList.SetString(2928, H(ShiftMode).ToString()); TriList.SetString(2929, I(ShiftMode).ToString()); TriList.SetString(2930, J(ShiftMode).ToString()); TriList.SetString(2931, K(ShiftMode).ToString()); TriList.SetString(2932, L(ShiftMode).ToString()); TriList.SetString(2933, M(ShiftMode).ToString()); TriList.SetString(2934, N(ShiftMode).ToString()); TriList.SetString(2935, O(ShiftMode).ToString()); TriList.SetString(2936, P(ShiftMode).ToString()); TriList.SetString(2937, Q(ShiftMode).ToString()); TriList.SetString(2938, R(ShiftMode).ToString()); TriList.SetString(2939, S(ShiftMode).ToString()); TriList.SetString(2940, T(ShiftMode).ToString()); TriList.SetString(2941, U(ShiftMode).ToString()); TriList.SetString(2942, V(ShiftMode).ToString()); TriList.SetString(2943, W(ShiftMode).ToString()); TriList.SetString(2944, X(ShiftMode).ToString()); TriList.SetString(2945, Y(ShiftMode).ToString()); TriList.SetString(2946, Z(ShiftMode).ToString()); TriList.SetString(2954, DotComButtonString); TriList.SetUshort(2951, (ushort)ShiftMode); // 0 = up, 1 = down, 2 = #, 3 = 123 TriList.SetUshort(2952, (ushort)(ShiftMode < 2 ? 0 : 1)); // 0 = #, 1 = abc } /// /// Event fire helper for text /// /// void OnKeyPress(string text) { var handler = KeyPress; if (handler != null) KeyPress(this, new KeyboardControllerPressEventArgs(text)); } /// /// event helper for special keys /// /// void OnKeyPress(KeyboardSpecialKey key) { var handler = KeyPress; if (handler != null) KeyPress(this, new KeyboardControllerPressEventArgs(key)); } /// /// 2901 /// public const uint KeyboardVisible = 2901; /// /// 2902 /// public const uint ClosePressJoin = 2902; /// /// 2903 /// public const uint GoButtonPressJoin = 2903; /// /// 2903 /// public const uint GoButtonTextJoin = 2903; /// /// 2904 /// public const uint SecondaryButtonPressJoin = 2904; /// /// 2904 /// public const uint SecondaryButtonTextJoin = 2904; /// /// 2905 /// public const uint GoButtonVisibleJoin = 2905; /// /// 2906 /// public const uint SecondaryButtonVisibleJoin = 2906; /// /// 2907 /// public const uint GoButtonEnableJoin = 2907; /// /// 2910 /// public const uint ClearPressJoin = 2910; /// /// 2911 /// public const uint ClearVisibleJoin = 2911; } /// /// Event args for keyboard key presses /// public class KeyboardControllerPressEventArgs : EventArgs { /// /// Gets or sets the Text /// public string Text { get; private set; } /// /// Gets or sets the SpecialKey /// public KeyboardSpecialKey SpecialKey { get; private set; } /// /// Constructor /// /// public KeyboardControllerPressEventArgs(string text) { Text = text; } /// /// Constructor /// /// special keyboard key public KeyboardControllerPressEventArgs(KeyboardSpecialKey key) { SpecialKey = key; } } /// /// Enumeration of KeyboardSpecialKey values /// public enum KeyboardSpecialKey { /// /// None /// None = 0, /// /// Backspace /// Backspace, /// /// Clear /// Clear, /// /// GoButton /// GoButton, /// /// SecondaryButton /// SecondaryButton } } ================================================ FILE: src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs ================================================ using System; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { /// /// Represents a ModalDialog /// public class ModalDialog { /// /// Bool press 3991 /// public const uint Button1Join = 3991; /// /// Bool press 3992 /// public const uint Button2Join = 3992; /// /// 3993 /// public const uint CancelButtonJoin = 3993; /// ///For visibility of single button. Bool feedback 3994 /// public const uint OneButtonVisibleJoin = 3994; /// /// For visibility of two buttons. Bool feedback 3995. /// public const uint TwoButtonVisibleJoin = 3995; /// /// Shows the timer guage if in use. Bool feedback 3996 /// public const uint TimerVisibleJoin = 3996; /// /// Visibility join to show "X" button 3997 /// public const uint CancelVisibleJoin = 3997; /// /// Shows the modal subpage. Boolean feeback join 3999 /// public const uint ModalVisibleJoin = 3999; ///// ///// The seconds value of the countdown timer. Ushort join 3991 ///// //public const uint TimerSecondsJoin = 3991; /// /// The full ushort value of the countdown timer for a gauge. Ushort join 3992 /// public const uint TimerGaugeJoin = 3992; /// /// Text on button one. String join 3991 /// public const uint Button1TextJoin = 3991; /// /// Text on button two. String join 3992 /// public const uint Button2TextJoin = 3992; /// /// Message text. String join 3994 /// public const uint MessageTextJoin = 3994; /// /// Title text. String join 3995 /// public const uint TitleTextJoin = 3995; /// /// Icon name. String join 3996 /// public const uint IconNameJoin = 3996; /// /// Returns true when modal is showing /// public bool ModalIsVisible { get { return TriList.BooleanInput[ModalVisibleJoin].BoolValue; } } /// /// /// public bool CanCancel { get; private set; } BasicTriList TriList; Action ModalCompleteAction; static object CompleteActionLock = new object(); /// /// Creates a new modal to be shown on provided TriList /// /// public ModalDialog(BasicTriList triList) { TriList = triList; // Attach actions to buttons triList.SetSigFalseAction(Button1Join, () => OnModalComplete(1)); triList.SetSigFalseAction(Button2Join, () => OnModalComplete(2)); triList.SetSigFalseAction(CancelButtonJoin, () => { if (CanCancel) CancelDialog(); }); CanCancel = true; } /// /// Shows the dialog /// /// Number of buttons to show. 0, 1, 2 /// Title text /// Icon name /// Message text /// Button 1 text /// Button 2 text /// True to show the gauge /// True to show the cancel "X" button /// The action to run when the dialog is dismissed. Parameter will be 1 or 2 if button pressed, or 0 if dialog times out /// True when modal is created. public bool PresentModalDialog(uint numberOfButtons, string title, string iconName, string message, string button1Text, string button2Text, bool showGauge, bool showCancel, Action completeAction) { // Don't reset dialog if visible now if (!ModalIsVisible) { ModalCompleteAction = completeAction; TriList.StringInput[TitleTextJoin].StringValue = title; if (string.IsNullOrEmpty(iconName)) iconName = "Blank"; TriList.StringInput[IconNameJoin].StringValue = iconName; TriList.StringInput[MessageTextJoin].StringValue = message; if (numberOfButtons == 0) { // Show no buttons TriList.BooleanInput[OneButtonVisibleJoin].BoolValue = false; TriList.BooleanInput[TwoButtonVisibleJoin].BoolValue = false; } else if (numberOfButtons == 1) { // Show one button TriList.BooleanInput[OneButtonVisibleJoin].BoolValue = true; TriList.BooleanInput[TwoButtonVisibleJoin].BoolValue = false; TriList.StringInput[Button1TextJoin].StringValue = button1Text; } else if (numberOfButtons == 2) { // Show two TriList.BooleanInput[OneButtonVisibleJoin].BoolValue = false; TriList.BooleanInput[TwoButtonVisibleJoin].BoolValue = true; TriList.StringInput[Button1TextJoin].StringValue = button1Text; TriList.StringInput[Button2TextJoin].StringValue = button2Text; } // Show/hide guage TriList.BooleanInput[TimerVisibleJoin].BoolValue = showGauge; CanCancel = showCancel; TriList.BooleanInput[CancelVisibleJoin].BoolValue = showCancel; //Reveal and activate TriList.BooleanInput[ModalVisibleJoin].BoolValue = true; WakePanel(); return true; } return false; } /// /// WakePanel method /// public void WakePanel() { try { var panel = TriList as TswFt5Button; if (panel != null && panel.ExtenderSystemReservedSigs.BacklightOffFeedback.BoolValue) panel.ExtenderSystemReservedSigs.BacklightOn(); } catch { Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?"); } } /// /// CancelDialog method /// public void CancelDialog() { OnModalComplete(0); } /// /// Hides dialog. Fires no action /// public void HideDialog() { TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; } // When the modal is cleared or times out, clean up the various bits void OnModalComplete(uint buttonNum) { TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; var action = ModalCompleteAction; if (action != null) action(buttonNum); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using Crestron.SimplSharpPro; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using Serilog.Events; namespace PepperDash.Essentials.Core.Touchpanels { /// /// A wrapper class for the touchpanel portion of an MPC3 class process to allow for configurable /// behavior of the keybad buttons /// public class Mpc3TouchpanelController : Device { readonly MPC3Basic _touchpanel; readonly Dictionary _buttons; /// /// Constructor /// /// device key /// device name /// control system processor /// dictionary of keypad buttons public Mpc3TouchpanelController(string key, string name, CrestronControlSystem processor, Dictionary buttons) : base(key, name) { _touchpanel = processor.ControllerTouchScreenSlotDevice as MPC3Basic; if (_touchpanel == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Failed to construct MPC3 Touchpanel Controller with key {0}, check configuration", key); return; } if (_touchpanel.Registerable) { var registrationResponse = _touchpanel.Register(); Debug.LogMessage(LogEventLevel.Information, this, "touchpanel registration response: {0}", registrationResponse); } _touchpanel.BaseEvent += Touchpanel_BaseEvent; _touchpanel.ButtonStateChange += Touchpanel_ButtonStateChange; _touchpanel.PanelStateChange += Touchpanel_PanelStateChange; _buttons = buttons; if (_buttons == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Button properties are null, failed to setup MPC3 Touch Controller, check configuration"); return; } AddPostActivationAction(() => { foreach (var button in _buttons) { var buttonKey = button.Key.ToLower(); var buttonConfig = button.Value; InitializeButton(buttonKey, buttonConfig); InitializeButtonFeedback(buttonKey, buttonConfig); } ListButtons(); }); } /// /// Enables/disables buttons based on event type configuration /// /// /// /// /// InitializeButton method /// public void InitializeButton(string key, KeypadButton config) { if (config == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' config is null, unable to initialize", key); return; } TryParseInt(key, out int buttonNumber); var buttonEventTypes = config.EventTypes; BoolOutputSig enabledFb = null; BoolOutputSig disabledFb = null; switch (key) { case ("power"): { if (buttonEventTypes == null || buttonEventTypes.Keys == null) _touchpanel.DisablePowerButton(); else _touchpanel.EnablePowerButton(); enabledFb = _touchpanel.PowerButtonEnabledFeedBack; disabledFb = _touchpanel.PowerButtonDisabledFeedBack; break; } //case ("volumeup"): // { // break; // } //case ("volumedown"): // { // break; // } //case ("volumefeedback"): // { // break; // } case ("mute"): { if (buttonEventTypes == null || buttonEventTypes.Keys == null) _touchpanel.DisableMuteButton(); else _touchpanel.EnableMuteButton(); enabledFb = _touchpanel.MuteButtonEnabledFeedBack; disabledFb = _touchpanel.MuteButtonDisabledFeedBack; break; } default: { if (buttonNumber == 0 || buttonNumber > 9) break; if (buttonEventTypes == null || buttonEventTypes.Keys == null) _touchpanel.DisableNumericalButton((uint)buttonNumber); else _touchpanel.EnableNumericalButton((uint)buttonNumber); if (_touchpanel.NumericalButtonEnabledFeedBack != null) enabledFb = _touchpanel.NumericalButtonEnabledFeedBack[(uint)buttonNumber]; if (_touchpanel.NumericalButtonDisabledFeedBack != null) disabledFb = _touchpanel.NumericalButtonDisabledFeedBack[(uint)buttonNumber]; break; } } Debug.LogMessage(LogEventLevel.Information, this, "InitializeButton: key-'{0}' enabledFb-'{1}', disabledFb-'{2}'", key, enabledFb ?? (object)"null", disabledFb ?? (object)"null"); } /// /// Links button feedback if configured /// /// /// /// /// InitializeButtonFeedback method /// public void InitializeButtonFeedback(string key, KeypadButton config) { //Debug.LogMessage(LogEventLevel.Debug, this, "Initializing button '{0}' feedback...", key); if (config == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' config is null, skipping.", key); return; } TryParseInt(key, out int buttonNumber); // Link up the button feedbacks to the specified device feedback var buttonFeedback = config.Feedback; if (buttonFeedback == null || string.IsNullOrEmpty(buttonFeedback.DeviceKey)) { Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback not configured, skipping.", key); return; } Feedback deviceFeedback; try { if (!(DeviceManager.GetDeviceForKey(buttonFeedback.DeviceKey) is Device device)) { Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback deviceKey '{1}' not found.", key, buttonFeedback.DeviceKey); return; } deviceFeedback = device.GetFeedbackProperty(buttonFeedback.FeedbackName); if (deviceFeedback == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedbackName property '{1}' not found.", key, buttonFeedback.FeedbackName); return; } // TODO [ ] verify if this can replace the current method //Debug.LogMessage(LogEventLevel.Information, this, "deviceFeedback.GetType().Name: '{0}'", deviceFeedback.GetType().Name); //switch (feedback.GetType().Name.ToLower()) //{ // case("boolfeedback"): // { // break; // } // case("intfeedback"): // { // break; // } // case("stringfeedback"): // { // break; // } //} } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Debug, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') Exception Message: {0}", ex.Message, key, buttonFeedback.DeviceKey); Debug.LogMessage(LogEventLevel.Verbose, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') Exception StackTrace: {0}", ex.StackTrace, key, buttonFeedback.DeviceKey); if (ex.InnerException != null) Debug.LogMessage(LogEventLevel.Verbose, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') InnerException: {0}", ex.InnerException, key, buttonFeedback.DeviceKey); return; } var boolFeedback = deviceFeedback as BoolFeedback; switch (key) { case ("power"): { boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackPower); break; } case ("volumeup"): case ("volumedown"): case ("volumefeedback"): { if (deviceFeedback is IntFeedback intFeedback) { var volumeFeedback = intFeedback; volumeFeedback.LinkInputSig(_touchpanel.VolumeBargraph); } break; } case ("mute"): { boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackMute); break; } default: { boolFeedback?.LinkCrestronFeedback(_touchpanel.Feedbacks[(uint)buttonNumber]); break; } } } /// /// Try parse int helper method /// /// /// /// public bool TryParseInt(string str, out int result) { try { result = int.Parse(str); return true; } catch { result = 0; return false; } } private void Touchpanel_BaseEvent(GenericBase device, BaseEventArgs args) { Debug.LogMessage(LogEventLevel.Debug, this, "BaseEvent: eventId-'{0}', index-'{1}'", args.EventId, args.Index); } private void Touchpanel_ButtonStateChange(GenericBase device, Crestron.SimplSharpPro.DeviceSupport.ButtonEventArgs args) { Debug.LogMessage(LogEventLevel.Debug, this, "ButtonStateChange: buttonNumber-'{0}' buttonName-'{1}', buttonState-'{2}'", args.Button.Number, args.Button.Name, args.NewButtonState); var type = args.NewButtonState.ToString(); if (_buttons.ContainsKey(args.Button.Number.ToString(CultureInfo.InvariantCulture))) { Press(args.Button.Number.ToString(CultureInfo.InvariantCulture), type); } else if (_buttons.ContainsKey(args.Button.Name.ToString())) { Press(args.Button.Name.ToString(), type); } } private void Touchpanel_PanelStateChange(GenericBase device, BaseEventArgs args) { Debug.LogMessage(LogEventLevel.Debug, this, "PanelStateChange: eventId-'{0}', index-'{1}'", args.EventId, args.Index); } /// /// Runs the function associated with this button/type. One of the following strings: /// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased /// /// /// /// /// Press method /// public void Press(string buttonKey, string type) { this.LogVerbose("Press: buttonKey-'{buttonKey}', type-'{type}'", buttonKey, type); // TODO: In future, consider modifying this to generate actions at device activation time // to prevent the need to dynamically call the method via reflection on each button press if (!_buttons.ContainsKey(buttonKey)) return; var button = _buttons[buttonKey]; if (!button.EventTypes.ContainsKey(type)) return; foreach (var eventType in button.EventTypes[type]) DeviceJsonApi.DoDeviceAction(eventType); } /// /// ListButtons method /// public void ListButtons() { this.LogVerbose("MPC3 Controller {0} - Available Buttons", Key); foreach (var button in _buttons) { this.LogVerbose("Key: {key}", button.Key); } } } /// /// Represents a KeypadButton /// public class KeypadButton { /// /// Gets or sets the EventTypes /// [JsonProperty("eventTypes")] public Dictionary EventTypes { get; set; } /// /// Gets or sets the Feedback /// [JsonProperty("feedback")] public KeypadButtonFeedback Feedback { get; set; } /// /// Constructor /// public KeypadButton() { EventTypes = new Dictionary(); Feedback = new KeypadButtonFeedback(); } } /// /// Represents a KeypadButtonFeedback /// public class KeypadButtonFeedback { /// /// Gets or sets the DeviceKey /// [JsonProperty("deviceKey")] public string DeviceKey { get; set; } /// /// Gets or sets the FeedbackName /// [JsonProperty("feedbackName")] public string FeedbackName { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs ================================================ 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; namespace PepperDash.Essentials.Core { /// /// Extensions used for more-clear attachment of Actions to user objects on sigs /// public static class SigAndTriListExtensions { /// /// Attaches Action to Sig's user object and returns the same Sig. This provides no protection /// from null sigs /// /// The BoolOutputSig to attach the Action to /// An action to run when sig is pressed and when released /// The Sig, sig public static BoolOutputSig SetBoolSigAction(this BoolOutputSig sig, Action a) { sig.UserObject = a; return sig; } /// /// Attaches Action to Sig's user object and returns the same Sig. /// /// /// /// /// /// /// SetBoolSigAction method /// public static BoolOutputSig SetBoolSigAction(this BasicTriList tl, uint sigNum, Action a) { return tl.BooleanOutput[sigNum].SetBoolSigAction(a); } /// /// Attaches a void Action to a TriList's output sig's UserObject, to be run on press /// /// trilist /// number of the signal /// action to run when the signal is true (pressed) /// public static BoolOutputSig SetSigTrueAction(this BasicTriList tl, uint sigNum, Action a) { return tl.BooleanOutput[sigNum].SetBoolSigAction(b => { if(b) a(); }); } /// /// Attaches a void Action to a TriList's output sig's UserObject, to be run on release /// /// The sig public static BoolOutputSig SetSigFalseAction(this BasicTriList tl, uint sigNum, Action a) { return tl.BooleanOutput[sigNum].SetBoolSigAction(b => { if (!b) a(); }); } /// /// Attaches a void Action to an output sig's UserObject, to be run on release /// /// The Sig public static BoolOutputSig SetSigFalseAction(this BoolOutputSig sig, Action a) { return sig.SetBoolSigAction(b => { if (!b) a(); }); } /// /// Sets an action to a held sig /// /// The sig public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction) { return SetSigHeldAction(tl, sigNum, heldMs, heldAction, null); } /// /// Sets an action to a held sig as well as a released-without-hold action /// /// public static BoolOutputSig SetSigHeldAction(this BoolOutputSig sig, uint heldMs, Action heldAction, Action holdReleasedAction, Action releaseAction) { CTimer heldTimer = null; bool wasHeld = false; return sig.SetBoolSigAction(press => { if (press) { wasHeld = false; // Could insert a pressed action here heldTimer = new CTimer(o => { // if still held and there's an action if (sig.BoolValue && heldAction != null) { wasHeld = true; // Hold action here heldAction(); } }, heldMs); } else if (!press && !wasHeld) // released, no hold { heldTimer.Stop(); if (releaseAction != null) releaseAction(); } else // !press && wasHeld // released after held { heldTimer.Stop(); if (holdReleasedAction != null) holdReleasedAction(); } }); } /// /// Sets an action to a held sig as well as a released-without-hold action /// /// The sig /// /// SetSigHeldAction method /// public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction, Action releaseAction) { return tl.BooleanOutput[sigNum].SetSigHeldAction(heldMs, heldAction, null, releaseAction); } /// /// Sets an action to a held sig, an action for the release of hold, as well as a released-without-hold action /// /// public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction, Action holdReleasedAction, Action releaseAction) { return tl.BooleanOutput[sigNum].SetSigHeldAction(heldMs, heldAction, holdReleasedAction, releaseAction); } /// /// SetUShortSigAction method /// /// /// /// The Sig public static UShortOutputSig SetUShortSigAction(this UShortOutputSig sig, Action a) { sig.UserObject = a; return sig; } /// /// SetUShortSigAction method /// /// /// /// /// public static UShortOutputSig SetUShortSigAction(this BasicTriList tl, uint sigNum, Action a) { return tl.UShortOutput[sigNum].SetUShortSigAction(a); } /// /// SetStringSigAction method /// /// /// /// public static StringOutputSig SetStringSigAction(this StringOutputSig sig, Action a) { sig.UserObject = a; return sig; } /// /// SetStringSigAction method /// /// /// /// /// public static StringOutputSig SetStringSigAction(this BasicTriList tl, uint sigNum, Action a) { return tl.StringOutput[sigNum].SetStringSigAction(a); } /// /// ClearSigAction method /// /// /// public static Sig ClearSigAction(this Sig sig) { sig.UserObject = null; return sig; } /// /// ClearBoolSigAction method /// /// trilist /// signal number to clear /// public static BoolOutputSig ClearBoolSigAction(this BasicTriList tl, uint sigNum) { return ClearSigAction(tl.BooleanOutput[sigNum]) as BoolOutputSig; } /// /// ClearUShortSigAction method /// public static UShortOutputSig ClearUShortSigAction(this BasicTriList tl, uint sigNum) { return ClearSigAction(tl.UShortOutput[sigNum]) as UShortOutputSig; } /// /// ClearStringSigAction method /// public static StringOutputSig ClearStringSigAction(this BasicTriList tl, uint sigNum) { return ClearSigAction(tl.StringOutput[sigNum]) as StringOutputSig; } /// /// ClearAllSigActions method /// public static void ClearAllSigActions(this BasicTriList t1) { foreach (var sig in t1.BooleanOutput) { ClearSigAction(sig); } foreach (var sig in t1.UShortOutput) { ClearSigAction(sig); } foreach (var sig in t1.StringOutput) { ClearSigAction(sig); } } /// /// SetBool method /// public static void SetBool(this BasicTriList tl, uint sigNum, bool value) { tl.BooleanInput[sigNum].BoolValue = value; } /// /// Sends an true-false pulse to the sig /// /// /// public static void PulseBool(this BasicTriList tl, uint sigNum) { tl.BooleanInput[sigNum].Pulse(); } /// /// Sends a timed pulse to the sig /// /// /// /// public static void PulseBool(this BasicTriList tl, uint sigNum, int ms) { tl.BooleanInput[sigNum].Pulse(ms); } /// /// Helper method to set the value of a ushort Sig on TriList /// public static void SetUshort(this BasicTriList tl, uint sigNum, ushort value) { tl.UShortInput[sigNum].UShortValue = value; } /// /// Helper method to set the value of a string Sig on TriList /// public static void SetString(this BasicTriList tl, uint sigNum, string value) { tl.StringInput[sigNum].StringValue = value; } /// /// Helper method to set the value of a string Sig on TriList with encoding /// /// trilist /// signal number to set /// string value to set /// string encoding to use public static void SetString(this BasicTriList tl, uint sigNum, string value, eStringEncoding encoding) { tl.StringInput[sigNum].StringEncoding = encoding; tl.StringInput[sigNum].StringValue = value; } /// /// Returns bool value of trilist sig /// /// /// /// public static bool GetBool(this BasicTriList tl, uint sigNum) { return tl.BooleanOutput[sigNum].BoolValue; } /// /// Returns ushort value of trilist sig /// /// /// /// public static ushort GetUshort(this BasicTriList tl, uint sigNum) { return tl.UShortOutput[sigNum].UShortValue; } /// /// Returns string value of trilist sig. /// /// /// /// public static string GetString(this BasicTriList tl, uint sigNum) { return tl.StringOutput[sigNum].StringValue; } } } ================================================ FILE: src/PepperDash.Essentials.Core/TriListBridges/HandlerBridge.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; namespace PepperDash.Essentials.Core { /// /// Abstract base class for TriList handler bridges /// public abstract class HandlerBridge { /// /// Gets or sets the IsAttached /// public bool IsAttached { get; protected set; } /// /// Attaches the handler to the panel's user objects /// public abstract void AttachToTriListOutputs(bool sendUpdate); /// /// Removes the handler from the panel's user objects /// public abstract void DetachFromTriListOutputs(); } } ================================================ FILE: src/PepperDash.Essentials.Core/UI/TouchpanelBase.cs ================================================ using System; using System.Linq; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Core.Logging; using Serilog.Events; namespace PepperDash.Essentials.Core.UI { /// /// Base class for Touchpanel devices /// public abstract class TouchpanelBase : EssentialsDevice, IHasBasicTriListWithSmartObject { /// /// Gets or sets the configuration for the Crestron touchpanel. /// protected CrestronTouchpanelPropertiesConfig _config; /// /// Gets or sets the Panel /// public BasicTriListWithSmartObject Panel { get; private set; } /// /// Constructor for use with device Factory. A touch panel device will be created based on the provided IP-ID and the /// type of the panel. The SGD File path can be specified using the config property, or a default one located in the program directory if none /// is provided. /// /// Essentials Device Key /// Essentials Device Name /// Crestron Touchpanel Device /// Touchpanel Configuration protected TouchpanelBase(string key, string name, BasicTriListWithSmartObject panel, CrestronTouchpanelPropertiesConfig config) : base(key, name) { if (panel == null) { Debug.LogMessage(LogEventLevel.Information, this, "Panel is not valid. Touchpanel class WILL NOT work correctly"); return; } Panel = panel; Panel.SigChange += Panel_SigChange; if (Panel is TswFt5ButtonSystem) { var tsw = Panel as TswFt5ButtonSystem; tsw.ExtenderSystemReservedSigs.Use(); tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange += ExtenderSystemReservedSigs_DeviceExtenderSigChange; tsw.ButtonStateChange += Tsw_ButtonStateChange; } _config = config; AddPreActivationAction(() => { // Give up cleanly if SGD is not present. var sgdName = Global.FilePathPrefix + "sgd" + Global.DirectorySeparator + _config.SgdFile; if (!File.Exists(sgdName)) { this.LogInformation("Smart object file '{0}' not present in User folder. Looking for embedded file", sgdName); sgdName = Global.ApplicationDirectoryPathPrefix + Global.DirectorySeparator + "SGD" + Global.DirectorySeparator + _config.SgdFile; if (!File.Exists(sgdName)) { this.LogWarning("Unable to find SGD file '{0}' in User sgd or application SGD folder. Exiting touchpanel load.", sgdName); return; } } Panel.LoadSmartObjects(sgdName); }); AddPostActivationAction(() => { // Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event if (DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) is IEssentialsRoomCombiner roomCombiner) { // Subscribe to the even roomCombiner.RoomCombinationScenarioChanged += new EventHandler(RoomCombiner_RoomCombinationScenarioChanged); // Connect to the initial roomKey if (roomCombiner.CurrentScenario != null) { // Use the current scenario DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario); } else { // Current Scenario not yet set. Use default SetupPanelDrivers(_config.DefaultRoomKey); } } else { // No room combiner, use the default key SetupPanelDrivers(_config.DefaultRoomKey); } var panelRegistrationResponse = Panel.Register(); if (panelRegistrationResponse != eDeviceRegistrationUnRegistrationResponse.Success) this.LogInformation("WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason); }); } /// /// Setup Panel operation /// /// Room Key for this panel protected abstract void SetupPanelDrivers(string roomKey); /// /// Event handler for System Extender Events /// /// /// protected abstract void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args); /// /// /// /// /// protected virtual void RoomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e) { var roomCombiner = sender as IEssentialsRoomCombiner; DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario); } /// /// Determines the room key to use based on the scenario /// /// protected virtual void DetermineRoomKeyFromScenario(IRoomCombinationScenario scenario) { string newRoomKey = null; if (scenario.UiMap.ContainsKey(Key)) { newRoomKey = scenario.UiMap[Key]; } else if (scenario.UiMap.ContainsKey(_config.DefaultRoomKey)) { newRoomKey = scenario.UiMap[_config.DefaultRoomKey]; } SetupPanelDrivers(newRoomKey); } private void Panel_SigChange(object currentDevice, SigEventArgs args) { this.LogVerbose("Sig change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); var uo = args.Sig.UserObject; if (uo is Action) (uo as Action)(args.Sig.BoolValue); else if (uo is Action) (uo as Action)(args.Sig.UShortValue); else if (uo is Action) (uo as Action)(args.Sig.StringValue); } private void Tsw_ButtonStateChange(GenericBase device, ButtonEventArgs args) { var uo = args.Button.UserObject; if (uo is Action) (uo as Action)(args.Button.State == eButtonState.Pressed); } } } ================================================ FILE: src/PepperDash.Essentials.Core/UI PageManagers/BlurayPageManager.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.PageManagers { /// /// Represents a DiscPlayerMediumPageManager /// public class DiscPlayerMediumPageManager : MediumLeftSwitchablePageManager { IDiscPlayerControls Player; /// /// Constructor /// /// player controls object /// trilist object public DiscPlayerMediumPageManager(IDiscPlayerControls player, BasicTriListWithSmartObject trilist) : base(player.DisplayUiType) { Player = player; TriList = trilist; } /// /// Show method /// /// public override void Show() { uint offset = GetOffsetJoin(); BackingPageJoin = offset + 1; AllLeftSubpages = new uint[] { 7, 8 }; if (LeftSubpageJoin == 0) LeftSubpageJoin = offset + 8; // default to transport TriList.BooleanInput[BackingPageJoin].BoolValue = true; TriList.BooleanInput[LeftSubpageJoin].BoolValue = true; // Attach buttons to interlock foreach(var p in AllLeftSubpages) { var p2 = p; // scope TriList.SetSigFalseAction(10000 + p2, () => InterlockLeftSubpage(p2)); } } /// /// Hide method /// /// public override void Hide() { TriList.BooleanInput[BackingPageJoin].BoolValue = false; TriList.BooleanInput[LeftSubpageJoin].BoolValue = false; } } } ================================================ FILE: src/PepperDash.Essentials.Core/UI PageManagers/PageManager.cs ================================================ using System.Collections.Generic; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.PageManagers { /// /// The PageManager classes are used to bridge a device to subpage /// visibility. /// public abstract class PageManager { /// /// ActiveJoins list /// protected List ActiveJoins = new List(); /// /// Show method /// public abstract void Show(); /// /// Hide method /// public abstract void Hide(); /// /// For device types 1-49, returns the offset join for subpage management 10100 - 14900 /// /// 1 through 49, as defined in some constants somewhere! /// public uint GetOffsetJoin(uint deviceType) { return 10000 + (deviceType * 100); } } /// /// A simple class that hides and shows the default subpage for a given source type /// public class DefaultPageManager : PageManager { BasicTriList TriList; uint BackingPageJoin; /// /// Constructor /// /// device /// trilist object public DefaultPageManager(IUiDisplayInfo device, BasicTriList trilist) { TriList = trilist; BackingPageJoin = GetOffsetJoin(device.DisplayUiType) + 1; } /// /// Constructor /// /// back page join /// trilist object public DefaultPageManager(uint join, BasicTriList trilist) { TriList = trilist; BackingPageJoin = join; } /// /// Show method /// /// public override void Show() { TriList.BooleanInput[BackingPageJoin].BoolValue = true; } /// /// Hide method /// public override void Hide() { TriList.BooleanInput[BackingPageJoin].BoolValue = false; } } /// /// A page manager for a page with backing panel and a switchable side panel /// public abstract class MediumLeftSwitchablePageManager : PageManager { /// /// TriList object /// protected BasicTriListWithSmartObject TriList; /// /// Left subpage join /// protected uint LeftSubpageJoin; /// /// Backing page join /// protected uint BackingPageJoin; /// /// All left subpages /// protected uint[] AllLeftSubpages; /// /// Display UI Type /// protected uint DisplayUiType; /// /// Constructor /// /// UI type protected MediumLeftSwitchablePageManager(uint displayUiType) { DisplayUiType = displayUiType; } /// /// Interlock left subpage /// /// protected void InterlockLeftSubpage(uint join) { join = join + GetOffsetJoin(); ClearLeftInterlock(); TriList.BooleanInput[join].BoolValue = true; LeftSubpageJoin = join; } /// /// Clear left interlock /// protected void ClearLeftInterlock() { foreach (var p in AllLeftSubpages) TriList.BooleanInput[GetOffsetJoin() + p].BoolValue = false; } /// /// Get offset join /// /// protected uint GetOffsetJoin() { return GetOffsetJoin(DisplayUiType); } } } ================================================ FILE: src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxThreePanelPageManager.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Presets; using Serilog.Events; namespace PepperDash.Essentials.Core.PageManagers { /// /// Represents a ThreePanelPlusOnePageManager /// public class ThreePanelPlusOnePageManager : PageManager { /// /// The trilist /// protected BasicTriListWithSmartObject TriList; /// /// Gets or sets the Position5TabsId /// public uint Position5TabsId { get; set; } /// /// Show the tabs on the third panel /// protected bool ShowPosition5Tabs; /// /// Joins that are always visible when this manager is visible /// protected uint[] FixedVisibilityJoins; /// /// Gets or sets the current visible item in position 5 /// protected uint CurrentVisiblePosition5Item; /// /// Constructor /// /// public ThreePanelPlusOnePageManager(BasicTriListWithSmartObject trilist) { TriList = trilist; CurrentVisiblePosition5Item = 1; } /// /// The joins for the switchable panel in position 5 /// Dictionary Position5SubpageJoins = new Dictionary { { 1, 10053 }, { 2, 10054 } }; /// /// /// public override void Show() { // Project the joins into corresponding sigs. var fixedSigs = FixedVisibilityJoins.Select(u => TriList.BooleanInput[u]).ToList(); foreach (var sig in fixedSigs) sig.BoolValue = true; if (ShowPosition5Tabs) { // Show selected tab TriList.BooleanInput[Position5SubpageJoins[CurrentVisiblePosition5Item]].BoolValue = true; // hook up tab object var tabSo = TriList.SmartObjects[Position5TabsId]; tabSo.BooleanOutput["Tab Button 1 Press"].UserObject = new Action(b => { if (!b) ShowTab(1); }); tabSo.BooleanOutput["Tab Button 2 Press"].UserObject = new Action(b => { if (!b) ShowTab(2); }); tabSo.SigChange -= tabSo_SigChange; tabSo.SigChange += tabSo_SigChange; } } void tabSo_SigChange(Crestron.SimplSharpPro.GenericBase currentDevice, Crestron.SimplSharpPro.SmartObjectEventArgs args) { var uo = args.Sig.UserObject; if(uo is Action) (uo as Action)(args.Sig.BoolValue); } /// /// Hide method /// /// public override void Hide() { var fixedSigs = FixedVisibilityJoins.Select(u => TriList.BooleanInput[u]).ToList(); foreach (var sig in fixedSigs) sig.BoolValue = false; if (ShowPosition5Tabs) { TriList.BooleanInput[Position5SubpageJoins[CurrentVisiblePosition5Item]].BoolValue = false; //var tabSo = TriList.SmartObjects[Position5TabsId]; //tabSo.BooleanOutput["Tab Button 1 Press"].UserObject = null; //tabSo.BooleanOutput["Tab Button 2 Press"].UserObject = null; } } void ShowTab(uint number) { // Ignore re-presses if (CurrentVisiblePosition5Item == number) return; // Swap subpage var bi = TriList.BooleanInput; if (CurrentVisiblePosition5Item > 0) bi[Position5SubpageJoins[CurrentVisiblePosition5Item]].BoolValue = false; CurrentVisiblePosition5Item = number; bi[Position5SubpageJoins[CurrentVisiblePosition5Item]].BoolValue = true; } } /// /// Represents a SetTopBoxThreePanelPageManager /// public class SetTopBoxThreePanelPageManager : ThreePanelPlusOnePageManager { ISetTopBoxControls SetTopBox; DevicePresetsView PresetsView; /// /// Gets or sets the DpadSmartObjectId /// public uint DpadSmartObjectId { get; set; } /// /// Gets or sets the NumberPadSmartObjectId /// public uint NumberPadSmartObjectId { get; set; } /// /// Gets or sets the PresetsSmartObjectId /// public uint PresetsSmartObjectId { get; set; } /// /// A page manager for set top box that shows some combination of four different panels, /// in three slots on the page. /// /// /// public SetTopBoxThreePanelPageManager(ISetTopBoxControls stb, BasicTriListWithSmartObject trilist) : base(trilist) { SetTopBox = stb; TriList = trilist; DpadSmartObjectId = 10011; NumberPadSmartObjectId = 10014; PresetsSmartObjectId = 10012; Position5TabsId = 10081; bool dpad = stb.HasDpad; bool preset = stb.HasPresets; bool dvr = stb.HasDvr; bool numbers = stb.HasNumeric; if (dpad && !preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10031, 10091 }; else if (!dpad && preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10032, 10091 }; else if (!dpad && !preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10033, 10091 }; else if (!dpad && !preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10034, 10091 }; else if (dpad && preset && !dvr && !numbers) FixedVisibilityJoins = new uint[] { 10042, 10021, 10092 }; else if (dpad && !preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10043, 10021, 10092 }; else if (dpad && !preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10021, 10092 }; else if (!dpad && preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10043, 10022, 10092 }; else if (!dpad && preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10022, 10092 }; else if (!dpad && !preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10044, 10023, 10092 }; else if (dpad && preset && dvr && !numbers) FixedVisibilityJoins = new uint[] { 10053, 10032, 10011, 10093 }; else if (dpad && preset && !dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10032, 10011, 10093 }; else if (dpad && !preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10033, 10011, 10093 }; else if (!dpad && preset && dvr && numbers) FixedVisibilityJoins = new uint[] { 10054, 10033, 10012, 10093 }; else if (dpad && preset && dvr && numbers) { FixedVisibilityJoins = new uint[] { 10081, 10032, 10011, 10093 }; // special case ShowPosition5Tabs = true; } // Bad config case else { Debug.LogMessage(LogEventLevel.Debug, stb, "WARNING: Not configured to show any UI elements"); FixedVisibilityJoins = new uint[] { 10091 }; } // Build presets if (stb.HasPresets && stb.TvPresets != null) { PresetsView = new DevicePresetsView(trilist, stb.TvPresets); } } /// /// Show method /// /// public override void Show() { if(PresetsView != null) PresetsView.Attach(); base.Show(); } /// /// Hide method /// /// public override void Hide() { if (PresetsView != null) PresetsView.Detach(); base.Hide(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/UI PageManagers/SetTopBoxTwoPanelPageManager.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Presets; namespace PepperDash.Essentials.Core.PageManagers { /// /// Represents a SetTopBoxMediumPageManager /// public class SetTopBoxMediumPageManager : MediumLeftSwitchablePageManager { ISetTopBoxControls SetTopBox; DevicePresetsView PresetsView; /// /// Constructor /// /// set top box controls device /// trilist device public SetTopBoxMediumPageManager(ISetTopBoxControls stb, BasicTriListWithSmartObject trilist) : base(stb.DisplayUiType) { SetTopBox = stb; TriList = trilist; if(stb.TvPresets != null) PresetsView = new DevicePresetsView(trilist, stb.TvPresets); } /// /// Show method /// /// public override void Show() { if(PresetsView != null) PresetsView.Attach(); uint offset = GetOffsetJoin(); if (SetTopBox.HasDvr) // Show backing page with DVR controls { BackingPageJoin = offset + 1; AllLeftSubpages = new uint[] { 6, 7, 8 }; } else // Show the backing page with no DVR controls { BackingPageJoin = offset + 2; AllLeftSubpages = new uint[] { 6, 7 }; } if (LeftSubpageJoin == 0) LeftSubpageJoin = offset + 6; // default to presets TriList.BooleanInput[BackingPageJoin].BoolValue = true; TriList.BooleanInput[LeftSubpageJoin].BoolValue = true; // Attach buttons to interlock foreach(var p in AllLeftSubpages) { var p2 = p; // scope TriList.SetSigFalseAction(10000 + p2, () => InterlockLeftSubpage(p2)); } } /// /// Hide method /// /// public override void Hide() { TriList.BooleanInput[BackingPageJoin].BoolValue = false; TriList.BooleanInput[LeftSubpageJoin].BoolValue = false; } } } ================================================ FILE: src/PepperDash.Essentials.Core/UI PageManagers/SinglePageManager.cs ================================================ using System.Collections.Generic; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.PageManagers { /// /// Represents a SinglePageManager /// public class SinglePageManager : PageManager { BasicTriList TriList; uint BackingPageJoin; /// /// Constructor /// /// join for thepage /// trilist public SinglePageManager(uint pageJoin, BasicTriList trilist) { TriList = trilist; BackingPageJoin = pageJoin; } /// /// Show method /// /// public override void Show() { TriList.BooleanInput[BackingPageJoin].BoolValue = true; } /// /// Hide method /// public override void Hide() { TriList.BooleanInput[BackingPageJoin].BoolValue = false; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Utilities/ActionSequence.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.CrestronThread; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Newtonsoft.Json; using Serilog.Events; namespace PepperDash.Essentials.Core.Utilities { /// /// A device that executes a sequence of actions with optional delays between actions /// [Description("A device that executes a sequence of actions with optional delays between actions")] public class ActionSequence : EssentialsDevice { private ActionSequencePropertiesConfig _propertiesConfig; private CrestronQueue _actionQueue; private Thread _worker; private bool _allowActionsToExecute; /// /// Constructor /// /// /// public ActionSequence(string key, DeviceConfig config) : base(key, config.Name) { var props = config.Properties.ToObject(); _propertiesConfig = props; if (_propertiesConfig != null) { if (_propertiesConfig.ActionSequence.Count > 0) { _actionQueue = new CrestronQueue(_propertiesConfig.ActionSequence.Count); } } } /// /// StartSequence method /// public void StartSequence() { if (_worker !=null && _worker.ThreadState == Thread.eThreadStates.ThreadRunning) { Debug.LogMessage(LogEventLevel.Debug, this, "Thread already running. Cannot Start Sequence"); return; } Debug.LogMessage(LogEventLevel.Debug, this, "Starting Action Sequence"); _allowActionsToExecute = true; AddActionsToQueue(); _worker = new Thread(ProcessActions, null, Thread.eThreadStartOptions.Running); } /// /// StopSequence method /// public void StopSequence() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Action Sequence"); _allowActionsToExecute = false; _worker.Abort(); } /// /// Populates the queue from the configuration information /// private void AddActionsToQueue() { Debug.LogMessage(LogEventLevel.Debug, this, "Adding {0} actions to queue", _propertiesConfig.ActionSequence.Count); for (int i = 0; i < _propertiesConfig.ActionSequence.Count; i++) { _actionQueue.Enqueue(_propertiesConfig.ActionSequence[i]); } } private object ProcessActions(object obj) { while (_allowActionsToExecute && _actionQueue.Count > 0) { SequencedDeviceActionWrapper action = null; action = _actionQueue.Dequeue(); if (action == null) break; // Delay before executing if (action.DelayMs > 0) Thread.Sleep(action.DelayMs); ExecuteAction(action); } return null; } private void ExecuteAction(DeviceActionWrapper action) { if (action == null) return; try { DeviceJsonApi.DoDeviceAction(action); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, this, "Error Executing Action: {0}", e); } } } /// /// Represents a ActionSequencePropertiesConfig /// public class ActionSequencePropertiesConfig { /// /// Gets or sets the ActionSequence /// [JsonProperty("actionSequence")] public List ActionSequence { get; set; } /// /// Constructor /// public ActionSequencePropertiesConfig() { ActionSequence = new List(); } } /// /// Represents a SequencedDeviceActionWrapper /// public class SequencedDeviceActionWrapper : DeviceActionWrapper { /// /// Gets or sets the DelayMs /// [JsonProperty("delayMs")] public int DelayMs { get; set; } } /// /// Represents a ActionSequenceFactory /// public class ActionSequenceFactory : EssentialsDeviceFactory { /// /// Constructor /// public ActionSequenceFactory() { TypeNames = new List() { "actionsequence" }; } /// /// BuildDevice method /// /// device config /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new ActionSequence Device"); return new ActionSequence(dc.Key, dc); } } } ================================================ FILE: src/PepperDash.Essentials.Core/VideoStatus/VideoStatusOutputs.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DM; namespace PepperDash.Essentials.Core { /// /// Use this class to pass in values to RoutingInputPorts. Unused properties will have default /// funcs assigned to them. /// public class VideoStatusFuncsWrapper { /// /// Gets or sets the HasVideoStatusFunc /// public Func HasVideoStatusFunc { get; set; } /// /// Gets or sets the HdcpActiveFeedbackFunc /// public Func HdcpActiveFeedbackFunc { get; set; } /// /// Gets or sets the HdcpStateFeedbackFunc /// public Func HdcpStateFeedbackFunc { get; set; } /// /// Gets or sets the VideoResolutionFeedbackFunc /// public Func VideoResolutionFeedbackFunc { get; set; } /// /// Gets or sets the VideoSyncFeedbackFunc /// public Func VideoSyncFeedbackFunc { get; set; } /// /// Constructor /// public VideoStatusFuncsWrapper() { HasVideoStatusFunc = () => true; HdcpActiveFeedbackFunc = () => false; HdcpStateFeedbackFunc = () => ""; VideoResolutionFeedbackFunc = () => "n/a"; VideoSyncFeedbackFunc = () => false; } } /// /// Represents a VideoStatusOutputs /// public class VideoStatusOutputs { /// /// Gets or sets the HasVideoStatusFeedback /// public BoolFeedback HasVideoStatusFeedback { get; private set; } /// /// Gets or sets the HdcpActiveFeedback /// public BoolFeedback HdcpActiveFeedback { get; private set; } /// /// Gets or sets the HdcpStateFeedback /// public StringFeedback HdcpStateFeedback { get; private set; } /// /// Gets or sets the VideoResolutionFeedback /// public StringFeedback VideoResolutionFeedback { get; private set; } /// /// Gets or sets the VideoSyncFeedback /// public BoolFeedback VideoSyncFeedback { get; private set; } /// /// Gets or sets the NoStatus /// public static VideoStatusOutputs NoStatus { get { return _Default; } } static VideoStatusOutputs _Default = new VideoStatusOutputs(new VideoStatusFuncsWrapper { HasVideoStatusFunc = () => false }); /// /// Constructor /// /// public VideoStatusOutputs(VideoStatusFuncsWrapper funcs) { HasVideoStatusFeedback = new BoolFeedback("HasVideoStatusFeedback", funcs.HasVideoStatusFunc); HdcpActiveFeedback = new BoolFeedback("HdcpActiveFeedback", funcs.HdcpActiveFeedbackFunc); HdcpStateFeedback = new StringFeedback("HdcpStateFeedback", funcs.HdcpStateFeedbackFunc); VideoResolutionFeedback = new StringFeedback("VideoResolutionFeedback", funcs.VideoResolutionFeedbackFunc); VideoSyncFeedback = new BoolFeedback("VideoSyncFeedback", funcs.VideoSyncFeedbackFunc); } /// /// FireAll method /// public void FireAll() { HasVideoStatusFeedback.FireUpdate(); HdcpActiveFeedback.FireUpdate(); HdcpActiveFeedback.FireUpdate(); VideoResolutionFeedback.FireUpdate(); VideoSyncFeedback.FireUpdate(); } /// /// ToList method /// public List ToList() { return new List { HasVideoStatusFeedback, HdcpActiveFeedback, HdcpStateFeedback, VideoResolutionFeedback, VideoSyncFeedback }; } } // /// // /// Wraps up the common video statuses exposed on a video input port // /// //public class BasicVideoStatus : IBasicVideoStatus //{ // public event VideoStatusChangeHandler VideoStatusChange; // public bool HasVideoStatus { get; private set; } // public bool HdcpActive // { // get { return HdcpActiveFunc != null ? HdcpActiveFunc() : false; } // } // public string HdcpState // { // get { return HdcpStateFunc != null? HdcpStateFunc() : ""; } // } // public string VideoResolution // { // get { return VideoResolutionFunc != null ? VideoResolutionFunc() : ""; } // } // public bool VideoSync // { // get { return VideoSyncFunc != null ? VideoSyncFunc() : false; } // } // Func HdcpActiveFunc; // Func HdcpStateFunc; // Func VideoResolutionFunc; // Func VideoSyncFunc; // public BasicVideoStatus(bool hasVideoStatus, Func hdcpActiveFunc, // Func hdcpStateFunc, Func videoResolutionFunc, Func videoSyncFunc) // { // HasVideoStatus = hasVideoStatus; // HdcpActiveFunc = hdcpActiveFunc; // HdcpStateFunc = hdcpStateFunc; // VideoResolutionFunc = videoResolutionFunc; // VideoSyncFunc = videoSyncFunc; // } //} //public enum eVideoStatusChangeType //{ // HdcpActive, // HdcpState, // VideoResolution, // VideoSync //} //public interface IBasicVideoStatus //{ // event VideoStatusChangeHandler VideoStatusChange; // bool HdcpActive { get; } // string HdcpState { get; } // string VideoResolution { get; } // bool VideoSync { get; } //} //public delegate void VideoStatusChangeHandler(IBasicVideoStatus device, eVideoStatusChangeType type); } ================================================ FILE: src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using PepperDash.Core; using PepperDash.Core.Web; using PepperDash.Essentials.Core.Web.RequestHandlers; using Serilog.Events; namespace PepperDash.Essentials.Core.Web { /// /// Represents a EssentialsWebApi /// public class EssentialsWebApi : EssentialsDevice { private readonly WebApiServer _server; private readonly WebApiServer _debugServer; /// /// http(s)://{ipaddress}/cws/{basePath} /// http(s)://{ipaddress}/VirtualControl/Rooms/{roomId}/cws/{basePath} /// private readonly string _defaultBasePath = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? string.Format("/app{0:00}/api", InitialParametersClass.ApplicationNumber) : "/api"; private const int DebugTrace = 0; private const int DebugInfo = 1; private const int DebugVerbose = 2; /// /// Gets or sets the BasePath /// public string BasePath { get; private set; } /// /// Tracks if CWS is registered /// public bool IsRegistered { get { return _server.IsRegistered; } } /// /// Constructor /// /// /// public EssentialsWebApi(string key, string name) : this(key, name, null) { } /// /// Constructor /// /// /// /// public EssentialsWebApi(string key, string name, EssentialsWebApiPropertiesConfig config) : base(key, name) { Key = key; if (config == null) BasePath = _defaultBasePath; else BasePath = string.IsNullOrEmpty(config.BasePath) ? _defaultBasePath : config.BasePath; _server = new WebApiServer(Key, Name, BasePath); _debugServer = new WebApiServer($"{key}-debug-app", $"{name} Debug App", "/debug"); _debugServer.SetFallbackHandler(new ServeDebugAppRequestHandler()); SetupRoutes(); } private void SetupRoutes() { var routes = new List { new HttpCwsRoute("login") { Name = "Root", RouteHandler = new LoginRequestHandler() }, new HttpCwsRoute("versions") { Name = "ReportVersions", RouteHandler = new ReportVersionsRequestHandler() }, new HttpCwsRoute("appdebug") { Name = "AppDebug", RouteHandler = new AppDebugRequestHandler() }, new HttpCwsRoute("devices") { Name = "DevList", RouteHandler = new DevListRequestHandler() }, new HttpCwsRoute("deviceCommands/{deviceKey}") { Name = "DevJson", RouteHandler = new DevJsonRequestHandler() }, new HttpCwsRoute("deviceProperties/{deviceKey}") { Name = "DevProps", RouteHandler = new DevPropsRequestHandler() }, new HttpCwsRoute("deviceMethods/{deviceKey}") { Name = "DevMethods", RouteHandler = new DevMethodsRequestHandler() }, new HttpCwsRoute("deviceFeedbacks/{deviceKey}") { Name = "GetFeedbacksForDeviceKey", RouteHandler = new GetFeedbacksForDeviceRequestHandler() }, new HttpCwsRoute("deviceStreamDebug") { Name = "SetDeviceStreamDebug", RouteHandler = new SetDeviceStreamDebugRequestHandler() }, new HttpCwsRoute("disableAllStreamDebug") { Name = "DisableAllStreamDebug", RouteHandler = new DisableAllStreamDebugRequestHandler() }, new HttpCwsRoute("config") { Name = "ShowConfig", RouteHandler = new ShowConfigRequestHandler() }, new HttpCwsRoute("types") { Name = "GetTypes", RouteHandler = new GetTypesRequestHandler() }, new HttpCwsRoute("types/{filter}") { Name = "GetTypesByFilter", RouteHandler = new GetTypesByFilterRequestHandler() }, new HttpCwsRoute("joinMap/{bridgeKey}") { Name = "GetJoinMapsForBridgeKey", RouteHandler = new GetJoinMapForBridgeKeyRequestHandler() }, new HttpCwsRoute("joinMap/{bridgeKey}/{deviceKey}") { Name = "GetJoinMapsForDeviceKey", RouteHandler = new GetJoinMapForDeviceKeyRequestHandler() }, new HttpCwsRoute("debugSession") { Name = "DebugSession", RouteHandler = new DebugSessionRequestHandler() }, new HttpCwsRoute("doNotLoadConfigOnNextBoot") { Name = "DoNotLoadConfigOnNextBoot", RouteHandler = new DoNotLoadConfigOnNextBootRequestHandler() }, new HttpCwsRoute("restartProgram") { Name = "Restart Program", RouteHandler = new RestartProgramRequestHandler() }, new HttpCwsRoute("loadConfig") { Name = "Load Config", RouteHandler = new LoadConfigRequestHandler() }, new HttpCwsRoute("tielines") { Name = "Get TieLines", RouteHandler = new GetTieLinesRequestHandler() }, new HttpCwsRoute("device/{deviceKey}/routingPorts") { Name = "Get Routing Ports for a device", RouteHandler = new GetRoutingPortsHandler() }, new HttpCwsRoute("routingDevicesAndTieLines") { Name = "Get Routing Devices and TieLines", RouteHandler = new GetRoutingDevicesAndTieLinesHandler() }, }; AddRoute(routes); } /// /// Add a single route to the API. MUST be done during the activation phase /// /// /// /// AddRoute method /// public void AddRoute(HttpCwsRoute route) { _server.AddRoute(route); } /// /// Add a collection of routes to the API. MUST be done during the activation phase /// /// public void AddRoute(List routes) { foreach (var route in routes) { AddRoute(route); } } /// /// Initialize method /// /// public override void Initialize() { AddRoute(new HttpCwsRoute("apiPaths") { Name = "GetPaths", RouteHandler = new GetRoutesHandler(_server.GetRouteCollection(), BasePath) }); // If running on an appliance if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) { /* WEBSERVER [ON | OFF | TIMEOUT | MAXSESSIONSPERUSER ] */ var response = string.Empty; CrestronConsole.SendControlSystemCommand("webserver", ref response); if (response.Contains("OFF")) return; var is4Series = eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4); Debug.LogMessage(LogEventLevel.Verbose, "Starting Essentials Web API on {0} Appliance", is4Series ? "4-series" : "3-series"); _server.Start(); _debugServer.Start(); GetPaths(); return; } // Automatically start CWS when running on a server (Linux OS, Virtual Control) Debug.LogMessage(LogEventLevel.Verbose, "Starting Essentials Web API on Virtual Control Server"); _server.Start(); _debugServer.Start(); GetPaths(); } /// /// Print the available paths /// /// /// http(s)://{ipaddress}/cws/{basePath} /// http(s)://{ipaddress}/VirtualControl/Rooms/{roomId}/cws/{basePath} /// /// /// GetPaths method /// public void GetPaths() { Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50)); var currentIp = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); var hostname = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server ? $"https://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{BasePath}" : $"https://{currentIp}/cws{BasePath}"; Debug.LogMessage(LogEventLevel.Information, this, "Server:{path:l}", path); var routeCollection = _server.GetRouteCollection(); if (routeCollection == null) { Debug.LogMessage(LogEventLevel.Information, this, "Server route collection is null"); return; } Debug.LogMessage(LogEventLevel.Information, this, "Configured Routes:"); foreach (var route in routeCollection) { Debug.LogMessage(LogEventLevel.Information, this, "{routeName:l}: {routePath:l}/{routeUrl:l}", route.Name, path, route.Url); } Debug.LogInformation(this, "Web API initialized and ready to accept requests"); Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50)); var debugAppUrl = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server ? $"https://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws/debug" : $"https://{currentIp}/cws/debug"; Debug.LogMessage(LogEventLevel.Information, this, "Developer Tools Web App available at: {debugAppUrl:l}", debugAppUrl); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/EssentialsWebApiFactory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core.Web { /// /// Represents a EssentialsWebApiFactory /// public class EssentialsWebApiFactory : EssentialsDeviceFactory { /// /// Constructor /// public EssentialsWebApiFactory() { TypeNames = new List { "EssentialsWebApi" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Essentials Web API Server"); var props = dc.Properties.ToObject(); if (props != null) return new EssentialsWebApi(dc.Key, dc.Name, props); Debug.LogMessage(LogEventLevel.Debug, "Factory failed to create new Essentials Web API Server"); return null; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/EssentialsWebApiHelpers.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp.WebScripting; using PepperDash.Core; namespace PepperDash.Essentials.Core.Web { /// /// EssentialsWebApiHelpers class /// public static class EssentialsWebApiHelpers { /// /// GetRequestBody method /// public static string GetRequestBody(this HttpCwsRequest request) { var bytes = new byte[request.ContentLength]; request.InputStream.Read(bytes, 0, request.ContentLength); return Encoding.UTF8.GetString(bytes, 0, bytes.Length); } /// /// MapToAssemblyObject method /// public static object MapToAssemblyObject(LoadedAssembly assembly) { return new { assembly.Name, assembly.Version }; } /// /// MapToDeviceListObject method /// public static object MapToDeviceListObject(IKeyed device) { var interfaces = device.GetType() .GetInterfaces() .Select(i => i.Name) .ToList(); return new { device.Key, Name = (device is IKeyName) ? (device as IKeyName).Name : "---", Interfaces = interfaces }; } /// /// MapJoinToObject method /// public static object MapJoinToObject(string key, JoinMapBaseAdvanced join) { var kp = new KeyValuePair(key, join); return MapJoinToObject(kp); } /// /// MapJoinToObject method /// public static object MapJoinToObject(KeyValuePair join) { return new { DeviceKey = join.Key, Joins = join.Value.Joins.Select(j => MapJoinDataCompleteToObject(j)) }; } /// /// MapJoinDataCompleteToObject method /// public static object MapJoinDataCompleteToObject(KeyValuePair joinData) { return new { Signal = joinData.Key, Description = joinData.Value.Metadata.Description, JoinNumber = joinData.Value.JoinNumber, JoinSpan = joinData.Value.JoinSpan, JoinType = joinData.Value.Metadata.JoinType.ToString(), JoinCapabilities = joinData.Value.Metadata.JoinCapabilities.ToString() }; } /// /// MapDeviceTypeToObject method /// public static object MapDeviceTypeToObject(string key, DeviceFactoryWrapper device) { var kp = new KeyValuePair(key, device); return MapDeviceTypeToObject(kp); } /// /// MapDeviceTypeToObject method /// public static object MapDeviceTypeToObject(KeyValuePair device) { return new { Type = device.Key, Description = device.Value.Description, CType = device.Value.Type == null ? "---": device.Value.Type.ToString() }; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/EssentialsWebApiPropertiesConfig.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Core.Web { /// /// Represents a EssentialsWebApiPropertiesConfig /// public class EssentialsWebApiPropertiesConfig { /// /// Gets or sets the BasePath /// [JsonProperty("basePath")] public string BasePath { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/AppDebugRequestHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using System; using Serilog.Events; using Newtonsoft.Json.Converters; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a AppDebugRequestHandler /// public class AppDebugRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public AppDebugRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var appDebug = new AppDebug { MinimumLevel = Debug.WebsocketMinimumLogLevel }; var body = JsonConvert.SerializeObject(appDebug, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.Write(body, false); context.Response.End(); } /// /// Handles POST method requests /// /// protected override void HandlePost(HttpCwsContext context) { if (context.Request.ContentLength < 0) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var data = context.Request.GetRequestBody(); if (string.IsNullOrEmpty(data)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var appDebug = new AppDebug(); var requestBody = JsonConvert.DeserializeObject(data); Debug.SetWebSocketMinimumDebugLevel(requestBody.MinimumLevel); appDebug.MinimumLevel = Debug.WebsocketMinimumLogLevel; var responseBody = JsonConvert.SerializeObject(appDebug, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.Write(responseBody, false); context.Response.End(); } } /// /// Represents a AppDebug /// public class AppDebug { /// /// Gets or sets the MinimumLevel /// [JsonProperty("minimumLevel", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public LogEventLevel MinimumLevel { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/DebugSessionRequestHandler.cs ================================================ using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharpPro.EthernetCommunication; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using Serilog.Events; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a DebugSessionRequestHandler /// public class DebugSessionRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// public DebugSessionRequestHandler() : base(true) { } /// /// Gets details for a debug session /// /// protected override void HandleGet(Crestron.SimplSharp.WebScripting.HttpCwsContext context) { var routeData = context.Request.RouteData; if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } try { var ip = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); var port = 0; if (!Debug.WebsocketSink.IsRunning) { Debug.LogMessage(LogEventLevel.Information, "Starting WS Server"); // Generate a random port within a specified range port = new Random().Next(65435, 65535); // Start the WS Server Debug.WebsocketSink.StartServerAndSetPort(port); Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose); } var url = Debug.WebsocketSink.Url; object data = new { url = Debug.WebsocketSink.Url }; Debug.LogMessage(LogEventLevel.Information, "Debug Session URL: {0}", url); // Return the port number with the full url of the WS Server var res = JsonConvert.SerializeObject(data); context.Response.ContentType = "application/json"; context.Response.ContentEncoding = Encoding.UTF8; context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.Write(res, false); context.Response.End(); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Error: {0}", e); } } /// /// Stops a debug session /// /// protected override void HandlePost(HttpCwsContext context) { Debug.WebsocketSink.StopServer(); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.End(); Debug.LogMessage(LogEventLevel.Information, "Websocket Debug Session Stopped"); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/DefaultRequestHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a DefaultRequestHandler /// public class DefaultRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public DefaultRequestHandler() : base(true) { } /// /// Handles CONNECT method requests /// /// protected override void HandleConnect(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } /// /// Handles DELETE method requests /// /// protected override void HandleDelete(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } /// /// Handles HEAD method requests /// /// protected override void HandleHead(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } /// /// Handles OPTIONS method requests /// /// protected override void HandleOptions(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } /// /// Handles PATCH method requests /// /// protected override void HandlePatch(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } /// /// Handles POST method requests /// /// protected override void HandlePost(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } /// /// Handles PUT method requests /// /// protected override void HandlePut(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } /// /// Handles TRACE method requests /// /// protected override void HandleTrace(HttpCwsContext context) { context.Response.StatusCode = 418; context.Response.StatusDescription = "I'm a teapot"; context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/DevJsonRequestHandler.cs ================================================ using System; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using Serilog.Events; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a DevJsonRequestHandler /// public class DevJsonRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public DevJsonRequestHandler() : base(true) { } /// /// Handles POST method requests /// /// protected override void HandlePost(HttpCwsContext context) { var routeData = context.Request.RouteData; if(routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } if (context.Request.ContentLength < 0) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request: no body"; context.Response.End(); return; } var data = context.Request.GetRequestBody(); if (string.IsNullOrEmpty(data)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request: no body"; context.Response.End(); return; } try { var daw = new DeviceActionWrapper { DeviceKey = (string) deviceKey}; JsonConvert.PopulateObject(data, daw); Debug.LogMessage(LogEventLevel.Verbose, "Device Action Wrapper: {@wrapper}", null, daw); DeviceJsonApi.DoDeviceAction(daw); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.End(); } catch (Exception ex) { Debug.LogMessage(ex, "Error handling device command: {Exception}"); context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.Write(JsonConvert.SerializeObject(new { error = ex.Message }), false); context.Response.End(); } } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/DevListRequestHandler.cs ================================================ using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a DevListRequestHandler /// public class DevListRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public DevListRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var allDevices = DeviceManager.AllDevices; if (allDevices == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } allDevices.Sort((a, b) => string.Compare(a.Key, b.Key, System.StringComparison.Ordinal)); var deviceList = allDevices.Select(d => EssentialsWebApiHelpers.MapToDeviceListObject(d)).ToList(); var js = JsonConvert.SerializeObject(deviceList, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(js, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/DevMethodsRequestHandler.cs ================================================ using System.Text; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a DevMethodsRequestHandler /// public class DevMethodsRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public DevMethodsRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting DevMethods: {@routeData}", routeData); if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } object deviceObj; if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var device = DeviceManager.GetDeviceForKey(deviceObj.ToString()); if (device == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Device Not Found"; context.Response.End(); return; } var deviceMethods = DeviceJsonApi.GetMethods(device.Key); if (deviceMethods == null || deviceMethods.ToLower().Contains("no device")) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = Encoding.UTF8; context.Response.Write(deviceMethods, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/DevPropsRequestHandler.cs ================================================ using System.Text; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a DevPropsRequestHandler /// public class DevPropsRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public DevPropsRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } object deviceObj; if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var device = DeviceManager.GetDeviceForKey(deviceObj.ToString()); if (device == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Device Not Found"; context.Response.End(); return; } var deviceProperties = DeviceJsonApi.GetProperties(device.Key); if (deviceProperties == null || deviceProperties.ToLower().Contains("no device")) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = Encoding.UTF8; context.Response.Write(deviceProperties, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/DisableAllStreamDebugRequestHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a DisableAllStreamDebugRequestHandler /// public class DisableAllStreamDebugRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public DisableAllStreamDebugRequestHandler() : base(true) { } /// /// Handles POST method requests /// /// protected override void HandlePost(HttpCwsContext context) { DeviceManager.DisableAllDeviceStreamDebugging(); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/DoNotLoadConfigOnNextBootRequestHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a DoNotLoadConfigOnNextBootRequestHandler /// public class DoNotLoadConfigOnNextBootRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public DoNotLoadConfigOnNextBootRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var data = new Data { DoNotLoadConfigOnNextBoot = Debug.DoNotLoadConfigOnNextBoot }; var body = JsonConvert.SerializeObject(data, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.Write(body, false); context.Response.End(); } /// /// Handles POST method requests /// /// protected override void HandlePost(HttpCwsContext context) { if (context.Request.ContentLength < 0) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var data = context.Request.GetRequestBody(); if (string.IsNullOrEmpty(data)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var d = new Data(); var requestBody = JsonConvert.DeserializeAnonymousType(data, d); Debug.SetDoNotLoadConfigOnNextBoot(requestBody.DoNotLoadConfigOnNextBoot); var responseBody = JsonConvert.SerializeObject(d, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.Write(responseBody, false); context.Response.End(); } } /// /// Represents a Data /// public class Data { /// /// Gets or sets the DoNotLoadConfigOnNextBoot /// [JsonProperty("doNotLoadConfigOnNextBoot", NullValueHandling = NullValueHandling.Ignore)] public bool DoNotLoadConfigOnNextBoot { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetFeedbacksForDeviceRequestHandler.cs ================================================ using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a GetFeedbacksForDeviceRequestHandler /// public class GetFeedbacksForDeviceRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public GetFeedbacksForDeviceRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } object deviceObj; if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var device = DeviceManager.GetDeviceForKey(deviceObj.ToString()) as IHasFeedback; if (device == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } var boolFeedback = from feedback in device.Feedbacks.OfType() where !string.IsNullOrEmpty(feedback.Key) select new { FeedbackKey = feedback.Key, Value = feedback.BoolValue }; var intFeedback = from feedback in device.Feedbacks.OfType() where !string.IsNullOrEmpty(feedback.Key) select new { FeedbackKey = feedback.Key, Value = feedback.IntValue }; var stringFeedback = from feedback in device.Feedbacks.OfType() where !string.IsNullOrEmpty(feedback.Key) select new { FeedbackKey = feedback.Key, Value = feedback.StringValue ?? string.Empty }; var responseObj = new { BoolValues = boolFeedback, IntValues = intFeedback, SerialValues = stringFeedback }; var js = JsonConvert.SerializeObject(responseObj, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(js, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForBridgeKeyRequestHandler.cs ================================================ using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Bridges; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a GetJoinMapForBridgeKeyRequestHandler /// public class GetJoinMapForBridgeKeyRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public GetJoinMapForBridgeKeyRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } object bridgeObj; if (!routeData.Values.TryGetValue("bridgeKey", out bridgeObj)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var bridge = DeviceManager.GetDeviceForKey(bridgeObj.ToString()) as EiscApiAdvanced; if (bridge == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var joinMap = bridge.JoinMaps.Select(j => EssentialsWebApiHelpers.MapJoinToObject(j)).ToList(); if (joinMap == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } var js = JsonConvert.SerializeObject(joinMap, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(js, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetJoinMapForDeviceKeyRequestHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Bridges; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a GetJoinMapForDeviceKeyRequestHandler /// public class GetJoinMapForDeviceKeyRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public GetJoinMapForDeviceKeyRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } object bridgeObj; if (!routeData.Values.TryGetValue("bridgeKey", out bridgeObj)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } object deviceObj; if (!routeData.Values.TryGetValue("deviceKey", out deviceObj)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var bridge = DeviceManager.GetDeviceForKey(bridgeObj.ToString()) as EiscApiAdvanced; if (bridge == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } JoinMapBaseAdvanced deviceJoinMap; if (!bridge.JoinMaps.TryGetValue(deviceObj.ToString(), out deviceJoinMap)) { context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); return; } var joinMap = EssentialsWebApiHelpers.MapJoinToObject(deviceObj.ToString(), deviceJoinMap); var js = JsonConvert.SerializeObject(joinMap, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore, TypeNameHandling = TypeNameHandling.None }); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(js, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutesHandler.cs ================================================ using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a GetRoutesHandler /// public class GetRoutesHandler:WebApiBaseRequestHandler { private HttpCwsRouteCollection routeCollection; private string basePath; /// /// Constructor /// /// /// public GetRoutesHandler(HttpCwsRouteCollection routeCollection, string basePath) { this.routeCollection = routeCollection; this.basePath = basePath; } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var currentIp = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); var hostname = CrestronEthernetHelper.GetEthernetParameter( CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server ? $"https://{hostname}/VirtualControl/Rooms/{InitialParametersClass.RoomId}/cws{basePath}" : $"https://{currentIp}/cws{basePath}"; var response = JsonConvert.SerializeObject(new RoutesResponseObject() { Url = path, Routes = routeCollection }); context.Response.StatusCode = 200; context.Response.ContentType = "application/json"; context.Response.Headers.Add("Content-Type", "application/json"); context.Response.Write(response, false); context.Response.End(); } } /// /// Represents a RoutesResponseObject /// public class RoutesResponseObject { /// /// Gets or sets the Url /// [JsonProperty("url")] public string Url { set; get; } /// /// Gets or sets the Routes /// [JsonProperty("routes")] public HttpCwsRouteCollection Routes { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingDevicesAndTieLinesHandler.cs ================================================ using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Handles HTTP requests to retrieve routing devices and tielines information /// public class GetRoutingDevicesAndTieLinesHandler : WebApiBaseRequestHandler { public GetRoutingDevicesAndTieLinesHandler() : base(true) { } protected override void HandleGet(HttpCwsContext context) { var devices = new List(); // Get all devices from DeviceManager foreach (var device in DeviceManager.AllDevices) { var deviceInfo = new RoutingDeviceInfo { Key = device.Key, Name = (device as IKeyName)?.Name ?? device.Key }; // Check if device implements IRoutingInputs if (device is IRoutingInputs inputDevice) { deviceInfo.HasInputs = true; deviceInfo.InputPorts = inputDevice.InputPorts.Select(p => new PortInfo { Key = p.Key, SignalType = p.Type.ToString(), ConnectionType = p.ConnectionType.ToString(), IsInternal = p.IsInternal }).ToList(); } // Check if device implements IRoutingOutputs if (device is IRoutingOutputs outputDevice) { deviceInfo.HasOutputs = true; deviceInfo.OutputPorts = outputDevice.OutputPorts.Select(p => new PortInfo { Key = p.Key, SignalType = p.Type.ToString(), ConnectionType = p.ConnectionType.ToString(), IsInternal = p.IsInternal }).ToList(); } // Check if device implements IRoutingInputsOutputs if (device is IRoutingInputsOutputs) { deviceInfo.HasInputsAndOutputs = true; } // Only include devices that have routing capabilities if (deviceInfo.HasInputs || deviceInfo.HasOutputs) { devices.Add(deviceInfo); } } // Get all tielines var tielines = TieLineCollection.Default.Select(tl => new TieLineInfo { SourceDeviceKey = tl.SourcePort.ParentDevice.Key, SourcePortKey = tl.SourcePort.Key, DestinationDeviceKey = tl.DestinationPort.ParentDevice.Key, DestinationPortKey = tl.DestinationPort.Key, SignalType = tl.Type.ToString(), IsInternal = tl.IsInternal }).ToList(); var response = new RoutingSystemInfo { Devices = devices, TieLines = tielines }; var jsonResponse = JsonConvert.SerializeObject(response, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = Encoding.UTF8; context.Response.Write(jsonResponse, false); context.Response.End(); } } /// /// Represents the complete routing system information including devices and tielines /// public class RoutingSystemInfo { [JsonProperty("devices")] public List Devices { get; set; } [JsonProperty("tieLines")] public List TieLines { get; set; } } /// /// Represents a routing device with its ports information /// public class RoutingDeviceInfo { [JsonProperty("key")] public string Key { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("hasInputs")] public bool HasInputs { get; set; } [JsonProperty("hasOutputs")] public bool HasOutputs { get; set; } [JsonProperty("hasInputsAndOutputs")] public bool HasInputsAndOutputs { get; set; } [JsonProperty("inputPorts", NullValueHandling = NullValueHandling.Ignore)] public List InputPorts { get; set; } [JsonProperty("outputPorts", NullValueHandling = NullValueHandling.Ignore)] public List OutputPorts { get; set; } } /// /// Represents a routing port with its properties /// public class PortInfo { [JsonProperty("key")] public string Key { get; set; } [JsonProperty("signalType")] public string SignalType { get; set; } [JsonProperty("connectionType")] public string ConnectionType { get; set; } [JsonProperty("isInternal")] public bool IsInternal { get; set; } } /// /// Represents a tieline connection between two ports /// public class TieLineInfo { [JsonProperty("sourceDeviceKey")] public string SourceDeviceKey { get; set; } [JsonProperty("sourcePortKey")] public string SourcePortKey { get; set; } [JsonProperty("destinationDeviceKey")] public string DestinationDeviceKey { get; set; } [JsonProperty("destinationPortKey")] public string DestinationPortKey { get; set; } [JsonProperty("signalType")] public string SignalType { get; set; } [JsonProperty("isInternal")] public bool IsInternal { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetRoutingPortsHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using System.Collections.Generic; using System.Linq; using System.Text; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a GetRoutingPortsHandler /// public class GetRoutingPortsHandler : WebApiBaseRequestHandler { /// /// Constructor /// public GetRoutingPortsHandler() : base(true) { } /// /// Handles the GET request /// /// protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } if(!routeData.Values.TryGetValue("deviceKey", out var deviceKey)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var device = DeviceManager.GetDeviceForKey(deviceKey.ToString()); if (device == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Device Not Found"; context.Response.End(); return; } var inputPorts = (device as IRoutingInputs)?.InputPorts; var outputPorts = (device as IRoutingOutputs)?.OutputPorts; var response = JsonConvert.SerializeObject( new ReturnValue { InputPorts = inputPorts?.Select(p => p.Key).ToList(), OutputPorts = outputPorts?.Select(p => p.Key).ToList() }); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = Encoding.UTF8; context.Response.Write(response, false); context.Response.End(); } } internal class ReturnValue { /// /// Gets or sets the InputPorts /// [JsonProperty("inputPorts", NullValueHandling = NullValueHandling.Ignore)] public List InputPorts { get; set; } /// /// Gets or sets the OutputPorts /// [JsonProperty("outputPorts", NullValueHandling = NullValueHandling.Ignore)] public List OutputPorts { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTieLinesRequestHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using System.Linq; using System.Text; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a GetTieLinesRequestHandler /// public class GetTieLinesRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// public GetTieLinesRequestHandler() : base(true) { } /// /// Handles the GET request /// /// protected override void HandleGet(HttpCwsContext context) { var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new { sourceKey = tl.SourcePort.ParentDevice.Key, sourcePort = tl.SourcePort.Key, destinationKey = tl.DestinationPort.ParentDevice.Key, destinationPort = tl.DestinationPort.Key, type = tl.Type.ToString(), })); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = Encoding.UTF8; context.Response.Write(tieLineString, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesByFilterRequestHandler.cs ================================================ using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a GetTypesByFilterRequestHandler /// public class GetTypesByFilterRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public GetTypesByFilterRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } object filterObj; if (!routeData.Values.TryGetValue("filter", out filterObj)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var deviceFactory = DeviceFactory.GetDeviceFactoryDictionary(filterObj.ToString()); if (deviceFactory == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } var deviceTypes = deviceFactory.Select(t => EssentialsWebApiHelpers.MapDeviceTypeToObject(t)).ToList(); var js = JsonConvert.SerializeObject(deviceTypes, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(js, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/GetTypesRequestHandler.cs ================================================ using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a GetTypesRequestHandler /// public class GetTypesRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public GetTypesRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var routeData = context.Request.RouteData; if (routeData == null) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var deviceFactory = DeviceFactory.GetDeviceFactoryDictionary(null); if (deviceFactory == null) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } var deviceTypes = deviceFactory.Select(t => EssentialsWebApiHelpers.MapDeviceTypeToObject(t)).ToList(); var js = JsonConvert.SerializeObject(deviceTypes, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(js, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/LoadConfigRequestHandler.cs ================================================ using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a LoadConfigRequestHandler /// public class LoadConfigRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public LoadConfigRequestHandler() : base(true) { } /// /// Handles POST method requests /// /// protected override void HandlePost(HttpCwsContext context) { var message = ""; var cs = Global.ControlSystem as ILoadConfig; if(cs != null) cs.GoWithLoad(); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.Write(message, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/LoginRequestHandler.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp.CrestronAuthentication; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a LoginRequestHandler /// public class LoginRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public LoginRequestHandler() : base(true) { } /// /// Handles POST method requests for user login and token generation /// /// The HTTP context for the request. protected override void HandlePost(HttpCwsContext context) { try { if (context.Request.ContentLength < 0) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var data = context.Request.GetRequestBody(); if (string.IsNullOrEmpty(data)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var loginRequest = JsonConvert.DeserializeObject(data); if (loginRequest == null || string.IsNullOrEmpty(loginRequest.Username) || string.IsNullOrEmpty(loginRequest.Password)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } Authentication.UserToken token; try { token = Authentication.GetAuthenticationToken(loginRequest.Username, loginRequest.Password); } catch (ArgumentException) { context.Response.StatusCode = 401; context.Response.StatusDescription = "Bad Request"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(JsonConvert.SerializeObject(new { Error = "Unauthorized" }, Formatting.Indented), false); context.Response.End(); return; } if (!token.Valid) { context.Response.StatusCode = 401; context.Response.StatusDescription = "Unauthorized"; context.Response.End(); return; } context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(JsonConvert.SerializeObject( new { Token = new LoginResponse { UserName = token.UserName, Access = token.Access, State = token.State, Groups = token.Groups, ADConnect = token.ADConnect, Valid = token.Valid } }, Formatting.Indented), false); context.Response.End(); } catch (System.Exception ex) { context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(JsonConvert.SerializeObject(new { Error = ex.Message }, Formatting.Indented), false); context.Response.End(); } } } /// /// Represents a LoginRequest /// public class LoginRequest { /// /// Gets or sets the username. /// public string Username { get; set; } /// /// Gets or sets the password. /// public string Password { get; set; } } /// /// Represents a LoginResponse /// internal class LoginResponse { /// /// Gets or sets the username. /// public string UserName { get; set; } /// /// Gets or sets the access level. /// public Authentication.UserAuthenticationLevelEnum Access { get; set; } /// /// Gets or sets the token authenticated state. /// public Authentication.eTokenAuthenticatedState State { get; set; } /// /// Gets or sets the list of groups. /// public List Groups { get; set; } /// /// Gets or sets the active directory connection flag. /// public int ADConnect { get; set; } /// /// Gets or sets the valid flag indicating whether the token is valid. /// public bool Valid { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/ReportVersionsRequestHandler.cs ================================================ using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a ReportVersionsRequestHandler /// public class ReportVersionsRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public ReportVersionsRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var loadAssemblies = PluginLoader.LoadedAssemblies; if (loadAssemblies == null) { context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); return; } var assemblies = loadAssemblies.Select(a => EssentialsWebApiHelpers.MapToAssemblyObject(a)).ToList(); var js = JsonConvert.SerializeObject(assemblies, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(js, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/RestartProgramRequestHandler.cs ================================================ using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a RestartProgramRequestHandler /// public class RestartProgramRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public RestartProgramRequestHandler() : base(true) { } /// /// Handles POST method requests /// /// protected override void HandlePost(HttpCwsContext context) { var message = ""; if(CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance) CrestronConsole.SendControlSystemCommand($"progres -p:{InitialParametersClass.ApplicationNumber}", ref message); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.Write(message, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/ServeDebugAppRequestHandler.cs ================================================ using System; using System.Collections.Generic; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.WebScripting; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using Serilog.Events; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Serves the React debug app from the processor's /HTML/debug folder. /// The root route (debug) and all sub-paths (debug/{*filePath}) are handled here. /// Text assets are sent as UTF-8 strings; binary assets are written to the response /// OutputStream. Any sub-path that does not match a real file falls back to /// index.html so that client-side (React Router) routing continues to work. /// public class ServeDebugAppRequestHandler : WebApiBaseRequestHandler { private static readonly Dictionary MimeTypes = new Dictionary(StringComparer.OrdinalIgnoreCase) { { ".html", "text/html; charset=utf-8" }, { ".htm", "text/html; charset=utf-8" }, { ".js", "application/javascript" }, { ".mjs", "application/javascript" }, { ".jsx", "application/javascript" }, { ".css", "text/css" }, { ".json", "application/json" }, { ".map", "application/json" }, { ".svg", "image/svg+xml" }, { ".ico", "image/x-icon" }, { ".png", "image/png" }, { ".jpg", "image/jpeg" }, { ".jpeg", "image/jpeg" }, { ".gif", "image/gif" }, { ".woff", "font/woff" }, { ".woff2","font/woff2" }, { ".ttf", "font/ttf" }, { ".eot", "application/vnd.ms-fontobject" }, }; private static readonly HashSet TextExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { ".html", ".htm", ".js", ".mjs", ".jsx", ".css", ".json", ".map", ".svg", ".txt", ".xml" }; /// /// Constructor. CORS is enabled so browser dev-tools requests succeed. /// public ServeDebugAppRequestHandler() : base(true) { } /// /// Handles GET requests for the debug app and its static assets. /// protected override void HandleGet(HttpCwsContext context) { // When acting as the server-level fallback handler, only handle // requests that are actually for the /debug path; defer everything // else to the base class (which returns 501 Not Implemented). var rawUrl = context.Request.RawUrl ?? string.Empty; if (rawUrl.IndexOf("/debug", StringComparison.OrdinalIgnoreCase) < 0) { base.HandleGet(context); return; } try { var htmlDebugPath = GetHtmlDebugPath(); if (htmlDebugPath == null) { SendResponse(context, 500, "Internal Server Error"); return; } var requestedPath = GetRequestedFilePath(context); // Paths with no file extension are SPA client-side routes — serve index.html string candidate; if (string.IsNullOrEmpty(requestedPath) || !System.IO.Path.HasExtension(requestedPath)) { candidate = System.IO.Path.Combine(htmlDebugPath, "index.html"); } else { var relativePart = requestedPath.Replace('/', System.IO.Path.DirectorySeparatorChar); candidate = System.IO.Path.Combine(htmlDebugPath, relativePart); } // Resolve to an absolute path and guard against path-traversal attacks var resolvedCandidate = System.IO.Path.GetFullPath(candidate); var resolvedBase = System.IO.Path.GetFullPath(htmlDebugPath) + System.IO.Path.DirectorySeparatorChar; if (!resolvedCandidate.StartsWith(resolvedBase, StringComparison.OrdinalIgnoreCase)) { SendResponse(context, 403, "Forbidden"); return; } // Missing static asset → fall back to index.html (SPA deep-link support) if (!File.Exists(resolvedCandidate) && System.IO.Path.HasExtension(requestedPath ?? string.Empty)) { resolvedCandidate = System.IO.Path.Combine(htmlDebugPath, "index.html"); Debug.LogMessage(LogEventLevel.Debug, "ServeDebugAppRequestHandler: '{requestedPath:l}' not found, falling back to index.html", requestedPath); } if (!File.Exists(resolvedCandidate)) { SendResponse(context, 404, "Not Found"); return; } var ext = System.IO.Path.GetExtension(resolvedCandidate); var contentType = MimeTypes.TryGetValue(ext, out var mime) ? mime : "application/octet-stream"; context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = contentType; if (TextExtensions.Contains(ext)) { string content; using (var reader = new StreamReader(resolvedCandidate, Encoding.UTF8)) content = reader.ReadToEnd(); context.Response.ContentEncoding = Encoding.UTF8; context.Response.Write(content, false); } else { var bytes = System.IO.File.ReadAllBytes(resolvedCandidate); context.Response.OutputStream.Write(bytes, 0, bytes.Length); } context.Response.End(); } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Error, ex, "ServeDebugAppRequestHandler: Unhandled error serving '{rawUrl:l}'", context.Request.RawUrl); try { SendResponse(context, 500, "Internal Server Error"); } catch { /* best-effort */ } } } /// /// Resolves the absolute path of the /HTML/debug folder on the processor. /// /// /// Global.FilePathPrefix is always {root}/user/programX/ (or /// equivalent), so walking up two parents gives the processor root that /// contains the html folder. This mirrors the two-hop strategy used /// by AssetLoader.ExtractDevToolsZip so that serving and extraction /// always resolve to the same directory. /// private static string GetHtmlDebugPath() { try { var separators = new[] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar }; var programDir = new DirectoryInfo(Global.FilePathPrefix.TrimEnd(separators)); // Walk up two levels: {root}/user/programX/ → {root}/user/ → {root} // This matches the path calculation used in AssetLoader.ExtractDevToolsZip. var userOrNvramDir = programDir.Parent; var rootDir = userOrNvramDir?.Parent; if (rootDir == null) { Debug.LogMessage(LogEventLevel.Error, "ServeDebugAppRequestHandler: Cannot resolve HTML root from FilePathPrefix '{prefix:l}'", Global.FilePathPrefix); return null; } return System.IO.Path.Combine(rootDir.FullName, "html", "debug"); } catch (Exception ex) { Debug.LogMessage(LogEventLevel.Error, ex, "ServeDebugAppRequestHandler: Error resolving HTML debug path"); return null; } } /// /// Extracts the file sub-path from the request by parsing RawUrl. /// Returns an empty string when the URL ends at /debug (root hit). /// private static string GetRequestedFilePath(HttpCwsContext context) { var rawUrl = context.Request.RawUrl ?? string.Empty; // Locate the /debug segment in the URL const string debugToken = "/debug"; var idx = rawUrl.IndexOf(debugToken, StringComparison.OrdinalIgnoreCase); if (idx < 0) return string.Empty; var afterDebug = rawUrl.Substring(idx + debugToken.Length); // Strip query string var qIdx = afterDebug.IndexOf('?'); if (qIdx >= 0) afterDebug = afterDebug.Substring(0, qIdx); // Strip leading slash to get a relative file path return afterDebug.TrimStart('/'); } private static void SendResponse(HttpCwsContext context, int statusCode, string statusDescription) { context.Response.StatusCode = statusCode; context.Response.StatusDescription = statusDescription; context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/SetDeviceStreamDebugRequestHandler.cs ================================================ using System; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a SetDeviceStreamDebugRequestHandler /// public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler { /// /// Handles CONNECT method requests /// /// protected override void HandleConnect(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles DELETE method requests /// /// protected override void HandleDelete(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles HEAD method requests /// /// protected override void HandleHead(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles OPTIONS method requests /// /// protected override void HandleOptions(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles PATCH method requests /// /// protected override void HandlePatch(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles POST method requests /// /// protected override void HandlePost(HttpCwsContext context) { if (context.Request.ContentLength < 0) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } var data = context.Request.GetRequestBody(); if (data == null) { context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); return; } var config = new SetDeviceStreamDebugConfig(); var body = JsonConvert.DeserializeAnonymousType(data, config); if (body == null) { context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); return; } if (string.IsNullOrEmpty(body.DeviceKey) || string.IsNullOrEmpty(body.Setting)) { context.Response.StatusCode = 400; context.Response.StatusDescription = "Bad Request"; context.Response.End(); return; } if (!(DeviceManager.GetDeviceForKey(body.DeviceKey) is IStreamDebugging device)) { context.Response.StatusCode = 404; context.Response.StatusDescription = "Not Found"; context.Response.End(); return; } eStreamDebuggingSetting debugSetting; try { debugSetting = (eStreamDebuggingSetting)Enum.Parse(typeof(eStreamDebuggingSetting), body.Setting, true); } catch (Exception ex) { Debug.LogMessage(ex, "Exception handling set debug request"); context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); return; } try { var mins = Convert.ToUInt32(body.Timeout); if (mins > 0) { device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, mins); } else { device.StreamDebugging.SetDebuggingWithDefaultTimeout(debugSetting); } context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.End(); } catch (Exception ex) { Debug.LogMessage(ex, "Exception handling set debug request"); context.Response.StatusCode = 500; context.Response.StatusDescription = "Internal Server Error"; context.Response.End(); } } /// /// Handles PUT method requests /// /// protected override void HandlePut(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } /// /// Handles TRACE method requests /// /// protected override void HandleTrace(HttpCwsContext context) { context.Response.StatusCode = 501; context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } } /// /// Configuration class for SetDeviceStreamDebugRequestHandler /// public class SetDeviceStreamDebugConfig { /// /// Gets or sets the DeviceKey /// [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Include)] public string DeviceKey { get; set; } /// /// Gets or sets the Setting /// [JsonProperty("setting", NullValueHandling = NullValueHandling.Include)] public string Setting { get; set; } /// /// Gets or sets the Timeout /// [JsonProperty("timeout")] public int Timeout { get; set; } /// /// Constructor /// public SetDeviceStreamDebugConfig() { DeviceKey = null; Setting = null; Timeout = 15; } } } ================================================ FILE: src/PepperDash.Essentials.Core/Web/RequestHandlers/ShowConfigRequestHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core.Web.RequestHandlers { /// /// Represents a ShowConfigRequestHandler /// public class ShowConfigRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// /// /// base(true) enables CORS support by default /// public ShowConfigRequestHandler() : base(true) { } /// /// Handles GET method requests /// /// protected override void HandleGet(HttpCwsContext context) { var config = JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented); context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentType = "application/json"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; context.Response.Write(config, false); context.Response.End(); } } } ================================================ FILE: src/PepperDash.Essentials.Core/app.config ================================================  ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { /// /// Represents and audio endpoint /// public class GenericAudioOut : EssentialsDevice, IRoutingSink { /// /// Gets the current input port /// public RoutingInputPort CurrentInputPort => AnyAudioIn; /// /// Event fired when the current source changes /// public event SourceInfoChangeHandler CurrentSourceChange; /// /// Gets or sets the current source info key /// public string CurrentSourceInfoKey { get; set; } /// /// Gets or sets the current source info /// public SourceListItem CurrentSourceInfo { get { return _CurrentSourceInfo; } set { if (value == _CurrentSourceInfo) return; var handler = CurrentSourceChange; if (handler != null) handler(_CurrentSourceInfo, ChangeType.WillChange); _CurrentSourceInfo = value; if (handler != null) handler(_CurrentSourceInfo, ChangeType.DidChange); } } SourceListItem _CurrentSourceInfo; /// /// Gets or sets the AnyAudioIn /// public RoutingInputPort AnyAudioIn { get; private set; } /// /// Constructor for GenericAudioOut /// /// Device key /// Device name public GenericAudioOut(string key, string name) : base(key, name) { AnyAudioIn = new RoutingInputPort(RoutingPortNames.AnyAudioIn, eRoutingSignalType.Audio, eRoutingPortConnectionType.LineAudio, null, this); } #region IRoutingInputs Members /// /// Gets the collection of input ports /// public RoutingPortCollection InputPorts { get { return new RoutingPortCollection { AnyAudioIn }; } } #endregion } /// /// Represents a GenericAudioOutWithVolume /// public class GenericAudioOutWithVolume : GenericAudioOut, IHasVolumeDevice { /// /// Gets the volume device key /// public string VolumeDeviceKey { get; private set; } /// /// Gets the volume zone /// public uint VolumeZone { get; private set; } /// /// Gets the volume device /// public IBasicVolumeControls VolumeDevice { get { var dev = DeviceManager.GetDeviceForKey(VolumeDeviceKey); if (dev is IAudioZones) return (dev as IAudioZones).Zone[VolumeZone]; else return dev as IBasicVolumeControls; } } /// /// Constructor - adds the name to the attached audio device, if appropriate. /// /// /// /// /// public GenericAudioOutWithVolume(string key, string name, string audioDevice, uint zone) : base(key, name) { VolumeDeviceKey = audioDevice; VolumeZone = zone; } } /// /// Factory for creating GenericAudioOutWithVolume devices /// public class GenericAudioOutWithVolumeFactory : EssentialsDeviceFactory { /// /// Constructor for GenericAudioOutWithVolumeFactory /// public GenericAudioOutWithVolumeFactory() { TypeNames = new List() { "genericaudiooutwithvolume" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new GenericAudioOutWithVolumeFactory Device"); var zone = dc.Properties.Value("zone"); return new GenericAudioOutWithVolume(dc.Key, dc.Name, dc.Properties.Value("volumeDeviceKey"), zone); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.Devices.Common.AudioCodec { /// /// Abstract base class for audio codec devices /// public abstract class AudioCodecBase : EssentialsDevice, IHasDialer, IUsageTracking, IAudioCodecInfo { /// /// Event fired when call status changes /// public event EventHandler CallStatusChange; /// /// Gets or sets the CodecInfo /// public AudioCodecInfo CodecInfo { get; protected set; } #region IUsageTracking Members /// /// Gets or sets the UsageTracker /// public UsageTracking UsageTracker { get; set; } #endregion /// /// Returns true when any call is not in state Unknown, Disconnecting, Disconnected /// public bool IsInCall { get { bool value; if (ActiveCalls != null) value = ActiveCalls.Any(c => c.IsActiveCall); else value = false; return value; } } // In most cases only a single call can be active /// /// Gets or sets the ActiveCalls /// public List ActiveCalls { get; set; } /// /// Constructor for AudioCodecBase /// /// Device key /// Device name public AudioCodecBase(string key, string name) : base(key, name) { ActiveCalls = new List(); } /// /// Helper method to fire CallStatusChange event with old and new status /// protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call) { call.Status = newStatus; OnCallStatusChange(call); } /// /// Handles call status change events /// /// The call item that changed status protected void OnCallStatusChange(CodecActiveCallItem item) { var handler = CallStatusChange; if (handler != null) handler(this, new CodecCallStatusItemChangeEventArgs(item)); if (UsageTracker != null) { if (IsInCall && !UsageTracker.UsageTrackingStarted) UsageTracker.StartDeviceUsage(); else if (UsageTracker.UsageTrackingStarted && !IsInCall) UsageTracker.EndDeviceUsage(); } } #region IHasDialer Members /// public abstract void Dial(string number); /// public abstract void EndCall(CodecActiveCallItem activeCall); /// public abstract void EndAllCalls(); /// public abstract void AcceptCall(CodecActiveCallItem item); /// public abstract void RejectCall(CodecActiveCallItem item); /// public abstract void SendDtmf(string digit); #endregion } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs ================================================ namespace PepperDash.Essentials.Devices.Common.AudioCodec { /// /// Implements a common set of data about a codec /// public interface IAudioCodecInfo { /// /// Gets the codec information /// AudioCodecInfo CodecInfo { get; } } /// /// Stores general information about a codec /// public abstract class AudioCodecInfo { /// /// Gets or sets the phone number /// public abstract string PhoneNumber { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.AudioCodec { /// /// For rooms that have audio codec /// public interface IHasAudioCodec : IHasInCallFeedback { /// /// Gets the audio codec device /// AudioCodecBase AudioCodec { get; } //List ActiveCalls { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Devices.Common.Codec; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.AudioCodec { /// /// Represents a MockAC /// public class MockAC : AudioCodecBase { /// /// Constructor for MockAC /// /// Device key /// Device name /// MockAC properties configuration public MockAC(string key, string name, MockAcPropertiesConfig props) : base(key, name) { CodecInfo = new MockAudioCodecInfo(); CodecInfo.PhoneNumber = props.PhoneNumber; } /// /// Dial method /// /// public override void Dial(string number) { if (!IsInCall) { Debug.LogMessage(LogEventLevel.Debug, this, "Dial: {0}", number); var call = new CodecActiveCallItem() { Name = "Mock Outgoing Call", Number = number, Type = eCodecCallType.Audio, Status = eCodecCallStatus.Connected, Direction = eCodecCallDirection.Outgoing, Id = "mockAudioCall-1" }; ActiveCalls.Add(call); OnCallStatusChange(call); } else { Debug.LogMessage(LogEventLevel.Debug, this, "Already in call. Cannot dial new call."); } } /// /// EndCall method /// /// public override void EndCall(CodecActiveCallItem call) { Debug.LogMessage(LogEventLevel.Debug, this, "EndCall"); ActiveCalls.Remove(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); } /// /// EndAllCalls method /// /// public override void EndAllCalls() { Debug.LogMessage(LogEventLevel.Debug, this, "EndAllCalls"); for (int i = ActiveCalls.Count - 1; i >= 0; i--) { var call = ActiveCalls[i]; ActiveCalls.Remove(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); } } /// /// AcceptCall method /// /// public override void AcceptCall(CodecActiveCallItem call) { Debug.LogMessage(LogEventLevel.Debug, this, "AcceptCall"); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); } /// /// RejectCall method /// public override void RejectCall(CodecActiveCallItem call) { Debug.LogMessage(LogEventLevel.Debug, this, "RejectCall"); ActiveCalls.Remove(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); } /// /// SendDtmf method /// /// public override void SendDtmf(string s) { Debug.LogMessage(LogEventLevel.Debug, this, "BEEP BOOP SendDTMF: {0}", s); } /// /// TestIncomingAudioCall method /// /// Phone number to call from public void TestIncomingAudioCall(string number) { Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingAudioCall from {0}", number); var call = new CodecActiveCallItem() { Name = number, Id = number, Number = number, Type = eCodecCallType.Audio, Direction = eCodecCallDirection.Incoming }; ActiveCalls.Add(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); } } /// /// Represents a MockAudioCodecInfo /// public class MockAudioCodecInfo : AudioCodecInfo { string _phoneNumber; /// public override string PhoneNumber { get { return _phoneNumber; } set { _phoneNumber = value; } } } /// /// Represents a MockACFactory /// public class MockACFactory : EssentialsDeviceFactory { /// /// Constructor for MockACFactory /// public MockACFactory() { TypeNames = new List() { "mockac" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MockAc Device"); var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); return new AudioCodec.MockAC(dc.Key, dc.Name, props); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.AudioCodec { /// /// Represents a MockAcPropertiesConfig /// public class MockAcPropertiesConfig { /// /// Gets or sets the PhoneNumber /// [JsonProperty("phoneNumber")] public string PhoneNumber { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.Presets; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Enumeration of eCameraCapabilities values /// public enum eCameraCapabilities { /// /// No camera capabilities /// None = 0, /// /// Camera supports pan movement /// Pan = 1, /// /// Camera supports tilt movement /// Tilt = 2, /// /// Camera supports zoom functionality /// Zoom = 4, /// /// Camera supports focus adjustment /// Focus = 8 } /// /// Abstract base class for camera devices that provides common camera functionality and capabilities /// public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs { /// /// Gets or sets the ControlMode /// [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] public eCameraControlMode ControlMode { get; protected set; } #region IRoutingOutputs Members /// /// Gets or sets the OutputPorts /// [JsonIgnore] public RoutingPortCollection OutputPorts { get; protected set; } #endregion /// /// Gets a value indicating whether this camera supports pan movement /// [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] public bool CanPan { get { return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan; } } /// /// Gets a value indicating whether this camera supports tilt movement /// [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] public bool CanTilt { get { return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt; } } /// /// Gets a value indicating whether this camera supports zoom functionality /// [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] public bool CanZoom { get { return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom; } } /// /// Gets a value indicating whether this camera supports focus adjustment /// [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] public bool CanFocus { get { return (Capabilities & eCameraCapabilities.Focus) == eCameraCapabilities.Focus; } } /// /// Gets or sets a bitmasked value to indicate the movement capabilities of this camera /// protected eCameraCapabilities Capabilities { get; set; } /// /// Initializes a new instance of the CameraBase class with the specified device configuration /// /// The device configuration protected CameraBase(DeviceConfig config) : base(config) { OutputPorts = new RoutingPortCollection(); ControlMode = eCameraControlMode.Manual; } /// /// Initializes a new instance of the CameraBase class with the specified key and name /// /// The unique key for this camera device /// The friendly name for this camera device protected CameraBase(string key, string name) : this(new DeviceConfig { Name = name, Key = key }) { } /// /// Links the camera device to the API bridge for control and feedback /// /// The camera device to link /// The trilist for communication /// The starting join number for the camera controls /// The join map key for custom join mappings /// The EiscApiAdvanced bridge for advanced join mapping protected void LinkCameraToApi(CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { CameraControllerJoinMap joinMap = new CameraControllerJoinMap(joinStart); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); if (customJoins != null) { joinMap.SetCustomJoinData(customJoins); } Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); Debug.LogMessage(LogEventLevel.Information, "Linking to Bridge Type {0}", cameraDevice.GetType().Name.ToString()); var commMonitor = cameraDevice as ICommunicationMonitor; commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig( trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); var ptzCamera = cameraDevice as IHasCameraPtzControl; if (ptzCamera != null) { trilist.SetBoolSigAction(joinMap.PanLeft.JoinNumber, (b) => { if (b) { ptzCamera.PanLeft(); } else { ptzCamera.PanStop(); } }); trilist.SetBoolSigAction(joinMap.PanRight.JoinNumber, (b) => { if (b) { ptzCamera.PanRight(); } else { ptzCamera.PanStop(); } }); trilist.SetBoolSigAction(joinMap.TiltUp.JoinNumber, (b) => { if (b) { ptzCamera.TiltUp(); } else { ptzCamera.TiltStop(); } }); trilist.SetBoolSigAction(joinMap.TiltDown.JoinNumber, (b) => { if (b) { ptzCamera.TiltDown(); } else { ptzCamera.TiltStop(); } }); trilist.SetBoolSigAction(joinMap.ZoomIn.JoinNumber, (b) => { if (b) { ptzCamera.ZoomIn(); } else { ptzCamera.ZoomStop(); } }); trilist.SetBoolSigAction(joinMap.ZoomOut.JoinNumber, (b) => { if (b) { ptzCamera.ZoomOut(); } else { ptzCamera.ZoomStop(); } }); } var powerCamera = cameraDevice as IHasPowerControl; if (powerCamera != null) { trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () => powerCamera.PowerOn()); trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () => powerCamera.PowerOff()); var powerFbCamera = powerCamera as IHasPowerControlWithFeedback; if (powerFbCamera != null) { powerFbCamera.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]); powerFbCamera.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]); } } if (cameraDevice is ICommunicationMonitor) { var monitoredCamera = cameraDevice as ICommunicationMonitor; monitoredCamera.CommunicationMonitor.IsOnlineFeedback.LinkInputSig( trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); } if (cameraDevice is IHasCameraPresets) { // Set the preset lables when they change var presetsCamera = cameraDevice as IHasCameraPresets; presetsCamera.PresetsListHasChanged += new EventHandler((o, a) => { SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); }); SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); for (int i = 0; i < joinMap.PresetRecallStart.JoinSpan; i++) { int tempNum = i; trilist.SetSigTrueAction((ushort)(joinMap.PresetRecallStart.JoinNumber + tempNum), () => { presetsCamera.PresetSelect(tempNum); }); trilist.SetSigTrueAction((ushort)(joinMap.PresetSaveStart.JoinNumber + tempNum), () => { var label = trilist.GetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum)); presetsCamera.PresetStore(tempNum, label); }); } trilist.OnlineStatusChange += (sender, args) => { if (!args.DeviceOnLine) { return; } SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); }; } } private void SendCameraPresetNamesToApi(IHasCameraPresets presetsCamera, CameraControllerJoinMap joinMap, BasicTriList trilist) { for (int i = 1; i <= joinMap.NumberOfPresets.JoinNumber; i++) { int tempNum = i - 1; string label = ""; var preset = presetsCamera.Presets.FirstOrDefault(p => p.ID.Equals(i)); if (preset != null) label = preset.Description; trilist.SetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum), label); } } } /// /// Represents a CameraPreset /// public class CameraPreset : PresetBase { /// /// Initializes a new instance of the CameraPreset class /// /// The preset ID /// The preset description /// Whether the preset is defined /// Whether the preset can be defined public CameraPreset(int id, string description, bool isDefined, bool isDefinable) : base(id, description, isDefined, isDefinable) { } } /// /// Represents a CameraPropertiesConfig /// public class CameraPropertiesConfig { /// /// Gets or sets the CommunicationMonitorProperties /// public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } /// /// Gets or sets the Control /// public ControlPropertiesConfig Control { get; set; } /// /// Gets or sets the SupportsAutoMode /// [JsonProperty("supportsAutoMode")] public bool SupportsAutoMode { get; set; } /// /// Gets or sets the SupportsOffMode /// [JsonProperty("supportsOffMode")] public bool SupportsOffMode { get; set; } /// /// Gets or sets the Presets /// [JsonProperty("presets")] public List Presets { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Represents a CameraVisca /// [Obsolete("CameraVisca is no longer supported and will be removed in a future release. Use the CameraVisca plugin instead.")] public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IHasPowerControlWithFeedback, IBridgeAdvanced, IHasCameraFocusControl, IHasAutoFocusMode { private readonly CameraViscaPropertiesConfig PropertiesConfig; /// /// Gets or sets the Communication /// public IBasicCommunication Communication { get; private set; } /// /// Gets or sets the CommunicationMonitor /// public StatusMonitorBase CommunicationMonitor { get; private set; } /// /// Used to store the actions to parse inquiry responses as the inquiries are sent /// private readonly CrestronQueue> InquiryResponseQueue; /// /// Camera ID (Default 1) /// public byte ID = 0x01; /// /// Response ID used for VISCA communication /// public byte ResponseID; /// /// Slow speed value for pan movement /// public byte PanSpeedSlow = 0x10; /// /// Slow speed value for tilt movement /// public byte TiltSpeedSlow = 0x10; /// /// Fast speed value for pan movement /// public byte PanSpeedFast = 0x13; /// /// Fast speed value for tilt movement /// public byte TiltSpeedFast = 0x13; // private bool IsMoving; private bool IsZooming; bool _powerIsOn; /// /// Gets or sets a value indicating whether the camera power is on /// public bool PowerIsOn { get { return _powerIsOn; } private set { if (value != _powerIsOn) { _powerIsOn = value; PowerIsOnFeedback.FireUpdate(); CameraIsOffFeedback.FireUpdate(); } } } const byte ZoomInCmd = 0x02; const byte ZoomOutCmd = 0x03; const byte ZoomStopCmd = 0x00; /// /// Used to determine when to move the camera at a faster speed if a direction is held /// CTimer SpeedTimer; // TODO: Implment speed timer for PTZ controls long FastSpeedHoldTimeMs = 2000; byte[] IncomingBuffer = new byte[] { }; /// /// Feedback indicating whether the camera power is on /// public BoolFeedback PowerIsOnFeedback { get; private set; } /// /// Initializes a new instance of the CameraVisca class /// /// The unique key for this camera device /// The friendly name for this camera device /// The communication interface for VISCA protocol /// The camera properties configuration public CameraVisca(string key, string name, IBasicCommunication comm, CameraViscaPropertiesConfig props) : base(key, name) { InquiryResponseQueue = new CrestronQueue>(15); Presets = props.Presets; PropertiesConfig = props; ID = (byte)(props.Id + 0x80); ResponseID = (byte)((props.Id * 0x10) + 0x80); SetupCameraSpeeds(); OutputPorts.Add(new RoutingOutputPort("videoOut", eRoutingSignalType.Video, eRoutingPortConnectionType.None, null, this, true)); // Default to all capabilties Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; Communication = comm; if (comm is ISocketStatus socket) { // This instance uses IP control socket.ConnectionChange += new EventHandler(Socket_ConnectionChange); } else { // This instance uses RS-232 control } Communication.BytesReceived += new EventHandler(Communication_BytesReceived); PowerIsOnFeedback = new BoolFeedback("powerIsOn", () => { return PowerIsOn; }); CameraIsOffFeedback = new BoolFeedback("cameraIsOff", () => { return !PowerIsOn; }); if (props.CommunicationMonitorProperties != null) { CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties); } else { CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 20000, 120000, 300000, "\x81\x09\x04\x00\xFF"); } DeviceManager.AddDevice(CommunicationMonitor); } /// /// Sets up camera speed values based on config /// void SetupCameraSpeeds() { if (PropertiesConfig.FastSpeedHoldTimeMs > 0) { FastSpeedHoldTimeMs = PropertiesConfig.FastSpeedHoldTimeMs; } if (PropertiesConfig.PanSpeedSlow > 0) { PanSpeedSlow = (byte)PropertiesConfig.PanSpeedSlow; } if (PropertiesConfig.PanSpeedFast > 0) { PanSpeedFast = (byte)PropertiesConfig.PanSpeedFast; } if (PropertiesConfig.TiltSpeedSlow > 0) { TiltSpeedSlow = (byte)PropertiesConfig.TiltSpeedSlow; } if (PropertiesConfig.TiltSpeedFast > 0) { TiltSpeedFast = (byte)PropertiesConfig.TiltSpeedFast; } } /// /// CustomActivate method /// /// public override bool CustomActivate() { Communication.Connect(); CommunicationMonitor.StatusChange += (o, a) => { Debug.LogMessage(LogEventLevel.Verbose, this, "Communication monitor state: {0}", CommunicationMonitor.Status); }; CommunicationMonitor.Start(); CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator); return true; } /// /// LinkToApi method /// public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); } void Socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) { Debug.LogMessage(LogEventLevel.Verbose, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString()); if (e.Client.IsConnected) { } else { } } void SendBytes(byte[] b) { if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1 Debug.LogMessage(LogEventLevel.Verbose, this, "Sending:{0}", ComTextHelper.GetEscapedText(b)); Communication.SendBytes(b); } void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) { var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length]; try { // This is probably not thread-safe buffering // Append the incoming bytes with whatever is in the buffer IncomingBuffer.CopyTo(newBytes, 0); e.Bytes.CopyTo(newBytes, IncomingBuffer.Length); if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1 Debug.LogMessage(LogEventLevel.Verbose, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes)); byte[] message = new byte[] { }; // Search for the delimiter 0xFF character for (int i = 0; i < newBytes.Length; i++) { if (newBytes[i] == 0xFF) { // i will be the index of the delmiter character message = newBytes.Take(i).ToArray(); // Skip over what we just took and save the rest for next time newBytes = newBytes.Skip(i).ToArray(); } } if (message.Length > 0) { // Check for matching ID if (message[0] != ResponseID) { return; } switch (message[1]) { case 0x40: { // ACK received Debug.LogMessage(LogEventLevel.Verbose, this, "ACK Received"); break; } case 0x50: { if (message[2] == 0xFF) { // Completion received Debug.LogMessage(LogEventLevel.Verbose, this, "Completion Received"); } else { // Inquiry response received. Dequeue the next response handler and invoke it if (InquiryResponseQueue.Count > 0) { var inquiryAction = InquiryResponseQueue.Dequeue(); inquiryAction.Invoke(message.Skip(2).ToArray()); } else { Debug.LogMessage(LogEventLevel.Verbose, this, "Response Queue is empty. Nothing to dequeue."); } } break; } case 0x60: { // Error message switch (message[2]) { case 0x01: { // Message Length Error Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Message Length Error"); break; } case 0x02: { // Syntax Error Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Syntax Error"); break; } case 0x03: { // Command Buffer Full Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command Buffer Full"); break; } case 0x04: { // Command Cancelled Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command Cancelled"); break; } case 0x05: { // No Socket Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: No Socket"); break; } case 0x41: { // Command not executable Debug.LogMessage(LogEventLevel.Verbose, this, "Error from device: Command not executable"); break; } } break; } } if (message == new byte[] { ResponseID, 0x50, 0x02, 0xFF }) { PowerIsOn = true; } else if (message == new byte[] { ResponseID, 0x50, 0x03, 0xFF }) { PowerIsOn = false; } } } catch (Exception err) { Debug.LogMessage(LogEventLevel.Verbose, this, "Error parsing feedback: {0}", err); } finally { // Save whatever partial message is here IncomingBuffer = newBytes; } } /// /// Sends a pan/tilt command. If the command is not for fastSpeed then it starts a timer to initiate fast speed. /// /// The VISCA command to send /// Whether fast speed is enabled for this command private void SendPanTiltCommand(byte[] cmd, bool fastSpeedEnabled) { SendBytes(GetPanTiltCommand(cmd, fastSpeedEnabled)); if (!fastSpeedEnabled) { if (SpeedTimer != null) { StopSpeedTimer(); } // Start the timer to send fast speed if still moving after FastSpeedHoldTime elapses SpeedTimer = new CTimer((o) => SendPanTiltCommand(GetPanTiltCommand(cmd, true), true), FastSpeedHoldTimeMs); } } private void StopSpeedTimer() { if (SpeedTimer != null) { SpeedTimer.Stop(); SpeedTimer.Dispose(); SpeedTimer = null; } } /// /// Generates the pan/tilt command with either slow or fast speed /// /// /// /// private byte[] GetPanTiltCommand(byte[] cmd, bool fastSpeed) { byte panSpeed; byte tiltSpeed; if (!fastSpeed) { panSpeed = PanSpeedSlow; tiltSpeed = TiltSpeedSlow; } else { panSpeed = PanSpeedFast; tiltSpeed = TiltSpeedFast; } var temp = new byte[] { ID, 0x01, 0x06, 0x01, panSpeed, tiltSpeed }; int length = temp.Length + cmd.Length + 1; byte[] sum = new byte[length]; temp.CopyTo(sum, 0); cmd.CopyTo(sum, temp.Length); sum[length - 1] = 0xFF; return sum; } void SendPowerQuery() { SendBytes(new byte[] { ID, 0x09, 0x04, 0x00, 0xFF }); InquiryResponseQueue.Enqueue(HandlePowerResponse); } /// /// PowerOn method /// public void PowerOn() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x02, 0xFF }); SendPowerQuery(); } void HandlePowerResponse(byte[] response) { switch (response[0]) { case 0x02: { PowerIsOn = true; break; } case 0x03: { PowerIsOn = false; break; } } } /// /// PowerOff method /// public void PowerOff() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x03, 0xFF }); SendPowerQuery(); } /// /// PowerToggle method /// public void PowerToggle() { if (PowerIsOnFeedback.BoolValue) PowerOff(); else PowerOn(); } /// /// PanLeft method /// public void PanLeft() { SendPanTiltCommand(new byte[] { 0x01, 0x03 }, false); // IsMoving = true; } /// /// PanRight method /// public void PanRight() { SendPanTiltCommand(new byte[] { 0x02, 0x03 }, false); // IsMoving = true; } /// /// PanStop method /// public void PanStop() { Stop(); } /// /// TiltDown method /// public void TiltDown() { SendPanTiltCommand(new byte[] { 0x03, 0x02 }, false); // IsMoving = true; } /// /// TiltUp method /// public void TiltUp() { SendPanTiltCommand(new byte[] { 0x03, 0x01 }, false); // IsMoving = true; } /// /// TiltStop method /// public void TiltStop() { Stop(); } private void SendZoomCommand(byte cmd) { SendBytes(new byte[] { ID, 0x01, 0x04, 0x07, cmd, 0xFF }); } /// /// ZoomIn method /// public void ZoomIn() { SendZoomCommand(ZoomInCmd); IsZooming = true; } /// /// ZoomOut method /// public void ZoomOut() { SendZoomCommand(ZoomOutCmd); IsZooming = true; } /// /// ZoomStop method /// public void ZoomStop() { Stop(); } /// /// Stop method /// public void Stop() { if (IsZooming) { SendZoomCommand(ZoomStopCmd); IsZooming = false; } else { StopSpeedTimer(); SendPanTiltCommand(new byte[] { 0x03, 0x03 }, false); // IsMoving = false; } } /// /// PositionHome method /// public void PositionHome() { SendBytes(new byte[] { ID, 0x01, 0x06, 0x02, PanSpeedFast, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }); SendBytes(new byte[] { ID, 0x01, 0x04, 0x47, 0x00, 0x00, 0x00, 0x00, 0xFF }); } /// /// RecallPreset method /// public void RecallPreset(int presetNumber) { SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x02, (byte)presetNumber, 0xFF }); } /// /// SavePreset method /// public void SavePreset(int presetNumber) { SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF }); } #region IHasCameraPresets Members /// /// Event that is raised when the presets list has changed /// public event EventHandler PresetsListHasChanged; /// /// Raises the PresetsListHasChanged event /// protected void OnPresetsListHasChanged() { var handler = PresetsListHasChanged; if (handler == null) return; handler.Invoke(this, EventArgs.Empty); } /// /// Gets or sets the Presets /// public List Presets { get; private set; } /// /// PresetSelect method /// public void PresetSelect(int preset) { RecallPreset(preset); } /// /// PresetStore method /// public void PresetStore(int preset, string description) { SavePreset(preset); } #endregion #region IHasCameraFocusControl Members /// /// FocusNear method /// public void FocusNear() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x03, 0xFF }); } /// /// FocusFar method /// public void FocusFar() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x02, 0xFF }); } /// /// FocusStop method /// public void FocusStop() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x08, 0x00, 0xFF }); } /// /// TriggerAutoFocus method /// public void TriggerAutoFocus() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x18, 0x01, 0xFF }); SendAutoFocusQuery(); } #endregion #region IHasAutoFocus Members /// /// SetFocusModeAuto method /// public void SetFocusModeAuto() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x02, 0xFF }); SendAutoFocusQuery(); } /// /// SetFocusModeManual method /// public void SetFocusModeManual() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x03, 0xFF }); SendAutoFocusQuery(); } /// /// ToggleFocusMode method /// public void ToggleFocusMode() { SendBytes(new byte[] { ID, 0x01, 0x04, 0x38, 0x10, 0xFF }); SendAutoFocusQuery(); } #endregion void SendAutoFocusQuery() { SendBytes(new byte[] { ID, 0x09, 0x04, 0x38, 0xFF }); InquiryResponseQueue.Enqueue(HandleAutoFocusResponse); } void HandleAutoFocusResponse(byte[] response) { switch (response[0]) { case 0x02: { // Auto Mode PowerIsOn = true; break; } case 0x03: { // Manual Mode PowerIsOn = false; break; } } } #region IHasCameraOff Members /// /// Gets or sets the CameraIsOffFeedback /// public BoolFeedback CameraIsOffFeedback { get; private set; } /// /// CameraOff method /// public void CameraOff() { PowerOff(); } #endregion } /// /// Represents a CameraViscaFactory /// public class CameraViscaFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the CameraViscaFactory class /// public CameraViscaFactory() { TypeNames = new List() { "cameravisca" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new CameraVisca Device"); var comm = CommFactory.CreateCommForDevice(dc); var props = Newtonsoft.Json.JsonConvert.DeserializeObject( dc.Properties.ToString()); return new Cameras.CameraVisca(dc.Key, dc.Name, comm, props); } } /// /// Represents a CameraViscaPropertiesConfig /// public class CameraViscaPropertiesConfig : CameraPropertiesConfig { /// /// Control ID of the camera (1-7) /// Gets or sets the Id /// [JsonProperty("id")] public uint Id { get; set; } /// /// Slow Pan speed (0-18) /// [JsonProperty("panSpeedSlow")] public uint PanSpeedSlow { get; set; } /// /// Fast Pan speed (0-18) /// [JsonProperty("panSpeedFast")] public uint PanSpeedFast { get; set; } /// /// Slow tilt speed (0-18) /// [JsonProperty("tiltSpeedSlow")] public uint TiltSpeedSlow { get; set; } /// /// Fast tilt speed (0-18) /// [JsonProperty("tiltSpeedFast")] public uint TiltSpeedFast { get; set; } /// /// Time a button must be held before fast speed is engaged (Milliseconds) /// [JsonProperty("fastSpeedHoldTimeMs")] public uint FastSpeedHoldTimeMs { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Describes a camera with preset functionality /// public interface IHasCameraPresets { /// /// Event that is raised when the presets list has changed /// event EventHandler PresetsListHasChanged; /// /// Gets the list of camera presets /// List Presets { get; } /// /// Selects the specified preset /// /// The preset number to select void PresetSelect(int preset); /// /// Stores a preset at the specified location with the given description /// /// The preset number to store /// The description for the preset void PresetStore(int preset, string description); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/CameraSelectedEventArgs.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Event arguments for the CameraSelected event /// [Obsolete("Use CameraSelectedEventArgs instead. This class will be removed in a future version")] public class CameraSelectedEventArgs : EventArgs { /// /// Gets or sets the SelectedCamera /// public CameraBase SelectedCamera { get; private set; } /// /// Constructor for CameraSelectedEventArgs /// /// public CameraSelectedEventArgs(CameraBase camera) { SelectedCamera = camera; } } /// /// Event arguments for the CameraSelected event /// /// public class CameraSelectedEventArgs : EventArgs { /// /// Gets or sets the SelectedCamera /// public T SelectedCamera { get; private set; } /// /// Constructor for CameraSelectedEventArgs /// /// public CameraSelectedEventArgs(T camera) { SelectedCamera = camera; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IAmFarEndCamera.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Defines the contract for IAmFarEndCamera /// public interface IAmFarEndCamera : IKeyName { } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/ICameraCapabilities.cs ================================================ using Newtonsoft.Json; using PepperDash.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for camera capabilities /// public interface ICameraCapabilities: IKeyName { /// /// Indicates whether the camera can pan /// [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] bool CanPan { get; } /// /// Indicates whether the camera can tilt /// [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] bool CanTilt { get; } /// /// Indicates whether the camera can zoom /// [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] bool CanZoom { get; } /// /// Indicates whether the camera can focus /// [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] bool CanFocus { get; } } /// /// Indicates the capabilities of a camera /// public class CameraCapabilities : ICameraCapabilities { /// /// Unique Key /// [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key { get; set; } /// /// Isn't it obvious :) /// [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } /// /// Indicates whether the camera can pan /// [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] public bool CanPan { get; set; } /// /// Indicates whether the camera can tilt /// [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] public bool CanTilt { get; set; } /// /// Indicates whether the camera can zoom /// [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] public bool CanZoom { get; set; } /// /// Indicates whether the camera can focus /// [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] public bool CanFocus { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasAutoFocusMode.cs ================================================  namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for devices that have auto focus mode control /// public interface IHasAutoFocusMode : IHasCameraControls { /// /// Sets the focus mode to auto or manual, or toggles between them. /// void SetFocusModeAuto(); /// /// Sets the focus mode to manual, allowing for manual focus adjustments. /// void SetFocusModeManual(); /// /// Toggles the focus mode between auto and manual. /// void ToggleFocusMode(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraAutoMode.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for devices that have camera auto mode control /// public interface IHasCameraAutoMode : IHasCameraControls { /// /// Enables or disables the camera's auto mode, which may include automatic adjustments for focus, exposure, and other settings. /// void CameraAutoModeOn(); /// /// Disables the camera's auto mode, allowing for manual control of camera settings. /// void CameraAutoModeOff(); /// /// Toggles the camera's auto mode state. If the camera is in auto mode, it will switch to manual mode, and vice versa. /// void CameraAutoModeToggle(); /// /// Feedback that indicates whether the camera's auto mode is currently enabled. /// BoolFeedback CameraAutoModeIsOnFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraControls.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for devices that have camera controls /// public interface IHasCameraControls : IKeyName { } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraFocusControl.cs ================================================  namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Defines the contract for IHasCameraFocusControl /// public interface IHasCameraFocusControl : IHasCameraControls { /// /// Focuses the camera near /// void FocusNear(); /// /// Focuses the camera far /// void FocusFar(); /// /// Stops the camera focus movement /// void FocusStop(); /// /// Triggers the camera's auto focus functionality, if available. /// void TriggerAutoFocus(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMute.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Describes the ability to mute and unmute camera video /// public interface IHasCameraMute : IKeyName { /// /// Feedback that indicates whether the camera is muted /// BoolFeedback CameraIsMutedFeedback { get; } /// /// Mutes the camera video, preventing it from being sent to the far end /// void CameraMuteOn(); /// /// Unmutes the camera video, allowing it to be sent to the far end /// void CameraMuteOff(); /// /// Toggles the camera mute state. If the camera is muted, it will be unmuted, and vice versa. /// void CameraMuteToggle(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMuteWithUnmuteRequest.cs ================================================ using System; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for devices that can mute and unmute their camera video, with an event for unmute requests /// public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute { /// /// Event that is raised when a video unmute is requested, typically by the far end /// event EventHandler VideoUnmuteRequested; } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraOff.cs ================================================ using PepperDash.Essentials.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// To be implmented on codecs that can disable their camera(s) to blank the near end video /// public interface IHasCameraOff : IHasCameraControls { /// /// Feedback that indicates whether the camera is off /// BoolFeedback CameraIsOffFeedback { get; } /// /// Turns the camera off, blanking the near end video /// void CameraOff(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPanControl.cs ================================================  namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for camera pan control /// public interface IHasCameraPanControl : IHasCameraControls { /// /// Pans the camera left /// void PanLeft(); /// /// Pans the camera right /// void PanRight(); /// /// Stops the camera pan movement /// void PanStop(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPtzControl.cs ================================================  namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Defines the contract for IHasCameraPtzControl /// public interface IHasCameraPtzControl : IHasCameraPanControl, IHasCameraTiltControl, IHasCameraZoomControl { /// /// Resets the camera position /// void PositionHome(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraTiltControl.cs ================================================  namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Defines the contract for IHasCameraTiltControl /// public interface IHasCameraTiltControl : IHasCameraControls { /// /// Tilts the camera down /// void TiltDown(); /// /// Tilts the camera up /// void TiltUp(); /// /// Stops the camera tilt movement /// void TiltStop(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraZoomControl.cs ================================================  namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Defines the contract for IHasCameraZoomControl /// public interface IHasCameraZoomControl : IHasCameraControls { /// /// Zooms the camera in /// void ZoomIn(); /// /// Zooms the camera out /// void ZoomOut(); /// /// Stops the camera zoom movement /// void ZoomStop(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameras.cs ================================================ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using System; using System.Collections.Generic; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for devices that have cameras /// [Obsolete("Use IHasCamerasWithControls instead. This interface will be removed in a future version")] public interface IHasCameras : IKeyName { /// /// Event that is raised when a camera is selected /// event EventHandler CameraSelected; /// /// List of cameras on the device. This should be a list of CameraBase objects /// List Cameras { get; } /// /// The currently selected camera. This should be a CameraBase object /// CameraBase SelectedCamera { get; } /// /// Feedback that indicates the currently selected camera /// StringFeedback SelectedCameraFeedback { get; } /// /// Selects a camera from the list of available cameras based on the provided key. /// /// The unique identifier or name of the camera to select. void SelectCamera(string key); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCamerasWithControls.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.Core; using System; using System.Collections.Generic; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for devices that have cameras with controls /// public interface IHasCamerasWithControls : IKeyName, IKeyed { /// /// List of cameras on the device. This should be a list of IHasCameraControls objects /// List Cameras { get; } /// /// The currently selected camera. This should be an IHasCameraControls object /// IHasCameraControls SelectedCamera { get; } /// /// Feedback that indicates the currently selected camera /// StringFeedback SelectedCameraFeedback { get; } /// /// Event that is raised when a camera is selected /// event EventHandler> CameraSelected; /// /// Selects a camera from the list of available cameras based on the provided key. /// /// void SelectCamera(string key); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCodecCameras.cs ================================================  namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Defines the contract for IHasCodecCameras /// public interface IHasCodecCameras : IHasCameras, IHasFarEndCameraControl { } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasFarEndCameraControl.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Interface for devices that have a far end camera control /// public interface IHasFarEndCameraControl : IKeyName { /// /// Gets the far end camera, which is typically a CameraBase object that represents the camera at the far end of a call /// CameraBase FarEndCamera { get; } /// /// Feedback that indicates whether the far end camera is being controlled /// BoolFeedback ControllingFarEndCameraFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/eCameraControlMode.cs ================================================  namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Enum for camera control modes /// public enum eCameraControlMode { /// /// Manual control mode, where the camera is controlled directly by the user or system /// Manual = 0, /// /// Off control mode, where the camera is turned off or disabled /// Off, /// /// Auto control mode, where the camera automatically adjusts settings based on the environment or conditions /// Auto } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/Call.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a Call /// public class Call { /// /// Gets or sets the Number /// public string Number { get; set; } /// /// Gets or sets the Protocol /// public string Protocol { get; set; } /// /// Gets or sets the CallRate /// public string CallRate { get; set; } /// /// Gets or sets the CallType /// public string CallType { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec.Cisco { /// /// Describes the available tracking modes for a Cisco codec's Presenter Track feature. /// public enum ePresenterTrackMode { /// /// Presenter Track is turned off. /// Off, /// /// Presenter Track follows the speaker's movements. /// Follow, /// /// Presenter Track is set to background mode, where it tracks the speaker but does not actively follow. /// Background, /// /// Presenter Track is set to persistent mode, where it maintains a fixed position or focus on the speaker. /// Persistent } /// /// Describes the Presenter Track controls for a Cisco codec. /// public interface IPresenterTrack : IKeyed { /// /// /// bool PresenterTrackAvailability { get; } /// /// Feedback indicating whether Presenter Track is available. /// BoolFeedback PresenterTrackAvailableFeedback { get; } /// /// Feedback indicating the current status of Presenter Track is off /// BoolFeedback PresenterTrackStatusOffFeedback { get; } /// /// Feedback indicating the current status of Presenter Track is follow /// BoolFeedback PresenterTrackStatusFollowFeedback { get; } /// /// Feedback indicating the current status of Presenter Track is background /// BoolFeedback PresenterTrackStatusBackgroundFeedback { get; } /// /// Feedback indicating the current status of Presenter Track is persistent /// BoolFeedback PresenterTrackStatusPersistentFeedback { get; } /// /// Indicates the current status of Presenter Track. /// bool PresenterTrackStatus { get; } /// /// Turns off Presenter Track. /// void PresenterTrackOff(); /// /// Turns on Presenter Track in follow mode. /// void PresenterTrackFollow(); /// /// Turns on Presenter Track in background mode. /// void PresenterTrackBackground(); /// /// Turns on Presenter Track in persistent mode. /// void PresenterTrackPersistent(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec.Cisco { /// /// Describes the available tracking modes for a Cisco codec /// public interface ISpeakerTrack : IKeyed { /// /// Indicates whether Speaker Track is available on the codec. /// bool SpeakerTrackAvailability { get; } /// /// /// BoolFeedback SpeakerTrackAvailableFeedback { get; } /// /// Feedback indicating the current status of Speaker Track is off /// bool SpeakerTrackStatus { get; } /// /// Turns Speaker Track off /// void SpeakerTrackOff(); /// /// Turns Speaker Track on /// void SpeakerTrackOn(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs ================================================  using System; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a CodecActiveCallItem /// public class CodecActiveCallItem { /// /// Gets or sets the Name /// [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } /// /// Gets or sets the Number /// [JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)] public string Number { get; set; } /// /// Gets or sets the Type /// [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public eCodecCallType Type { get; set; } /// /// Gets or sets the Status /// [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public eCodecCallStatus Status { get; set; } /// /// Gets or sets the Direction /// [JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public eCodecCallDirection Direction { get; set; } /// /// Gets or sets the Id /// [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public string Id { get; set; } /// /// Gets or sets the IsOnHold /// [JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)] public bool IsOnHold { get; set; } /// /// Gets or sets the Duration /// [JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)] public TimeSpan Duration { get; set; } //public object CallMetaData { get; set; } /// /// Returns true when this call is any status other than /// Unknown, Disconnected, Disconnecting /// [JsonProperty("isActiveCall", NullValueHandling = NullValueHandling.Ignore)] public bool IsActiveCall { get { return !(Status == eCodecCallStatus.Disconnected || Status == eCodecCallStatus.Disconnecting || Status == eCodecCallStatus.Idle || Status == eCodecCallStatus.Unknown); } } } /// /// Represents a CodecCallStatusItemChangeEventArgs /// public class CodecCallStatusItemChangeEventArgs : EventArgs { /// /// Gets or sets the CallItem /// public CodecActiveCallItem CallItem { get; private set; } /// /// Initializes a new instance of the CodecCallStatusItemChangeEventArgs class /// /// The call item that changed public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item) { CallItem = item; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/CodecDirectory.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a codec directory /// public class CodecDirectory { /// /// Represents the contents of the directory /// We don't want to serialize this for messages to MobileControl. MC can combine Contacts and Folders to get the same data /// [JsonIgnore] public List CurrentDirectoryResults { get; private set; } /// /// Gets the Contacts in the CurrentDirectoryResults /// [JsonProperty("contacts")] public List Contacts { get { return CurrentDirectoryResults.OfType().Cast().ToList(); } } /// /// Gets the Folders in the CurrentDirectoryResults /// [JsonProperty("folders")] public List Folders { get { return CurrentDirectoryResults.OfType().Cast().ToList(); } } /// /// Used to store the ID of the current folder for CurrentDirectoryResults /// Gets or sets the ResultsFolderId /// [JsonProperty("resultsFolderId")] public string ResultsFolderId { get; set; } /// /// Constructor for /// public CodecDirectory() { CurrentDirectoryResults = new List(); } /// /// Adds folders to the directory /// /// public void AddFoldersToDirectory(List folders) { if (folders != null) CurrentDirectoryResults.AddRange(folders); SortDirectory(); } /// /// Adds contacts to the directory /// /// public void AddContactsToDirectory(List contacts) { if (contacts != null) CurrentDirectoryResults.AddRange(contacts); SortDirectory(); } /// /// Filters the CurrentDirectoryResults by the predicate /// /// public void FilterContacts(Func predicate) { CurrentDirectoryResults = CurrentDirectoryResults.Where(predicate).ToList(); } /// /// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically /// private void SortDirectory() { var sortedFolders = new List(); sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder)); sortedFolders.OrderBy(f => f.Name); var sortedContacts = new List(); sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact)); sortedFolders.OrderBy(c => c.Name); CurrentDirectoryResults.Clear(); CurrentDirectoryResults.AddRange(sortedFolders); CurrentDirectoryResults.AddRange(sortedContacts); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/CodecScheduleAwareness.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a CodecScheduleAwareness /// public class CodecScheduleAwareness { List _meetings; /// /// Event that is raised when a meeting event changes /// public event EventHandler MeetingEventChange; /// /// Event that is raised when the meetings list has changed /// public event EventHandler MeetingsListHasChanged; private int _meetingWarningMinutes = 5; //private Meeting _previousChangedMeeting; //private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown; /// /// Gets or sets the number of minutes before a meeting to issue a warning /// public int MeetingWarningMinutes { get { return _meetingWarningMinutes; } set { _meetingWarningMinutes = value; } } /// /// Setter triggers MeetingsListHasChanged event /// public List Meetings { get { return _meetings; } set { _meetings = value; MeetingsListHasChanged?.Invoke(this, new EventArgs()); } } private readonly CTimer _scheduleChecker; /// /// Initializes a new instance of the CodecScheduleAwareness class with default poll time /// public CodecScheduleAwareness() { Meetings = new List(); _scheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000); } /// /// Initializes a new instance of the CodecScheduleAwareness class with specified poll time /// /// The poll time in milliseconds for checking schedule changes public CodecScheduleAwareness(long pollTime) { Meetings = new List(); _scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime); } /// /// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting /// /// /// private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting) { Debug.LogMessage(LogEventLevel.Verbose, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType); if (changeType != (changeType & meeting.NotifiedChangeTypes)) { // Add this change type to the NotifiedChangeTypes meeting.NotifiedChangeTypes |= changeType; MeetingEventChange?.Invoke(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting }); } else { Debug.LogMessage(LogEventLevel.Verbose, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType); } } /// /// Checks the schedule to see if any MeetingEventChange updates should be fired /// /// private void CheckSchedule(object o) { // Iterate the meeting list and check if any meeting need to do anything const double meetingTimeEpsilon = 0.05; foreach (var m in Meetings) { var changeType = eMeetingEventChangeType.Unknown; if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start { Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds); changeType = eMeetingEventChangeType.MeetingStartWarning; } else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start { Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStart"); changeType = eMeetingEventChangeType.MeetingStart; } else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end { Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds); changeType = eMeetingEventChangeType.MeetingEndWarning; } else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended { Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEnd"); changeType = eMeetingEventChangeType.MeetingEnd; } if (changeType != eMeetingEventChangeType.Unknown) { OnMeetingChange(changeType, m); } } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/ContactMethod.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a ContactMethod /// public class ContactMethod { /// /// Gets or sets the ContactMethodId /// [JsonProperty("contactMethodId")] public string ContactMethodId { get; set; } /// /// Gets or sets the Number /// [JsonProperty("number")] public string Number { get; set; } /// /// Gets or sets the Device /// [JsonProperty("device")] [JsonConverter(typeof(StringEnumConverter))] public eContactMethodDevice Device { get; set; } /// /// Gets or sets the CallType /// [JsonProperty("callType")] [JsonConverter(typeof(StringEnumConverter))] public eContactMethodCallType CallType { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/DirectoryContact.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a DirectoryContact /// public class DirectoryContact : DirectoryItem { /// /// Gets or sets the ContactId /// [JsonProperty("contactId")] public string ContactId { get; set; } /// /// Gets or sets the Title /// [JsonProperty("title")] public string Title { get; set; } /// /// Gets or sets the ContactMethods /// [JsonProperty("contactMethods")] public List ContactMethods { get; set; } /// /// Constructor for /// public DirectoryContact() { ContactMethods = new List(); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/DirectoryEventArgs.cs ================================================ using System; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a DirectoryEventArgs /// public class DirectoryEventArgs : EventArgs { /// /// Gets or sets the Directory /// public CodecDirectory Directory { get; set; } /// /// Gets or sets the DirectoryIsOnRoot /// public bool DirectoryIsOnRoot { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/DirectoryFolder.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a DirectoryFolder /// public class DirectoryFolder : DirectoryItem { /// /// Gets or sets the Contacts /// [JsonProperty("contacts")] public List Contacts { get; set; } /// /// Constructor for /// public DirectoryFolder() { Contacts = new List(); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/DirectoryItem.cs ================================================ using System; using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a DirectoryItem /// public class DirectoryItem : ICloneable { /// /// Clone method /// public object Clone() { return MemberwiseClone(); } /// /// Gets or sets the FolderId /// [JsonProperty("folderId")] public string FolderId { get; set; } /// /// Gets or sets the Name /// [JsonProperty("name")] public string Name { get; set; } /// /// Gets or sets the ParentFolderId /// [JsonProperty("parentFolderId")] public string ParentFolderId { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Describes a cisco codec device that can allow configuration of cameras /// public interface ICiscoCodecCameraConfig { /// /// Sets the assigned serial number for the specified camera /// /// The camera identifier /// The serial number to assign void SetCameraAssignedSerialNumber(uint cameraId, string serialNumber); /// /// Sets the name for the camera on the specified video connector /// /// The video connector identifier /// The name to assign void SetCameraName(uint videoConnectorId, string name); /// /// Sets the input source type for the specified video connector /// /// The video connector identifier /// The source type to set void SetInputSourceType(uint videoConnectorId, eCiscoCodecInputSourceType sourceType); } /// /// Enumeration of Cisco codec input source types /// public enum eCiscoCodecInputSourceType { /// /// PC source type /// PC, /// /// Camera source type /// camera, /// /// Document camera source type /// document_camera, /// /// Media player source type /// mediaplayer, /// /// Other source type /// other, /// /// Whiteboard source type /// whiteboard } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the contract for IHasCallHold /// public interface IHasCallHold { /// /// Put the specified call on hold /// /// void HoldCall(CodecActiveCallItem activeCall); /// /// Resume the specified call /// /// void ResumeCall(CodecActiveCallItem activeCall); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/IHasDirectoryHistoryStack.cs ================================================ using System.Collections.Generic; using PepperDash.Essentials.Devices.Common.Codec; /// /// Defines the contract for IHasDirectoryHistoryStack /// public interface IHasDirectoryHistoryStack : IHasDirectory { /// /// Gets the DirectoryBrowseHistoryStack /// Stack DirectoryBrowseHistoryStack { get; } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Describes a device that has Do Not Disturb mode capability /// public interface IHasDoNotDisturbMode { /// /// Indictes whether Do Not Disturb mode is on (Activated) /// BoolFeedback DoNotDisturbModeIsOnFeedback { get; } /// /// Activates Do Not Disturb mode /// void ActivateDoNotDisturbMode(); /// /// Deactivates Do Not Disturb mode /// void DeactivateDoNotDisturbMode(); /// /// Toggles Do Not Disturb mode /// void ToggleDoNotDisturbMode(); } /// /// Defines the contract for devices that support Do Not Disturb mode with timeout functionality /// public interface IHasDoNotDisturbModeWithTimeout : IHasDoNotDisturbMode { /// /// Activates Do Not Disturb mode with a timeout /// /// void ActivateDoNotDisturbMode(int timeout); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs ================================================ using System; using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the contract for IHasExternalSourceSwitching /// public interface IHasExternalSourceSwitching { /// /// Gets a value indicating whether the external source list is enabled /// bool ExternalSourceListEnabled { get; } /// /// Gets the external source input port identifier /// string ExternalSourceInputPort { get; } /// /// Adds an external source to the available sources /// /// The connector identifier /// The unique key for the source /// The display name for the source /// The type of external source void AddExternalSource(string connectorId, string key, string name, eExternalSourceType type); /// /// Sets the state of the specified external source /// /// The unique key of the external source /// The mode to set for the source void SetExternalSourceState(string key, eExternalSourceMode mode); /// /// Clears all external sources from the list /// void ClearExternalSources(); /// /// Sets the selected source by its key /// /// The unique key of the source to select void SetSelectedSource(string key); /// /// Sets the action to run when routing between sources /// Action RunRouteAction { set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/IInvitableContact.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the contract for IInvitableContact /// public interface IInvitableContact { /// /// Gets a value indicating whether this contact is invitable /// bool IsInvitableContact { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/InvitableDirectoryContact.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents an InvitableDirectoryContact /// public class InvitableDirectoryContact : DirectoryContact, IInvitableContact { /// /// Gets a value indicating whether this contact is invitable /// [JsonProperty("isInvitableContact")] public bool IsInvitableContact { get { return this is IInvitableContact; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/Meeting.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a Meeting /// public class Meeting { /// /// Minutes before the meeting to show warning /// [JsonProperty("minutesBeforeMeeting")] public int MinutesBeforeMeeting; /// /// Gets or sets the meeting ID /// [JsonProperty("id")] public string Id { get; set; } /// /// Gets or sets the meeting organizer /// [JsonProperty("organizer")] public string Organizer { get; set; } /// /// Gets or sets the Title /// [JsonProperty("title")] public string Title { get; set; } /// /// Gets or sets the Agenda /// [JsonProperty("agenda")] public string Agenda { get; set; } /// /// Gets the meeting warning time span in minutes before the meeting starts /// [JsonProperty("meetingWarningMinutes")] public TimeSpan MeetingWarningMinutes { get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); } } /// /// Gets the time remaining until the meeting starts /// [JsonProperty("timeToMeetingStart")] public TimeSpan TimeToMeetingStart { get { return StartTime - DateTime.Now; } } /// /// Gets the time remaining until the meeting ends /// [JsonProperty("timeToMeetingEnd")] public TimeSpan TimeToMeetingEnd { get { return EndTime - DateTime.Now; } } /// /// Gets or sets the StartTime /// [JsonProperty("startTime")] public DateTime StartTime { get; set; } /// /// Gets or sets the EndTime /// [JsonProperty("endTime")] public DateTime EndTime { get; set; } /// /// Gets the duration of the meeting /// [JsonProperty("duration")] public TimeSpan Duration { get { return EndTime - StartTime; } } /// /// Gets or sets the Privacy /// [JsonProperty("privacy")] public eMeetingPrivacy Privacy { get; set; } /// /// Gets a value indicating whether the meeting can be joined /// [JsonProperty("joinable")] public bool Joinable { get { var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now && DateTime.Now <= EndTime.AddSeconds(-_joinableCooldownSeconds); //Debug.LogMessage(LogEventLevel.Verbose, "Meeting Id: {0} joinable: {1}", Id, joinable); return joinable; } } /// /// Gets or sets the Dialable /// [JsonProperty("dialable")] public bool Dialable { get; set; } //public string ConferenceNumberToDial { get; set; } /// /// Gets or sets the ConferencePassword /// [JsonProperty("conferencePassword")] public string ConferencePassword { get; set; } /// /// Gets or sets the IsOneButtonToPushMeeting /// [JsonProperty("isOneButtonToPushMeeting")] public bool IsOneButtonToPushMeeting { get; set; } /// /// Gets or sets the Calls /// [JsonProperty("calls")] public List Calls { get; private set; } /// /// Tracks the change types that have already been notified for /// Gets or sets the NotifiedChangeTypes /// [JsonIgnore] public eMeetingEventChangeType NotifiedChangeTypes { get; set; } [JsonIgnore] private readonly int _joinableCooldownSeconds; /// /// Constructor for Meeting /// public Meeting() { Calls = new List(); _joinableCooldownSeconds = 300; } /// /// Constructor for Meeting /// /// Number of seconds after meeting start when it is no longer joinable public Meeting(int joinableCooldownSeconds) { Calls = new List(); _joinableCooldownSeconds = joinableCooldownSeconds; } #region Overrides of Object /// /// ToString method /// /// public override string ToString() { return string.Format("{0}:{1}: {2}-{3}", Title, Agenda, StartTime, EndTime); } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/MeetingEventArgs.cs ================================================ using System; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Represents a MeetingEventArgs /// public class MeetingEventArgs : EventArgs { /// /// Gets or sets the ChangeType /// public eMeetingEventChangeType ChangeType { get; set; } /// /// Gets or sets the Meeting /// public Meeting Meeting { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eCodecCallDirection values /// public enum eCodecCallDirection { /// /// Unknown call direction /// Unknown = 0, /// /// Incoming call direction /// Incoming, /// /// Outgoing call direction /// Outgoing } /// /// Represents a CodecCallDirection /// public class CodecCallDirection { /// /// Takes the Cisco call type and converts to the matching enum /// /// /// /// /// ConvertToDirectionEnum method /// public static eCodecCallDirection ConvertToDirectionEnum(string s) { switch (s.ToLower()) { case "incoming": { return eCodecCallDirection.Incoming; } case "outgoing": { return eCodecCallDirection.Outgoing; } default: return eCodecCallDirection.Unknown; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eCodecCallStatus values /// public enum eCodecCallStatus { /// /// Unknown call status /// Unknown = 0, /// /// Call is connected /// Connected, /// /// Call is connecting /// Connecting, /// /// Call is dialing /// Dialing, /// /// Call is disconnected /// Disconnected, /// /// Call is disconnecting /// Disconnecting, /// /// Early media is being sent/received /// EarlyMedia, /// /// Call is idle /// Idle, /// /// Call is on hold /// OnHold, /// /// Call is ringing /// Ringing, /// /// Call is preserved /// Preserved, /// /// Call is remote preserved /// RemotePreserved, } /// /// Represents a CodecCallStatus /// public class CodecCallStatus { /// /// Takes the Cisco call type and converts to the matching enum /// /// /// /// /// ConvertToStatusEnum method /// public static eCodecCallStatus ConvertToStatusEnum(string s) { switch (s) { case "Connected": { return eCodecCallStatus.Connected; } case "Connecting": { return eCodecCallStatus.Connecting; } case "Dialling": { return eCodecCallStatus.Dialing; } case "Disconnected": { return eCodecCallStatus.Disconnected; } case "Disconnecting": { return eCodecCallStatus.Disconnecting; } case "EarlyMedia": { return eCodecCallStatus.EarlyMedia; } case "Idle": { return eCodecCallStatus.Idle; } case "OnHold": { return eCodecCallStatus.OnHold; } case "Ringing": { return eCodecCallStatus.Ringing; } case "Preserved": { return eCodecCallStatus.Preserved; } case "RemotePreserved": { return eCodecCallStatus.RemotePreserved; } default: return eCodecCallStatus.Unknown; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eCodecCallType values /// public enum eCodecCallType { /// /// Unknown call type /// Unknown = 0, /// /// Audio-only call type /// Audio, /// /// Video call type /// Video, /// /// Audio call that can be escalated to video /// AudioCanEscalate, /// /// Forward all call type /// ForwardAllCall } /// /// Represents a CodecCallType /// public class CodecCallType { /// /// Takes the Cisco call type and converts to the matching enum /// /// /// /// /// ConvertToTypeEnum method /// public static eCodecCallType ConvertToTypeEnum(string s) { switch (s) { case "Audio": { return eCodecCallType.Audio; } case "Video": { return eCodecCallType.Video; } case "AudioCanEscalate": { return eCodecCallType.AudioCanEscalate; } case "ForwardAllCall": { return eCodecCallType.ForwardAllCall; } default: return eCodecCallType.Unknown; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/eContactMethodCallType.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eContactMethodCallType values /// public enum eContactMethodCallType { /// /// Unknown call type /// Unknown = 0, /// /// Audio call type /// Audio, /// /// Video call type /// Video } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/eContactMethodDevice.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eContactMethodDevice values /// public enum eContactMethodDevice { /// /// Unknown contact method /// Unknown = 0, /// /// Mobile contact method /// Mobile, /// /// Other contact method /// Other, /// /// Telephone contact method /// Telephone, /// /// Video contact method /// Video } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/eMeetingEventChangeType.cs ================================================ using System; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eMeetingEventChangeType values /// [Flags] public enum eMeetingEventChangeType { /// /// Unknown change type /// Unknown = 0, /// /// Meeting start warning /// MeetingStartWarning = 1, /// /// Meeting start /// MeetingStart = 2, /// /// Meeting end warning /// MeetingEndWarning = 4, /// /// Meeting end /// MeetingEnd = 8 } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eMeetingPrivacy values /// public enum eMeetingPrivacy { /// /// Unknown meeting privacy level /// Unknown = 0, /// /// Public meeting /// Public, /// /// Private meeting /// Private } /// /// Represents a CodecCallPrivacy /// public class CodecCallPrivacy { /// /// Takes the Cisco privacy type and converts to the matching enum /// /// /// /// /// ConvertToDirectionEnum method /// public static eMeetingPrivacy ConvertToDirectionEnum(string s) { switch (s.ToLower()) { case "public": { return eMeetingPrivacy.Public; } case "private": { return eMeetingPrivacy.Private; } default: return eMeetingPrivacy.Unknown; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines minimum volume controls for a codec device with dialing capabilities /// public interface ICodecAudio : IBasicVolumeWithFeedback, IPrivacy { } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs ================================================ using System.Collections.Generic; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the contract for IHasCallFavorites /// public interface IHasCallFavorites { /// /// Gets the call favorites for this device /// CodecCallFavorites CallFavorites { get; } } /// /// Represents a CodecCallFavorites /// public class CodecCallFavorites { /// /// Gets or sets the Favorites /// public List Favorites { get; set; } /// /// Initializes a new instance of the CodecCallFavorites class /// public CodecCallFavorites() { Favorites = new List(); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs ================================================  using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the contract for IHasCallHistory /// public interface IHasCallHistory { /// /// Gets the call history for this device /// CodecCallHistory CallHistory { get; } /// /// Removes the specified call history entry /// /// The call history entry to remove void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry); } /// /// Enumeration of eCodecOccurrenceType values /// public enum eCodecOccurrenceType { /// /// Unknown occurrence type /// Unknown = 0, /// /// Call was placed (outgoing) /// Placed = 1, /// /// Call was received (incoming) /// Received = 2, /// /// Call received no answer /// NoAnswer = 3, } /// /// Represents a CodecCallHistory /// public class CodecCallHistory { /// /// Event that is raised when the recent calls list has changed /// public event EventHandler RecentCallsListHasChanged; /// /// Gets or sets the RecentCalls /// public List RecentCalls { get; private set; } /// /// Item that gets added to the list when there are no recent calls in history /// CallHistoryEntry ListEmptyEntry; /// /// Initializes a new instance of the CodecCallHistory class /// public CodecCallHistory() { ListEmptyEntry = new CallHistoryEntry() { Name = "No Recent Calls" }; RecentCalls = new List(); RecentCalls.Add(ListEmptyEntry); } void OnRecentCallsListChange() { var handler = RecentCallsListHasChanged; if (handler != null) { handler(this, new EventArgs()); } } /// /// RemoveEntry method /// public void RemoveEntry(CallHistoryEntry entry) { RecentCalls.Remove(entry); OnRecentCallsListChange(); } /// /// Represents a CallHistoryEntry /// public class CallHistoryEntry : CodecActiveCallItem { /// /// Gets or sets the StartTime /// [JsonConverter(typeof(IsoDateTimeConverter))] [JsonProperty("startTime")] public DateTime StartTime { get; set; } /// /// Gets or sets the occurrence type for this call history entry /// [JsonConverter(typeof(StringEnumConverter))] [JsonProperty("occurrenceType")] public eCodecOccurrenceType OccurrenceType { get; set; } /// /// Gets or sets the occurrence history identifier /// [JsonProperty("occurrenceHistoryId")] public string OccurrenceHistoryId { get; set; } } /// /// Converts a list of call history entries returned by a Cisco codec to the generic list type /// /// /// /// /// ConvertCiscoCallHistoryToGeneric method /// public void ConvertCiscoCallHistoryToGeneric(List entries) { var genericEntries = new List(); foreach (CiscoCallHistory.Entry entry in entries) { genericEntries.Add(new CallHistoryEntry() { Name = entry.DisplayName.Value, Number = entry.CallbackNumber.Value, StartTime = entry.LastOccurrenceStartTime.Value, OccurrenceHistoryId = entry.LastOccurrenceHistoryId.Value, OccurrenceType = ConvertToOccurenceTypeEnum(entry.OccurrenceType.Value) }); } // Check if list is empty and if so, add an item to display No Recent Calls if (genericEntries.Count == 0) genericEntries.Add(ListEmptyEntry); RecentCalls = genericEntries; OnRecentCallsListChange(); } /// /// Takes the Cisco occurence type and converts it to the matching enum /// /// /// /// ConvertToOccurenceTypeEnum method /// public eCodecOccurrenceType ConvertToOccurenceTypeEnum(string s) { switch (s) { case "Placed": { return eCodecOccurrenceType.Placed; } case "Received": { return eCodecOccurrenceType.Received; } case "NoAnswer": { return eCodecOccurrenceType.NoAnswer; } default: return eCodecOccurrenceType.Unknown; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the contract for IHasContentSharing /// public interface IHasContentSharing { /// /// Gets feedback indicating whether content sharing is currently active /// BoolFeedback SharingContentIsOnFeedback { get; } /// /// Gets feedback about the current sharing source /// StringFeedback SharingSourceFeedback { get; } /// /// Gets a value indicating whether content should be automatically shared while in a call /// bool AutoShareContentWhileInCall { get; } /// /// Starts content sharing /// void StartSharing(); /// /// Stops content sharing /// void StopSharing(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs ================================================ using System; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Requirements for a device that has dialing capabilities /// public interface IHasDialer { // Add requirements for Dialer functionality /// /// Event that is raised when call status changes /// event EventHandler CallStatusChange; /// /// Dials the specified number /// /// The number to dial void Dial(string number); /// /// Ends the specified active call /// /// The active call to end void EndCall(CodecActiveCallItem activeCall); /// /// Ends all active calls /// void EndAllCalls(); /// /// Accepts the specified incoming call /// /// The call item to accept void AcceptCall(CodecActiveCallItem item); /// /// Rejects the specified incoming call /// /// The call item to reject void RejectCall(CodecActiveCallItem item); /// /// Sends DTMF digits during a call /// /// The DTMF digit(s) to send void SendDtmf(string digit); /// /// Gets a value indicating whether the device is currently in a call /// bool IsInCall { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs ================================================  using System; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the API for codecs with a directory /// public interface IHasDirectory { /// /// Event that fires when a directory result is returned from the codec /// event EventHandler DirectoryResultReturned; /// /// Gets the DirectoryRoot /// CodecDirectory DirectoryRoot { get; } /// /// Gets the CurrentDirectoryResult /// CodecDirectory CurrentDirectoryResult { get; } /// /// Gets the PhonebookSyncState /// CodecPhonebookSyncState PhonebookSyncState { get; } /// /// Method to initiate a search of the directory on the server /// void SearchDirectory(string searchString); /// /// Method to get the contents of a specific folder in the directory on the server /// void GetDirectoryFolderContents(string folderId); /// /// Method to set the current directory to the root folder /// void SetCurrentDirectoryToRoot(); /// /// Method to get the contents of the parent folder in the directory on the server /// void GetDirectoryParentFolderContents(); /// /// Gets the CurrentDirectoryResultIsNotDirectoryRoot /// BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the contract for IHasScheduleAwareness /// public interface IHasScheduleAwareness { /// /// Gets the CodecScheduleAwareness instance /// CodecScheduleAwareness CodecSchedule { get; } /// /// Method to initiate getting the schedule from the server /// void GetSchedule(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs ================================================ using System; using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.Devices.Common.DSP { /// /// Base class for DSP devices /// public abstract class DspBase : EssentialsDevice, ILevelControls { /// /// Gets the collection of level control points /// public Dictionary LevelControlPoints { get; private set; } /// /// Gets the collection of dialer control points /// public Dictionary DialerControlPoints { get; private set; } /// /// Gets the collection of switcher control points /// public Dictionary SwitcherControlPoints { get; private set; } /// /// Initializes a new instance of the DspBase class /// /// The device key /// The device name public DspBase(string key, string name) : base(key, name) { LevelControlPoints = new Dictionary(); DialerControlPoints = new Dictionary(); SwitcherControlPoints = new Dictionary(); } // in audio call feedback // VOIP // Phone dialer } // Fusion // Privacy state // Online state // level/mutes ? // AC Log call stats // Typical presets: // call default preset to restore levels and mutes /// /// Base class for DSP control points /// public abstract class DspControlPoint : IKeyName { /// /// Gets or sets the Key /// public string Key { get; } /// /// Gets or sets the Name /// public string Name { get; private set; } /// /// Initializes a new instance of the DspControlPoint class /// /// The control point key protected DspControlPoint(string key) => Key = key; } /// /// Base class for DSP level control points with volume and mute functionality /// public abstract class DspLevelControlPoint : DspControlPoint, IBasicVolumeWithFeedback { /// /// Gets or sets the MuteFeedback /// public BoolFeedback MuteFeedback { get; } /// /// Gets or sets the VolumeLevelFeedback /// public IntFeedback VolumeLevelFeedback { get; } /// /// Initializes a new instance of the DspLevelControlPoint class /// /// The control point key /// Function to get mute status /// Function to get volume level protected DspLevelControlPoint(string key, Func muteFeedbackFunc, Func volumeLevelFeedbackFunc) : base(key) { MuteFeedback = new BoolFeedback("mute", muteFeedbackFunc); VolumeLevelFeedback = new IntFeedback("volume", volumeLevelFeedbackFunc); } /// /// Turns mute off /// public abstract void MuteOff(); /// /// Turns mute on /// public abstract void MuteOn(); /// /// Toggles mute state /// public abstract void MuteToggle(); /// /// Sets the volume level /// /// The volume level to set public abstract void SetVolume(ushort level); /// /// Decreases volume /// /// True when pressed, false when released public abstract void VolumeDown(bool pressRelease); /// /// Increases volume /// /// True when pressed, false when released public abstract void VolumeUp(bool pressRelease); } /// /// Base class for DSP dialer control points /// public abstract class DspDialerBase : DspControlPoint { /// /// Initializes a new instance of the DspDialerBase class /// /// The dialer control point key protected DspDialerBase(string key) : base(key) { } } // Main program // VTC // ATC // Mics, unusual } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs ================================================  using System; using System.Linq; using System.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a DeviceFactory /// public class DeviceFactory { /// /// Initializes a new instance of the DeviceFactory class /// public DeviceFactory() { var assy = Assembly.GetExecutingAssembly(); PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy); var types = assy.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract); if (types != null) { foreach (var type in types) { try { var factory = (IDeviceFactory)Activator.CreateInstance(type); LoadDeviceFactories(factory); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, "Unable to load type: '{1}' DeviceFactory: {0}", e, type.Name); } } } } /// /// Loads device factories from the specified plugin device factory and registers them for use. /// /// This method retrieves metadata from the provided , including /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type /// names are converted to lowercase for registration. /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered. private static void LoadDeviceFactories(IDeviceFactory deviceFactory) { foreach (var typeName in deviceFactory.TypeNames) { //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); string description = (deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0) ? descriptionAttribute[0].Description : "No description available"; Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice); } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Displays { /// /// Represents a BasicIrDisplay /// public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced { /// /// Gets or sets the IrPort /// public IrOutputPortController IrPort { get; private set; } /// /// Gets or sets the IrPulseTime /// public ushort IrPulseTime { get; set; } /// /// Gets the power is on feedback function /// protected Func PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } } /// /// Gets the is cooling down feedback function /// protected override Func IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } } /// /// Gets the is warming up feedback function /// protected override Func IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } } bool _PowerIsOn; bool _IsWarmingUp; bool _IsCoolingDown; /// /// Initializes a new instance of the BasicIrDisplay class /// /// The device key /// The device name /// The IR output port /// The path to the IR driver file public BasicIrDisplay(string key, string name, IROutputPort port, string irDriverFilepath) : base(key, name) { IrPort = new IrOutputPortController(key + "-ir", port, irDriverFilepath); DeviceManager.AddDevice(IrPort); IsWarmingUpFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Warming up={0}", _IsWarmingUp); IsCoolingDownFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Cooling down={0}", _IsCoolingDown); InputPorts.AddRange(new RoutingPortCollection { new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi1), this, false), new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi2), this, false), new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi3), this, false), new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi4), this, false), new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Component1), this, false), new RoutingInputPort(RoutingPortNames.CompositeIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Video1), this, false), new RoutingInputPort(RoutingPortNames.AntennaIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Antenna), this, false), }); } /// /// Hdmi1 method /// public void Hdmi1() { IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_1, IrPulseTime); } /// /// Hdmi2 method /// public void Hdmi2() { IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_2, IrPulseTime); } /// /// Hdmi3 method /// public void Hdmi3() { IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_3, IrPulseTime); } /// /// Hdmi4 method /// public void Hdmi4() { IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_4, IrPulseTime); } /// /// Component1 method /// public void Component1() { IrPort.Pulse(IROutputStandardCommands.IROut_COMPONENT_1, IrPulseTime); } /// /// Video1 method /// public void Video1() { IrPort.Pulse(IROutputStandardCommands.IROut_VIDEO_1, IrPulseTime); } /// /// Antenna method /// public void Antenna() { IrPort.Pulse(IROutputStandardCommands.IROut_ANTENNA, IrPulseTime); } #region IPower Members /// /// PowerOn method /// /// public override void PowerOn() { IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime); _PowerIsOn = true; } /// /// PowerOff method /// public override void PowerOff() { _PowerIsOn = false; IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime); } /// /// PowerToggle method /// public override void PowerToggle() { _PowerIsOn = false; IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime); } #endregion #region IBasicVolumeControls Members /// /// VolumeUp method /// public void VolumeUp(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_PLUS, pressRelease); } /// /// VolumeDown method /// public void VolumeDown(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_MINUS, pressRelease); } /// /// MuteToggle method /// public void MuteToggle() { IrPort.Pulse(IROutputStandardCommands.IROut_MUTE, 200); } #endregion void StartWarmingTimer() { _IsWarmingUp = true; IsWarmingUpFeedback.FireUpdate(); new CTimer(o => { _IsWarmingUp = false; IsWarmingUpFeedback.FireUpdate(); }, 10000); } void StartCoolingTimer() { _IsCoolingDown = true; IsCoolingDownFeedback.FireUpdate(); new CTimer(o => { _IsCoolingDown = false; IsCoolingDownFeedback.FireUpdate(); }, 7000); } #region IRoutingSink Members /// /// Typically called by the discovery routing algorithm. /// /// A delegate containing the input selector method to call /// /// ExecuteSwitch method /// /// public override void ExecuteSwitch(object inputSelector) { Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString()); Action finishSwitch = () => { var action = inputSelector as Action; if (action != null) action(); }; if (!_PowerIsOn) { PowerOn(); EventHandler oneTimer = null; oneTimer = (o, a) => { if (IsWarmingUpFeedback.BoolValue) return; // Only catch done warming IsWarmingUpFeedback.OutputChange -= oneTimer; finishSwitch(); }; IsWarmingUpFeedback.OutputChange += oneTimer; } else // Do it! finishSwitch(); } #endregion /// /// LinkToApi method /// public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge); } } /// /// Represents a BasicIrDisplayFactory /// public class BasicIrDisplayFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the BasicIrDisplayFactory class /// public BasicIrDisplayFactory() { TypeNames = new List() { "basicirdisplay" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BasicIrDisplay Device"); var ir = IRPortHelper.GetIrPort(dc.Properties); if (ir != null) { var display = new BasicIrDisplay(dc.Key, dc.Name, ir.Port, ir.FileName); display.IrPulseTime = 200; // Set default pulse time for IR commands. return display; } return null; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Routing; using Serilog.Events; using Feedback = PepperDash.Essentials.Core.Feedback; namespace PepperDash.Essentials.Devices.Common.Displays { /// /// Abstract base class for display devices that provides common display functionality /// including power control, input switching, and routing capabilities. /// public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources, IHasFeedback { private RoutingInputPort _currentInputPort; /// /// Gets or sets the current input port that is selected on the display. /// public RoutingInputPort CurrentInputPort { get { return _currentInputPort; } protected set { if (_currentInputPort == value) return; _currentInputPort = value; InputChanged?.Invoke(this, _currentInputPort); } } /// /// Event that is raised when the input changes on the display. /// public event InputChangedEventHandler InputChanged; /// /// Event that is raised when the current source information changes. /// public event SourceInfoChangeHandler CurrentSourceChange; /// /// Gets or sets the CurrentSourceInfoKey /// public string CurrentSourceInfoKey { get; set; } /// /// Gets or sets the current source information for the display. /// public SourceListItem CurrentSourceInfo { get { return _CurrentSourceInfo; } set { if (value == _CurrentSourceInfo) return; var handler = CurrentSourceChange; handler?.Invoke(_CurrentSourceInfo, ChangeType.WillChange); _CurrentSourceInfo = value; handler?.Invoke(_CurrentSourceInfo, ChangeType.DidChange); } } SourceListItem _CurrentSourceInfo; /// public Dictionary CurrentSources { get; private set; } /// public Dictionary CurrentSourceKeys { get; private set; } /// public event EventHandler CurrentSourcesChanged; /// /// Gets feedback indicating whether the display is currently cooling down after being powered off. /// public BoolFeedback IsCoolingDownFeedback { get; protected set; } /// /// Gets or sets the IsWarmingUpFeedback /// public BoolFeedback IsWarmingUpFeedback { get; private set; } /// /// Gets or sets the UsageTracker /// public UsageTracking UsageTracker { get; set; } /// /// Gets or sets the WarmupTime /// public uint WarmupTime { get; set; } /// /// Gets or sets the CooldownTime /// public uint CooldownTime { get; set; } /// /// Abstract function that must be implemented by derived classes to provide the cooling down feedback value. /// Must be implemented by concrete sub-classes. /// abstract protected Func IsCoolingDownFeedbackFunc { get; } /// /// Abstract function that must be implemented by derived classes to provide the warming up feedback value. /// Must be implemented by concrete sub-classes. /// abstract protected Func IsWarmingUpFeedbackFunc { get; } /// /// Timer used for managing display warmup timing. /// protected CTimer WarmupTimer; /// /// Timer used for managing display cooldown timing. /// protected CTimer CooldownTimer; #region IRoutingInputs Members /// /// Gets the collection of input ports available on this display device. /// public RoutingPortCollection InputPorts { get; private set; } #endregion /// /// Initializes a new instance of the DisplayBase class. /// /// The unique key identifier for this display device. /// The friendly name for this display device. protected DisplayBase(string key, string name) : base(key, name) { IsCoolingDownFeedback = new BoolFeedback("IsCoolingDown", IsCoolingDownFeedbackFunc); IsWarmingUpFeedback = new BoolFeedback("IsWarmingUp", IsWarmingUpFeedbackFunc); Feedbacks.Add(IsCoolingDownFeedback); Feedbacks.Add(IsWarmingUpFeedback); InputPorts = new RoutingPortCollection(); CurrentSources = new Dictionary { { eRoutingSignalType.Audio, null }, { eRoutingSignalType.Video, null }, }; CurrentSourceKeys = new Dictionary { { eRoutingSignalType.Audio, string.Empty }, { eRoutingSignalType.Video, string.Empty }, }; } /// /// Powers on the display device. Must be implemented by derived classes. /// public abstract void PowerOn(); /// /// Powers off the display device. Must be implemented by derived classes. /// public abstract void PowerOff(); /// /// Toggles the power state of the display device. Must be implemented by derived classes. /// public abstract void PowerToggle(); /// /// Gets the collection of feedback objects for this display device. /// /// public virtual FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); /// /// Executes a switch to the specified input on the display device. Must be implemented by derived classes. /// /// The selector object that identifies which input to switch to. public abstract void ExecuteSwitch(object selector); /// /// Links the display device to an API using a trilist, join start, join map key, and bridge. /// This overload uses serialized join map configuration. /// /// The display device to link. /// The BasicTriList for communication. /// The starting join number for the device. /// The key for the join map configuration. /// The EISC API bridge instance. protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new DisplayControllerJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } LinkDisplayToApi(displayDevice, trilist, joinMap); } /// /// Links the display device to an API using a trilist and join map. /// This overload uses a pre-configured join map instance. /// /// The display device to link. /// The BasicTriList for communication. /// The join map configuration for the device. protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, DisplayControllerJoinMap joinMap) { this.LogDebug("Linking to Trilist {ipId}", trilist.ID.ToString("X")); this.LogDebug("Linking to Display: {displayName}", displayDevice.Name); trilist.StringInput[joinMap.Name.JoinNumber].StringValue = displayDevice.Name; if (displayDevice is ICommunicationMonitor commMonitor) { commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); } // TODO: revisit this as there could be issues with this approach var inputNumber = 0; var inputKeys = new List(); var inputNumberFeedback = new IntFeedback("inputNumber", () => inputNumber); // Add input number feedback to the device feedback collection to keep it around... Feedbacks.Add(inputNumberFeedback); // Two way feedbacks if (displayDevice is TwoWayDisplayBase twoWayDisplay) { trilist.SetBool(joinMap.IsTwoWayDisplay.JoinNumber, true); twoWayDisplay.CurrentInputFeedback.OutputChange += (o, a) => this.LogDebug("CurrentInputFeedback_OutputChange {input}", a.StringValue); inputNumberFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputSelect.JoinNumber]); twoWayDisplay.PowerIsOnFeedback.OutputChange += (o, a) => { if (!a.BoolValue) { inputNumber = 102; inputNumberFeedback.FireUpdate(); } else { inputNumber = 0; inputNumberFeedback.FireUpdate(); } }; twoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]); twoWayDisplay.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]); } // Power Off trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () => { inputNumber = 102; inputNumberFeedback.FireUpdate(); displayDevice.PowerOff(); }); // PowerOn trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () => { inputNumber = 0; inputNumberFeedback.FireUpdate(); displayDevice.PowerOn(); }); for (int i = 0; i < displayDevice.InputPorts.Count; i++) { var localindex = i; if (localindex >= joinMap.InputNamesOffset.JoinSpan) { this.LogWarning("Device has {inputCount} inputs. The Join Map allows up to {joinSpan} inputs. Discarding inputs {discardStart} - {discardEnd} from bridge.", displayDevice.InputPorts.Count, joinMap.InputNamesOffset.JoinSpan, localindex + 1, displayDevice.InputPorts.Count); continue; } else { inputKeys.Add(displayDevice.InputPorts[localindex].Key); var tempKey = inputKeys.ElementAt(localindex); trilist.SetSigTrueAction((ushort)(joinMap.InputSelectOffset.JoinNumber + localindex), () => displayDevice.ExecuteSwitch(displayDevice.InputPorts[tempKey].Selector)); this.LogDebug("Setting Input Select Action on Digital Join {joinNumber} to Input: {input}", joinMap.InputSelectOffset.JoinNumber + localindex, displayDevice.InputPorts[tempKey].Key); trilist.SetString((uint)(joinMap.InputNamesOffset.JoinNumber + localindex), displayDevice.InputPorts[localindex].Key); } } this.LogDebug("Setting Input Select Action on Analog Join {inputSelectJoin}", joinMap.InputSelect); trilist.SetUShortSigAction(joinMap.InputSelect.JoinNumber, (requestedInput) => { if (requestedInput == 0) { displayDevice.PowerOff(); inputNumber = 0; return; } // using 1-based indexing for inputs coming from SIMPL, so need to check if the input is <= the count, not < if (requestedInput > 0 && requestedInput <= displayDevice.InputPorts.Count && requestedInput != inputNumber) { displayDevice.ExecuteSwitch(displayDevice.InputPorts.ElementAt(requestedInput - 1).Selector); inputNumber = requestedInput; return; } if (requestedInput == 102) { displayDevice.PowerToggle(); return; } if (displayDevice is TwoWayDisplayBase) { inputNumberFeedback?.FireUpdate(); } }); var volumeDisplay = displayDevice as IBasicVolumeControls; if (volumeDisplay == null) return; trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, volumeDisplay.VolumeUp); trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, volumeDisplay.VolumeDown); trilist.SetSigTrueAction(joinMap.VolumeMute.JoinNumber, volumeDisplay.MuteToggle); var volumeDisplayWithFeedback = volumeDisplay as IBasicVolumeWithFeedback; if (volumeDisplayWithFeedback == null) return; trilist.SetSigTrueAction(joinMap.VolumeMuteOn.JoinNumber, volumeDisplayWithFeedback.MuteOn); trilist.SetSigTrueAction(joinMap.VolumeMuteOff.JoinNumber, volumeDisplayWithFeedback.MuteOff); trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, volumeDisplayWithFeedback.SetVolume); volumeDisplayWithFeedback.VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]); volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMute.JoinNumber]); volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]); volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]); } /// public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) { foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType))) { var flagValue = Convert.ToInt32(type); // Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag). // (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set. if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0) { this.LogDebug("Skipping {type}", type); continue; } this.LogDebug("setting {type}", type); if (signalType.HasFlag(type)) { UpdateCurrentSources(type, sourceListKey, sourceListItem); } } // Raise the CurrentSourcesChanged event CurrentSourcesChanged?.Invoke(this, EventArgs.Empty); } private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) { if (CurrentSources.ContainsKey(signalType)) { CurrentSources[signalType] = sourceListItem; } else { CurrentSources.Add(signalType, sourceListItem); } // Update the current source key for the specified signal type if (CurrentSourceKeys.ContainsKey(signalType)) { CurrentSourceKeys[signalType] = sourceListKey; } else { CurrentSourceKeys.Add(signalType, sourceListKey); } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs ================================================ using System; namespace PepperDash.Essentials.Devices.Displays { /// /// Defines the contract for IInputHdmi1 /// [Obsolete()] public interface IInputHdmi1 { /// /// Switches to HDMI 1 input /// void InputHdmi1(); } /// /// Defines the contract for IInputHdmi2 /// [Obsolete()] public interface IInputHdmi2 { /// /// Switches to HDMI 2 input /// void InputHdmi2(); } /// /// Defines the contract for IInputHdmi3 /// [Obsolete()] public interface IInputHdmi3 { /// /// Switches to HDMI 3 input /// void InputHdmi3(); } /// /// Defines the contract for IInputHdmi4 /// [Obsolete()] public interface IInputHdmi4 { /// /// Switches to HDMI 4 input /// void InputHdmi4(); } /// /// Defines the contract for IInputDisplayPort1 /// [Obsolete()] public interface IInputDisplayPort1 { /// /// Switches to DisplayPort 1 input /// void InputDisplayPort1(); } /// /// Defines the contract for IInputDisplayPort2 /// [Obsolete()] public interface IInputDisplayPort2 { /// /// Switches to DisplayPort 2 input /// void InputDisplayPort2(); } /// /// Defines the contract for IInputVga1 /// [Obsolete()] public interface IInputVga1 { /// /// Switches to VGA 1 input /// void InputVga1(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Displays { /// /// Represents a MockDisplay /// public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback { /// /// Gets or sets the Inputs /// public ISelectableItems Inputs { get; private set; } bool _PowerIsOn; bool _IsWarmingUp; bool _IsCoolingDown; /// /// Gets the power is on feedback function /// protected override Func PowerIsOnFeedbackFunc { get { return () => { return _PowerIsOn; }; } } /// /// Gets the is cooling down feedback function /// protected override Func IsCoolingDownFeedbackFunc { get { return () => { return _IsCoolingDown; }; } } /// /// Gets the is warming up feedback function /// protected override Func IsWarmingUpFeedbackFunc { get { return () => { return _IsWarmingUp; }; } } /// /// Gets the current input feedback function /// protected override Func CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } } int VolumeHeldRepeatInterval = 200; ushort VolumeInterval = 655; ushort _FakeVolumeLevel = 31768; bool _IsMuted; /// /// Initializes a new instance of the MockDisplay class /// /// The device key /// The device name public MockDisplay(string key, string name) : base(key, name) { Inputs = new MockDisplayInputs { Items = new Dictionary { { "HDMI1", new MockDisplayInput ( "HDMI1", "HDMI 1",this ) }, { "HDMI2", new MockDisplayInput ("HDMI2", "HDMI 2",this ) }, { "HDMI3", new MockDisplayInput ("HDMI3", "HDMI 3",this ) }, { "HDMI4", new MockDisplayInput ("HDMI4", "HDMI 4",this )}, { "DP", new MockDisplayInput ("DP", "DisplayPort", this ) } } }; Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate(); var hdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, "HDMI1", this); var hdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, "HDMI2", this); var hdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, "HDMI3", this); var hdmiIn4 = new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, "HDMI4", this); var dpIn = new RoutingInputPort(RoutingPortNames.DisplayPortIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.DisplayPort, "DP", this); InputPorts.AddRange(new[] { hdmiIn1, hdmiIn2, hdmiIn3, hdmiIn4, dpIn }); VolumeLevelFeedback = new IntFeedback("volume", () => { return _FakeVolumeLevel; }); MuteFeedback = new BoolFeedback("muteOn", () => _IsMuted); WarmupTime = 10000; CooldownTime = 10000; } /// /// PowerOn method /// /// public override void PowerOn() { if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) { _IsWarmingUp = true; IsWarmingUpFeedback.InvokeFireUpdate(); // Fake power-up cycle WarmupTimer = new CTimer(o => { _IsWarmingUp = false; _PowerIsOn = true; IsWarmingUpFeedback.InvokeFireUpdate(); PowerIsOnFeedback.InvokeFireUpdate(); }, WarmupTime); } } /// /// PowerOff method /// /// public override void PowerOff() { // If a display has unreliable-power off feedback, just override this and // remove this check. if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) { _IsCoolingDown = true; IsCoolingDownFeedback.InvokeFireUpdate(); // Fake cool-down cycle CooldownTimer = new CTimer(o => { Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this); _IsCoolingDown = false; IsCoolingDownFeedback.InvokeFireUpdate(); _PowerIsOn = false; PowerIsOnFeedback.InvokeFireUpdate(); }, CooldownTime); } } /// /// PowerToggle method /// /// public override void PowerToggle() { if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue) PowerOff(); else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue) PowerOn(); } /// /// ExecuteSwitch method /// /// public override void ExecuteSwitch(object selector) { try { Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector); if (!_PowerIsOn) { PowerOn(); } if (!Inputs.Items.TryGetValue(selector.ToString(), out var input)) return; Debug.LogMessage(LogEventLevel.Verbose, "Selected input: {input}", this, input.Key); input.Select(); var inputPort = InputPorts.FirstOrDefault(port => { Debug.LogMessage(LogEventLevel.Verbose, "Checking input port {inputPort} with selector {portSelector} against {selector}", this, port, port.Selector, selector); return port.Selector.ToString() == selector.ToString(); }); if (inputPort == null) { Debug.LogMessage(LogEventLevel.Verbose, "Unable to find input port for selector {selector}", this, selector); return; } Debug.LogMessage(LogEventLevel.Verbose, "Setting current input port to {inputPort}", this, inputPort); CurrentInputPort = inputPort; } catch (Exception ex) { Debug.LogMessage(ex, "Error making switch: {Exception}", this, ex); } } /// /// SetInput method /// public void SetInput(string selector) { ISelectableItem currentInput = null; try { currentInput = Inputs.Items.SingleOrDefault(Inputs => Inputs.Value.IsSelected).Value; } catch { } if (currentInput != null) { Debug.LogMessage(LogEventLevel.Verbose, this, "SetInput: {0}", selector); currentInput.IsSelected = false; } if (!Inputs.Items.TryGetValue(selector, out var input)) return; input.IsSelected = true; Inputs.CurrentItem = selector; } #region IBasicVolumeWithFeedback Members /// /// Gets or sets the VolumeLevelFeedback /// public IntFeedback VolumeLevelFeedback { get; private set; } /// /// SetVolume method /// public void SetVolume(ushort level) { _FakeVolumeLevel = level; VolumeLevelFeedback.InvokeFireUpdate(); } /// /// MuteOn method /// public void MuteOn() { _IsMuted = true; MuteFeedback.InvokeFireUpdate(); } /// /// MuteOff method /// public void MuteOff() { _IsMuted = false; MuteFeedback.InvokeFireUpdate(); } /// /// Gets or sets the MuteFeedback /// public BoolFeedback MuteFeedback { get; private set; } #endregion #region IBasicVolumeControls Members /// /// VolumeUp method /// public void VolumeUp(bool pressRelease) { //while (pressRelease) //{ Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease); if (pressRelease) { var newLevel = _FakeVolumeLevel + VolumeInterval; SetVolume((ushort)newLevel); CrestronEnvironment.Sleep(VolumeHeldRepeatInterval); } //} } /// /// VolumeDown method /// public void VolumeDown(bool pressRelease) { //while (pressRelease) //{ Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease); if (pressRelease) { var newLevel = _FakeVolumeLevel - VolumeInterval; SetVolume((ushort)newLevel); CrestronEnvironment.Sleep(VolumeHeldRepeatInterval); } //} } /// /// MuteToggle method /// public void MuteToggle() { _IsMuted = !_IsMuted; MuteFeedback.InvokeFireUpdate(); } #endregion /// /// LinkToApi method /// public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge); } } /// /// Represents a MockDisplayFactory /// public class MockDisplayFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the MockDisplayFactory class /// public MockDisplayFactory() { TypeNames = new List() { "mockdisplay", "mockdisplay2" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device"); return new MockDisplay(dc.Key, dc.Name); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs ================================================ using System; using System.Collections.Generic; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.Devices.Common.Displays { /// /// Represents a MockDisplayInputs /// public class MockDisplayInputs : ISelectableItems { private Dictionary _items; /// /// Gets or sets the collection of selectable items /// public Dictionary Items { get { return _items; } set { if (_items == value) return; _items = value; ItemsUpdated?.Invoke(this, null); } } private string _currentItem; /// /// Gets or sets the currently selected item /// public string CurrentItem { get { return _currentItem; } set { if (_currentItem == value) return; _currentItem = value; CurrentItemChanged?.Invoke(this, null); } } /// /// Occurs when the items collection is updated /// public event EventHandler ItemsUpdated; /// /// Occurs when the current item changes /// public event EventHandler CurrentItemChanged; } /// /// Represents a MockDisplayInput /// public class MockDisplayInput : ISelectableItem { private MockDisplay _parent; private bool _isSelected; /// /// Gets or sets a value indicating whether this input is selected /// public bool IsSelected { get { return _isSelected; } set { if (_isSelected == value) return; _isSelected = value; ItemUpdated?.Invoke(this, null); } } /// /// Gets or sets the Name /// public string Name { get; set; } /// /// Gets or sets the Key /// public string Key { get; set; } /// /// Occurs when this item is updated /// public event EventHandler ItemUpdated; /// /// Initializes a new instance of the MockDisplayInput class /// /// The input key /// The input name /// The parent mock display public MockDisplayInput(string key, string name, MockDisplay parent) { Key = key; Name = name; _parent = parent; } /// /// Select method /// public void Select() { if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn(); foreach (var input in _parent.Inputs.Items) { input.Value.IsSelected = input.Key == this.Key; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs ================================================ using System; using System.Collections.Generic; using System.Timers; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.CrestronIO; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Devices.Common.Displays; namespace PepperDash.Essentials.Devices.Common.Shades { /// /// Enumeration for requested state /// enum RequestedState { None, Raise, Lower, } /// /// Controls a single shade using three relays /// public class ScreenLiftController : EssentialsDevice, IProjectorScreenLiftControl { readonly ScreenLiftControllerConfigProperties Config; readonly ScreenLiftRelaysConfig RaiseRelayConfig; readonly ScreenLiftRelaysConfig LowerRelayConfig; readonly ScreenLiftRelaysConfig LatchedRelayConfig; DisplayBase DisplayDevice; ISwitchedOutput RaiseRelay; ISwitchedOutput LowerRelay; ISwitchedOutput LatchedRelay; private bool _isMoving; private RequestedState _requestedState; private RequestedState _currentMovement; private Timer _movementTimer; /// /// Gets or sets the InUpPosition /// public bool InUpPosition { get { return _isInUpPosition; } set { if (value == _isInUpPosition) return; _isInUpPosition = value; IsInUpPosition.FireUpdate(); PositionChanged?.Invoke(this, new EventArgs()); } } private bool _isInUpPosition { get; set; } /// /// Gets or sets the Type /// public eScreenLiftControlType Type { get; private set; } /// /// Gets or sets the Mode /// public eScreenLiftControlMode Mode { get; private set; } /// /// Gets or sets the DisplayDeviceKey /// public string DisplayDeviceKey { get; private set; } /// /// Gets or sets the IsInUpPosition /// public BoolFeedback IsInUpPosition { get; private set; } /// /// Event that fires when the position changes /// public event EventHandler PositionChanged; /// /// Constructor for ScreenLiftController /// public ScreenLiftController( string key, string name, ScreenLiftControllerConfigProperties config ) : base(key, name) { Config = config; DisplayDeviceKey = Config.DisplayDeviceKey; Mode = Config.Mode; Type = Config.Type; IsInUpPosition = new BoolFeedback("isInUpPosition", () => _isInUpPosition); // Initialize movement timer for reuse _movementTimer = new Timer(); _movementTimer.Elapsed += OnMovementComplete; _movementTimer.AutoReset = false; switch (Mode) { case eScreenLiftControlMode.momentary: { RaiseRelayConfig = Config.Relays["raise"]; LowerRelayConfig = Config.Relays["lower"]; break; } case eScreenLiftControlMode.latched: { LatchedRelayConfig = Config.Relays["latched"]; break; } } IsInUpPosition.OutputChange += (sender, args) => { this.LogDebug( "ScreenLiftController '{name}' IsInUpPosition changed to {position}", Name, IsInUpPosition.BoolValue ? "Up" : "Down" ); if (!Config.MuteOnScreenUp) { return; } if (args.BoolValue) { return; } if (DisplayDevice is IBasicVideoMuteWithFeedback videoMute) { this.LogInformation("Unmuting video because screen is down"); videoMute.VideoMuteOff(); } }; IsInUpPosition.FireUpdate(); } private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) { if ( !DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.lift ) { Raise(); return; } if ( DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.screen ) { Raise(); return; } } private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e) { if (DisplayDevice.IsWarmingUpFeedback.BoolValue) { Lower(); } } /// /// CustomActivate method /// /// public override bool CustomActivate() { //Create ISwitchedOutput objects based on props switch (Mode) { case eScreenLiftControlMode.momentary: { this.LogDebug("Getting relays for {mode}", Mode); RaiseRelay = GetSwitchedOutputFromDevice(RaiseRelayConfig.DeviceKey); LowerRelay = GetSwitchedOutputFromDevice(LowerRelayConfig.DeviceKey); break; } case eScreenLiftControlMode.latched: { this.LogDebug("Getting relays for {mode}", Mode); LatchedRelay = GetSwitchedOutputFromDevice(LatchedRelayConfig.DeviceKey); break; } } this.LogDebug("Getting display with key {displayKey}", DisplayDeviceKey); DisplayDevice = GetDisplayBaseFromDevice(DisplayDeviceKey); if (DisplayDevice != null) { this.LogDebug("Subscribing to {displayKey} feedbacks", DisplayDeviceKey); DisplayDevice.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange; DisplayDevice.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; } return base.CustomActivate(); } /// /// Raise method /// public void Raise() { if (RaiseRelay == null && LatchedRelay == null) return; this.LogDebug("Raise called for {type}", Type); if (Config.MuteOnScreenUp && DisplayDevice is IBasicVideoMuteWithFeedback videoMute) { this.LogInformation("Muting video because screen is going up"); videoMute.VideoMuteOn(); } // If device is moving, bank the command if (_isMoving) { this.LogDebug("Device is moving, banking Raise command"); _requestedState = RequestedState.Raise; return; } this.LogDebug("Raising {type}", Type); switch (Mode) { case eScreenLiftControlMode.momentary: { PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs); // Set moving flag and start timer if movement time is configured if (RaiseRelayConfig.MoveTimeInMs > 0) { _isMoving = true; _currentMovement = RequestedState.Raise; if (_movementTimer.Enabled) { _movementTimer.Stop(); } _movementTimer.Interval = RaiseRelayConfig.MoveTimeInMs; _movementTimer.Start(); } else { InUpPosition = true; } break; } case eScreenLiftControlMode.latched: { LatchedRelay.Off(); InUpPosition = true; break; } } } /// /// Lower method /// public void Lower() { if (LowerRelay == null && LatchedRelay == null) return; this.LogDebug("Lower called for {type}", Type); // If device is moving, bank the command if (_isMoving) { this.LogDebug("Device is moving, banking Lower command"); _requestedState = RequestedState.Lower; return; } this.LogDebug("Lowering {type}", Type); switch (Mode) { case eScreenLiftControlMode.momentary: { PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs); // Set moving flag and start timer if movement time is configured if (LowerRelayConfig.MoveTimeInMs > 0) { _isMoving = true; _currentMovement = RequestedState.Lower; if (_movementTimer.Enabled) { _movementTimer.Stop(); } _movementTimer.Interval = LowerRelayConfig.MoveTimeInMs; _movementTimer.Start(); } else { InUpPosition = false; } break; } case eScreenLiftControlMode.latched: { LatchedRelay.On(); InUpPosition = false; break; } } } private void DisposeMovementTimer() { if (_movementTimer != null) { _movementTimer.Stop(); _movementTimer.Elapsed -= OnMovementComplete; _movementTimer.Dispose(); _movementTimer = null; } } /// /// Called when movement timer completes /// private void OnMovementComplete(object sender, ElapsedEventArgs e) { this.LogDebug("Movement complete"); // Update position based on completed movement if (_currentMovement == RequestedState.Raise) { InUpPosition = true; } else if (_currentMovement == RequestedState.Lower) { InUpPosition = false; } _isMoving = false; _currentMovement = RequestedState.None; // Execute banked command if one exists if (_requestedState != RequestedState.None) { this.LogDebug("Executing next command: {command}", _requestedState); var commandToExecute = _requestedState; _requestedState = RequestedState.None; // Check if current state matches what the banked command would do and execute if different switch (commandToExecute) { case RequestedState.Raise: Raise(); break; case RequestedState.Lower: Lower(); break; } } } private void PulseOutput(ISwitchedOutput output, int pulseTime) { output.On(); var timer = new Timer(pulseTime) { AutoReset = false }; timer.Elapsed += (sender, e) => { output.Off(); timer.Dispose(); }; timer.Start(); } private ISwitchedOutput GetSwitchedOutputFromDevice(string relayKey) { var portDevice = DeviceManager.GetDeviceForKey(relayKey); if (portDevice != null) { return portDevice; } else { this.LogWarning( "Error: Unable to get relay device with key '{relayKey}'", relayKey ); return null; } } private DisplayBase GetDisplayBaseFromDevice(string displayKey) { var displayDevice = DeviceManager.GetDeviceForKey(displayKey); if (displayDevice != null) { return displayDevice; } else { this.LogWarning( "Error: Unable to get display device with key '{displayKey}'", displayKey ); return null; } } } /// /// Factory for ScreenLiftController devices /// public class ScreenLiftControllerFactory : EssentialsDeviceFactory { /// /// Constructor for ScreenLiftControllerFactory /// public ScreenLiftControllerFactory() { TypeNames = new List() { "screenliftcontroller" }; } /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogDebug("Factory Attempting to create new ScreenLiftController Device"); var props = dc.Properties.ToObject(); return new ScreenLiftController(dc.Key, dc.Name, props); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftControllerConfigProperties.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.Devices.Common.Shades { /// /// Represents a ScreenLiftControllerConfigProperties /// public class ScreenLiftControllerConfigProperties { /// /// Gets or sets the DisplayDeviceKey /// [JsonProperty("displayDeviceKey")] public string DisplayDeviceKey { get; set; } /// /// Gets or sets the Type /// [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter))] public eScreenLiftControlType Type { get; set; } /// /// Gets or sets the Mode /// [JsonProperty("mode")] [JsonConverter(typeof(StringEnumConverter))] public eScreenLiftControlMode Mode { get; set; } /// /// Gets or sets the Relays /// [JsonProperty("relays")] public Dictionary Relays { get; set; } /// /// Mutes the display when the screen is in the up position /// [JsonProperty("muteOnScreenUp")] public bool MuteOnScreenUp { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Shades { /// /// Represents a ScreenLiftRelaysConfig /// public class ScreenLiftRelaysConfig { /// /// Gets or sets the DeviceKey /// [JsonProperty("deviceKey")] public string DeviceKey { get; set; } /// /// Gets or sets the PulseTimeInMs /// [JsonProperty("pulseTimeInMs")] public int PulseTimeInMs { get; set; } /// /// Gets or sets the MoveTimeInMs - time in milliseconds for the movement to complete /// [JsonProperty("moveTimeInMs")] public int MoveTimeInMs { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/TwoWayDisplayBase.cs ================================================ using System; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Displays { /// /// Abstract base class for two-way display devices that provide feedback capabilities. /// Extends DisplayBase with routing feedback and power control feedback functionality. /// public abstract class TwoWayDisplayBase : DisplayBase, IRoutingFeedback, IHasPowerControlWithFeedback { /// /// Gets feedback for the current input selection on the display. /// public StringFeedback CurrentInputFeedback { get; private set; } /// /// Abstract function that must be implemented by derived classes to provide the current input feedback value. /// Must be implemented by concrete sub-classes. /// abstract protected Func CurrentInputFeedbackFunc { get; } /// /// Gets feedback indicating whether the display is currently powered on. /// public BoolFeedback PowerIsOnFeedback { get; protected set; } /// /// Abstract function that must be implemented by derived classes to provide the power state feedback value. /// Must be implemented by concrete sub-classes. /// abstract protected Func PowerIsOnFeedbackFunc { get; } /// /// Gets the default mock display instance for testing and development purposes. /// public static MockDisplay DefaultDisplay { get { if (_DefaultDisplay == null) _DefaultDisplay = new MockDisplay("default", "Default Display"); return _DefaultDisplay; } } static MockDisplay _DefaultDisplay; /// /// Initializes a new instance of the TwoWayDisplayBase class. /// /// The unique key identifier for this display device. /// The friendly name for this display device. public TwoWayDisplayBase(string key, string name) : base(key, name) { CurrentInputFeedback = new StringFeedback("currentInput", CurrentInputFeedbackFunc); WarmupTime = 7000; CooldownTime = 15000; PowerIsOnFeedback = new BoolFeedback("PowerOnFeedback", PowerIsOnFeedbackFunc); Feedbacks.Add(CurrentInputFeedback); Feedbacks.Add(PowerIsOnFeedback); PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; } void PowerIsOnFeedback_OutputChange(object sender, EventArgs e) { if (UsageTracker != null) { if (PowerIsOnFeedback.BoolValue) UsageTracker.StartDeviceUsage(); else UsageTracker.EndDeviceUsage(); } } /// /// Event that is raised when a numeric switch change occurs on the display. /// public event EventHandler NumericSwitchChange; /// /// Raise an event when the status of a switch object changes. /// /// Arguments defined as IKeyName sender, output, input, and eRoutingSignalType protected void OnSwitchChange(RoutingNumericEventArgs e) { NumericSwitchChange?.Invoke(this, e); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Displays/eScreenLiftControlMode.cs ================================================ namespace PepperDash.Essentials.Devices.Common.Shades { /// /// Enumeration of eScreenLiftControlMode values /// public enum eScreenLiftControlMode { /// /// Momentary control mode for screen lift /// momentary, /// /// Latched control mode for screen lift /// latched } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs ================================================ using System; using System.Collections.Generic; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Generic { /// /// Represents a GenericSink /// public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputPort, ICurrentSources { /// public Dictionary CurrentSources { get; private set; } /// public Dictionary CurrentSourceKeys { get; private set; } /// public event EventHandler CurrentSourcesChanged; /// /// Initializes a new instance of the GenericSink class /// /// The device key /// The device name public GenericSink(string key, string name) : base(key, name) { InputPorts = new RoutingPortCollection(); var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo | eRoutingSignalType.SecondaryAudio, eRoutingPortConnectionType.Hdmi, null, this); InputPorts.Add(inputPort); CurrentSources = new Dictionary { { eRoutingSignalType.Audio, null }, { eRoutingSignalType.Video, null }, }; CurrentSourceKeys = new Dictionary { { eRoutingSignalType.Audio, string.Empty }, { eRoutingSignalType.Video, string.Empty }, }; } /// public void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) { foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType))) { var flagValue = Convert.ToInt32(type); // Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag). // (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set. if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0) { this.LogDebug("Skipping {type}", type); continue; } this.LogDebug("setting {type}", type); if (signalType.HasFlag(type)) { UpdateCurrentSources(type, sourceListKey, sourceListItem); } } // Raise the CurrentSourcesChanged event CurrentSourcesChanged?.Invoke(this, EventArgs.Empty); } private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) { CurrentSources[signalType] = sourceListItem; CurrentSourceKeys[signalType] = sourceListKey; } /// /// Gets or sets the InputPorts /// public RoutingPortCollection InputPorts { get; private set; } /// /// Gets or sets the CurrentSourceInfoKey /// public string CurrentSourceInfoKey { get; set; } private SourceListItem _currentSource; /// /// Gets or sets the CurrentSourceInfo /// public SourceListItem CurrentSourceInfo { get => _currentSource; set { if (value == _currentSource) { return; } CurrentSourceChange?.Invoke(_currentSource, ChangeType.WillChange); _currentSource = value; CurrentSourceChange?.Invoke(_currentSource, ChangeType.DidChange); } } /// /// Gets the current input port /// public RoutingInputPort CurrentInputPort => InputPorts[0]; /// /// Event fired when the current source changes /// public event SourceInfoChangeHandler CurrentSourceChange; /// public event InputChangedEventHandler InputChanged; /// public void ExecuteSwitch(object inputSelector) { this.LogDebug("GenericSink Executing Switch to: {inputSelector}", inputSelector); } } /// /// Represents a GenericSinkFactory /// public class GenericSinkFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the GenericSinkFactory class /// public GenericSinkFactory() { TypeNames = new List() { "genericsink", "genericdestination" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Sink Device"); return new GenericSink(dc.Key, dc.Name); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a GenericSource /// public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking { /// /// Gets or sets the DisplayUiType /// public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } } /// /// Initializes a new instance of the GenericSource class /// /// The device key /// The device name public GenericSource(string key, string name) : base(key, name) { AnyOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); OutputPorts = new RoutingPortCollection { AnyOut }; } #region IRoutingOutputs Members /// /// Gets or sets the AnyOut /// public RoutingOutputPort AnyOut { get; private set; } /// /// Gets or sets the OutputPorts /// public RoutingPortCollection OutputPorts { get; private set; } #endregion #region IUsageTracking Members /// /// Gets or sets the UsageTracker /// public UsageTracking UsageTracker { get; set; } #endregion } /// /// Represents a GenericSourceFactory /// public class GenericSourceFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the GenericSourceFactory class /// public GenericSourceFactory() { TypeNames = new List() { "genericsource" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Source Device"); return new GenericSource(dc.Key, dc.Name); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Lighting; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Lighting { /// /// Base class for lighting devices that support scenes /// public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes { #region ILightingScenes Members /// /// Event fired when lighting scene changes /// public event EventHandler LightingSceneChange; /// /// Gets or sets the LightingScenes /// public List LightingScenes { get; protected set; } /// /// Gets or sets the CurrentLightingScene /// public LightingScene CurrentLightingScene { get; protected set; } /// /// Gets or sets the CurrentLightingSceneFeedback /// public IntFeedback CurrentLightingSceneFeedback { get; protected set; } #endregion /// /// Initializes a new instance of the LightingBase class /// /// The device key /// The device name protected LightingBase(string key, string name) : base(key, name) { LightingScenes = new List(); CurrentLightingScene = new LightingScene(); //CurrentLightingSceneFeedback = new IntFeedback(() => { return int.Parse(this.CurrentLightingScene.ID); }); } /// /// Selects the specified lighting scene /// /// The lighting scene to select public abstract void SelectScene(LightingScene scene); /// /// SimulateSceneSelect method /// public void SimulateSceneSelect(string sceneName) { Debug.LogMessage(LogEventLevel.Debug, this, "Simulating selection of scene '{0}'", sceneName); var scene = LightingScenes.FirstOrDefault(s => s.Name.Equals(sceneName)); if (scene != null) { CurrentLightingScene = scene; OnLightingSceneChange(); } } /// /// Sets the IsActive property on each scene and fires the LightingSceneChange event /// protected void OnLightingSceneChange() { foreach (var scene in LightingScenes) { if (scene == CurrentLightingScene) scene.IsActive = true; else scene.IsActive = false; } LightingSceneChange?.Invoke(this, new LightingSceneChangeEventArgs(CurrentLightingScene)); } /// /// Links the lighting device to API with join map configuration /// /// The lighting device to link /// The trilist to link to /// The starting join number /// The join map key /// The EISC API bridge /// The configured join map protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new GenericLightingJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } return LinkLightingToApi(lightingDevice, trilist, joinMap); } /// /// Links the lighting device to API using an existing join map /// /// The lighting device to link /// The trilist to link to /// The join map to use /// The join map used for linking protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap) { Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); Debug.LogMessage(LogEventLevel.Information, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); // GenericLighitng Actions & FeedBack trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); var sceneIndex = 0; foreach (var scene in lightingDevice.LightingScenes) { var index = sceneIndex; trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index])); scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]); trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; sceneIndex++; } trilist.OnlineStatusChange += (sender, args) => { if (!args.DeviceOnLine) return; sceneIndex = 0; foreach (var scene in lightingDevice.LightingScenes) { var index = sceneIndex; trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; scene.IsActiveFeedback.FireUpdate(); sceneIndex++; } }; return joinMap; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj ================================================  Debug;Release;Debug 4.7.2 net472 true bin\$(Configuration)\ Essentials Devices Common PepperDash.Essentials.Devices.Common true PepperDash Essentials Devices Common PepperDash.Essentials.Devices.Common $(Version) false full full pdbonly bin\$(Configuration)\Essentials Devices Common.xml ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Properties/ControlSystem.cfg ================================================ ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs ================================================ using PepperDash.Essentials.Core; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Devices.Common.Room { /// /// Defines the contract for IEssentialsHuddleSpaceRoom /// public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IHasDefaultDisplay, IHasCurrentVolumeControls, IRoomOccupancy, IEmergency, IMicrophonePrivacy { /// /// Gets whether to exclude this room from global functions /// bool ExcludeFromGlobalFunctions { get; } /// /// Runs the route action for the given routeKey and sourceListKey /// /// The route key void RunRouteAction(string routeKey); /// /// Gets the PropertiesConfig /// EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs ================================================ using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Devices.Common.Room { /// /// Defines the contract for IEssentialsHuddleVtc1Room /// public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback, IRoomOccupancy, IEmergency, IMicrophonePrivacy { /// /// Gets the PropertiesConfig /// EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } /// /// Gets whether to exclude this room from global functions /// bool ExcludeFromGlobalFunctions { get; } /// /// Runs the route action for the given routeKey and sourceListKey /// /// The route key void RunRouteAction(string routeKey); /// /// Gets the ScheduleSource /// IHasScheduleAwareness ScheduleSource { get; } /// /// Gets the InCallFeedback /// new BoolFeedback InCallFeedback { get; } /// /// Gets the PrivacyModeIsOnFeedback /// new BoolFeedback PrivacyModeIsOnFeedback { get; } /// /// Gets the DefaultCodecRouteString /// string DefaultCodecRouteString { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs ================================================ using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Devices.Common.Room { /// /// Defines the contract for IEssentialsRoomPropertiesConfig /// public interface IEssentialsRoomPropertiesConfig { /// /// Gets the PropertiesConfig /// EssentialsRoomPropertiesConfig PropertiesConfig { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs ================================================ using System.Collections.Generic; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Devices.Common.Displays; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Devices.Common.Room { /// /// Defines the contract for IEssentialsTechRoom /// public interface IEssentialsTechRoom : IEssentialsRoom, ITvPresetsProvider, IBridgeAdvanced, IRunDirectRouteAction { /// /// Gets the PropertiesConfig /// EssentialsTechRoomConfig PropertiesConfig { get; } /// /// Gets the Tuners /// Dictionary Tuners { get; } /// /// Gets the Displays /// Dictionary Displays { get; } /// /// Powers on the room /// void RoomPowerOn(); /// /// Powers off the room /// void RoomPowerOff(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs ================================================ using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Presets; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a IRSetTopBoxBase /// Wrapper class for an IR Set Top Box /// [Description("Wrapper class for an IR Set Top Box")] public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IRoutingOutputs, IUsageTracking, IHasPowerControl, ITvPresetsProvider { /// /// Gets or sets the IrPort /// public IrOutputPortController IrPort { get; private set; } /// /// Gets or sets the DisplayUiType /// public uint DisplayUiType { get { return DisplayUiConstants.TypeDirecTv; } } /// /// Gets or sets the IrPulseTime /// public ushort IrPulseTime { get; set; } /// /// Gets or sets the HasPresets /// public bool HasPresets { get; set; } /// /// Gets or sets the HasDvr /// public bool HasDvr { get; set; } /// /// Gets or sets the HasDpad /// public bool HasDpad { get; set; } /// /// Gets or sets the HasNumeric /// public bool HasNumeric { get; set; } /// /// Gets or sets the TvPresets /// public DevicePresetsModel TvPresets { get; private set; } /// /// Initializes a new instance of the class /// /// The unique identifier for the device /// The name of the device /// The IR output port controller /// The properties configuration public IRSetTopBoxBase(string key, string name, IrOutputPortController portCont, SetTopBoxPropertiesConfig props) : base(key, name) { IrPort = portCont; IrPulseTime = 200; if (props.IrPulseTime > 0) { IrPulseTime = (ushort)props.IrPulseTime; } DeviceManager.AddDevice(portCont); HasPresets = props.HasPresets; HasDvr = props.HasDvr; HasDpad = props.HasDpad; HasNumeric = props.HasNumeric; HasKeypadAccessoryButton1 = true; KeypadAccessoryButton1Command = "Dash"; KeypadAccessoryButton1Label = "-"; HasKeypadAccessoryButton2 = true; KeypadAccessoryButton2Command = "KEYPAD_ENTER"; KeypadAccessoryButton2Label = "Enter"; AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio, eRoutingPortConnectionType.DigitalAudio, null, this); OutputPorts = new RoutingPortCollection { AnyVideoOut, AnyAudioOut }; } /// /// LoadPresets method /// public void LoadPresets(string filePath) { TvPresets = new DevicePresetsModel(Key + "-presets", this, filePath); DeviceManager.AddDevice(TvPresets); } #region ISetTopBoxControls Members /// /// DvrList method /// public void DvrList(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_DVR, pressRelease); } /// /// Replay method /// public void Replay(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_REPLAY, pressRelease); } #endregion #region IDPad Members /// /// Up method /// public void Up(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_UP_ARROW, pressRelease); } /// /// Down method /// public void Down(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_DN_ARROW, pressRelease); } /// /// Left method /// public void Left(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_LEFT_ARROW, pressRelease); } /// /// Right method /// public void Right(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RIGHT_ARROW, pressRelease); } /// /// Select method /// public void Select(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease); } /// /// Menu method /// public void Menu(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_MENU, pressRelease); } /// /// Exit method /// public void Exit(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_EXIT, pressRelease); } #endregion #region INumericKeypad Members /// /// Digit0 method /// public void Digit0(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_0, pressRelease); } /// /// Digit1 method /// public void Digit1(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_1, pressRelease); } /// /// Digit2 method /// public void Digit2(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_2, pressRelease); } /// /// Digit3 method /// public void Digit3(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_3, pressRelease); } /// /// Digit4 method /// public void Digit4(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_4, pressRelease); } /// /// Digit5 method /// public void Digit5(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_5, pressRelease); } /// /// Digit6 method /// public void Digit6(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_6, pressRelease); } /// /// Digit7 method /// public void Digit7(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_7, pressRelease); } /// /// Digit8 method /// public void Digit8(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_8, pressRelease); } /// /// Digit9 method /// public void Digit9(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_9, pressRelease); } /// /// Gets or sets the HasKeypadAccessoryButton1 /// public bool HasKeypadAccessoryButton1 { get; set; } /// /// Defaults to "-" /// public string KeypadAccessoryButton1Label { get; set; } /// /// Defaults to "Dash" /// public string KeypadAccessoryButton1Command { get; set; } /// /// Presses the KeypadAccessoryButton1 /// public void KeypadAccessoryButton1(bool pressRelease) { IrPort.PressRelease(KeypadAccessoryButton1Command, pressRelease); } /// /// Gets or sets the HasKeypadAccessoryButton2 /// public bool HasKeypadAccessoryButton2 { get; set; } /// /// Defaults to "Enter" /// public string KeypadAccessoryButton2Label { get; set; } /// /// Defaults to "Enter" /// public string KeypadAccessoryButton2Command { get; set; } /// /// Presses the KeypadAccessoryButton2 /// public void KeypadAccessoryButton2(bool pressRelease) { IrPort.PressRelease(KeypadAccessoryButton2Command, pressRelease); } #endregion #region ISetTopBoxNumericKeypad Members /// /// Dash method /// public void Dash(bool pressRelease) { IrPort.PressRelease("dash", pressRelease); } /// /// Corresponds to "numericEnter" IR command /// public void KeypadEnter(bool pressRelease) { IrPort.PressRelease("numericEnter", pressRelease); } #endregion #region IChannelFunctions Members /// /// ChannelUp method /// public void ChannelUp(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_CH_PLUS, pressRelease); } /// /// ChannelDown method /// public void ChannelDown(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_CH_MINUS, pressRelease); } /// /// LastChannel method /// public void LastChannel(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_LAST, pressRelease); } /// /// Guide method /// public void Guide(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_GUIDE, pressRelease); } /// /// Info method /// public void Info(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_INFO, pressRelease); } #endregion #region IColorFunctions Members /// /// Red method /// public void Red(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RED, pressRelease); } /// /// Green method /// public void Green(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_GREEN, pressRelease); } /// /// Yellow method /// public void Yellow(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_YELLOW, pressRelease); } /// /// Blue method /// public void Blue(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_BLUE, pressRelease); } #endregion #region IRoutingOutputs Members /// /// Gets or sets the AnyVideoOut /// public RoutingOutputPort AnyVideoOut { get; private set; } /// /// Gets or sets the AnyAudioOut /// public RoutingOutputPort AnyAudioOut { get; private set; } /// /// Gets or sets the OutputPorts /// public RoutingPortCollection OutputPorts { get; private set; } #endregion #region ITransport Members /// /// ChapMinus method /// public void ChapMinus(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_REPLAY, pressRelease); } /// /// ChapPlus method /// public void ChapPlus(bool pressRelease) { } /// /// FFwd method /// public void FFwd(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_FSCAN, pressRelease); } /// /// Pause method /// public void Pause(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease); } /// /// Play method /// public void Play(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_PLAY, pressRelease); } /// /// Record method /// public void Record(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RECORD, pressRelease); } /// /// Rewind method /// public void Rewind(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease); } /// /// Stop method /// public void Stop(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_STOP, pressRelease); } #endregion #region IUsageTracking Members /// /// Gets or sets the UsageTracker /// public UsageTracking UsageTracker { get; set; } #endregion #region IPower Members /// /// PowerOn method /// public void PowerOn() { IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime); } /// /// PowerOff method /// public void PowerOff() { IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime); } /// /// PowerToggle method /// public void PowerToggle() { IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime); } #endregion /// /// LinkToApi method /// /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new SetTopBoxControllerJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); Debug.LogMessage(LogEventLevel.Information, "Linking to SetTopBox: {0}", Name); trilist.OnlineStatusChange += new OnlineStatusChangeEventHandler((o, a) => { if (a.DeviceOnLine) { trilist.StringInput[joinMap.Name.JoinNumber].StringValue = Name; } }); if (this is ISetTopBoxControls stbBase) { trilist.BooleanInput[joinMap.HasDpad.JoinNumber].BoolValue = stbBase.HasDpad; trilist.BooleanInput[joinMap.HasNumeric.JoinNumber].BoolValue = stbBase.HasNumeric; trilist.BooleanInput[joinMap.HasDvr.JoinNumber].BoolValue = stbBase.HasDvr; trilist.BooleanInput[joinMap.HasPresets.JoinNumber].BoolValue = stbBase.HasPresets; trilist.SetBoolSigAction(joinMap.DvrList.JoinNumber, stbBase.DvrList); trilist.SetBoolSigAction(joinMap.Replay.JoinNumber, stbBase.Replay); trilist.SetStringSigAction(joinMap.LoadPresets.JoinNumber, stbBase.LoadPresets); } if (this is IHasPowerControl stbPower) { trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, stbPower.PowerOn); trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, stbPower.PowerOff); trilist.SetSigTrueAction(joinMap.PowerToggle.JoinNumber, stbPower.PowerToggle); } if (this is IDPad stbDPad) { trilist.SetBoolSigAction(joinMap.Up.JoinNumber, stbDPad.Up); trilist.SetBoolSigAction(joinMap.Down.JoinNumber, stbDPad.Down); trilist.SetBoolSigAction(joinMap.Left.JoinNumber, stbDPad.Left); trilist.SetBoolSigAction(joinMap.Right.JoinNumber, stbDPad.Right); trilist.SetBoolSigAction(joinMap.Select.JoinNumber, stbDPad.Select); trilist.SetBoolSigAction(joinMap.Menu.JoinNumber, stbDPad.Menu); trilist.SetBoolSigAction(joinMap.Exit.JoinNumber, stbDPad.Exit); } if (this is IChannel stbChannel) { trilist.SetBoolSigAction(joinMap.ChannelUp.JoinNumber, stbChannel.ChannelUp); trilist.SetBoolSigAction(joinMap.ChannelDown.JoinNumber, stbChannel.ChannelDown); trilist.SetBoolSigAction(joinMap.LastChannel.JoinNumber, stbChannel.LastChannel); trilist.SetBoolSigAction(joinMap.Guide.JoinNumber, stbChannel.Guide); trilist.SetBoolSigAction(joinMap.Info.JoinNumber, stbChannel.Info); trilist.SetBoolSigAction(joinMap.Exit.JoinNumber, stbChannel.Exit); } if (this is IColor stbColor) { trilist.SetBoolSigAction(joinMap.Red.JoinNumber, stbColor.Red); trilist.SetBoolSigAction(joinMap.Green.JoinNumber, stbColor.Green); trilist.SetBoolSigAction(joinMap.Yellow.JoinNumber, stbColor.Yellow); trilist.SetBoolSigAction(joinMap.Blue.JoinNumber, stbColor.Blue); } if (this is ISetTopBoxNumericKeypad stbKeypad) { trilist.StringInput[joinMap.KeypadAccessoryButton1Label.JoinNumber].StringValue = stbKeypad.KeypadAccessoryButton1Label; trilist.StringInput[joinMap.KeypadAccessoryButton2Label.JoinNumber].StringValue = stbKeypad.KeypadAccessoryButton2Label; trilist.BooleanInput[joinMap.HasKeypadAccessoryButton1.JoinNumber].BoolValue = stbKeypad.HasKeypadAccessoryButton1; trilist.BooleanInput[joinMap.HasKeypadAccessoryButton2.JoinNumber].BoolValue = stbKeypad.HasKeypadAccessoryButton2; trilist.SetBoolSigAction(joinMap.Digit0.JoinNumber, stbKeypad.Digit0); trilist.SetBoolSigAction(joinMap.Digit1.JoinNumber, stbKeypad.Digit1); trilist.SetBoolSigAction(joinMap.Digit2.JoinNumber, stbKeypad.Digit2); trilist.SetBoolSigAction(joinMap.Digit3.JoinNumber, stbKeypad.Digit3); trilist.SetBoolSigAction(joinMap.Digit4.JoinNumber, stbKeypad.Digit4); trilist.SetBoolSigAction(joinMap.Digit5.JoinNumber, stbKeypad.Digit5); trilist.SetBoolSigAction(joinMap.Digit6.JoinNumber, stbKeypad.Digit6); trilist.SetBoolSigAction(joinMap.Digit7.JoinNumber, stbKeypad.Digit7); trilist.SetBoolSigAction(joinMap.Digit8.JoinNumber, stbKeypad.Digit8); trilist.SetBoolSigAction(joinMap.Digit9.JoinNumber, stbKeypad.Digit9); trilist.SetBoolSigAction(joinMap.KeypadAccessoryButton1Press.JoinNumber, stbKeypad.KeypadAccessoryButton1); trilist.SetBoolSigAction(joinMap.KeypadAccessoryButton2Press.JoinNumber, stbKeypad.KeypadAccessoryButton1); trilist.SetBoolSigAction(joinMap.Dash.JoinNumber, stbKeypad.Dash); trilist.SetBoolSigAction(joinMap.KeypadEnter.JoinNumber, stbKeypad.KeypadEnter); } if (this is ITransport stbTransport) { trilist.SetBoolSigAction(joinMap.Play.JoinNumber, stbTransport.Play); trilist.SetBoolSigAction(joinMap.Pause.JoinNumber, stbTransport.Pause); trilist.SetBoolSigAction(joinMap.Rewind.JoinNumber, stbTransport.Rewind); trilist.SetBoolSigAction(joinMap.FFwd.JoinNumber, stbTransport.FFwd); trilist.SetBoolSigAction(joinMap.ChapMinus.JoinNumber, stbTransport.ChapMinus); trilist.SetBoolSigAction(joinMap.ChapPlus.JoinNumber, stbTransport.ChapPlus); trilist.SetBoolSigAction(joinMap.Stop.JoinNumber, stbTransport.Stop); trilist.SetBoolSigAction(joinMap.Record.JoinNumber, stbTransport.Record); } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBaseFactory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a IRSetTopBoxBaseFactory /// public class IRSetTopBoxBaseFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the class /// public IRSetTopBoxBaseFactory() { TypeNames = new List() { "settopbox" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new SetTopBox Device"); var irCont = IRPortHelper.GetIrOutputPortController(dc); var config = dc.Properties.ToObject(); var stb = new IRSetTopBoxBase(dc.Key, dc.Name, irCont, config); var listName = dc.Properties.Value("presetsList"); if (listName != null) stb.LoadPresets(listName); return stb; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a SetTopBoxPropertiesConfig /// public class SetTopBoxPropertiesConfig : PepperDash.Essentials.Core.Config.SourceDevicePropertiesConfigBase { /// /// Gets or sets the HasPresets /// public bool HasPresets { get; set; } /// /// Gets or sets the HasDvr /// public bool HasDvr { get; set; } /// /// Gets or sets the HasDpad /// public bool HasDpad { get; set; } /// /// Gets or sets the HasNumeric /// public bool HasNumeric { get; set; } /// /// Gets or sets the IrPulseTime /// public int IrPulseTime { get; set; } /// /// Gets or sets the Control /// public ControlPropertiesConfig Control { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs ================================================ using System.Collections.Generic; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.CrestronIO; using PepperDash.Essentials.Core.Shades; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Shades { /// /// Controls a single shade using three relays /// public class RelayControlledShade : ShadeBase, IShadesOpenCloseStop { RelayControlledShadeConfigProperties Config; ISwitchedOutput OpenRelay; ISwitchedOutput StopOrPresetRelay; ISwitchedOutput CloseRelay; int RelayPulseTime; /// /// Gets or sets the StopOrPresetButtonLabel /// public string StopOrPresetButtonLabel { get; set; } /// /// Initializes a new instance of the RelayControlledShade class /// /// The device key /// The device name /// The relay controlled shade configuration public RelayControlledShade(string key, string name, RelayControlledShadeConfigProperties config) : base(key, name) { Config = config; RelayPulseTime = Config.RelayPulseTime; StopOrPresetButtonLabel = Config.StopOrPresetLabel; } /// /// CustomActivate method /// /// public override bool CustomActivate() { //Create ISwitchedOutput objects based on props OpenRelay = GetSwitchedOutputFromDevice(Config.Relays.Open); StopOrPresetRelay = GetSwitchedOutputFromDevice(Config.Relays.StopOrPreset); CloseRelay = GetSwitchedOutputFromDevice(Config.Relays.Close); return base.CustomActivate(); } /// /// Open method /// /// public override void Open() { Debug.LogMessage(LogEventLevel.Debug, this, "Opening Shade: '{0}'", this.Name); PulseOutput(OpenRelay, RelayPulseTime); } /// /// Stop method /// /// public override void Stop() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Shade: '{0}'", this.Name); PulseOutput(StopOrPresetRelay, RelayPulseTime); } /// /// Close method /// /// public override void Close() { Debug.LogMessage(LogEventLevel.Debug, this, "Closing Shade: '{0}'", this.Name); PulseOutput(CloseRelay, RelayPulseTime); } void PulseOutput(ISwitchedOutput output, int pulseTime) { output.On(); CTimer pulseTimer = new CTimer(new CTimerCallbackFunction((o) => output.Off()), pulseTime); } /// /// Attempts to get the port on teh specified device from config /// /// /// ISwitchedOutput GetSwitchedOutputFromDevice(IOPortConfig relayConfig) { var portDevice = DeviceManager.GetDeviceForKey(relayConfig.PortDeviceKey); if (portDevice != null) { return (portDevice as ISwitchedOutputCollection).SwitchedOutputs[relayConfig.PortNumber]; } else { Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get relay on port '{0}' from device with key '{1}'", relayConfig.PortNumber, relayConfig.PortDeviceKey); return null; } } } /// /// Represents a RelayControlledShadeConfigProperties /// public class RelayControlledShadeConfigProperties { /// /// Gets or sets the RelayPulseTime /// public int RelayPulseTime { get; set; } /// /// Gets or sets the Relays /// public ShadeRelaysConfig Relays { get; set; } /// /// Gets or sets the StopOrPresetLabel /// public string StopOrPresetLabel { get; set; } /// /// Represents a ShadeRelaysConfig /// public class ShadeRelaysConfig { /// /// Gets or sets the Open /// public IOPortConfig Open { get; set; } /// /// Gets or sets the StopOrPreset /// public IOPortConfig StopOrPreset { get; set; } /// /// Gets or sets the Close /// public IOPortConfig Close { get; set; } } } /// /// Represents a RelayControlledShadeFactory /// public class RelayControlledShadeFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the RelayControlledShadeFactory class /// public RelayControlledShadeFactory() { TypeNames = new List() { "relaycontrolledshade" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device"); var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); return new RelayControlledShade(dc.Key, dc.Name, props); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs ================================================ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Shades; namespace PepperDash.Essentials.Devices.Common.Shades { /// /// Base class for shade devices /// public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop { /// /// Initializes a new instance of the ShadeBase class /// /// The device key /// The device name public ShadeBase(string key, string name) : base(key, name) { } #region iShadesOpenClose Members /// /// Opens the shade /// public abstract void Open(); /// /// Stops the shade /// public abstract void Stop(); /// /// Closes the shade /// public abstract void Close(); #endregion } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Shades; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Shades { /// /// Class that contains the shades to be controlled in a room /// public class ShadeController : EssentialsDevice, IShades { ShadeControllerConfigProperties Config; /// /// Gets the collection of shades controlled by this controller /// public List Shades { get; private set; } /// /// Initializes a new instance of the ShadeController class /// /// The device key /// The device name /// The shade controller configuration public ShadeController(string key, string name, ShadeControllerConfigProperties config) : base(key, name) { Config = config; Shades = new List(); } /// /// CustomActivate method /// /// public override bool CustomActivate() { foreach (var shadeConfig in Config.Shades) { var shade = DeviceManager.GetDeviceForKey(shadeConfig.Key) as ShadeBase; if (shade != null) { AddShade(shade); } } return base.CustomActivate(); } void AddShade(IShadesOpenCloseStop shade) { Shades.Add(shade); } } /// /// Represents a ShadeControllerConfigProperties /// public class ShadeControllerConfigProperties { /// /// Gets or sets the Shades /// public List Shades { get; set; } /// /// Represents a ShadeConfig /// public class ShadeConfig { /// /// Gets or sets the Key /// public string Key { get; set; } } } /// /// Represents a ShadeControllerFactory /// public class ShadeControllerFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the ShadeControllerFactory class /// public ShadeControllerFactory() { TypeNames = new List() { "shadecontroller" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new ShadeController Device"); var props = Newtonsoft.Json.JsonConvert.DeserializeObject(dc.Properties.ToString()); return new ShadeController(dc.Key, dc.Name, props); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs ================================================ using System; using Crestron.SimplSharp; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Devices.Common.Sources; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.SoftCodec { /// /// Represents a BlueJeansPc /// public class BlueJeansPc : InRoomPc, IRunRouteAction, IRoutingSink { /// /// Gets or sets the AnyVideoIn /// public RoutingInputPort AnyVideoIn { get; private set; } /// /// Gets the CurrentInputPort /// public RoutingInputPort CurrentInputPort => AnyVideoIn; #region IRoutingInputs Members /// /// Gets or sets the InputPorts /// public RoutingPortCollection InputPorts { get; private set; } #endregion /// /// Initializes a new instance of the class /// /// The device key /// The device name public BlueJeansPc(string key, string name) : base(key, name) { InputPorts = new RoutingPortCollection { (AnyVideoIn = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.None, 0, this)) }; } #region IRunRouteAction Members /// /// RunRouteAction method /// public void RunRouteAction(string routeKey, string sourceListKey) { RunRouteAction(routeKey, sourceListKey, null); } /// /// RunRouteAction method /// public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback) { CrestronInvoke.BeginInvoke(o => { Debug.LogMessage(LogEventLevel.Debug, this, "Run route action '{0}' on SourceList: {1}", routeKey, sourceListKey); var dict = ConfigReader.ConfigObject.GetSourceListForKey(sourceListKey); if (dict == null) { Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: Config source list '{0}' not found", sourceListKey); return; } // Try to get the list item by it's string key if (!dict.ContainsKey(routeKey)) { Debug.LogMessage(LogEventLevel.Debug, this, "WARNING: No item '{0}' found on config list '{1}'", routeKey, sourceListKey); return; } var item = dict[routeKey]; foreach (var route in item.RouteList) { DoRoute(route); } // store the name and UI info for routes if (item.SourceKey == "none") { CurrentSourceInfoKey = routeKey; CurrentSourceInfo = null; } else if (item.SourceKey != null) { CurrentSourceInfoKey = routeKey; CurrentSourceInfo = item; } // report back when done if (successCallback != null) successCallback(); }); } #endregion /// /// /// /// /// bool DoRoute(SourceRouteListItem route) { IRoutingSink dest = null; dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink; if (dest == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Cannot route, unknown destination '{0}'", route.DestinationKey); return false; } if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase)) { dest.ReleaseRoute(); if (dest is IHasPowerControl) (dest as IHasPowerControl).PowerOff(); } else { var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs; if (source == null) { Debug.LogMessage(LogEventLevel.Debug, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey); return false; } dest.ReleaseAndMakeRoute(source, route.Type); } return true; } #region IHasCurrentSourceInfoChange Members /// /// Gets or sets the CurrentSourceInfoKey /// public string CurrentSourceInfoKey { get; set; } /// /// The SourceListItem last run - containing names and icons /// public SourceListItem CurrentSourceInfo { get { return _CurrentSourceInfo; } set { if (value == _CurrentSourceInfo) return; var handler = CurrentSourceChange; // remove from in-use tracker, if so equipped if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control"); if (handler != null) handler(_CurrentSourceInfo, ChangeType.WillChange); _CurrentSourceInfo = value; // add to in-use tracking if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control"); if (handler != null) handler(_CurrentSourceInfo, ChangeType.DidChange); } } SourceListItem _CurrentSourceInfo; /// /// Event fired when the current source changes /// public event SourceInfoChangeHandler CurrentSourceChange; #endregion } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPcFactory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.SoftCodec { /// /// Represents a BlueJeansPcFactory /// public class BlueJeansPcFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the class /// public BlueJeansPcFactory() { TypeNames = new List() { "bluejeanspc" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BlueJeansPc Device"); return new BlueJeansPc(dc.Key, dc.Name); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs ================================================ using System.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.SoftCodec { /// /// Represents a GenericSoftCodec /// public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitchingWithInputPort { private RoutingInputPort _currentInputPort; /// /// Gets or sets the CurrentInputPort /// public RoutingInputPort CurrentInputPort { get => _currentInputPort; set { _currentInputPort = value; InputChanged?.Invoke(this, _currentInputPort); } } /// /// Initializes a new instance of the class /// /// The device key /// The device name /// The device properties public GenericSoftCodec(string key, string name, GenericSoftCodecProperties props) : base(key, name) { InputPorts = new RoutingPortCollection(); OutputPorts = new RoutingPortCollection(); for (var i = 1; i <= props.OutputCount; i++) { var outputPort = new RoutingOutputPort($"output{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); OutputPorts.Add(outputPort); } for (var i = 1; i <= props.ContentInputCount; i++) { var inputPort = new RoutingInputPort($"contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this); InputPorts.Add(inputPort); } if (!props.HasCameraInputs) { return; } for (var i = 1; i <= props.CameraInputCount; i++) { var cameraPort = new RoutingInputPort($"cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this); InputPorts.Add(cameraPort); } } /// /// Gets or sets the InputPorts /// public RoutingPortCollection InputPorts { get; private set; } /// /// Gets or sets the OutputPorts /// public RoutingPortCollection OutputPorts { get; private set; } /// /// Gets or sets the CurrentSourceInfoKey /// public string CurrentSourceInfoKey { get; set; } /// /// Gets or sets the CurrentSourceInfo /// public SourceListItem CurrentSourceInfo { get { return _CurrentSourceInfo; } set { if (value == _CurrentSourceInfo) return; var handler = CurrentSourceChange; if (handler != null) handler(_CurrentSourceInfo, ChangeType.WillChange); _CurrentSourceInfo = value; if (handler != null) handler(_CurrentSourceInfo, ChangeType.DidChange); } } SourceListItem _CurrentSourceInfo; /// /// Event fired when the current source changes /// public event SourceInfoChangeHandler CurrentSourceChange; /// /// Event fired when the input changes /// public event InputChangedEventHandler InputChanged; /// /// ExecuteSwitch method /// public void ExecuteSwitch(object inputSelector) { var inputPort = InputPorts.FirstOrDefault(p => p.Selector == inputSelector); if (inputPort == null) { Debug.LogMessage(LogEventLevel.Warning, "No input port found for selector {inputSelector}", inputSelector); return; } CurrentInputPort = inputPort; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodecFactory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.SoftCodec { /// /// Represents a GenericSoftCodecFactory /// public class GenericSoftCodecFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the class /// public GenericSoftCodecFactory() { TypeNames = new List { "genericsoftcodec" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Generic SoftCodec Device"); var props = dc.Properties.ToObject(); return new GenericSoftCodec(dc.Key, dc.Name, props); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodecProperties.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.SoftCodec { /// /// Represents a GenericSoftCodecProperties /// public class GenericSoftCodecProperties { /// /// Gets or sets the HasCameraInputs /// [JsonProperty("hasCameraInputs")] public bool HasCameraInputs { get; set; } /// /// Gets or sets the CameraInputCount /// [JsonProperty("cameraInputCount")] public int CameraInputCount { get; set; } /// /// Gets or sets the ContentInputCount /// [JsonProperty("contentInputCount")] public int ContentInputCount { get; set; } /// /// Gets or sets the OutputCount /// [JsonProperty("contentOutputCount")] public int OutputCount { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Sources { /// /// Represents a InRoomPc /// public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { /// /// Gets or sets the DisplayUiType /// public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } /// /// Gets or sets the IconName /// public string IconName { get; set; } /// /// Gets or sets the HasPowerOnFeedback /// public BoolFeedback HasPowerOnFeedback { get; private set; } /// /// Gets or sets the AnyVideoOut /// public RoutingOutputPort AnyVideoOut { get; private set; } #region IRoutingOutputs Members /// /// Gets or sets the OutputPorts /// public RoutingPortCollection OutputPorts { get; private set; } #endregion /// /// Initializes a new instance of the class /// /// /// public InRoomPc(string key, string name) : base(key, name) { IconName = "PC"; HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); OutputPorts = new RoutingPortCollection { (AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this)) }; } #region IHasFeedback Members /// /// Passes through the VideoStatuses list /// public FeedbackCollection Feedbacks { get { var newList = new FeedbackCollection(); newList.AddRange(this.GetVideoStatuses().ToList()); return newList; } } #endregion #region IUsageTracking Members /// /// Gets or sets the UsageTracker /// public UsageTracking UsageTracker { get; set; } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Sources/InRoomPcFactory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Sources { /// /// Represents a InRoomPcFactory /// public class InRoomPcFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the class /// public InRoomPcFactory() { TypeNames = new List() { "inroompc" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new InRoomPc Device"); return new InRoomPc(dc.Key, dc.Name); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Sources { /// /// Represents a Laptop /// public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking { /// /// Gets or sets the DisplayUiType /// public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } /// /// Gets or sets the IconName /// public string IconName { get; set; } /// /// Gets or sets the HasPowerOnFeedback /// public BoolFeedback HasPowerOnFeedback { get; private set; } /// /// Gets or sets the AnyVideoOut /// public RoutingOutputPort AnyVideoOut { get; private set; } #region IRoutingOutputs Members /// /// Gets or sets the OutputPorts /// public RoutingPortCollection OutputPorts { get; private set; } #endregion /// /// Initializes a new instance of the Laptop class /// /// The device key /// The device name public Laptop(string key, string name) : base(key, name) { IconName = "Laptop"; HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); OutputPorts = new RoutingPortCollection { (AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this)) }; } #region IHasFeedback Members /// /// Passes through the VideoStatuses list /// public FeedbackCollection Feedbacks { get { var newList = new FeedbackCollection(); newList.AddRange(this.GetVideoStatuses().ToList()); return newList; } } #endregion #region IUsageTracking Members /// /// Gets or sets the UsageTracker /// public UsageTracking UsageTracker { get; set; } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Sources/LaptopFactory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Sources { /// /// Represents a LaptopFactory /// public class LaptopFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the class /// public LaptopFactory() { TypeNames = new List() { "laptop" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Laptop Device"); return new Laptop(dc.Key, dc.Name); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs ================================================ using System.Linq; using System.Reflection; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a AppleTV /// Wrapper class for an IR-Controlled AppleTV /// [Description("Wrapper class for an IR-Controlled AppleTV")] public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs { /// /// Gets or sets the IrPort /// public IrOutputPortController IrPort { get; private set; } /// /// Standard Driver Name /// public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir"; /// /// Gets or sets the DisplayUiType /// public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } } /// /// Initializes a new instance of the class /// /// The device key /// The device name /// The IR output port controller public AppleTV(string key, string name, IrOutputPortController portCont) : base(key, name) { IrPort = portCont; DeviceManager.AddDevice(portCont); HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio, eRoutingPortConnectionType.DigitalAudio, null, this); OutputPorts = new RoutingPortCollection { HdmiOut, AnyAudioOut }; PrintExpectedIrCommands(); } /// /// PrintExpectedIrCommands method /// public void PrintExpectedIrCommands() { var cmds = typeof(AppleTvIrCommands).GetFields(BindingFlags.Public | BindingFlags.Static); foreach (var value in cmds.Select(cmd => cmd.GetValue(null)).OfType()) { Debug.LogMessage(LogEventLevel.Verbose, this, "Expected IR Function Name: {0}", value); } } #region IDPad Members /// /// Up method /// public void Up(bool pressRelease) { IrPort.PressRelease(AppleTvIrCommands.Up, pressRelease); } /// /// Down method /// public void Down(bool pressRelease) { IrPort.PressRelease(AppleTvIrCommands.Down, pressRelease); } /// /// Left method /// public void Left(bool pressRelease) { IrPort.PressRelease(AppleTvIrCommands.Left, pressRelease); } /// /// Right method /// public void Right(bool pressRelease) { IrPort.PressRelease(AppleTvIrCommands.Right, pressRelease); } /// /// Select method /// public void Select(bool pressRelease) { IrPort.PressRelease(AppleTvIrCommands.Enter, pressRelease); } /// /// Menu method /// public void Menu(bool pressRelease) { IrPort.PressRelease(AppleTvIrCommands.Menu, pressRelease); } /// /// Exit method /// public void Exit(bool pressRelease) { } #endregion #region ITransport Members /// /// Play method /// public void Play(bool pressRelease) { IrPort.PressRelease(AppleTvIrCommands.PlayPause, pressRelease); } /// /// Pause method /// public void Pause(bool pressRelease) { IrPort.PressRelease(AppleTvIrCommands.PlayPause, pressRelease); } /// /// Not implemented /// /// /// /// Rewind method /// public void Rewind(bool pressRelease) { } /// /// Not implemented /// /// public void FFwd(bool pressRelease) { } /// /// Not implemented /// /// public void ChapMinus(bool pressRelease) { } /// /// Not implemented /// /// public void ChapPlus(bool pressRelease) { } /// /// Not implemented /// /// public void Stop(bool pressRelease) { } /// /// Not implemented /// /// public void Record(bool pressRelease) { } #endregion #region IRoutingOutputs Members /// /// Gets the HdmiOut /// public RoutingOutputPort HdmiOut { get; private set; } /// /// Gets the AnyAudioOut /// public RoutingOutputPort AnyAudioOut { get; private set; } /// /// Gets or sets the OutputPorts /// public RoutingPortCollection OutputPorts { get; private set; } #endregion /// /// LinkToApi method /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new AppleTvJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); if (!string.IsNullOrEmpty(joinMapSerialized)) joinMap = JsonConvert.DeserializeObject(joinMapSerialized); if (bridge != null) { bridge.AddJoinMap(Key, joinMap); } else { Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); Debug.LogMessage(LogEventLevel.Information, "Linking to Bridge Type {0}", GetType().Name); trilist.SetBoolSigAction(joinMap.UpArrow.JoinNumber, Up); trilist.SetBoolSigAction(joinMap.DnArrow.JoinNumber, Down); trilist.SetBoolSigAction(joinMap.LeftArrow.JoinNumber, Left); trilist.SetBoolSigAction(joinMap.RightArrow.JoinNumber, Right); trilist.SetBoolSigAction(joinMap.Select.JoinNumber, Select); trilist.SetBoolSigAction(joinMap.Menu.JoinNumber, Menu); trilist.SetBoolSigAction(joinMap.PlayPause.JoinNumber, Play); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Streaming/AppleTVFactory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a AppleTVFactory /// public class AppleTVFactory : EssentialsDeviceFactory { /// /// Initializes a new instance of the class /// public AppleTVFactory() { TypeNames = new List() { "appletv" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new AppleTV Device"); var irCont = IRPortHelper.GetIrOutputPortController(dc); return new AppleTV(dc.Key, dc.Name, irCont); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Streaming/AppleTvIrCommands.cs ================================================ using Crestron.SimplSharpPro; namespace PepperDash.Essentials.Devices.Common { /// /// Represents AppleTvIrCommands /// public static class AppleTvIrCommands { /// /// Up command /// public static string Up = "+"; /// /// Down command /// public static string Down = "-"; /// /// Left command /// public static string Left = IROutputStandardCommands.IROut_TRACK_MINUS; /// /// Right command /// public static string Right = IROutputStandardCommands.IROut_TRACK_PLUS; /// /// Enter command /// public static string Enter = IROutputStandardCommands.IROut_ENTER; /// /// PlayPause command /// public static string PlayPause = "PLAY/PAUSE"; /// /// Rewind command /// public static string Rewind = "REWIND"; /// /// Menu command /// public static string Menu = "Menu"; /// /// FastForward command /// public static string FastForward = "FASTFORWARD"; } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs ================================================ using Crestron.SimplSharpPro; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a Roku2 /// Wrapper class for an IR-Controlled Roku /// [Description("Wrapper class for an IR-Controlled Roku")] public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs { /// /// Gets or sets the IrPort /// [Api] public IrOutputPortController IrPort { get; private set; } /// /// Standard Driver Name /// public const string StandardDriverName = "Roku XD_S.ir"; /// /// Gets or sets the DisplayUiType /// [Api] public uint DisplayUiType { get { return DisplayUiConstants.TypeRoku; } } /// /// Initializes a new instance of the class /// public Roku2(string key, string name, IrOutputPortController portCont) : base(key, name) { IrPort = portCont; DeviceManager.AddDevice(portCont); ; HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); OutputPorts = new RoutingPortCollection { HdmiOut }; } #region IDPad Members /// /// Up method /// [Api] public void Up(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_UP_ARROW, pressRelease); } /// /// Down method /// [Api] public void Down(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_DN_ARROW, pressRelease); } /// /// Left method /// [Api] public void Left(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_LEFT_ARROW, pressRelease); } /// /// Right method /// [Api] public void Right(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RIGHT_ARROW, pressRelease); } /// /// Select method /// [Api] public void Select(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease); } /// /// Menu method /// [Api] public void Menu(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_MENU, pressRelease); } /// /// Exit method /// [Api] public void Exit(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_EXIT, pressRelease); } #endregion #region ITransport Members /// /// Play method /// [Api] public void Play(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_PLAY, pressRelease); } /// /// Pause method /// [Api] public void Pause(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_PAUSE, pressRelease); } /// /// Rewind method /// [Api] public void Rewind(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease); } /// /// FFwd method /// [Api] public void FFwd(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_FSCAN, pressRelease); } /// /// ChapMinus method - Not implemented /// /// public void ChapMinus(bool pressRelease) { } /// /// Not implemented /// /// public void ChapPlus(bool pressRelease) { } /// /// Not implemented /// /// public void Stop(bool pressRelease) { } /// /// Not implemented /// /// public void Record(bool pressRelease) { } #endregion #region IRoutingOutputs Members /// /// HdmiOut /// public RoutingOutputPort HdmiOut { get; private set; } /// /// OutputPorts /// public RoutingPortCollection OutputPorts { get; private set; } #endregion } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/Streaming/Roku2Factory.cs ================================================ using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { /// /// Represents a Roku2Factory /// public class Roku2Factory : EssentialsDeviceFactory { /// /// Roku2Factory constructor /// public Roku2Factory() { TypeNames = new List() { "roku" }; } /// /// BuildDevice method /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Roku Device"); var irCont = IRPortHelper.GetIrOutputPortController(dc); return new Roku2(dc.Key, dc.Name, irCont); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs ================================================ using System; using System.Collections.Generic; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Represents a CiscoCallHistory /// public class CiscoCallHistory { /// /// Represents a CallbackNumber /// public class CallbackNumber { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a DisplayName /// public class DisplayName { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a LastOccurrenceStartTime /// public class LastOccurrenceStartTime { /// /// Gets or sets the Value /// public DateTime Value { get; set; } } /// /// Represents a LastOccurrenceDaysAgo /// public class LastOccurrenceDaysAgo { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a LastOccurrenceHistoryId /// public class LastOccurrenceHistoryId { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a OccurrenceType /// public class OccurrenceType { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a IsAcknowledged /// public class IsAcknowledged { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a OccurrenceCount /// public class OccurrenceCount { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a Entry /// public class Entry { /// /// Gets or sets the id /// public string id { get; set; } /// /// Gets or sets the CallbackNumber /// public CallbackNumber CallbackNumber { get; set; } /// /// Gets or sets the DisplayName /// public DisplayName DisplayName { get; set; } /// /// Gets or sets the LastOccurrenceStartTime /// public LastOccurrenceStartTime LastOccurrenceStartTime { get; set; } /// /// Gets or sets the LastOccurrenceDaysAgo /// public LastOccurrenceDaysAgo LastOccurrenceDaysAgo { get; set; } /// /// Gets or sets the LastOccurrenceHistoryId /// public LastOccurrenceHistoryId LastOccurrenceHistoryId { get; set; } /// /// Gets or sets the OccurrenceType /// public OccurrenceType OccurrenceType { get; set; } /// /// Gets or sets the IsAcknowledged /// public IsAcknowledged IsAcknowledged { get; set; } /// /// Gets or sets the OccurrenceCount /// public OccurrenceCount OccurrenceCount { get; set; } } /// /// Represents a Offset /// public class Offset { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a Limit /// public class Limit { /// /// Gets or sets the Value /// public string Value { get; set; } } /// /// Represents a ResultInfo /// public class ResultInfo { /// /// Gets or sets the Offset /// public Offset Offset { get; set; } /// /// Gets or sets the Limit /// public Limit Limit { get; set; } } /// /// Represents a CallHistoryRecentsResult /// public class CallHistoryRecentsResult { /// /// Gets or sets the status /// public string status { get; set; } /// /// Gets or sets the Entry /// public List Entry { get; set; } /// /// Gets or sets the ResultInfo /// public ResultInfo ResultInfo { get; set; } } /// /// Represents a CommandResponse /// public class CommandResponse { /// /// Gets or sets the CallHistoryRecentsResult /// public CallHistoryRecentsResult CallHistoryRecentsResult { get; set; } } /// /// Represents a RootObject /// public class RootObject { /// /// Gets or sets the CommandResponse /// public CommandResponse CommandResponse { get; set; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using PepperDash.Essentials.Core.Presets; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Interface for camera presets /// public interface IHasCodecRoomPresets { /// /// Event that is raised when the list of room presets has changed. /// event EventHandler CodecRoomPresetsListHasChanged; /// /// List of near end presets that can be recalled. /// List NearEndPresets { get; } /// /// List of far end presets that can be recalled. /// List FarEndRoomPresets { get; } /// /// Selects a near end preset by its ID. /// /// void CodecRoomPresetSelect(int preset); /// /// Stores a near end preset with the given ID and description. /// /// /// void CodecRoomPresetStore(int preset, string description); /// /// Selects a far end preset by its ID. This is typically used to recall a preset that has been defined on the far end codec. /// /// void SelectFarEndPreset(int preset); } /// /// Static class for converting non-generic RoomPresets to generic CameraPresets. /// public static class RoomPresets { /// /// Converts non-generic RoomPresets to generic CameraPresets /// /// /// public static List GetGenericPresets(this List presets) where TSource : ConvertiblePreset where TDestination : PresetBase { return presets.Select(preset => preset.ConvertCodecPreset()) .Where(newPreset => newPreset != null) .Cast() .ToList(); } } /// /// Represents a CodecRoomPreset /// public class CodecRoomPreset : PresetBase { /// /// /// /// /// /// /// public CodecRoomPreset(int id, string description, bool def, bool isDef) : base(id, description, def, isDef) { } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eCommandType.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { /// /// Enumeration of eExternalSourceMode values /// public enum eExternalSourceMode { /// /// Ready state /// Ready, /// /// Not ready state /// NotReady, /// /// Hidden state /// Hidden, /// /// Error state /// Error } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { /// /// Enumeration of eExternalSourceType values /// public enum eExternalSourceType { /// /// Camera source type /// camera, /// /// Desktop source type /// desktop, /// /// Document camera source type /// document_camera, /// /// Media player source type /// mediaplayer, /// /// PC source type /// PC, /// /// Whiteboard source type /// whiteboard, /// /// Other source type /// other } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/CodecCommandWithLabel.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Represents a CodecCommandWithLabel /// public class CodecCommandWithLabel { /// /// Gets or sets the Command /// public string Command { get; private set; } /// /// Gets or sets the Label /// public string Label { get; private set; } /// /// Constructor for /// /// Command string /// Label string public CodecCommandWithLabel(string command, string label) { Command = command; Label = label; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/CodecPhonebookSyncState.cs ================================================ using System; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Represents a CodecPhonebookSyncState /// public class CodecPhonebookSyncState : IKeyed { private bool _InitialSyncComplete; /// /// Constructor for CodecPhonebookSyncState /// /// Key for the codec phonebook sync state public CodecPhonebookSyncState(string key) { Key = key; CodecDisconnected(); } /// /// Gets or sets the InitialSyncComplete /// public bool InitialSyncComplete { get { return _InitialSyncComplete; } private set { if (value == true) { InitialSyncCompleted?.Invoke(this, new EventArgs()); } _InitialSyncComplete = value; } } /// /// Gets or sets the InitialPhonebookFoldersWasReceived /// public bool InitialPhonebookFoldersWasReceived { get; private set; } /// /// Gets or sets the NumberOfContactsWasReceived /// public bool NumberOfContactsWasReceived { get; private set; } /// /// Gets or sets the PhonebookRootEntriesWasRecieved /// public bool PhonebookRootEntriesWasRecieved { get; private set; } /// /// Gets or sets the PhonebookHasFolders /// public bool PhonebookHasFolders { get; private set; } /// /// Gets or sets the NumberOfContacts /// public int NumberOfContacts { get; private set; } #region IKeyed Members /// /// Gets or sets the Key /// public string Key { get; private set; } #endregion /// /// Event InitialSyncCompleted /// public event EventHandler InitialSyncCompleted; /// /// InitialPhonebookFoldersReceived method /// public void InitialPhonebookFoldersReceived() { InitialPhonebookFoldersWasReceived = true; CheckSyncStatus(); } /// /// PhonebookRootEntriesReceived method /// public void PhonebookRootEntriesReceived() { PhonebookRootEntriesWasRecieved = true; CheckSyncStatus(); } /// /// SetPhonebookHasFolders method /// public void SetPhonebookHasFolders(bool value) { PhonebookHasFolders = value; Debug.LogMessage(LogEventLevel.Debug, this, "Phonebook has folders: {0}", PhonebookHasFolders); } /// /// SetNumberOfContacts method /// public void SetNumberOfContacts(int contacts) { NumberOfContacts = contacts; NumberOfContactsWasReceived = true; Debug.LogMessage(LogEventLevel.Debug, this, "Phonebook contains {0} contacts.", NumberOfContacts); CheckSyncStatus(); } /// /// CodecDisconnected method /// public void CodecDisconnected() { InitialPhonebookFoldersWasReceived = false; PhonebookHasFolders = false; NumberOfContacts = 0; NumberOfContactsWasReceived = false; } private void CheckSyncStatus() { if (InitialPhonebookFoldersWasReceived && NumberOfContactsWasReceived && PhonebookRootEntriesWasRecieved) { InitialSyncComplete = true; Debug.LogMessage(LogEventLevel.Debug, this, "Initial Phonebook Sync Complete!"); } else { InitialSyncComplete = false; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs ================================================ using PepperDash.Essentials.Core.Presets; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Base class for presets that can be converted to PresetBase /// public abstract class ConvertiblePreset { /// /// Converts the preset to a PresetBase /// /// public abstract PresetBase ConvertCodecPreset(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/CodecParticipants.cs ================================================ using System; using System.Collections.Generic; using System.Linq; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Represents a CodecParticipants /// public class CodecParticipants { private List _currentParticipants; /// /// Gets or sets the CurrentParticipants /// public List CurrentParticipants { get { return _currentParticipants; } set { _currentParticipants = value; OnParticipantsChanged(); } } /// /// Gets the Host participant /// public Participant Host { get { return _currentParticipants.FirstOrDefault(p => p.IsHost); } } /// /// Event fired when the participants list has changed /// public event EventHandler ParticipantsListHasChanged; /// /// Initializes a new instance of the CodecParticipants class /// public CodecParticipants() { _currentParticipants = new List(); } /// /// OnParticipantsChanged method /// public void OnParticipantsChanged() { var handler = ParticipantsListHasChanged; if (handler == null) return; handler(this, new EventArgs()); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Defines the required elements for layout control /// public interface IHasCodecLayouts { /// /// Feedback that indicates the current layout on the local display /// StringFeedback LocalLayoutFeedback { get; } /// /// Toggles the local layout /// void LocalLayoutToggle(); /// /// Toggles the local layout to single prominent /// void LocalLayoutToggleSingleProminent(); /// /// Toggle the MinMax layout /// void MinMaxLayoutToggle(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Defines the requred elements for selfview control /// public interface IHasCodecSelfView { /// /// Feedback that indicates whether Selfview is on /// BoolFeedback SelfviewIsOnFeedback { get; } /// /// Setting that indicates whether the device shows selfview by default /// bool ShowSelfViewByDefault { get; } /// /// Turns selfview on /// void SelfViewModeOn(); /// /// Turns selfview off /// void SelfViewModeOff(); /// /// Toggles selfview mode /// void SelfViewModeToggle(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs ================================================  using System; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Describes a device that provides meeting information (like a ZoomRoom) /// public interface IHasMeetingInfo { /// /// Raised when meeting info changes /// event EventHandler MeetingInfoChanged; /// /// Gets the current meeting information /// MeetingInfo MeetingInfo { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Defines the contract for IHasMeetingLock /// public interface IHasMeetingLock { /// /// Feedback that indicates whether the meeting is locked /// BoolFeedback MeetingIsLockedFeedback { get; } /// /// Locks the meeting /// void LockMeeting(); /// /// Unlocks the meeting /// void UnLockMeeting(); /// /// Toggles the meeting lock state /// void ToggleMeetingLock(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Defines the contract for IHasMeetingRecording /// public interface IHasMeetingRecording { /// /// Feedback that indicates whether the meeting is being recorded /// BoolFeedback MeetingIsRecordingFeedback { get; } /// /// Starts recording the meeting /// void StartRecording(); /// /// Stops recording the meeting /// void StopRecording(); /// /// Toggles recording the meeting /// void ToggleRecording(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecordingWithPrompt.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Defines the contract for IHasMeetingRecordingWithPrompt /// public interface IHasMeetingRecordingWithPrompt : IHasMeetingRecording { /// /// Feedback that indicates whether the recording consent prompt is visible /// BoolFeedback RecordConsentPromptIsVisible { get; } /// /// Used to agree or disagree to the meeting being recorded when prompted /// /// void RecordingPromptAcknowledgement(bool agree); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantAudioMute.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Defines the contract for IHasParticipantAudioMute /// public interface IHasParticipantAudioMute : IHasParticipantVideoMute { /// /// Mute audio of all participants /// void MuteAudioForAllParticipants(); /// /// Mute audio for participant /// /// The user ID of the participant to mute void MuteAudioForParticipant(int userId); /// /// Unmute audio for participant /// /// The user ID of the participant to unmute void UnmuteAudioForParticipant(int userId); /// /// Toggles audio for participant /// /// The user ID of the participant to toggle void ToggleAudioForParticipant(int userId); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantPinUnpin.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Defines the contract for IHasParticipantPinUnpin /// public interface IHasParticipantPinUnpin : IHasParticipants { /// /// Feedback that indicates the number of screens available for pinning participants /// IntFeedback NumberOfScreensFeedback { get; } /// /// Gets the screen index to pin the user to /// int ScreenIndexToPinUserTo { get; } /// /// Pins a participant to a screen /// /// The user ID of the participant to pin /// The screen index to pin the user to void PinParticipant(int userId, int screenIndex); /// /// Unpins a participant /// /// The user ID of the participant to unpin void UnPinParticipant(int userId); /// /// Toggles the pin state of a participant /// /// The user ID of the participant to toggle /// The screen index to pin the user to void ToggleParticipantPinState(int userId, int screenIndex); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantVideoMute.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Describes the ability to mute and unmute a participant's video in a meeting /// public interface IHasParticipantVideoMute : IHasParticipants { /// /// Mute video of all participants /// /// The user ID of the participant to mute void MuteVideoForParticipant(int userId); /// /// Unmute video of all participants /// /// The user ID of the participant to unmute void UnmuteVideoForParticipant(int userId); /// /// Toggles video of a participant /// /// The user ID of the participant to toggle void ToggleVideoForParticipant(int userId); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Describes a device that has call participants /// public interface IHasParticipants { /// /// Gets the collection of participants /// CodecParticipants Participants { get; } /// /// Removes the participant from the meeting /// /// void RemoveParticipant(int userId); /// /// Sets the participant as the new host /// /// void SetParticipantAsHost(int userId); /// /// Admits a participant from the waiting room /// /// void AdmitParticipantFromWaitingRoom(int userId); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Defines the contract for IHasPresentationOnlyMeeting /// public interface IHasPresentationOnlyMeeting { /// /// Starts a presentation only meeting /// void StartSharingOnlyMeeting(); /// /// Starts a presentation only meeting with specified display mode /// /// The display mode for the meeting void StartSharingOnlyMeeting(eSharingMeetingMode displayMode); /// /// Starts a presentation only meeting with specified display mode and duration /// /// The display mode for the meeting /// The duration for the meeting void StartSharingOnlyMeeting(eSharingMeetingMode displayMode, uint duration); /// /// Starts a presentation only meeting with specified display mode, duration, and password /// /// The display mode for the meeting /// The duration for the meeting /// The password for the meeting void StartSharingOnlyMeeting(eSharingMeetingMode displayMode, uint duration, string password); /// /// Starts a normal meeting from a sharing only meeting /// void StartNormalMeetingFromSharingOnlyMeeting(); } /// /// Enumeration of eSharingMeetingMode values /// public enum eSharingMeetingMode { /// /// No specific sharing mode /// None, /// /// Laptop sharing mode /// Laptop, /// /// iOS sharing mode /// Ios, } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs ================================================ using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IHasSelfviewPosition /// public interface IHasSelfviewPosition { /// /// Gets the SelfviewPipPositionFeedback /// StringFeedback SelfviewPipPositionFeedback { get; } /// /// Sets the selfview position /// void SelfviewPipPositionSet(CodecCommandWithLabel position); /// /// Toggles the selfview position /// void SelfviewPipPositionToggle(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs ================================================ using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// /// Defines the contract for IHasSelfviewSize /// public interface IHasSelfviewSize { /// /// Gets the SelfviewPipSizeFeedback /// StringFeedback SelfviewPipSizeFeedback { get; } /// /// Sets the selfview size /// /// The new selfview size void SelfviewPipSizeSet(CodecCommandWithLabel size); /// /// Toggles the selfview size /// void SelfviewPipSizeToggle(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Describes a device that has Standby Mode capability /// public interface IHasStandbyMode { /// /// Feedback that indicates whether Standby Mode is on /// BoolFeedback StandbyIsOnFeedback { get; } /// /// Activates Standby Mode /// void StandbyActivate(); /// /// Deactivates Standby Mode /// void StandbyDeactivate(); } /// /// Defines the contract for IHasHalfWakeMode /// public interface IHasHalfWakeMode : IHasStandbyMode { /// /// Feedback that indicates whether Half Wake Mode is on /// BoolFeedback HalfWakeModeIsOnFeedback { get; } /// /// Feedback that indicates whether the device is entering Standby Mode /// BoolFeedback EnteringStandbyModeFeedback { get; } /// /// Activates Half Wake Mode /// void HalfwakeActivate(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Describes the ability to start an ad-hoc meeting /// public interface IHasStartMeeting { /// /// The default meeting duration in minutes /// uint DefaultMeetingDurationMin { get; } /// /// Start an ad-hoc meeting for the specified duration /// /// void StartMeeting(uint duration); /// /// Leaves a meeting without ending it /// void LeaveMeeting(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// For rooms that have video codec /// public interface IHasVideoCodec : IHasInCallFeedback, IPrivacy { /// /// Gets the VideoCodecBase instance /// VideoCodecBase VideoCodec { get; } /// /// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis /// IntFeedback CallTypeFeedback { get; } /// /// When something in the room is sharing with the far end or through other means /// BoolFeedback IsSharingFeedback { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs ================================================ using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Defines the contract for IJoinCalls /// public interface IJoinCalls { /// /// Joins a call /// /// The active call to join void JoinCall(CodecActiveCallItem activeCall); /// /// Joins all calls /// void JoinAllCalls(); } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/MeetingInfo.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Represents a MeetingInfo /// public class MeetingInfo { /// /// Gets or sets the Id /// [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public string Id { get; private set; } /// /// Gets or sets the Name /// [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; private set; } /// /// Gets or sets the Host /// [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)] public string Host { get; private set; } /// /// Gets or sets the Password /// [JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)] public string Password { get; private set; } /// /// Gets or sets the ShareStatus /// [JsonProperty("shareStatus", NullValueHandling = NullValueHandling.Ignore)] public string ShareStatus { get; private set; } /// /// Gets or sets the IsHost /// [JsonProperty("isHost", NullValueHandling = NullValueHandling.Ignore)] public bool IsHost { get; private set; } /// /// Gets or sets the IsSharingMeeting /// [JsonProperty("isSharingMeeting", NullValueHandling = NullValueHandling.Ignore)] public bool IsSharingMeeting { get; private set; } /// /// Gets or sets the WaitingForHost /// [JsonProperty("waitingForHost", NullValueHandling = NullValueHandling.Ignore)] public bool WaitingForHost { get; private set; } /// /// Gets or sets the IsLocked /// [JsonProperty("isLocked", NullValueHandling = NullValueHandling.Ignore)] public bool IsLocked { get; private set; } /// /// Gets or sets the IsRecording /// [JsonProperty("isRecording", NullValueHandling = NullValueHandling.Ignore)] public bool IsRecording { get; private set; } /// /// Gets or sets the CanRecord /// [JsonProperty("canRecord", NullValueHandling = NullValueHandling.Ignore)] public bool CanRecord { get; private set; } /// /// Constructor for MeetingInfo /// /// The unique identifier for the meeting /// The name of the meeting /// The host of the meeting /// The password for the meeting /// The share status of the meeting /// Indicates whether the current user is the host /// Indicates whether the meeting is currently being shared /// Indicates whether the meeting is waiting for the host to join /// Indicates whether the meeting is locked /// Indicates whether the meeting is being recorded /// Indicates whether the meeting can be recorded public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost, bool isSharingMeeting, bool waitingForHost, bool isLocked, bool isRecording, bool canRecord) { Id = id; Name = name; Host = host; Password = password; ShareStatus = shareStatus; IsHost = isHost; IsSharingMeeting = isSharingMeeting; WaitingForHost = waitingForHost; IsLocked = isLocked; IsRecording = isRecording; CanRecord = CanRecord; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/MeetingInfoEventArgs.cs ================================================ using System; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Represents a MeetingInfoEventArgs /// public class MeetingInfoEventArgs : EventArgs { /// /// Gets or sets the Info /// public MeetingInfo Info { get; private set; } /// /// Initializes a new instance of the class. /// /// The meeting information. public MeetingInfoEventArgs(MeetingInfo info) { Info = info; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/Participant.cs ================================================ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Represents a Participant /// public class Participant { /// /// Gets or sets the UserId /// public int UserId { get; set; } /// /// Gets or sets the IsHost /// public bool IsHost { get; set; } /// /// Gets or sets the IsMyself /// public bool IsMyself { get; set; } /// /// Gets or sets the Name /// public string Name { get; set; } /// /// Gets or sets the Email /// public bool CanMuteVideo { get; set; } /// /// Gets or sets the CanUnmuteVideo /// public bool CanUnmuteVideo { get; set; } /// /// Gets or sets the CanMuteAudio /// public bool VideoMuteFb { get; set; } /// /// Gets or sets the AudioMuteFb /// public bool AudioMuteFb { get; set; } /// /// Gets or sets the HandIsRaisedFb /// public bool HandIsRaisedFb { get; set; } /// /// Gets or sets the IsPinnedFb /// public bool IsPinnedFb { get; set; } /// /// Gets or sets the ScreenIndexIsPinnedToFb /// public int ScreenIndexIsPinnedToFb { get; set; } /// /// Initializes a new instance of the class /// public Participant() { // Initialize to -1 (no screen) ScreenIndexIsPinnedToFb = -1; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Implements a common set of data about a codec /// public interface iVideoCodecInfo { /// /// Gets the codec information /// VideoCodecInfo CodecInfo { get; } } /// /// Stores general information about a codec /// public abstract class VideoCodecInfo { /// /// Gets a value indicating whether the multi-site option is enabled /// [JsonProperty("multiSiteOptionIsEnabled", NullValueHandling = NullValueHandling.Ignore)] public abstract bool MultiSiteOptionIsEnabled { get; } /// /// Gets the IP address of the codec /// [JsonProperty("ipAddress", NullValueHandling = NullValueHandling.Ignore)] public abstract string IpAddress { get; } /// /// Gets the SIP phone number for the codec /// [JsonProperty("sipPhoneNumber", NullValueHandling = NullValueHandling.Ignore)] public abstract string SipPhoneNumber { get; } /// /// Gets the E164 alias for the codec /// [JsonProperty("e164Alias", NullValueHandling = NullValueHandling.Ignore)] public abstract string E164Alias { get; } /// /// Gets the H323 ID for the codec /// [JsonProperty("h323Id", NullValueHandling = NullValueHandling.Ignore)] public abstract string H323Id { get; } /// /// Gets the SIP URI for the codec /// [JsonProperty("sipUri", NullValueHandling = NullValueHandling.Ignore)] public abstract string SipUri { get; } /// /// Gets a value indicating whether auto-answer is enabled /// [JsonProperty("autoAnswerEnabled", NullValueHandling = NullValueHandling.Ignore)] public abstract bool AutoAnswerEnabled { get; } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs ================================================ using System.Collections.Generic; using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Mock video codec directory structure /// public static class MockVideoCodecDirectory { /// /// Enumeration of eFolderId values /// public enum eFolderId { /// /// The United States folder /// UnitedStates, /// /// The Canada folder /// Canada, /// /// The New York folder /// NewYork, /// /// The Boston folder /// Boston, /// /// The San Francisco folder /// SanFrancisco, /// /// The Denver folder /// Denver, /// /// The Austin folder /// Austin, /// /// The Calgary folder /// Calgary } /// /// Aggregates the directory items for all directories into a single directory for searching purposes /// public static CodecDirectory CompleteDirectory { get { var completeDirectory = new CodecDirectory(); completeDirectory.AddContactsToDirectory(DirectoryRoot.CurrentDirectoryResults); completeDirectory.AddContactsToDirectory(UnitedStatesFolderContents.CurrentDirectoryResults); completeDirectory.AddContactsToDirectory(CanadaFolderContents.CurrentDirectoryResults); completeDirectory.AddContactsToDirectory(NewYorkFolderContents.CurrentDirectoryResults); completeDirectory.AddContactsToDirectory(BostonFolderContents.CurrentDirectoryResults); completeDirectory.AddContactsToDirectory(DenverFolderContents.CurrentDirectoryResults); completeDirectory.AddContactsToDirectory(AustinFolderContents.CurrentDirectoryResults); completeDirectory.AddContactsToDirectory(CalgaryFolderContents.CurrentDirectoryResults); return completeDirectory; } } /// /// The root of the directory structure /// public static CodecDirectory DirectoryRoot { get { var directory = new CodecDirectory(); directory.AddFoldersToDirectory ( new List() { new DirectoryFolder() { FolderId = eFolderId.UnitedStates.ToString(), Name = "United States", ParentFolderId = "", Contacts = null }, new DirectoryFolder() { FolderId = eFolderId.Canada.ToString(), Name = "Canada", ParentFolderId = "", Contacts = null } } ); directory.AddContactsToDirectory ( new List() { new DirectoryContact() { Name = "Corporate Bridge", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "c_1", Number = "site.corp.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } } } ); return directory; } } /// /// Contents of the United States folder /// public static CodecDirectory UnitedStatesFolderContents { get { var directory = new CodecDirectory { ResultsFolderId = eFolderId.UnitedStates.ToString() }; directory.AddFoldersToDirectory ( new List() { new DirectoryFolder() { FolderId = eFolderId.NewYork.ToString(), Name = "New York", ParentFolderId = eFolderId.UnitedStates.ToString(), Contacts = null }, new DirectoryFolder() { FolderId = eFolderId.Boston.ToString(), Name = "Boston", ParentFolderId = eFolderId.UnitedStates.ToString(), Contacts = null }, new DirectoryFolder() { FolderId = eFolderId.SanFrancisco.ToString(), Name = "San Francisco", ParentFolderId = eFolderId.UnitedStates.ToString(), Contacts = null }, new DirectoryFolder() { FolderId = eFolderId.Denver.ToString(), Name = "Denver", ParentFolderId = eFolderId.UnitedStates.ToString(), Contacts = null }, new DirectoryFolder() { FolderId = eFolderId.Austin.ToString(), Name = "Austin", ParentFolderId = eFolderId.UnitedStates.ToString(), Contacts = null } } ); return directory; } } /// /// Contents of the New York folder /// public static CodecDirectory NewYorkFolderContents { get { var directory = new CodecDirectory { ResultsFolderId = eFolderId.NewYork.ToString() }; directory.AddContactsToDirectory ( new List() { new DirectoryContact() { ContactId = "nyc_1", Name = "Meeting Room", Title = @"", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "cid_1", Number = "nycmeetingroom.pepperdash.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } }, new DirectoryContact() { ContactId = "nyc_2", Name = "Sumanth Rayancha", Title = @"CTO", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "cid_1", Number = "srayancha.pepperdash.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } }, new DirectoryContact() { ContactId = "nyc_3", Name = "Justin Gordon", Title = @"Software Developer", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "cid_1", Number = "jgordon.pepperdash.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } } } ); return directory; } } /// /// Contents of the Boston folder /// public static CodecDirectory BostonFolderContents { get { var directory = new CodecDirectory { ResultsFolderId = eFolderId.Boston.ToString() }; directory.AddContactsToDirectory ( new List() { new DirectoryContact() { ContactId = "bos_1", Name = "Board Room", Title = @"", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "cid_1", Number = "bosboardroom.pepperdash.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } } } ); return directory; } } /// /// Contents of the San Francisco folder /// public static CodecDirectory SanFranciscoFolderContents { get { var directory = new CodecDirectory { ResultsFolderId = eFolderId.SanFrancisco.ToString() }; directory.AddContactsToDirectory ( new List() { new DirectoryContact() { ContactId = "sfo_1", Name = "David Huselid", Title = @"Cive President, COO", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "cid_1", Number = "dhuselid.pepperdash.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } } } ); return directory; } } /// /// Contents of the Denver folder /// public static CodecDirectory DenverFolderContents { get { var directory = new CodecDirectory { ResultsFolderId = eFolderId.Denver.ToString() }; directory.AddContactsToDirectory ( new List() { new DirectoryContact() { ContactId = "den_1", Name = "Heath Volmer", Title = @"Software Developer", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "cid_1", Number = "hvolmer.pepperdash.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } } } ); return directory; } } /// /// Contents of the Austin folder /// public static CodecDirectory AustinFolderContents { get { var directory = new CodecDirectory { ResultsFolderId = eFolderId.Austin.ToString() }; directory.AddContactsToDirectory ( new List() { new DirectoryContact() { ContactId = "atx_1", Name = "Vincent Longano", Title = @"Product Development Manager", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "cid_1", Number = "vlongano.pepperdash.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } } } ); return directory; } } /// /// Contents of the Canada folder /// public static CodecDirectory CanadaFolderContents { get { var directory = new CodecDirectory { ResultsFolderId = eFolderId.Canada.ToString() }; directory.AddFoldersToDirectory ( new List() { new DirectoryFolder() { FolderId = eFolderId.Calgary.ToString(), Name = "Calgary", ParentFolderId = eFolderId.Canada.ToString(), Contacts = null } } ); return directory; } } /// /// Contents of the Calgary folder /// public static CodecDirectory CalgaryFolderContents { get { var directory = new CodecDirectory { ResultsFolderId = eFolderId.Calgary.ToString() }; directory.AddContactsToDirectory ( new List() { new DirectoryContact() { ContactId = "cdn_1", Name = "Neil Dorin", Title = @"Software Developer /SC", ContactMethods = new List() { new ContactMethod() { ContactMethodId = "cid_1", Number = "ndorin@pepperdash.com", Device = eContactMethodDevice.Video, CallType = eContactMethodCallType.Video } } } } ); return directory; } } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs ================================================  using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Codec; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Represents a MockVC /// public class MockVC : VideoCodecBase, IRoutingSource, IHasCallHistory, IHasScheduleAwareness, IHasCallFavorites, IHasDirectory, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets { /// /// Gets or sets the PropertiesConfig /// public MockVcPropertiesConfig PropertiesConfig; /// /// Gets or sets the CodecOsdIn /// public RoutingInputPort CodecOsdIn { get; private set; } /// /// Gets or sets the HdmiIn1 /// public RoutingInputPort HdmiIn1 { get; private set; } /// /// Gets or sets the HdmiIn2 /// public RoutingInputPort HdmiIn2 { get; private set; } /// /// Gets or sets the HdmiOut /// public RoutingOutputPort HdmiOut { get; private set; } /// /// Gets or sets the CallFavorites /// public CodecCallFavorites CallFavorites { get; private set; } /// /// /// public MockVC(DeviceConfig config) : base(config) { PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); CodecInfo = new MockCodecInfo(); // Get favoritesw if (PropertiesConfig.Favorites != null) { CallFavorites = new CodecCallFavorites(); CallFavorites.Favorites = PropertiesConfig.Favorites; } DirectoryBrowseHistory = new List(); // Debug helpers MuteFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Mute={0}", _IsMuted); PrivacyModeIsOnFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Privacy={0}", _PrivacyModeIsOn); SharingSourceFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "SharingSource={0}", _SharingSource); VolumeLevelFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Volume={0}", _VolumeLevel); CurrentDirectoryResultIsNotDirectoryRoot = new BoolFeedback("currentDirectoryResultIsNotDirectoryRoot", () => DirectoryBrowseHistory.Count > 0); CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); CodecOsdIn = new RoutingInputPort(RoutingPortNames.CodecOsd, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 0, this); InputPorts.Add(CodecOsdIn); HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 1, this); InputPorts.Add(HdmiIn1); HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, 2, this); InputPorts.Add(HdmiIn2); HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); OutputPorts.Add(HdmiOut); CallHistory = new CodecCallHistory(); for (int i = 0; i < 10; i++) { var call = new CodecCallHistory.CallHistoryEntry(); call.Name = "Call " + i; call.Number = i + "@call.com"; CallHistory.RecentCalls.Add(call); } // eventually fire history event here SetupCameras(); CreateOsdSource(); SetIsReady(); } /// protected override Func MuteFeedbackFunc { get { return () => _IsMuted; } } bool _IsMuted; /// protected override Func PrivacyModeIsOnFeedbackFunc { get { return () => _PrivacyModeIsOn; } } bool _PrivacyModeIsOn; /// protected override Func SharingSourceFeedbackFunc { get { return () => _SharingSource; } } string _SharingSource; /// protected override Func SharingContentIsOnFeedbackFunc { get { return () => _SharingIsOn; } } bool _SharingIsOn; /// protected override Func VolumeLevelFeedbackFunc { get { return () => _VolumeLevel; } } int _VolumeLevel; /// protected override Func StandbyIsOnFeedbackFunc { get { return () => _StandbyIsOn; } } bool _StandbyIsOn; /// /// Creates the fake OSD source, and connects it's AudioVideo output to the CodecOsdIn input /// to enable routing /// private void CreateOsdSource() { OsdSource = new DummyRoutingInputsDevice(Key + "[osd]"); DeviceManager.AddDevice(OsdSource); var tl = new TieLine(OsdSource.AudioVideoOutputPort, CodecOsdIn); TieLineCollection.Default.Add(tl); //foreach(var input in Status.Video. } /// public override void Dial(string number) { Debug.LogMessage(LogEventLevel.Debug, this, "Dial: {0}", number); var call = new CodecActiveCallItem() { Name = number, Number = number, Id = number, Status = eCodecCallStatus.Dialing, Direction = eCodecCallDirection.Outgoing, Type = eCodecCallType.Video }; ActiveCalls.Add(call); OnCallStatusChange(call); //ActiveCallCountFeedback.FireUpdate(); // Simulate 2-second ring, then connecting, then connected new CTimer(o => { call.Type = eCodecCallType.Video; SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); }, 2000); } /// public override void Dial(Meeting meeting) { Debug.LogMessage(LogEventLevel.Debug, this, "Dial Meeting: {0}", meeting.Id); var call = new CodecActiveCallItem() { Name = meeting.Title, Number = meeting.Id, Id = meeting.Id, Status = eCodecCallStatus.Dialing, Direction = eCodecCallDirection.Outgoing, Type = eCodecCallType.Video }; ActiveCalls.Add(call); OnCallStatusChange(call); //ActiveCallCountFeedback.FireUpdate(); // Simulate 2-second ring, then connecting, then connected new CTimer(o => { call.Type = eCodecCallType.Video; SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); }, 2000); } /// public override void EndCall(CodecActiveCallItem call) { Debug.LogMessage(LogEventLevel.Debug, this, "EndCall"); ActiveCalls.Remove(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); //ActiveCallCountFeedback.FireUpdate(); } /// public override void EndAllCalls() { Debug.LogMessage(LogEventLevel.Debug, this, "EndAllCalls"); for (int i = ActiveCalls.Count - 1; i >= 0; i--) { var call = ActiveCalls[i]; ActiveCalls.Remove(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); } //ActiveCallCountFeedback.FireUpdate(); } /// public override void AcceptCall(CodecActiveCallItem call) { Debug.LogMessage(LogEventLevel.Debug, this, "AcceptCall"); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); new CTimer(o => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); // should already be in active list } /// public override void RejectCall(CodecActiveCallItem call) { Debug.LogMessage(LogEventLevel.Debug, this, "RejectCall"); ActiveCalls.Remove(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Disconnected, call); //ActiveCallCountFeedback.FireUpdate(); } /// public override void SendDtmf(string s) { Debug.LogMessage(LogEventLevel.Debug, this, "SendDTMF: {0}", s); } /// public override void StartSharing() { _SharingIsOn = true; SharingContentIsOnFeedback.FireUpdate(); } /// public override void StopSharing() { _SharingIsOn = false; SharingContentIsOnFeedback.FireUpdate(); } /// public override void StandbyActivate() { _StandbyIsOn = true; } /// public override void StandbyDeactivate() { _StandbyIsOn = false; } /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { throw new NotImplementedException(); } /// public override void ExecuteSwitch(object selector) { Debug.LogMessage(LogEventLevel.Debug, this, "ExecuteSwitch: {0}", selector); _SharingSource = selector.ToString(); } /// public override void MuteOff() { _IsMuted = false; MuteFeedback.FireUpdate(); } /// public override void MuteOn() { _IsMuted = true; MuteFeedback.FireUpdate(); } /// public override void MuteToggle() { _IsMuted = !_IsMuted; MuteFeedback.FireUpdate(); } /// public override void SetVolume(ushort level) { _VolumeLevel = level; VolumeLevelFeedback.FireUpdate(); } /// public override void VolumeDown(bool pressRelease) { } /// public override void VolumeUp(bool pressRelease) { } /// public override void PrivacyModeOn() { Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteOn"); if (_PrivacyModeIsOn) return; _PrivacyModeIsOn = true; PrivacyModeIsOnFeedback.FireUpdate(); } /// public override void PrivacyModeOff() { Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteOff"); if (!_PrivacyModeIsOn) return; _PrivacyModeIsOn = false; PrivacyModeIsOnFeedback.FireUpdate(); } /// public override void PrivacyModeToggle() { _PrivacyModeIsOn = !_PrivacyModeIsOn; Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteToggle: {0}", _PrivacyModeIsOn); PrivacyModeIsOnFeedback.FireUpdate(); } //******************************************************** // SIMULATION METHODS /// /// TestIncomingVideoCall method /// /// public void TestIncomingVideoCall(string url) { Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingVideoCall from {0}", url); var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type = eCodecCallType.Video, Direction = eCodecCallDirection.Incoming }; ActiveCalls.Add(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); //OnCallStatusChange(eCodecCallStatus.Unknown, eCodecCallStatus.Ringing, call); } /// /// TestIncomingAudioCall method /// /// public void TestIncomingAudioCall(string url) { Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingAudioCall from {0}", url); var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type = eCodecCallType.Audio, Direction = eCodecCallDirection.Incoming }; ActiveCalls.Add(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); //OnCallStatusChange(eCodecCallStatus.Unknown, eCodecCallStatus.Ringing, call); } /// /// TestFarEndHangup method /// public void TestFarEndHangup() { Debug.LogMessage(LogEventLevel.Debug, this, "TestFarEndHangup"); } #region IHasCallHistory Members /// /// CallHistory property /// public CodecCallHistory CallHistory { get; private set; } /// /// RemoveCallHistoryEntry method /// public void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry) { } #endregion #region IHasScheduleAwareness Members /// /// GetSchedule method /// public void GetSchedule() { } /// /// CodecSchedule property /// public CodecScheduleAwareness CodecSchedule { get { // if the last meeting has past, generate a new list if (_CodecSchedule == null || _CodecSchedule.Meetings.Count == 0 || _CodecSchedule.Meetings[_CodecSchedule.Meetings.Count - 1].StartTime < DateTime.Now) { _CodecSchedule = new CodecScheduleAwareness(1000); for (int i = 0; i < 5; i++) { var m = new Meeting(); m.MinutesBeforeMeeting = 5; m.Id = i.ToString(); m.Organizer = "Employee " + 1; m.StartTime = DateTime.Now.AddMinutes(5).AddHours(i); m.EndTime = DateTime.Now.AddHours(i).AddMinutes(50); m.Title = "Meeting " + i; m.Calls.Add(new Call() { Number = i + "meeting@fake.com" }); _CodecSchedule.Meetings.Add(m); } } return _CodecSchedule; } } CodecScheduleAwareness _CodecSchedule; #endregion #region IHasDirectory Members /// /// DirectoryResultReturned event. Fired when the directory result changes /// public event EventHandler DirectoryResultReturned; /// /// DirectoryRoot property. The root of the directory /// public CodecDirectory DirectoryRoot { get { return MockVideoCodecDirectory.DirectoryRoot; } } /// /// CurrentDirectoryResult property. The current directory result /// public CodecDirectory CurrentDirectoryResult { get { if (DirectoryBrowseHistory.Count > 0) return DirectoryBrowseHistory[DirectoryBrowseHistory.Count - 1]; else return DirectoryRoot; } } /// /// PhonebookSyncState property. The current state of the phonebook synchronization /// public CodecPhonebookSyncState PhonebookSyncState { get { var syncState = new CodecPhonebookSyncState(Key + "PhonebookSync"); syncState.InitialPhonebookFoldersReceived(); syncState.PhonebookRootEntriesReceived(); syncState.SetPhonebookHasFolders(true); syncState.SetNumberOfContacts(0); // just need to call this method for the sync to complete return syncState; } } /// /// Search the directory for contacts that contain the search string /// /// The search string to use public void SearchDirectory(string searchString) { var searchResults = new CodecDirectory(); searchResults.ResultsFolderId = "searchResult"; // Search mock directory for contacts that contain the search string, ignoring case List matches = MockVideoCodecDirectory.CompleteDirectory.CurrentDirectoryResults.FindAll( s => s is DirectoryContact && s.Name.ToLower().Contains(searchString.ToLower())); if (matches != null) { searchResults.AddContactsToDirectory(matches); DirectoryBrowseHistory.Add(searchResults); } OnDirectoryResultReturned(searchResults); } /// /// Get the contents of the specified folder /// /// The ID of the folder to get the contents of public void GetDirectoryFolderContents(string folderId) { var folderDirectory = new CodecDirectory(); if (folderId == MockVideoCodecDirectory.eFolderId.UnitedStates.ToString()) folderDirectory = MockVideoCodecDirectory.UnitedStatesFolderContents; else if (folderId == MockVideoCodecDirectory.eFolderId.Canada.ToString()) folderDirectory = MockVideoCodecDirectory.CanadaFolderContents; else if (folderId == MockVideoCodecDirectory.eFolderId.NewYork.ToString()) folderDirectory = MockVideoCodecDirectory.NewYorkFolderContents; else if (folderId == MockVideoCodecDirectory.eFolderId.Boston.ToString()) folderDirectory = MockVideoCodecDirectory.BostonFolderContents; else if (folderId == MockVideoCodecDirectory.eFolderId.SanFrancisco.ToString()) folderDirectory = MockVideoCodecDirectory.SanFranciscoFolderContents; else if (folderId == MockVideoCodecDirectory.eFolderId.Denver.ToString()) folderDirectory = MockVideoCodecDirectory.DenverFolderContents; else if (folderId == MockVideoCodecDirectory.eFolderId.Austin.ToString()) folderDirectory = MockVideoCodecDirectory.AustinFolderContents; else if (folderId == MockVideoCodecDirectory.eFolderId.Calgary.ToString()) folderDirectory = MockVideoCodecDirectory.CalgaryFolderContents; DirectoryBrowseHistory.Add(folderDirectory); OnDirectoryResultReturned(folderDirectory); } /// /// Set the current directory to the root /// public void SetCurrentDirectoryToRoot() { DirectoryBrowseHistory.Clear(); OnDirectoryResultReturned(DirectoryRoot); } /// /// Get the contents of the parent folder /// public void GetDirectoryParentFolderContents() { var currentDirectory = new CodecDirectory(); if (DirectoryBrowseHistory.Count > 0) { var lastItemIndex = DirectoryBrowseHistory.Count - 1; var parentDirectoryContents = DirectoryBrowseHistory[lastItemIndex]; DirectoryBrowseHistory.Remove(DirectoryBrowseHistory[lastItemIndex]); currentDirectory = parentDirectoryContents; } else { currentDirectory = DirectoryRoot; } OnDirectoryResultReturned(currentDirectory); } /// /// Gets or sets the CurrentDirectoryResultIsNotDirectoryRoot /// public BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; private set; } /// /// Gets or sets the DirectoryBrowseHistory /// public List DirectoryBrowseHistory { get; private set; } /// /// OnDirectoryResultReturned method /// public void OnDirectoryResultReturned(CodecDirectory result) { CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); DirectoryResultReturned?.Invoke(this, new DirectoryEventArgs() { Directory = result, DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue }); } #endregion void SetupCameras() { SupportsCameraAutoMode = true; SupportsCameraOff = false; Cameras = new List(); var internalCamera = new MockVCCamera(Key + "-camera1", "Near End", this); Cameras.Add(internalCamera); var farEndCamera = new MockFarEndVCCamera(Key + "-cameraFar", "Far End", this); Cameras.Add(farEndCamera); SelectedCameraFeedback = new StringFeedback("selectedCamera", () => SelectedCamera.Key); ControllingFarEndCameraFeedback = new BoolFeedback("controllingFarEndCamera", () => SelectedCamera is IAmFarEndCamera); CameraAutoModeIsOnFeedback = new BoolFeedback("cameraAutoModeIsOn", () => _CameraAutoModeIsOn); SupportsCameraAutoMode = true; CameraAutoModeIsOnFeedback.FireUpdate(); DeviceManager.AddDevice(internalCamera); DeviceManager.AddDevice(farEndCamera); NearEndPresets = new List(15); // Fix the capacity to emulate Cisco if (PropertiesConfig.Presets != null && PropertiesConfig.Presets.Count > 0) { NearEndPresets = PropertiesConfig.Presets; } else { for (int i = 1; i <= NearEndPresets.Capacity; i++) { var label = string.Format("Near End Preset {0}", i); NearEndPresets.Add(new CodecRoomPreset(i, label, true, false)); } } FarEndRoomPresets = new List(15); // Fix the capacity to emulate Cisco // Add the far end presets for (int i = 1; i <= FarEndRoomPresets.Capacity; i++) { var label = string.Format("Far End Preset {0}", i); FarEndRoomPresets.Add(new CodecRoomPreset(i, label, true, false)); } SelectedCamera = internalCamera; ; // call the method to select the camera and ensure the feedbacks get updated. } #region IHasCameras Members /// /// CameraSelected event. Fired when a camera is selected /// public event EventHandler CameraSelected; /// /// Gets the list of cameras associated with this codec /// public List Cameras { get; private set; } private CameraBase _selectedCamera; /// /// Returns the selected camera /// public CameraBase SelectedCamera { get { return _selectedCamera; } private set { _selectedCamera = value; SelectedCameraFeedback.FireUpdate(); ControllingFarEndCameraFeedback.FireUpdate(); CameraSelected?.Invoke(this, new CameraSelectedEventArgs(SelectedCamera)); } } /// /// Gets or sets the SelectedCameraFeedback /// public StringFeedback SelectedCameraFeedback { get; private set; } /// /// SelectCamera method /// public void SelectCamera(string key) { var camera = Cameras.FirstOrDefault(c => c.Key.ToLower().IndexOf(key.ToLower()) > -1); if (camera != null) { Debug.LogMessage(LogEventLevel.Verbose, this, "Selected Camera with key: '{0}'", camera.Key); SelectedCamera = camera; } else Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to select camera with key: '{0}'", key); } #endregion #region IHasFarEndCameraControl Members /// /// Gets or sets the FarEndCamera /// public CameraBase FarEndCamera { get; private set; } /// /// Gets or sets the ControllingFarEndCameraFeedback /// public BoolFeedback ControllingFarEndCameraFeedback { get; private set; } #endregion #region IHasCameraAutoMode Members private bool _CameraAutoModeIsOn; /// /// CameraAutoModeOn method /// public void CameraAutoModeOn() { _CameraAutoModeIsOn = true; CameraAutoModeIsOnFeedback.FireUpdate(); } /// /// CameraAutoModeOff method /// public void CameraAutoModeOff() { _CameraAutoModeIsOn = false; CameraAutoModeIsOnFeedback.FireUpdate(); } /// /// CameraAutoModeToggle method /// public void CameraAutoModeToggle() { if (_CameraAutoModeIsOn) _CameraAutoModeIsOn = false; else _CameraAutoModeIsOn = true; CameraAutoModeIsOnFeedback.FireUpdate(); } /// /// Gets or sets the CameraAutoModeIsOnFeedback /// public BoolFeedback CameraAutoModeIsOnFeedback { get; private set; } #endregion #region IHasCameraPresets Members /// /// CodecRoomPresetsListHasChanged event. Fired when the presets list changes /// public event EventHandler CodecRoomPresetsListHasChanged; /// /// Gets or sets the NearEndPresets /// public List NearEndPresets { get; private set; } /// /// Gets or sets the FarEndRoomPresets /// public List FarEndRoomPresets { get; private set; } /// /// CodecRoomPresetSelect method /// public void CodecRoomPresetSelect(int preset) { if (SelectedCamera is IAmFarEndCamera) { Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Far End Preset: {0}", preset); } else { Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Near End Preset: {0}", preset); } } /// /// CodecRoomPresetStore method /// public void CodecRoomPresetStore(int preset, string description) { var editPreset = NearEndPresets.FirstOrDefault(p => p.ID.Equals(preset)); if (editPreset != null) { editPreset.Defined = true; editPreset.Description = description; } else NearEndPresets.Add(new CodecRoomPreset(preset, description, true, true)); CodecRoomPresetsListHasChanged?.Invoke(this, new EventArgs()); // Update the config SetConfig(Config); } /// /// SelectFarEndPreset method /// public void SelectFarEndPreset(int i) { Debug.LogMessage(LogEventLevel.Debug, this, "Selecting Far End Preset: {0}", i); } #endregion /// protected override void CustomSetConfig(DeviceConfig config) { PropertiesConfig.Presets = NearEndPresets; Config.Properties = JToken.FromObject(PropertiesConfig); ConfigWriter.UpdateDeviceConfig(config); } } /// /// Represents a MockCodecInfo /// public class MockCodecInfo : VideoCodecInfo { /// public override bool MultiSiteOptionIsEnabled { get { return true; } } /// public override string E164Alias { get { return "someE164alias"; } } /// public override string H323Id { get { return "someH323Id"; } } /// public override string IpAddress { get { return "xxx.xxx.xxx.xxx"; } } /// public override string SipPhoneNumber { get { return "333-444-5555"; } } /// public override string SipUri { get { return "mock@someurl.com"; } } /// public override bool AutoAnswerEnabled { get { return _AutoAnswerEnabled; } } bool _AutoAnswerEnabled; /// /// SetAutoAnswer method /// public void SetAutoAnswer(bool value) { _AutoAnswerEnabled = value; } } /// /// Represents a MockVCFactory /// public class MockVCFactory : EssentialsDeviceFactory { /// public MockVCFactory() { TypeNames = new List() { "mockvc" }; } /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new MockVC Device"); return new VideoCodec.MockVC(dc); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Devices.Common.VideoCodec; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Represents a MockVCCamera /// public class MockVCCamera : CameraBase, IHasCameraPtzControl, IHasCameraFocusControl, IBridgeAdvanced { /// /// Gets the parent video codec /// protected VideoCodecBase ParentCodec { get; private set; } /// /// Initializes a new instance of the MockVCCamera class /// /// The device key /// The device name /// The parent video codec public MockVCCamera(string key, string name, VideoCodecBase codec) : base(key, name) { Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; ParentCodec = codec; } #region IHasCameraPtzControl Members /// /// PositionHome method /// public void PositionHome() { Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); } #endregion #region IHasCameraPanControl Members /// /// PanLeft method /// public void PanLeft() { Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); } /// /// PanRight method /// public void PanRight() { Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); } /// /// PanStop method /// public void PanStop() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); } #endregion #region IHasCameraTiltControl Members /// /// TiltDown method /// public void TiltDown() { Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); } /// /// TiltUp method /// public void TiltUp() { Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); } /// /// TiltStop method /// public void TiltStop() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); } #endregion #region IHasCameraZoomControl Members /// /// ZoomIn method /// public void ZoomIn() { Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); } /// /// ZoomOut method /// public void ZoomOut() { Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); } /// /// ZoomStop method /// public void ZoomStop() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); } #endregion #region IHasCameraFocusControl Members /// /// FocusNear method /// public void FocusNear() { Debug.LogMessage(LogEventLevel.Debug, this, "Focusing Near"); } /// /// FocusFar method /// public void FocusFar() { Debug.LogMessage(LogEventLevel.Debug, this, "Focusing Far"); } /// /// FocusStop method /// public void FocusStop() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Focus"); } /// /// TriggerAutoFocus method /// public void TriggerAutoFocus() { Debug.LogMessage(LogEventLevel.Debug, this, "AutoFocus Triggered"); } #endregion /// /// LinkToApi method /// public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); } } /// /// Represents a MockFarEndVCCamera /// public class MockFarEndVCCamera : CameraBase, IHasCameraPtzControl, IAmFarEndCamera, IBridgeAdvanced { /// /// Gets the parent video codec /// protected VideoCodecBase ParentCodec { get; private set; } /// /// Initializes a new instance of the MockFarEndVCCamera class /// /// The device key /// The device name /// The parent video codec public MockFarEndVCCamera(string key, string name, VideoCodecBase codec) : base(key, name) { Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom; ParentCodec = codec; } #region IHasCameraPtzControl Members /// /// PositionHome method /// public void PositionHome() { Debug.LogMessage(LogEventLevel.Debug, this, "Resetting to home position"); } #endregion #region IHasCameraPanControl Members /// /// PanLeft method /// public void PanLeft() { Debug.LogMessage(LogEventLevel.Debug, this, "Panning Left"); } /// /// PanRight method /// public void PanRight() { Debug.LogMessage(LogEventLevel.Debug, this, "Panning Right"); } /// /// PanStop method /// public void PanStop() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Pan"); } #endregion #region IHasCameraTiltControl Members /// /// TiltDown method /// public void TiltDown() { Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Down"); } /// /// TiltUp method /// public void TiltUp() { Debug.LogMessage(LogEventLevel.Debug, this, "Tilting Up"); } /// /// TiltStop method /// public void TiltStop() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Tilt"); } #endregion #region IHasCameraZoomControl Members /// /// ZoomIn method /// public void ZoomIn() { Debug.LogMessage(LogEventLevel.Debug, this, "Zooming In"); } /// /// ZoomOut method /// public void ZoomOut() { Debug.LogMessage(LogEventLevel.Debug, this, "Zooming Out"); } /// /// ZoomStop method /// public void ZoomStop() { Debug.LogMessage(LogEventLevel.Debug, this, "Stopping Zoom"); } #endregion /// /// LinkToApi method /// public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Represents a MockVcPropertiesConfig /// public class MockVcPropertiesConfig { /// /// Gets or sets the Favorites /// [JsonProperty("favorites")] public List Favorites { get; set; } /// /// Gets or sets the Presets /// [JsonProperty("presets")] public List Presets { get; set; } /// /// Initializes a new instance of the class. /// public MockVcPropertiesConfig() { Favorites = new List(); Presets = new List(); } } } ================================================ FILE: src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Core.Intersystem; using PepperDash.Core.Intersystem.Tokens; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Bridges.JoinMaps; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; using Serilog.Events; using Feedback = PepperDash.Essentials.Core.Feedback; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// Base class for video codec devices /// public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs, IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced, IHasStandbyMode { private const int XSigEncoding = 28591; /// /// Maximum number of participants /// protected const int MaxParticipants = 50; private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs(); /// /// Time format specifier /// protected string _timeFormatSpecifier; /// /// Date format specifier /// protected string _dateFormatSpecifier; /// /// Initializes a new instance of the class. /// protected VideoCodecBase(DeviceConfig config) : base(config) { StandbyIsOnFeedback = new BoolFeedback("standbyIsOn", StandbyIsOnFeedbackFunc); PrivacyModeIsOnFeedback = new BoolFeedback("privacyModeIsOn", PrivacyModeIsOnFeedbackFunc); VolumeLevelFeedback = new IntFeedback("volumeLevel", VolumeLevelFeedbackFunc); MuteFeedback = new BoolFeedback("mute", MuteFeedbackFunc); SharingSourceFeedback = new StringFeedback("sharingSource", SharingSourceFeedbackFunc); SharingContentIsOnFeedback = new BoolFeedback("sharingContentIsOn", SharingContentIsOnFeedbackFunc); // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set MeetingsToDisplayFeedback = new IntFeedback("meetingsToDisplay", () => MeetingsToDisplay); InputPorts = new RoutingPortCollection(); OutputPorts = new RoutingPortCollection(); ActiveCalls = new List(); } /// /// Gets or sets the Communication /// public IBasicCommunication Communication { get; protected set; } /// /// Gets or sets the OsdSource /// public DummyRoutingInputsDevice OsdSource { get; protected set; } /// /// Gets or sets the StandbyIsOnFeedback /// public BoolFeedback StandbyIsOnFeedback { get; private set; } /// /// Gets or sets the PrivacyModeIsOnFeedbackFunc /// protected abstract Func PrivacyModeIsOnFeedbackFunc { get; } /// /// Gets or sets the VolumeLevelFeedbackFunc /// protected abstract Func VolumeLevelFeedbackFunc { get; } /// /// Gets or sets the MuteFeedbackFunc /// protected abstract Func MuteFeedbackFunc { get; } /// /// Gets or sets the StandbyIsOnFeedbackFunc /// protected abstract Func StandbyIsOnFeedbackFunc { get; } /// /// Gets or sets the ActiveCalls /// public List ActiveCalls { get; set; } /// /// Gets or sets the ShowSelfViewByDefault /// public bool ShowSelfViewByDefault { get; protected set; } /// /// Gets or sets the SupportsCameraOff /// public bool SupportsCameraOff { get; protected set; } /// /// Gets or sets the SupportsCameraAutoMode /// public bool SupportsCameraAutoMode { get; protected set; } /// /// Gets or sets the IsReady /// public bool IsReady { get; protected set; } /// public virtual List Feedbacks { get { return new List { PrivacyModeIsOnFeedback, SharingSourceFeedback }; } } /// /// Gets or sets the MeetingsToDisplay /// protected abstract Func SharingSourceFeedbackFunc { get; } /// /// Gets or sets the SharingContentIsOnFeedbackFunc /// protected abstract Func SharingContentIsOnFeedbackFunc { get; } #region ICodecAudio Members /// /// Set Privacy Mode On /// public abstract void PrivacyModeOn(); /// /// Set Privacy Mode Off /// public abstract void PrivacyModeOff(); /// /// Toggles the Privacy Mode /// public abstract void PrivacyModeToggle(); /// /// Gets or sets the PrivacyModeIsOnFeedback /// public BoolFeedback PrivacyModeIsOnFeedback { get; private set; } /// /// Gets or sets the MuteFeedback /// public BoolFeedback MuteFeedback { get; private set; } /// /// Sets the Mute state to Off /// public abstract void MuteOff(); /// /// Sets the Mute state to On /// public abstract void MuteOn(); /// /// Sets the Volume level /// public abstract void SetVolume(ushort level); /// /// Gets or sets the VolumeLevelFeedback /// public IntFeedback VolumeLevelFeedback { get; private set; } /// /// Toggles the Mute state /// public abstract void MuteToggle(); /// /// Decreases the Volume level /// public abstract void VolumeDown(bool pressRelease); /// /// Increases the Volume level /// public abstract void VolumeUp(bool pressRelease); #endregion #region IHasContentSharing Members /// /// Starts content sharing /// public abstract void StartSharing(); /// /// Stops content sharing /// public abstract void StopSharing(); /// /// Gets or sets the AutoShareContentWhileInCall /// public bool AutoShareContentWhileInCall { get; protected set; } /// /// Gets or sets the SharingSourceFeedback /// public StringFeedback SharingSourceFeedback { get; private set; } /// /// Gets or sets the SharingContentIsOnFeedback /// public BoolFeedback SharingContentIsOnFeedback { get; private set; } #endregion #region IHasDialer Members /// /// Fires when the status of any active, dialing, or incoming call changes or is new /// public event EventHandler CallStatusChange; /// /// Returns true when any call is not in state Unknown, Disconnecting, Disconnected /// public bool IsInCall { get { var value = ActiveCalls != null && ActiveCalls.Any(c => c.IsActiveCall); return value; } } /// /// Dials the specified number /// public abstract void Dial(string number); /// /// Ends the specified call /// public abstract void EndCall(CodecActiveCallItem call); /// /// Ends all active calls /// public abstract void EndAllCalls(); /// /// Accepts the specified call /// public abstract void AcceptCall(CodecActiveCallItem call); /// /// Rejects the specified call /// public abstract void RejectCall(CodecActiveCallItem call); /// /// Sends DTMF tones /// public abstract void SendDtmf(string s); /// /// SendDtmf method /// public virtual void SendDtmf(string s, CodecActiveCallItem call) { } #endregion #region IRoutingInputsOutputs Members /// /// Gets or sets the InputPorts /// public RoutingPortCollection InputPorts { get; private set; } /// /// Gets or sets the OutputPorts /// public RoutingPortCollection OutputPorts { get; private set; } #endregion #region IUsageTracking Members /// /// Gets or sets the UsageTracker /// public UsageTracking UsageTracker { get; set; } #endregion #region iVideoCodecInfo Members /// /// Gets the CodecInfo /// public VideoCodecInfo CodecInfo { get; protected set; } #endregion /// /// Fired when the Codec is ready to be used /// public event EventHandler IsReadyChange; /// /// Dials the specified meeting /// /// public abstract void Dial(Meeting meeting); /// /// Dial a contact /// /// The contact to dial public virtual void Dial(IInvitableContact contact) { } /// public abstract void ExecuteSwitch(object selector); /// /// Helper method to fire CallStatusChange event with old and new status /// protected void SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus newStatus, CodecActiveCallItem call) { call.Status = newStatus; OnCallStatusChange(call); } /// /// Sets the previous and new status for the call /// /// protected virtual void OnCallStatusChange(CodecActiveCallItem item) { CallStatusChange?.Invoke(this, new CodecCallStatusItemChangeEventArgs(item)); PrivacyModeIsOnFeedback.FireUpdate(); if (AutoShareContentWhileInCall) { StartSharing(); } if (UsageTracker != null) { if (IsInCall && !UsageTracker.UsageTrackingStarted) { UsageTracker.StartDeviceUsage(); } else if (UsageTracker.UsageTrackingStarted && !IsInCall) { UsageTracker.EndDeviceUsage(); } } } /// /// Sets IsReady property and fires the event. Used for dependent classes to sync up their data. /// protected void SetIsReady() { CrestronInvoke.BeginInvoke((o) => { try { IsReady = true; IsReadyChange?.Invoke(this, new EventArgs()); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, this, "Error in SetIsReady() : {0}", e); } }); } // **** DEBUGGING THINGS **** /// /// ListCalls method /// public virtual void ListCalls() { Debug.LogMessage(LogEventLevel.Debug, this, "Active Calls:"); var sb = new StringBuilder(); foreach (var c in ActiveCalls) { sb.AppendFormat("id: {0} number: {1} -- name: {2} status: {3} onHold: {4}\r\n", c.Id, c.Number, c.Name, c.Status, c.IsOnHold); } Debug.LogMessage(LogEventLevel.Debug, this, "\n{0}\n", sb.ToString()); } /// /// Activate standby /// public abstract void StandbyActivate(); /// /// Deactivate standby /// public abstract void StandbyDeactivate(); #region Implementation of IBridgeAdvanced /// public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); /// /// Use this method when using a plain VideoCodecControllerJoinMap /// /// codec to link /// trilist to link /// join to start with /// key for custom join maps /// bridge controller protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { var joinMap = new VideoCodecControllerJoinMap(joinStart); var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); if (customJoins != null) { joinMap.SetCustomJoinData(customJoins); } bridge?.AddJoinMap(Key, joinMap); LinkVideoCodecToApi(codec, trilist, joinMap); trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; }; } /// /// Use this method when you need to pass in a join map that extends VideoCodecControllerJoinMap /// /// codec to link /// trilist to link /// join map to use protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist {0}", trilist.ID.ToString("X")); LinkVideoCodecDtmfToApi(trilist, joinMap); LinkVideoCodecCallControlsToApi(trilist, joinMap); LinkVideoCodecContentSharingToApi(trilist, joinMap); LinkVideoCodecPrivacyToApi(trilist, joinMap); LinkVideoCodecVolumeToApi(trilist, joinMap); LinkVideoCodecInfoToApi(trilist, joinMap); // Register for this event to link any functions that require the codec to be ready first codec.IsReadyChange += (o, a) => { if (codec is IHasCodecCameras) { LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); } }; if (codec is ICommunicationMonitor) { LinkVideoCodecCommMonitorToApi(codec as ICommunicationMonitor, trilist, joinMap); } if (codec is IHasCodecSelfView) { LinkVideoCodecSelfviewToApi(codec as IHasCodecSelfView, trilist, joinMap); } if (codec is IHasCameraAutoMode) { trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode); LinkVideoCodecCameraModeToApi(codec as IHasCameraAutoMode, trilist, joinMap); } if (codec is IHasCameraOff) { trilist.SetBool(joinMap.CameraSupportsOffMode.JoinNumber, SupportsCameraOff); LinkVideoCodecCameraOffToApi(codec as IHasCameraOff, trilist, joinMap); } if (codec is IHasCodecLayouts) { LinkVideoCodecCameraLayoutsToApi(codec as IHasCodecLayouts, trilist, joinMap); } if (codec is IHasSelfviewPosition) { LinkVideoCodecSelfviewPositionToApi(codec as IHasSelfviewPosition, trilist, joinMap); } if (codec is IHasDirectory) { LinkVideoCodecDirectoryToApi(codec as IHasDirectory, trilist, joinMap); } if (codec is IHasScheduleAwareness) { LinkVideoCodecScheduleToApi(codec as IHasScheduleAwareness, trilist, joinMap); } if (codec is IHasParticipants) { LinkVideoCodecParticipantsToApi(codec as IHasParticipants, trilist, joinMap); } if (codec is IHasFarEndContentStatus) { (codec as IHasFarEndContentStatus).ReceivingContent.LinkInputSig(trilist.BooleanInput[joinMap.RecievingContent.JoinNumber]); } if (codec is IHasPhoneDialing) { LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap); } if (codec is IHasCallHistory) { LinkVideoCodecCallHistoryToApi(codec as IHasCallHistory, trilist, joinMap); } trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; if (codec is IHasDirectory) { (codec as IHasDirectory).SetCurrentDirectoryToRoot(); } if (codec is IHasScheduleAwareness) { (codec as IHasScheduleAwareness).GetSchedule(); } if (codec is IHasParticipants) { UpdateParticipantsXSig((codec as IHasParticipants).Participants.CurrentParticipants); } if (codec is IHasCameraAutoMode) { trilist.SetBool(joinMap.CameraSupportsAutoMode.JoinNumber, SupportsCameraAutoMode); (codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate(); } if (codec is IHasCodecSelfView) { (codec as IHasCodecSelfView).SelfviewIsOnFeedback.FireUpdate(); } if (codec is IHasCameraAutoMode) { (codec as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.FireUpdate(); } if (codec is IHasCameraOff) { (codec as IHasCameraOff).CameraIsOffFeedback.FireUpdate(); } if (codec is IHasPhoneDialing) { (codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate(); } if (codec is IHasCallHistory) { UpdateCallHistory((codec as IHasCallHistory), trilist, joinMap); } SharingContentIsOnFeedback.FireUpdate(); }; } private void LinkVideoCodecInfoToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); trilist.OnlineStatusChange += (o, a) => { if (a.DeviceOnLine) { trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); } }; } private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { codec.PhoneOffHookFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PhoneHookState.JoinNumber]); trilist.SetSigFalseAction(joinMap.DialPhone.JoinNumber, () => codec.DialPhoneCall(trilist.StringOutput[joinMap.PhoneDialString.JoinNumber].StringValue)); trilist.SetSigFalseAction(joinMap.HangUpPhone.JoinNumber, codec.EndPhoneCall); } private void LinkVideoCodecSelfviewPositionToApi(IHasSelfviewPosition codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.SelfviewPosition.JoinNumber, codec.SelfviewPipPositionToggle); codec.SelfviewPipPositionFeedback.LinkInputSig(trilist.StringInput[joinMap.SelfviewPositionFb.JoinNumber]); } private void LinkVideoCodecCameraOffToApi(IHasCameraOff codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.CameraModeOff.JoinNumber, codec.CameraOff); codec.CameraIsOffFeedback.OutputChange += (o, a) => { if (a.BoolValue) { trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); return; } trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); if (!(codec is IHasCameraAutoMode autoCodec)) return; trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoCodec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoCodec.CameraAutoModeIsOnFeedback.BoolValue); }; if (codec.CameraIsOffFeedback.BoolValue) { trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); return; } trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); if (!(codec is IHasCameraAutoMode autoModeCodec)) return; trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); } private void LinkVideoCodecVolumeToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]); MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]); trilist.SetSigFalseAction(joinMap.VolumeMuteOn.JoinNumber, MuteOn); trilist.SetSigFalseAction(joinMap.VolumeMuteOff.JoinNumber, MuteOff); trilist.SetSigFalseAction(joinMap.VolumeMuteToggle.JoinNumber, MuteToggle); VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]); trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, VolumeUp); trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, VolumeDown); trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, SetVolume); } private void LinkVideoCodecPrivacyToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { PrivacyModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.MicMuteOn.JoinNumber]); PrivacyModeIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.MicMuteOff.JoinNumber]); trilist.SetSigFalseAction(joinMap.MicMuteOn.JoinNumber, PrivacyModeOn); trilist.SetSigFalseAction(joinMap.MicMuteOff.JoinNumber, PrivacyModeOff); trilist.SetSigFalseAction(joinMap.MicMuteToggle.JoinNumber, PrivacyModeToggle); } private void LinkVideoCodecCommMonitorToApi(ICommunicationMonitor codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { codec.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); } private void LinkVideoCodecParticipantsToApi(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { // make sure to update the values when the EISC comes online trilist.OnlineStatusChange += (sender, args) => { if (sender.IsOnline) { UpdateParticipantsXSig(codec, trilist, joinMap); } }; // set actions and update the values when the list changes codec.Participants.ParticipantsListHasChanged += (sender, args) => { SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants); UpdateParticipantsXSig(codec, trilist, joinMap); }; trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; // TODO [ ] Issue #868 trilist.SetString(joinMap.CurrentParticipants.JoinNumber, "\xFC"); UpdateParticipantsXSig(codec, trilist, joinMap); }; } private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { string participantsXSig; if (codec.Participants.CurrentParticipants.Count == 0) { participantsXSig = Encoding.GetEncoding(XSigEncoding).GetString(_clearBytes, 0, _clearBytes.Length); trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count); return; } participantsXSig = UpdateParticipantsXSig(codec.Participants.CurrentParticipants); trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count); } /// /// Sets the actions for each participant in the list /// private void SetParticipantActions(BasicTriList trilist, VideoCodecControllerJoinMap joinMap, List currentParticipants) { uint index = 0; // track the index of the participant in the foreach (var participant in currentParticipants) { var p = participant; if (index > MaxParticipants) break; if (this is IHasParticipantAudioMute audioMuteCodec) { trilist.SetSigFalseAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index, () => audioMuteCodec.ToggleAudioForParticipant(p.UserId)); trilist.SetSigFalseAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index, () => audioMuteCodec.ToggleVideoForParticipant(p.UserId)); } if (this is IHasParticipantPinUnpin pinCodec) { trilist.SetSigFalseAction(joinMap.ParticipantPinToggleStart.JoinNumber + index, () => pinCodec.ToggleParticipantPinState(p.UserId, pinCodec.ScreenIndexToPinUserTo)); } index++; } // Clear out any previously set actions while (index < MaxParticipants) { trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index); trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index); trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index); index++; } } private string UpdateParticipantsXSig(List currentParticipants) { const int maxParticipants = MaxParticipants; const int maxDigitals = 7; const int maxStrings = 1; const int maxAnalogs = 1; const int offset = maxDigitals + maxStrings + maxAnalogs; // 9 var digitalIndex = (maxStrings + maxAnalogs) * maxParticipants; // 100 var stringIndex = 0; var analogIndex = stringIndex + maxParticipants; var meetingIndex = 0; var tokenArray = new XSigToken[maxParticipants * offset]; foreach (var participant in currentParticipants) { if (meetingIndex >= maxParticipants * offset) break; // Debug.LogMessage(LogEventLevel.Verbose, this, //@"Updating Participant on xsig: //Name: {0} (s{9}) //AudioMute: {1} (d{10}) //VideoMute: {2} (d{11}) //CanMuteVideo: {3} (d{12}) //CanUMuteVideo: {4} (d{13}) //IsHost: {5} (d{14}) //HandIsRaised: {6} (d{15}) //IsPinned: {7} (d{16}) //ScreenIndexIsPinnedTo: {8} (a{17}) //", // participant.Name, // participant.AudioMuteFb, // participant.VideoMuteFb, // participant.CanMuteVideo, // participant.CanUnmuteVideo, // participant.IsHost, // participant.HandIsRaisedFb, // participant.IsPinnedFb, // participant.ScreenIndexIsPinnedToFb, // stringIndex + 1, // digitalIndex + 1, // digitalIndex + 2, // digitalIndex + 3, // digitalIndex + 4, // digitalIndex + 5, // digitalIndex + 6, // digitalIndex + 7, // analogIndex + 1 // ); //digitals tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, participant.AudioMuteFb); tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, participant.VideoMuteFb); tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, participant.CanMuteVideo); tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, participant.CanUnmuteVideo); tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, participant.IsHost); tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, participant.HandIsRaisedFb); tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, participant.IsPinnedFb); Debug.LogMessage(LogEventLevel.Verbose, this, "Index: {0} byte value: {1}", digitalIndex + 7, ComTextHelper.GetEscapedText(tokenArray[digitalIndex + 6].GetBytes())); //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name); //analogs tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, (ushort)participant.ScreenIndexIsPinnedToFb); digitalIndex += maxDigitals; meetingIndex += offset; stringIndex += maxStrings; analogIndex += maxAnalogs; } while (meetingIndex < maxParticipants * offset) { //digitals tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, false); tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, false); tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, false); tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, false); tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, false); //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); //analogs tokenArray[analogIndex] = new XSigAnalogToken(analogIndex + 1, 0); digitalIndex += maxDigitals; meetingIndex += offset; stringIndex += maxStrings; analogIndex += maxAnalogs; } var returnString = GetXSigString(tokenArray); //Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", ComTextHelper.GetEscapedText(Encoding.GetEncoding(28591).GetBytes(returnString))); return returnString; } private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { SharingContentIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.SourceShareStart.JoinNumber]); SharingContentIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.SourceShareEnd.JoinNumber]); SharingSourceFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentSource.JoinNumber]); trilist.SetSigFalseAction(joinMap.SourceShareStart.JoinNumber, StartSharing); trilist.SetSigFalseAction(joinMap.SourceShareEnd.JoinNumber, StopSharing); trilist.SetBoolSigAction(joinMap.SourceShareAutoStart.JoinNumber, b => AutoShareContentWhileInCall = b); } private List _currentMeetings = new List(); private void LinkVideoCodecScheduleToApi(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.UpdateMeetings.JoinNumber, codec.GetSchedule); trilist.SetUShortSigAction(joinMap.MinutesBeforeMeetingStart.JoinNumber, (i) => { codec.CodecSchedule.MeetingWarningMinutes = i; }); for (uint i = 0; i < joinMap.DialMeetingStart.JoinSpan; i++) { Debug.LogMessage(LogEventLevel.Debug, this, "Setting action to Dial Meeting {0} to digital join {1}", i + 1, joinMap.DialMeetingStart.JoinNumber + i); var joinNumber = joinMap.DialMeetingStart.JoinNumber + i; var mtg = i + 1; var index = (int)i; trilist.SetSigFalseAction(joinNumber, () => { Debug.LogMessage(LogEventLevel.Debug, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", mtg, joinMap.DialMeetingStart.JoinNumber + i, index, _currentMeetings[index].Id, _currentMeetings[index].Title); if (_currentMeetings[index] != null) Dial(_currentMeetings[index]); }); } codec.CodecSchedule.MeetingsListHasChanged += (sender, args) => UpdateMeetingsList(codec, trilist, joinMap); codec.CodecSchedule.MeetingEventChange += (sender, args) => { if (args.ChangeType == eMeetingEventChangeType.MeetingStartWarning) { UpdateMeetingsList(codec, trilist, joinMap); } }; trilist.SetUShortSigAction(joinMap.MeetingsToDisplay.JoinNumber, m => MeetingsToDisplay = m); MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; // TODO [ ] Issue #868 trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); UpdateMeetingsList(codec, trilist, joinMap); // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); }; } private void UpdateMeetingsList(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { var currentTime = DateTime.Now; _currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); if (_currentMeetings.Count == 0) { var emptyXSigByteArray = XSigHelpers.ClearOutputs(); var emptyXSigString = Encoding.GetEncoding(XSigEncoding) .GetString(emptyXSigByteArray, 0, emptyXSigByteArray.Length); trilist.SetString(joinMap.Schedule.JoinNumber, emptyXSigString); return; } var meetingsData = UpdateMeetingsListXSig(_currentMeetings); trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData); trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)_currentMeetings.Count); trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; // TODO [ ] Issue #868 trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); UpdateMeetingsListXSig(_currentMeetings); }; } private int _meetingsToDisplay = 3; /// /// Gets or sets the number of meetings to display on the XSIG /// protected int MeetingsToDisplay { get { return _meetingsToDisplay; } set { _meetingsToDisplay = (ushort)(value == 0 ? 3 : value); MeetingsToDisplayFeedback.FireUpdate(); } } /// /// Gets or sets the MeetingsToDisplayFeedback /// public IntFeedback MeetingsToDisplayFeedback { get; set; } private string UpdateMeetingsListXSig(List meetings) { // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set //const int _meetingsToDisplay = 3; const int maxDigitals = 2; const int maxStrings = 7; const int offset = maxDigitals + maxStrings; var digitalIndex = maxStrings * _meetingsToDisplay; //15 var stringIndex = 0; var meetingIndex = 0; var tokenArray = new XSigToken[_meetingsToDisplay * offset]; /* * Digitals * IsJoinable - 1 * IsDialable - 2 * * Serials * Organizer - 1 * Title - 2 * Start Date - 3 * Start Time - 4 * End Date - 5 * End Time - 6 * Id - 7 */ foreach (var meeting in meetings) { var currentTime = DateTime.Now; if (meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue; if (meetingIndex >= _meetingsToDisplay * offset) { Debug.LogMessage(LogEventLevel.Verbose, this, "Max Meetings reached"); break; } //digitals tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, meeting.Joinable); tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, meeting.Dialable); //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer); tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title); tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id); digitalIndex += maxDigitals; meetingIndex += offset; stringIndex += maxStrings; } while (meetingIndex < _meetingsToDisplay * offset) { Debug.LogMessage(LogEventLevel.Verbose, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}", meetingIndex, _meetingsToDisplay * offset); //digitals tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, String.Empty); digitalIndex += maxDigitals; meetingIndex += offset; stringIndex += maxStrings; } return GetXSigString(tokenArray); } private void LinkVideoCodecDirectoryToApi(IHasDirectory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { codec.CurrentDirectoryResultIsNotDirectoryRoot.LinkComplementInputSig( trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]); trilist.SetStringSigAction(joinMap.DirectorySearchString.JoinNumber, codec.SearchDirectory); trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i, trilist, joinMap)); //Special Change for protected directory clear trilist.SetBoolSigAction(joinMap.DirectoryClearSelected.JoinNumber, (b) => SelectDirectoryEntry(codec, 0, trilist, joinMap)); // Report feedback for number of contact methods for selected contact trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot); trilist.SetSigFalseAction(joinMap.DirectoryFolderBack.JoinNumber, codec.GetDirectoryParentFolderContents); if (codec.DirectoryRoot != null) { var contactsCount = codec.DirectoryRoot.CurrentDirectoryResults.Where(c => c.ParentFolderId.Equals("root")).ToList().Count; trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)contactsCount); Debug.LogMessage(LogEventLevel.Verbose, this, ">>> contactsCount: {0}", contactsCount); var clearBytes = XSigHelpers.ClearOutputs(); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); } codec.DirectoryResultReturned += (sender, args) => { var isRoot = codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false; var argsCount = isRoot ? args.Directory.CurrentDirectoryResults.Where(a => a.ParentFolderId.Equals("root")).ToList().Count : args.Directory.CurrentDirectoryResults.Count; trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)argsCount); Debug.LogMessage(LogEventLevel.Verbose, this, ">>> argsCount: {0}", argsCount); var clearBytes = XSigHelpers.ClearOutputs(); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); var directoryXSig = UpdateDirectoryXSig(args.Directory, codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); }; trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; var clearBytes = XSigHelpers.ClearOutputs(); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); }; } private void SelectDirectoryEntry(IHasDirectory codec, ushort i, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { if (i > codec.CurrentDirectoryResult.CurrentDirectoryResults.Count) return; _selectedDirectoryItem = i == 0 ? null : codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; trilist.SetUshort(joinMap.DirectorySelectRowFeedback.JoinNumber, i); if (_selectedDirectoryItem == null) trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); if (_selectedDirectoryItem is DirectoryFolder) { codec.GetDirectoryFolderContents(_selectedDirectoryItem.FolderId); trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, _selectedDirectoryItem.Name); trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); return; } // not a folder. Clear this value trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, string.Empty); var selectedContact = _selectedDirectoryItem as DirectoryContact; if (selectedContact != null && selectedContact.ContactMethods.Count >= 1) { trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, true); } trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, selectedContact != null ? selectedContact.Name : string.Empty); // Allow auto dial of selected line. Always dials first contact method if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber)) { if (_selectedDirectoryItem is IInvitableContact invitableEntry) { Dial(invitableEntry); return; } trilist.SetString(joinMap.DirectoryEntrySelectedNumber.JoinNumber, selectedContact != null ? selectedContact.ContactMethods[0].Number : string.Empty); if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) return; Dial(entryToDial.ContactMethods[0].Number); } else { // If auto dial is disabled... if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) { // Clear out values and actions from last selected item trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); return; } trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count); // Update the action to dial the selected contact method trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) => { if (u < 1 || u > entryToDial.ContactMethods.Count) return; trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u - 1].Number)); }); // Sets DirectoryDialSelectedLine join action to dial first contact method trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); var clearBytes = XSigHelpers.ClearOutputs(); trilist.SetString(joinMap.ContactMethods.JoinNumber, Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); var contactMethodsXSig = UpdateContactMethodsXSig(entryToDial); trilist.SetString(joinMap.ContactMethods.JoinNumber, contactMethodsXSig); } } /// /// Generates the XSig data representing the available contact methods for the selected DirectoryContact /// /// /// private string UpdateContactMethodsXSig(DirectoryContact contact) { const int maxMethods = 10; const int maxStrings = 3; const int offset = maxStrings; var stringIndex = 0; var arrayIndex = 0; // Create a new token array and set the size to the number of methods times the total number of signals var tokenArray = new XSigToken[maxMethods * offset]; Debug.LogMessage(LogEventLevel.Verbose, this, "Creating XSIG token array with size {0}", maxMethods * offset); // TODO: Add code to generate XSig data foreach (var method in contact.ContactMethods) { if (arrayIndex >= maxMethods * offset) break; //serials tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, method.Number); tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, method.ContactMethodId.ToString()); tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, method.Device.ToString()); arrayIndex += offset; stringIndex += maxStrings; } while (arrayIndex < maxMethods) { tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); arrayIndex += offset; stringIndex += maxStrings; } return GetXSigString(tokenArray); } private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot) { var xSigMaxIndex = 1023; var tokenArray = new XSigToken[directory.CurrentDirectoryResults.Count > xSigMaxIndex ? xSigMaxIndex : directory.CurrentDirectoryResults.Count]; Debug.LogMessage(LogEventLevel.Verbose, this, "IsRoot: {0}, Directory Count: {1}, TokenArray.Length: {2}", isRoot, directory.CurrentDirectoryResults.Count, tokenArray.Length); var contacts = directory.CurrentDirectoryResults.Count > xSigMaxIndex ? directory.CurrentDirectoryResults.Take(xSigMaxIndex) : directory.CurrentDirectoryResults; var contactsToDisplay = isRoot ? contacts.Where(c => c.ParentFolderId == "root") : contacts.Where(c => c.ParentFolderId != "root"); var counterIndex = 1; foreach (var entry in contactsToDisplay) { var arrayIndex = counterIndex - 1; var entryIndex = counterIndex; Debug.LogMessage(LogEventLevel.Verbose, this, "Entry{2:0000} Name: {0}, Folder ID: {1}, Type: {3}, ParentFolderId: {4}", entry.Name, entry.FolderId, entryIndex, entry.GetType().FullName, entry.ParentFolderId); if (entry is DirectoryFolder) { tokenArray[arrayIndex] = new XSigSerialToken(entryIndex, String.Format("[+] {0}", entry.Name)); counterIndex++; continue; } tokenArray[arrayIndex] = new XSigSerialToken(entryIndex, entry.Name); counterIndex++; } return GetXSigString(tokenArray); } private void LinkVideoCodecCallControlsToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.ManualDial.JoinNumber, () => Dial(trilist.StringOutput[joinMap.CurrentDialString.JoinNumber].StringValue)); //End All calls trilist.SetSigFalseAction(joinMap.EndAllCalls.JoinNumber, EndAllCalls); //End a specific call, specified by index. Maximum 8 calls supported for (int i = 0; i < joinMap.EndCallStart.JoinSpan; i++) { var callIndex = i; trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () => { if (callIndex < 0 || callIndex >= ActiveCalls.Count) { Debug.LogMessage(LogEventLevel.Verbose, this, "Cannot end call. No call found at index: {0}", callIndex); return; } var call = ActiveCalls[callIndex]; if (call != null) { EndCall(call); } else { Debug.LogMessage(LogEventLevel.Information, this, "[End Call] Unable to find call at index '{0}'", i); } }); } trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); CallStatusChange += (sender, args) => { trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); Debug.LogMessage(LogEventLevel.Debug, this, "Call Direction: {0}", args.CallItem.Direction); Debug.LogMessage(LogEventLevel.Debug, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming); trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status == eCodecCallStatus.Ringing); if (args.CallItem.Direction == eCodecCallDirection.Incoming) { trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); trilist.SetString(joinMap.IncomingCallName.JoinNumber, args.CallItem.Name); trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, args.CallItem.Number); } else { trilist.SetString(joinMap.IncomingCallName.JoinNumber, string.Empty); trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, string.Empty); } trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); trilist.SetUshort(joinMap.ConnectedCallCount.JoinNumber, (ushort)ActiveCalls.Count); }; if (this is IJoinCalls joinCodec) { trilist.SetSigFalseAction(joinMap.JoinAllCalls.JoinNumber, () => joinCodec.JoinAllCalls()); for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++) { trilist.SetSigFalseAction((uint)(joinMap.JoinCallStart.JoinNumber + i), () => { var call = ActiveCalls[i]; if (call != null) { joinCodec.JoinCall(call); } else { Debug.LogMessage(LogEventLevel.Information, this, "[Join Call] Unable to find call at index '{0}'", i); } }); } } if (this is IHasCallHold holdCodec) { trilist.SetSigFalseAction(joinMap.HoldAllCalls.JoinNumber, () => { foreach (var call in ActiveCalls) { holdCodec.HoldCall(call); } }); for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) { var index = i; trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + index), () => { if (index < 0 || index >= ActiveCalls.Count) return; var call = ActiveCalls[index]; if (call != null) { holdCodec.HoldCall(call); } else { Debug.LogMessage(LogEventLevel.Information, this, "[Hold Call] Unable to find call at index '{0}'", i); } }); trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + index), () => { if (index < 0 || index >= ActiveCalls.Count) return; var call = ActiveCalls[index]; if (call != null) { holdCodec.ResumeCall(call); } else { Debug.LogMessage(LogEventLevel.Information, this, "[Resume Call] Unable to find call at index '{0}'", i); } }); } } trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; // TODO [ ] #983 Debug.LogMessage(LogEventLevel.Information, this, "LinkVideoCodecCallControlsToApi: device is {0}, IsInCall {1}", args.DeviceOnLine ? "online" : "offline", IsInCall); trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); trilist.SetString(joinMap.CurrentCallData.JoinNumber, "\xFC"); trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); }; } private string UpdateCallStatusXSig() { const int maxCalls = 8; const int maxStrings = 6; const int maxDigitals = 2; const int offset = maxStrings + maxDigitals; var stringIndex = 0; var digitalIndex = maxStrings * maxCalls; var arrayIndex = 0; var tokenArray = new XSigToken[maxCalls * offset]; //set array size for number of calls * pieces of info foreach (var call in ActiveCalls) { if (arrayIndex >= maxCalls * offset) break; //digitals tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold); //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, call.Number ?? String.Empty); tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString()); tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, call.Type.ToString()); tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, call.Status.ToString()); if (call.Duration != null) { // May need to verify correct string format here var dur = string.Format("{0:c}", call.Duration); tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, dur); } arrayIndex += offset; stringIndex += maxStrings; digitalIndex += maxDigitals; } while (arrayIndex < maxCalls * offset) { //digitals tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); arrayIndex += offset; stringIndex += maxStrings; digitalIndex += maxDigitals; } return GetXSigString(tokenArray); } private void LinkVideoCodecDtmfToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmfAction("0", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmfAction("1", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmfAction("2", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmfAction("3", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmfAction("4", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmfAction("5", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmfAction("6", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmfAction("7", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmfAction("8", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmfAction("9", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmfAction("*", trilist, joinMap)); trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmfAction("#", trilist, joinMap)); } /// /// Sends the specified string as a DTMF command. /// Reads the value of the SendDtmfToSpecificCallInstance digital join and SelectCall analog join to determine /// Whther to send to a specific call index or to the last connected call /// /// /// /// private void SendDtmfAction(string s, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { if (!trilist.GetBool(joinMap.SendDtmfToSpecificCallIndex.JoinNumber)) { SendDtmf(s); } else { var callIndex = trilist.GetUshort(joinMap.SelectCall.JoinNumber); if (callIndex > 0 && callIndex <= 8) { var call = ActiveCalls[callIndex - 1]; if (call != null && call.IsActiveCall) { SendDtmf(s, call); } else { Debug.LogMessage(LogEventLevel.Information, this, "Warning: No call found at index {0} or call is not active.", callIndex); } } else { Debug.LogMessage(LogEventLevel.Information, this, "Warning: Invalid call index specified. Please use a value of 1-8."); } } } private void LinkVideoCodecCameraLayoutsToApi(IHasCodecLayouts codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.CameraLayout.JoinNumber, codec.LocalLayoutToggle); codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentLayoutStringFb.JoinNumber]); } private void LinkVideoCodecCameraModeToApi(IHasCameraAutoMode codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeOn); trilist.SetSigFalseAction(joinMap.CameraModeManual.JoinNumber, codec.CameraAutoModeOff); codec.CameraAutoModeIsOnFeedback.OutputChange += (o, a) => { if (codec is IHasCameraOff offCodec) { if (offCodec.CameraIsOffFeedback.BoolValue) { trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); return; } trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); return; } trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); }; if (codec is IHasCameraOff offModeCodec) { if (offModeCodec.CameraIsOffFeedback.BoolValue) { trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); return; } trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); return; } trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); } private void LinkVideoCodecSelfviewToApi(IHasCodecSelfView codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.CameraSelfView.JoinNumber, codec.SelfViewModeToggle); codec.SelfviewIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.CameraSelfView.JoinNumber]); } private void LinkVideoCodecCameraToApi(IHasCodecCameras codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { //Camera PTZ trilist.SetBoolSigAction(joinMap.CameraTiltUp.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; if (b) camera.TiltUp(); else camera.TiltStop(); }); trilist.SetBoolSigAction(joinMap.CameraTiltDown.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; if (b) camera.TiltDown(); else camera.TiltStop(); }); trilist.SetBoolSigAction(joinMap.CameraPanLeft.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; if (b) camera.PanLeft(); else camera.PanStop(); }); trilist.SetBoolSigAction(joinMap.CameraPanRight.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; if (b) camera.PanRight(); else camera.PanStop(); }); trilist.SetBoolSigAction(joinMap.CameraZoomIn.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; if (b) camera.ZoomIn(); else camera.ZoomStop(); }); trilist.SetBoolSigAction(joinMap.CameraZoomOut.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; if (b) camera.ZoomOut(); else camera.ZoomStop(); }); trilist.SetBoolSigAction(joinMap.CameraFocusNear.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; if (b) camera.FocusNear(); else camera.FocusStop(); }); trilist.SetBoolSigAction(joinMap.CameraFocusFar.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; if (b) camera.FocusFar(); else camera.FocusStop(); }); trilist.SetSigFalseAction(joinMap.CameraFocusAuto.JoinNumber, () => { if (codec.SelectedCamera == null) return; if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; camera.TriggerAutoFocus(); }); // Camera count trilist.SetUshort(joinMap.CameraCount.JoinNumber, (ushort)codec.Cameras.Count); // Camera names for (uint i = 0; i < joinMap.CameraNamesFb.JoinSpan; i++) { //Check the count first if (i < codec.Cameras.Count && codec.Cameras[(int)i] != null) { trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, codec.Cameras[(int)i].Name); } else { trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, ""); } } //Camera Select trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => { if (i > 0 && i <= codec.Cameras.Count) { codec.SelectCamera(codec.Cameras[i - 1].Key); } else { Debug.LogMessage(LogEventLevel.Information, this, "Unable to select. No camera found at index {0}", i); } }); // Set initial selected camera feedback if (codec.SelectedCamera != null) { trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)codec.Cameras.FindIndex((c) => c.Key == codec.SelectedCamera.Key)); } codec.CameraSelected += (sender, args) => { var i = (ushort)codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key); trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)(i + 1)); if (codec is IHasCodecRoomPresets) { return; } if (!(args.SelectedCamera is IHasCameraPresets)) { return; } var cam = args.SelectedCamera as IHasCameraPresets; SetCameraPresetNames(cam.Presets); (args.SelectedCamera as IHasCameraPresets).PresetsListHasChanged += (o, eventArgs) => SetCameraPresetNames(cam.Presets); trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, (a) => { cam.PresetSelect(a); trilist.SetUshort(joinMap.CameraPresetSelect.JoinNumber, a); }); trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, () => { cam.PresetStore(trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, String.Empty); trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); }); }; if (!(codec is IHasCodecRoomPresets)) return; var presetCodec = codec as IHasCodecRoomPresets; presetCodec.CodecRoomPresetsListHasChanged += (sender, args) => SetCameraPresetNames(presetCodec.NearEndPresets); //Camera Presets trilist.SetUShortSigAction(joinMap.CameraPresetSelect.JoinNumber, (i) => { presetCodec.CodecRoomPresetSelect(i); }); // Far End Presets trilist.SetUShortSigAction(joinMap.FarEndPresetSelect.JoinNumber, (i) => { presetCodec.SelectFarEndPreset(i); }); trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, () => { presetCodec.CodecRoomPresetStore( trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, String.Empty); trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); }); trilist.OnlineStatusChange += (device, args) => { if (!args.DeviceOnLine) return; // TODO [ ] Issue #868 trilist.SetString(joinMap.CameraPresetNames.JoinNumber, "\xFC"); SetCameraPresetNames(presetCodec.NearEndPresets); }; } // Following fields only used for Bridging private int _selectedRecentCallItemIndex; private DirectoryItem _selectedDirectoryItem; private void LinkVideoCodecCallHistoryToApi(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { codec.CallHistory.RecentCallsListHasChanged += (o, a) => { UpdateCallHistory(codec, trilist, joinMap); }; // Selected item action and feedback trilist.SetUShortSigAction(joinMap.SelectRecentCallItem.JoinNumber, (u) => { if (u == 0 || u > codec.CallHistory.RecentCalls.Count) { Debug.LogMessage(LogEventLevel.Verbose, this, "Recent Call History index out of range"); return; } _selectedRecentCallItemIndex = (int)(u - 1); trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex]; if (_selectedRecentCallItem != null) { trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name); trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, _selectedRecentCallItem.Number); trilist.SetSigFalseAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber, () => codec.RemoveCallHistoryEntry(_selectedRecentCallItem)); trilist.SetSigFalseAction(joinMap.DialSelectedRecentCallItem.JoinNumber, () => this.Dial(_selectedRecentCallItem.Number)); } else { trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); trilist.ClearBoolSigAction(joinMap.DialSelectedRecentCallItem.JoinNumber); } }); } private void UpdateCallHistory(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { // Clear out selected item _selectedRecentCallItemIndex = 0; trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, 0); trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); // trilist.SetUshort(joinMap.RecentCallCount.JoinNumber, (ushort)codec.CallHistory.RecentCalls.Count); // Update the call history joins var maxItems = joinMap.RecentCallNamesStart.JoinSpan; // Create history uint index = 0; for (uint i = 0; i < maxItems && i < codec.CallHistory.RecentCalls.Count; i++) { trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].Name); trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].StartTime.ToShortTimeString()); trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)codec.CallHistory.RecentCalls[(int)i].OccurrenceType); //i++; index = i; } //foreach(var item in codec.CallHistory.RecentCalls) //{ // trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name); // trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString()); // trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType); // i++; //} // Clears existing items for (uint j = index; j < maxItems; j++) { trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + j, string.Empty); trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + j, string.Empty); trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + j, 0); } } private string SetCameraPresetNames(IEnumerable presets) { return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); } private string SetCameraPresetNames(IEnumerable presets) { return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); } private string SetCameraPresetNames(ICollection presets) { var i = 1; //start index for xsig; var tokenArray = new XSigToken[presets.Count]; foreach (var preset in presets) { var cameraPreset = new XSigSerialToken(i, preset); tokenArray[i - 1] = cameraPreset; i++; } return GetXSigString(tokenArray); } private string GetXSigString(XSigToken[] tokenArray) { string returnString; using (var s = new MemoryStream()) { using (var tw = new XSigTokenStreamWriter(s, true)) { tw.WriteXSigData(tokenArray); } var xSig = s.ToArray(); returnString = Encoding.GetEncoding(XSigEncoding).GetString(xSig, 0, xSig.Length); } return returnString; } #endregion } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials { /// /// Represents a AuthorizationResponse /// public class AuthorizationResponse { /// /// Gets or sets the Authorized /// [JsonProperty("authorized")] public bool Authorized { get; set; } /// /// Gets or sets the Reason /// [JsonProperty("reason", NullValueHandling = NullValueHandling.Ignore)] public string Reason { get; set; } = null; } /// /// Represents a AuthorizationRequest /// public class AuthorizationRequest { /// /// Gets or sets the GrantCode /// [JsonProperty("grantCode")] public string GrantCode { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/ClientSpecificUpdateRequest.cs ================================================ using System; namespace PepperDash.Essentials { /// /// Send an update request for a specific client /// [Obsolete] public class ClientSpecificUpdateRequest { /// /// Initialize an instance of the class. /// /// public ClientSpecificUpdateRequest(Action action) { ResponseMethod = action; } /// /// Gets or sets the ResponseMethod /// public Action ResponseMethod { get; private set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/IDelayedConfiguration.cs ================================================ using System; namespace PepperDash.Essentials { /// /// Defines the contract for IDelayedConfiguration /// public interface IDelayedConfiguration { /// /// Event triggered when the configuration is ready. Used when Mobile Control is interacting with a SIMPL program. /// event EventHandler ConfigurationIsReady; } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/MessageToClients.cs ================================================ using System; using System.Threading; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core.Queues; using PepperDash.Essentials.WebSocketServer; using Serilog.Events; namespace PepperDash.Essentials { /// /// Represents a MessageToClients /// public class MessageToClients : IQueueMessage { private readonly MobileControlWebsocketServer _server; private readonly object msgToSend; /// /// Message to send to Direct Server Clients /// /// message object to send /// WebSocket server instance public MessageToClients(object msg, MobileControlWebsocketServer server) { _server = server; msgToSend = msg; } /// /// Message to send to Direct Server Clients /// /// message object to send /// WebSocket server instance public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server) { _server = server; msgToSend = msg; } #region Implementation of IQueueMessage /// /// Dispatch method /// public void Dispatch() { try { if (_server == null) { Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null"); return; } var message = JsonConvert.SerializeObject(msgToSend, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } }); var clientSpecificMessage = msgToSend as MobileControlMessage; if (clientSpecificMessage.ClientId != null) { var clientId = clientSpecificMessage.ClientId; _server.LogVerbose("Message TX To client {clientId}: {message}", clientId, message); _server.SendMessageToClient(clientId, message); return; } _server.SendMessageToAllClients(message); _server.LogVerbose("Message TX To all clients: {message}", message); } catch (ThreadAbortException) { //Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace } catch (Exception ex) { Debug.LogMessage(ex, "Caught an exception in the Transmit Processor"); } } #endregion } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/MobileControlAction.cs ================================================ using System; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials { /// /// Represents a MobileControlAction /// public class MobileControlAction : IMobileControlAction { /// /// Gets the Messenger /// public IMobileControlMessenger Messenger { get; private set; } /// /// Action to execute when this path is matched /// public Action Action { get; private set; } /// /// Initialize an instance of the class /// /// Messenger associated with this action /// Action to take when this path is matched public MobileControlAction(IMobileControlMessenger messenger, Action handler) { Messenger = messenger; Action = handler; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace PepperDash.Essentials { /// /// Represents a MobileControlConfig /// public class MobileControlConfig { /// /// Gets or sets the ServerUrl /// [JsonProperty("serverUrl")] public string ServerUrl { get; set; } /// /// Gets or sets the ClientAppUrl /// [JsonProperty("clientAppUrl")] public string ClientAppUrl { get; set; } /// /// Gets or sets the DirectServer /// [JsonProperty("directServer")] public MobileControlDirectServerPropertiesConfig DirectServer { get; set; } /// /// Gets or sets the ApplicationConfig /// [JsonProperty("applicationConfig")] public MobileControlApplicationConfig ApplicationConfig { get; set; } = null; /// /// Gets or sets the EnableApiServer /// [JsonProperty("enableApiServer")] public bool EnableApiServer { get; set; } = true; /// /// Enable subscriptions for Messengers /// [JsonProperty("enableMessengerSubscriptions")] public bool EnableMessengerSubscriptions { get; set; } } /// /// Represents a MobileControlDirectServerPropertiesConfig /// public class MobileControlDirectServerPropertiesConfig { /// /// Gets or sets the EnableDirectServer /// [JsonProperty("enableDirectServer")] public bool EnableDirectServer { get; set; } /// /// Gets or sets the Port /// [JsonProperty("port")] public int Port { get; set; } /// /// Gets or sets the Logging /// [JsonProperty("logging")] public MobileControlLoggingConfig Logging { get; set; } /// /// Gets or sets the AutomaticallyForwardPortToCSLAN /// [JsonProperty("automaticallyForwardPortToCSLAN")] public bool? AutomaticallyForwardPortToCSLAN { get; set; } /// /// Gets or sets the CSLanUiDeviceKeys /// /// /// A list of device keys for the CS LAN UI. These devices will get the CS LAN IP address instead of the LAN IP Address /// [JsonProperty("csLanUiDeviceKeys")] public List CSLanUiDeviceKeys { get; set; } /// /// Get or set the Secure property /// /// /// Indicates whether the connection is secure (HTTPS). /// [JsonProperty("Secure")] public bool Secure { get; set; } /// /// Initializes a new instance of the MobileControlDirectServerPropertiesConfig class. /// public MobileControlDirectServerPropertiesConfig() { Logging = new MobileControlLoggingConfig(); } } /// /// Represents a MobileControlLoggingConfig /// public class MobileControlLoggingConfig { /// /// Gets or sets the EnableRemoteLogging /// [JsonProperty("enableRemoteLogging")] public bool EnableRemoteLogging { get; set; } /// /// Gets or sets the Host /// [JsonProperty("host")] public string Host { get; set; } /// /// Gets or sets the Port /// [JsonProperty("port")] public int Port { get; set; } } /// /// Represents a MobileControlRoomBridgePropertiesConfig /// public class MobileControlRoomBridgePropertiesConfig { /// /// Gets or sets the Key /// [JsonProperty("key")] public string Key { get; set; } /// /// Gets or sets the RoomKey /// [JsonProperty("roomKey")] public string RoomKey { get; set; } } /// /// Represents a MobileControlSimplRoomBridgePropertiesConfig /// public class MobileControlSimplRoomBridgePropertiesConfig { /// /// Gets or sets the EiscId /// [JsonProperty("eiscId")] public string EiscId { get; set; } } /// /// Represents a MobileControlApplicationConfig /// public class MobileControlApplicationConfig { /// /// Gets or sets the ApiPath /// [JsonProperty("apiPath")] public string ApiPath { get; set; } /// /// Gets or sets the GatewayAppPath /// [JsonProperty("gatewayAppPath")] public string GatewayAppPath { get; set; } /// /// Gets or sets the EnableDev /// [JsonProperty("enableDev")] public bool? EnableDev { get; set; } /// /// Gets or sets the LogoPath /// [JsonProperty("logoPath")] public string LogoPath { get; set; } /// /// Gets or sets the IconSet /// [JsonProperty("iconSet")] [JsonConverter(typeof(StringEnumConverter))] public MCIconSet? IconSet { get; set; } /// /// Gets or sets the LoginMode /// [JsonProperty("loginMode")] public string LoginMode { get; set; } /// /// Gets or sets the Modes /// [JsonProperty("modes")] public Dictionary Modes { get; set; } /// /// Gets or sets the Logging /// [JsonProperty("enableRemoteLogging")] public bool Logging { get; set; } /// /// Gets or sets the PartnerMetadata /// [JsonProperty("partnerMetadata", NullValueHandling = NullValueHandling.Ignore)] public List PartnerMetadata { get; set; } } /// /// Represents a MobileControlPartnerMetadata /// public class MobileControlPartnerMetadata { /// /// Gets or sets the Role /// [JsonProperty("role")] public string Role { get; set; } /// /// Gets or sets the Description /// [JsonProperty("description")] public string Description { get; set; } /// /// Gets or sets the LogoPath /// [JsonProperty("logoPath")] public string LogoPath { get; set; } } /// /// Represents a McMode /// public class McMode { /// /// Gets or sets the ListPageText /// [JsonProperty("listPageText")] public string ListPageText { get; set; } /// /// Gets or sets the LoginHelpText /// [JsonProperty("loginHelpText")] public string LoginHelpText { get; set; } /// /// Gets or sets the PasscodePageText /// [JsonProperty("passcodePageText")] public string PasscodePageText { get; set; } } /// /// Enumeration of MCIconSet values /// public enum MCIconSet { /// /// Google icon set /// GOOGLE, /// /// Habanero icon set /// HABANERO, /// /// Neo icon set /// NEO } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/MobileControlDeviceFactory.cs ================================================ using System; using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials { /// /// Factory to create a Mobile Control System Controller /// public class MobileControlDeviceFactory : EssentialsDeviceFactory { /// /// Create the factory for a Mobile Control System Controller /// public MobileControlDeviceFactory() { TypeNames = new List { "appserver", "mobilecontrol", "webserver" }; } /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { try { var props = dc.Properties.ToObject(); return new MobileControlSystemController(dc.Key, dc.Name, props); } catch (Exception e) { Debug.LogMessage(e, "Error building Mobile Control System Controller"); return null; } } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials { /// /// Configuration class for sending data to Mobile Control Edge or a client using the Direct Server /// public class MobileControlEssentialsConfig : EssentialsConfig { /// /// Current versions for the system /// [JsonProperty("runtimeInfo")] public MobileControlRuntimeInfo RuntimeInfo { get; set; } /// /// Create Configuration for Mobile Control. Used as part of the data sent to a client /// /// The base configuration public MobileControlEssentialsConfig(EssentialsConfig config) : base() { Devices = config.Devices; Info = config.Info; JoinMaps = config.JoinMaps; Rooms = config.Rooms; SourceLists = config.SourceLists; DestinationLists = config.DestinationLists; SystemUrl = config.SystemUrl; TemplateUrl = config.TemplateUrl; TieLines = config.TieLines; if (Info == null) Info = new InfoConfig(); RuntimeInfo = new MobileControlRuntimeInfo(); } } /// /// Represents a MobileControlRuntimeInfo /// public class MobileControlRuntimeInfo { /// /// Gets or sets the PluginVersion /// [JsonProperty("pluginVersion")] public string PluginVersion { get; set; } /// /// Essentials Version /// [JsonProperty("essentialsVersion")] public string EssentialsVersion { get; set; } /// /// PepperDash Core Version /// [JsonProperty("pepperDashCoreVersion")] public string PepperDashCoreVersion { get; set; } /// /// List of Plugins loaded on this system /// [JsonProperty("essentialsPlugins")] public List EssentialsPlugins { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/MobileControlFactory.cs ================================================ using System; using System.Linq; using System.Reflection; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials { /// /// Factory class for the Mobile Control App Controller /// public class MobileControlFactory { /// /// Create an instance of the class. /// public MobileControlFactory() { var assembly = Assembly.GetExecutingAssembly(); PluginLoader.SetEssentialsAssembly(assembly.GetName().Name, assembly); var types = assembly.GetTypes().Where(t => typeof(IDeviceFactory).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); if (types == null) { return; } foreach (var type in types) { try { var factory = (IDeviceFactory)Activator.CreateInstance(type); LoadDeviceFactories(factory); } catch (Exception ex) { Debug.LogMessage(ex, "Unable to load type '{type}' DeviceFactory: {factory}", null, type.Name); } } } /// /// Loads device factories from the specified plugin device factory and registers them for use. /// /// This method retrieves metadata from the provided , including /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type /// names are converted to lowercase for registration. /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered. private static void LoadDeviceFactories(IDeviceFactory deviceFactory) { foreach (var typeName in deviceFactory.TypeNames) { string description = (deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0) ? descriptionAttribute[0].Description : "No description available"; // Default value if no DescriptionAttribute is found DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice); } } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/MobileControlSimplDeviceBridge.cs ================================================ using Crestron.SimplSharpPro.EthernetCommunication; using PepperDash.Core; using PepperDash.Essentials.Core; using System; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a MobileControlSimplDeviceBridge /// public class MobileControlSimplDeviceBridge : Device, IChannel, INumericKeypad { /// /// EISC used to talk to Simpl /// private readonly ThreeSeriesTcpIpEthernetIntersystemCommunications _eisc; public MobileControlSimplDeviceBridge(string key, string name, ThreeSeriesTcpIpEthernetIntersystemCommunications eisc) : base(key, name) { _eisc = eisc; } #region IChannel Members /// /// ChannelUp method /// public void ChannelUp(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// ChannelDown method /// public void ChannelDown(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// LastChannel method /// public void LastChannel(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Guide method /// public void Guide(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Info method /// public void Info(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Exit method /// public void Exit(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } #endregion #region INumericKeypad Members /// /// Digit0 method /// public void Digit0(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit1 method /// public void Digit1(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit2 method /// public void Digit2(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit3 method /// public void Digit3(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit4 method /// public void Digit4(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit5 method /// public void Digit5(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit6 method /// public void Digit6(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit7 method /// public void Digit7(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit8 method /// public void Digit8(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } /// /// Digit9 method /// public void Digit9(bool pressRelease) { _eisc.SetBool(1111, pressRelease); } public bool HasKeypadAccessoryButton1 { get { throw new NotImplementedException(); } } public string KeypadAccessoryButton1Label { get { throw new NotImplementedException(); } } /// /// KeypadAccessoryButton1 method /// public void KeypadAccessoryButton1(bool pressRelease) { throw new NotImplementedException(); } public bool HasKeypadAccessoryButton2 { get { throw new NotImplementedException(); } } public string KeypadAccessoryButton2Label { get { throw new NotImplementedException(); } } /// /// KeypadAccessoryButton2 method /// public void KeypadAccessoryButton2(bool pressRelease) { throw new NotImplementedException(); } #endregion } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.CrestronIO; using PepperDash.Essentials.Core.DeviceInfo; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Lighting; using PepperDash.Essentials.Core.Monitoring; using PepperDash.Essentials.Core.Queues; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Shades; using PepperDash.Essentials.Core.Web; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Displays; using PepperDash.Essentials.Devices.Common.Lighting; using PepperDash.Essentials.Devices.Common.SoftCodec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Room.MobileControl; using PepperDash.Essentials.RoomBridges; using PepperDash.Essentials.Services; using PepperDash.Essentials.WebApiHandlers; using PepperDash.Essentials.WebSocketServer; using WebSocketSharp; namespace PepperDash.Essentials { /// /// Represents a MobileControlSystemController /// public class MobileControlSystemController : EssentialsDevice, IMobileControl { private bool _initialized = false; private const long ServerReconnectInterval = 5000; private const long PingInterval = 25000; private readonly Dictionary> _actionDictionary = new Dictionary>( StringComparer.InvariantCultureIgnoreCase ); /// /// Actions /// public ReadOnlyDictionary> ActionDictionary => new ReadOnlyDictionary>(_actionDictionary); private readonly GenericQueue _receiveQueue; private readonly List _roomBridges = new List(); private readonly Dictionary _messengers = new Dictionary(); private readonly Dictionary _defaultMessengers = new Dictionary(); /// /// Get the custom messengers with subscriptions /// public ReadOnlyDictionary Messengers => new ReadOnlyDictionary(_messengers.Values.OfType().ToDictionary(k => k.Key, v => v)); /// /// Get the default messengers /// public ReadOnlyDictionary DefaultMessengers => new ReadOnlyDictionary(_defaultMessengers.Values.OfType().ToDictionary(k => k.Key, v => v)); private readonly GenericQueue _transmitToServerQueue; private readonly GenericQueue _transmitToClientsQueue; private bool _disableReconnect; private WebSocket _wsClient2; /// /// Gets or sets the ApiService /// public MobileControlApiService ApiService { get; private set; } /// /// Get Room Bridges associated with this controller /// public List RoomBridges => _roomBridges; private readonly MobileControlWebsocketServer _directServer; /// /// Get the Direct Server instance associated with this controller /// public MobileControlWebsocketServer DirectServer => _directServer; private readonly CCriticalSection _wsCriticalSection = new CCriticalSection(); /// /// Gets or sets the SystemUrl /// public string SystemUrl; //set only from SIMPL Bridge! /// /// True if the Mobile Control Edge Server Websocket is connected /// public bool Connected => _wsClient2 != null && _wsClient2.IsAlive; private IEssentialsRoomCombiner _roomCombiner; /// /// Gets the SystemUuid from configuration or SIMPL Bridge /// public string SystemUuid { get { // Check to see if the SystemUuid value is populated. If not populated from configuration, check for value from SIMPL bridge. if ( !string.IsNullOrEmpty(ConfigReader.ConfigObject.SystemUuid) && ConfigReader.ConfigObject.SystemUuid != "missing url" ) { return ConfigReader.ConfigObject.SystemUuid; } this.LogWarning( "No system_url value defined in config. Checking for value from SIMPL Bridge." ); if (string.IsNullOrEmpty(SystemUrl)) { this.LogError( "No system_url value defined in config or SIMPL Bridge. Unable to connect to Mobile Control." ); return string.Empty; } var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*"); string uuid = result.Groups[1].Value; return uuid; } } /// /// Gets or sets the ApiOnlineAndAuthorized /// public BoolFeedback ApiOnlineAndAuthorized { get; private set; } /// /// Used for tracking HTTP debugging /// private bool _httpDebugEnabled; private bool _isAuthorized; /// /// Tracks if the system is authorized to the API server /// public bool IsAuthorized { get { return _isAuthorized; } private set { if (value == _isAuthorized) return; _isAuthorized = value; ApiOnlineAndAuthorized.FireUpdate(); } } private DateTime _lastAckMessage; /// /// Gets the LastAckMessage timestamp /// public DateTime LastAckMessage => _lastAckMessage; private CTimer _pingTimer; private CTimer _serverReconnectTimer; private LogLevel _wsLogLevel = LogLevel.Error; /// /// Initializes a new instance of the class. /// /// The unique key for this controller. /// The name of the controller. /// The configuration settings for the controller. public MobileControlSystemController(string key, string name, MobileControlConfig config) : base(key, name) { Config = config; // The queue that will collect the incoming messages in the order they are received //_receiveQueue = new ReceiveQueue(key, ParseStreamRx); _receiveQueue = new GenericQueue( key + "-rxqueue", Crestron.SimplSharpPro.CrestronThread.Thread.eThreadPriority.HighPriority, 25 ); // The queue that will collect the outgoing messages in the order they are received _transmitToServerQueue = new GenericQueue( key + "-txqueue", Crestron.SimplSharpPro.CrestronThread.Thread.eThreadPriority.HighPriority, 25 ); if (Config.DirectServer != null && Config.DirectServer.EnableDirectServer) { _directServer = new MobileControlWebsocketServer( Key + "-directServer", Config.DirectServer.Port, this ); DeviceManager.AddDevice(_directServer); _transmitToClientsQueue = new GenericQueue( key + "-clienttxqueue", Crestron.SimplSharpPro.CrestronThread.Thread.eThreadPriority.HighPriority, 25 ); } Host = config.ServerUrl; if (!Host.StartsWith("http")) { Host = "https://" + Host; } ApiService = new MobileControlApiService(Host); this.LogInformation( "Mobile UI controller initializing for server:{0}", config.ServerUrl ); if (Global.Platform == eDevicePlatform.Appliance) { AddConsoleCommands(); } AddPreActivationAction(() => LinkSystemMonitorToAppServer()); AddPreActivationAction(() => SetupDefaultDeviceMessengers()); AddPreActivationAction(() => SetupDefaultRoomMessengers()); AddPreActivationAction(() => AddWebApiPaths()); AddPreActivationAction(() => { _roomCombiner = DeviceManager.AllDevices.OfType().FirstOrDefault(); if (_roomCombiner == null) return; _roomCombiner.RoomCombinationScenarioChanged += OnRoomCombinationScenarioChanged; }); CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; ApiOnlineAndAuthorized = new BoolFeedback("apiOnlineAndAuthorized", () => { if (_wsClient2 == null) return false; return _wsClient2.IsAlive && IsAuthorized; }); } private void SetupDefaultRoomMessengers() { this.LogVerbose("Setting up room messengers"); foreach (var room in DeviceManager.AllDevices.OfType()) { this.LogVerbose( "Setting up room messengers for room: {key}", room.Key ); var messenger = new MobileControlEssentialsRoomBridge(room); messenger.AddParent(this); _roomBridges.Add(messenger); AddDefaultDeviceMessenger(messenger); this.LogVerbose( "Attempting to set up default room messengers for room: {0}", room.Key ); if (room is IRoomEventSchedule) { this.LogInformation("Setting up event schedule messenger for room: {key}", room.Key); var scheduleMessenger = new RoomEventScheduleMessenger( $"{room.Key}-schedule-{Key}", string.Format("/room/{0}", room.Key), room as IRoomEventSchedule ); AddDefaultDeviceMessenger(scheduleMessenger); } if (room is ITechPassword) { this.LogInformation("Setting up tech password messenger for room: {key}", room.Key); var techPasswordMessenger = new ITechPasswordMessenger( $"{room.Key}-techPassword-{Key}", string.Format("/room/{0}", room.Key), room as ITechPassword ); AddDefaultDeviceMessenger(techPasswordMessenger); } if (room is IShutdownPromptTimer) { this.LogInformation("Setting up shutdown prompt timer messenger for room: {key}", this, room.Key); var shutdownPromptTimerMessenger = new IShutdownPromptTimerMessenger( $"{room.Key}-shutdownPromptTimer-{Key}", string.Format("/room/{0}", room.Key), room as IShutdownPromptTimer ); AddDefaultDeviceMessenger(shutdownPromptTimerMessenger); } if (room is ILevelControls levelControls) { this.LogInformation("Setting up level controls messenger for room: {key}", this, room.Key); var levelControlsMessenger = new ILevelControlsMessenger( $"{room.Key}-levelControls-{Key}", $"/room/{room.Key}", levelControls ); AddDefaultDeviceMessenger(levelControlsMessenger); } } } /// /// Set up the messengers for each device type /// private void SetupDefaultDeviceMessengers() { bool messengerAdded = false; var allDevices = DeviceManager.AllDevices.Where((d) => !(d is IEssentialsRoom)); this.LogInformation( "All Devices that aren't rooms count: {0}", allDevices?.Count() ); var count = allDevices.Count(); foreach (var device in allDevices) { try { this.LogVerbose( "Attempting to set up device messengers for {deviceKey}", device.Key ); // StatusMonitorBase which is prop of ICommunicationMonitor is not a PepperDash.Core.Device, but is in the device array if (device is ICommunicationMonitor) { this.LogVerbose( "Checking if {deviceKey} implements ICommunicationMonitor", device.Key ); if (!(device is ICommunicationMonitor commMonitor)) { this.LogDebug( "{deviceKey} does not implement ICommunicationMonitor. Skipping CommunicationMonitorMessenger", device.Key ); this.LogDebug("Created all messengers for {deviceKey}. Devices Left: {deviceCount}", device.Key, --count); continue; } this.LogDebug( "Adding CommunicationMonitorMessenger for {deviceKey}", device.Key ); var commMessenger = new ICommunicationMonitorMessenger( $"{device.Key}-commMonitor-{Key}", string.Format("/device/{0}", device.Key), commMonitor ); AddDefaultDeviceMessenger(commMessenger); messengerAdded = true; } // Default to IHasCameraControls if CameraBase and IHasCameraControls if (device is CameraBase cameraDevice && !(device is IHasCameraControls)) { this.LogVerbose( "Adding CameraBaseMessenger for {deviceKey}", device.Key ); var cameraMessenger = new CameraBaseMessenger( $"{device.Key}-cameraBase-{Key}", cameraDevice, $"/device/{device.Key}" ); AddDefaultDeviceMessenger(cameraMessenger); messengerAdded = true; } if (device is IHasCameraControls cameraControlDev) { this.LogVerbose( "Adding IHasCamerasWithControlMessenger for {deviceKey}", device.Key ); var cameraControlMessenger = new CameraBaseMessenger( $"{device.Key}-hasCamerasWithControls-{Key}", cameraControlDev, $"/device/{device.Key}" ); AddDefaultDeviceMessenger(cameraControlMessenger); messengerAdded = true; } if (device is BlueJeansPc) { this.LogVerbose( "Adding IRunRouteActionMessnger for {deviceKey}", device.Key ); var routeMessenger = new RunRouteActionMessenger( $"{device.Key}-runRouteAction-{Key}", device as BlueJeansPc, $"/device/{device.Key}" ); AddDefaultDeviceMessenger(routeMessenger); messengerAdded = true; } if (device is ITvPresetsProvider) { this.LogVerbose( "Trying to cast to ITvPresetsProvider for {deviceKey}", device.Key ); var presetsDevice = device as ITvPresetsProvider; this.LogVerbose( "Adding ITvPresetsProvider for {deviceKey}", device.Key ); var presetsMessenger = new DevicePresetsModelMessenger( $"{device.Key}-presets-{Key}", $"/device/{device.Key}", presetsDevice ); AddDefaultDeviceMessenger(presetsMessenger); messengerAdded = true; } if (device is DisplayBase) { this.LogVerbose("Adding actions for device: {0}", device.Key); var dbMessenger = new DisplayBaseMessenger( $"{device.Key}-displayBase-{Key}", $"/device/{device.Key}", device as DisplayBase ); AddDefaultDeviceMessenger(dbMessenger); messengerAdded = true; } if (device is TwoWayDisplayBase twoWayDisplay) { this.LogVerbose( "Adding TwoWayDisplayBase for {deviceKey}", device.Key ); var twoWayDisplayMessenger = new TwoWayDisplayBaseMessenger( $"{device.Key}-twoWayDisplay-{Key}", string.Format("/device/{0}", device.Key), twoWayDisplay ); AddDefaultDeviceMessenger(twoWayDisplayMessenger); messengerAdded = true; } if (device is IBasicVolumeControls) { var deviceKey = device.Key; this.LogVerbose( "Adding IBasicVolumeControls for {deviceKey}", deviceKey ); var volControlDevice = device as IBasicVolumeControls; var messenger = new DeviceVolumeMessenger( $"{device.Key}-volume-{Key}", string.Format("/device/{0}", deviceKey), volControlDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IBasicVideoMuteWithFeedback) { var deviceKey = device.Key; this.LogVerbose( "Adding IBasicVideoMuteWithFeedback for {deviceKey}", deviceKey ); var videoMuteControlDevice = device as IBasicVideoMuteWithFeedback; var messenger = new IBasicVideoMuteWithFeedbackMessenger( $"{device.Key}-videoMute-{Key}", string.Format("/device/{0}", deviceKey), videoMuteControlDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is ILightingScenes || device is LightingBase) { var deviceKey = device.Key; this.LogVerbose( "Adding LightingBaseMessenger for {deviceKey}", deviceKey ); var lightingDevice = device as ILightingScenes; var messenger = new ILightingScenesMessenger( $"{device.Key}-lighting-{Key}", lightingDevice, string.Format("/device/{0}", deviceKey) ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IShadesOpenCloseStop) { var deviceKey = device.Key; var shadeDevice = device as IShadesOpenCloseStop; this.LogVerbose( "Adding ShadeBaseMessenger for {deviceKey}", deviceKey ); var messenger = new IShadesOpenCloseStopMessenger( $"{device.Key}-shades-{Key}", shadeDevice, string.Format("/device/{0}", deviceKey) ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is VideoCodecBase codec) { this.LogVerbose( "Adding VideoCodecBaseMessenger for {deviceKey}", codec.Key); var messenger = new VideoCodecBaseMessenger( $"{codec.Key}-videoCodec-{Key}", codec, $"/device/{codec.Key}" ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is AudioCodecBase audioCodec) { this.LogVerbose( "Adding AudioCodecBaseMessenger for {deviceKey}", audioCodec.Key ); var messenger = new AudioCodecBaseMessenger( $"{audioCodec.Key}-audioCodec-{Key}", audioCodec, $"/device/{audioCodec.Key}" ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is ISetTopBoxControls stbDevice) { this.LogVerbose( "Adding ISetTopBoxControlMessenger for {deviceKey}" ); var messenger = new ISetTopBoxControlsMessenger( $"{device.Key}-stb-{Key}", $"/device/{device.Key}", stbDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IChannel channelDevice) { this.LogVerbose( "Adding IChannelMessenger for {deviceKey}", device.Key ); var messenger = new IChannelMessenger( $"{device.Key}-channel-{Key}", $"/device/{device.Key}", channelDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IColor colorDevice) { this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key); var messenger = new IColorMessenger( $"{device.Key}-color-{Key}", $"/device/{device.Key}", colorDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IDPad dPadDevice) { this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key); var messenger = new IDPadMessenger( $"{device.Key}-dPad-{Key}", $"/device/{device.Key}", dPadDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is INumericKeypad nkDevice) { this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key); var messenger = new INumericKeypadMessenger( $"{device.Key}-numericKeypad-{Key}", $"/device/{device.Key}", nkDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHasPowerControl pcDevice) { this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key); var messenger = new IHasPowerMessenger( $"{device.Key}-powerControl-{Key}", $"/device/{device.Key}", pcDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHasPowerControlWithFeedback powerControl) { var deviceKey = device.Key; this.LogVerbose( "Adding IHasPowerControlWithFeedbackMessenger for {deviceKey}", deviceKey ); var messenger = new IHasPowerControlWithFeedbackMessenger( $"{device.Key}-powerFeedback-{Key}", string.Format("/device/{0}", deviceKey), powerControl ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is ITransport transportDevice) { this.LogVerbose( "Adding ITransportMessenger for {deviceKey}", device.Key ); var messenger = new ITransportMessenger( $"{device.Key}-transport-{Key}", $"/device/{device.Key}", transportDevice ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHasCurrentSourceInfoChange csiChange) { this.LogVerbose("Adding IHasCurrentSourceInfoMessenger for {deviceKey}", device.Key); var messenger = new IHasCurrentSourceInfoMessenger( $"{device.Key}-currentSource-{Key}", $"/device/{device.Key}", csiChange ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is ICurrentSources currentSources) { this.LogVerbose("Adding CurrentSourcesMessenger for {deviceKey}", device.Key); var messenger = new CurrentSourcesMessenger($"{device.Key}-currentSources-{Key}", $"/device/{device.Key}", currentSources); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is ISwitchedOutput switchedDevice) { this.LogVerbose( "Adding ISwitchedOutputMessenger for {deviceKey}", device.Key ); var messenger = new ISwitchedOutputMessenger( $"{device.Key}-switchedOutput-{Key}", switchedDevice, $"/device/{device.Key}" ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IDeviceInfoProvider provider) { this.LogVerbose("Adding IHasDeviceInfoMessenger for {deviceKey}", device.Key ); var messenger = new DeviceInfoMessenger( $"{device.Key}-deviceInfo-{Key}", $"/device/{device.Key}", provider ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is ILevelControls levelControls) { this.LogVerbose( "Adding LevelControlsMessenger for {deviceKey}", device.Key ); var messenger = new ILevelControlsMessenger( $"{device.Key}-levelControls-{Key}", $"/device/{device.Key}", levelControls ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHasInputs stringInputs) { this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); var messenger = new IHasInputsMessenger( $"{device.Key}-inputs-{Key}", $"/device/{device.Key}", stringInputs ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHasInputs byteInputs) { this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); var messenger = new IHasInputsMessenger( $"{device.Key}-inputs-{Key}", $"/device/{device.Key}", byteInputs ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHasInputs intInputs) { this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key); var messenger = new IHasInputsMessenger( $"{device.Key}-inputs-{Key}", $"/device/{device.Key}", intInputs ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IMatrixRouting matrix) { this.LogVerbose( "Adding IMatrixRoutingMessenger for {deviceKey}", device.Key ); var messenger = new IMatrixRoutingMessenger( $"{device.Key}-matrixRouting", $"/device/{device.Key}", matrix ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is ITemperatureSensor tempSensor) { this.LogVerbose( "Adding ITemperatureSensor for {deviceKey}", device.Key ); var messenger = new ITemperatureSensorMessenger( $"{device.Key}-tempSensor", tempSensor, $"/device/{device.Key}" ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHumiditySensor humSensor) { this.LogVerbose( "Adding IHumiditySensor for {deviceKey}", device.Key ); var messenger = new IHumiditySensorMessenger( $"{device.Key}-humiditySensor", humSensor, $"/device/{device.Key}" ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IEssentialsRoomCombiner roomCombiner) { this.LogVerbose( "Adding IEssentialsRoomCombinerMessenger for {deviceKey}", device.Key ); var messenger = new IEssentialsRoomCombinerMessenger( $"{device.Key}-roomCombiner-{Key}", $"/device/{device.Key}", roomCombiner ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IProjectorScreenLiftControl screenLiftControl) { this.LogVerbose("Adding IProjectorScreenLiftControlMessenger for {deviceKey}", device.Key ); var messenger = new IProjectorScreenLiftControlMessenger( $"{device.Key}-screenLiftControl-{Key}", $"/device/{device.Key}", screenLiftControl ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IDspPresets dspPresets) { this.LogVerbose("Adding IDspPresetsMessenger for {deviceKey}", device.Key ); var messenger = new IDspPresetsMessenger( $"{device.Key}-dspPresets-{Key}", $"/device/{device.Key}", dspPresets ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHasCameras cameras) { this.LogVerbose("Adding IHasCamerasMessenger for {deviceKey}", device.Key ); var messenger = new IHasCamerasMessenger( $"{device.Key}-cameras-{Key}", $"/device/{device.Key}", cameras ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } if (device is IHasCamerasWithControls cameras2) { this.LogVerbose("Adding IHasCamerasWithControlsMessenger for {deviceKey}", device.Key ); var messenger = new IHasCamerasWithControlMessenger( $"{device.Key}-cameras-{Key}", $"/device/{device.Key}", cameras2 ); AddDefaultDeviceMessenger(messenger); messengerAdded = true; } this.LogVerbose("Trying to cast to generic device for device: {key}", device.Key); if (device is EssentialsDevice) { if (!(device is EssentialsDevice genericDevice) || messengerAdded) { this.LogVerbose( "Skipping GenericMessenger for {deviceKey}. Messenger(s) Added: {messengersAdded}.", device.Key, messengerAdded ); this.LogDebug( "AllDevices Completed a device. Devices Left: {count}", --count ); continue; } this.LogDebug( "Adding GenericMessenger for {deviceKey}", this, genericDevice?.Key ); AddDefaultDeviceMessenger( new GenericMessenger( genericDevice.Key + "-" + Key + "-generic", genericDevice, string.Format("/device/{0}", genericDevice.Key) ) ); } else { this.LogVerbose( "Not Essentials Device. Skipping GenericMessenger for {deviceKey}", device.Key ); } this.LogDebug( "AllDevices Completed a device. Devices Left: {count}", --count ); } catch (Exception ex) { this.LogException(ex, "Exception setting up default device messengers"); } } } private void AddWebApiPaths() { var apiServer = DeviceManager .AllDevices.OfType() .FirstOrDefault(d => d.Key == "essentialsWebApi"); if (apiServer == null) { this.LogWarning("No API Server available"); return; } // TODO: Add routes for the rest of the MC console commands var routes = new List { new HttpCwsRoute($"device/{Key}/authorize") { Name = "MobileControlAuthorize", RouteHandler = new MobileAuthRequestHandler(this) }, new HttpCwsRoute($"device/{Key}/info") { Name = "MobileControlInformation", RouteHandler = new MobileInfoHandler(this) }, new HttpCwsRoute($"device/{Key}/actionPaths") { Name = "MobileControlActionPaths", RouteHandler = new ActionPathsHandler(this) } }; apiServer.AddRoute(routes); } private void AddConsoleCommands() { CrestronConsole.AddNewConsoleCommand( AuthorizeSystem, "mobileauth", "Authorizes system to talk to Mobile Control server", ConsoleAccessLevelEnum.AccessOperator ); CrestronConsole.AddNewConsoleCommand( s => ShowInfo(), "mobileinfo", "Shows information for current mobile control session", ConsoleAccessLevelEnum.AccessOperator ); CrestronConsole.AddNewConsoleCommand( s => { s = s.Trim(); if (!string.IsNullOrEmpty(s)) { _httpDebugEnabled = (s.Trim() != "0"); } CrestronConsole.ConsoleCommandResponse( "HTTP Debug {0}", _httpDebugEnabled ? "Enabled" : "Disabled" ); }, "mobilehttpdebug", "1 enables more verbose HTTP response debugging", ConsoleAccessLevelEnum.AccessOperator ); CrestronConsole.AddNewConsoleCommand( TestHttpRequest, "mobilehttprequest", "Tests an HTTP get to URL given", ConsoleAccessLevelEnum.AccessOperator ); CrestronConsole.AddNewConsoleCommand( PrintActionDictionaryPaths, "mobileshowactionpaths", "Prints the paths in the Action Dictionary", ConsoleAccessLevelEnum.AccessOperator ); CrestronConsole.AddNewConsoleCommand( s => { _disableReconnect = false; CrestronConsole.ConsoleCommandResponse( $"Connecting to MC API server" ); ConnectWebsocketClient(); }, "mobileconnect", "Forces connect of websocket", ConsoleAccessLevelEnum.AccessOperator ); CrestronConsole.AddNewConsoleCommand( s => { _disableReconnect = true; CleanUpWebsocketClient(); CrestronConsole.ConsoleCommandResponse( $"Disonnected from MC API server" ); }, "mobiledisco", "Disconnects websocket", ConsoleAccessLevelEnum.AccessOperator ); CrestronConsole.AddNewConsoleCommand( ParseStreamRx, "mobilesimulateaction", "Simulates a message from the server", ConsoleAccessLevelEnum.AccessOperator ); CrestronConsole.AddNewConsoleCommand( SetWebsocketDebugLevel, "mobilewsdebug", "Set Websocket debug level", ConsoleAccessLevelEnum.AccessProgrammer ); } /// /// Gets or sets the Config /// public MobileControlConfig Config { get; private set; } /// /// Gets or sets the Host /// public string Host { get; private set; } /// /// Gets the configured Client App URL /// public string ClientAppUrl => Config.ClientAppUrl; private void OnRoomCombinationScenarioChanged( object sender, EventArgs eventArgs ) { SendMessageObject(new MobileControlMessage { Type = "/system/roomCombinationChanged" }); } /// /// Checks if a device messenger exists for the given key. /// public bool CheckForDeviceMessenger(string key) { return _messengers.ContainsKey(key); } /// /// Add the provided messenger to the messengers collection /// public void AddDeviceMessenger(IMobileControlMessenger messenger) { if (_messengers.ContainsKey(messenger.Key)) { this.LogWarning("Messenger with key {messengerKey} already added", messenger.Key); return; } if (messenger is IDelayedConfiguration simplMessenger) { simplMessenger.ConfigurationIsReady += Bridge_ConfigurationIsReady; } if (messenger is MobileControlBridgeBase roomBridge) { _roomBridges.Add(roomBridge); } this.LogVerbose( "Adding messenger with key {messengerKey} for path {messengerPath}", messenger.Key, messenger.MessagePath ); _messengers.Add(messenger.Key, messenger); if (_initialized) { RegisterMessengerWithServer(messenger); } } private void AddDefaultDeviceMessenger(IMobileControlMessenger messenger) { if (_defaultMessengers.ContainsKey(messenger.Key)) { this.LogWarning( "Default messenger with key {messengerKey} already added", messenger.Key ); return; } if (messenger is IDelayedConfiguration simplMessenger) { simplMessenger.ConfigurationIsReady += Bridge_ConfigurationIsReady; } this.LogVerbose( "Adding default messenger with key {messengerKey} for path {messengerPath}", messenger.Key, messenger.MessagePath ); _defaultMessengers.Add(messenger.Key, messenger); if (_initialized) { RegisterMessengerWithServer(messenger); } } private void RegisterMessengerWithServer(IMobileControlMessenger messenger) { this.LogVerbose( "Registering messenger with key {messengerKey} for path {messengerPath}", messenger.Key, messenger.MessagePath ); if (messenger is IMobileControlMessengerWithSubscriptions subMessenger) { subMessenger.RegisterWithAppServer(this, Config.EnableMessengerSubscriptions); return; } messenger.RegisterWithAppServer(this); } /// public override void Initialize() { if (!Config.EnableMessengerSubscriptions) { this.LogWarning("Messenger subscriptions disabled. add \"enableMessengerSubscriptions\": true to config for {key} to enable.", Key); } foreach (var messenger in _messengers) { try { RegisterMessengerWithServer(messenger.Value); } catch (Exception ex) { this.LogException(ex, "Exception registering custom messenger {messengerKey}", messenger.Key); continue; } } foreach (var messenger in _defaultMessengers) { try { RegisterMessengerWithServer(messenger.Value); } catch (Exception ex) { this.LogException(ex, "Exception registering default messenger {messengerKey}", messenger.Key); continue; } } var simplMessengers = _messengers.OfType().ToList(); if (simplMessengers.Count > 0) { return; } _initialized = true; RegisterSystemToServer(); } #region IMobileControl Members /// /// Gets the App Server instance /// public static IMobileControl GetAppServer() { try { var appServer = DeviceManager.GetDevices().SingleOrDefault(s => s is IMobileControl) as MobileControlSystemController; return appServer; } catch (Exception e) { Debug.LogMessage(e, "Unable to find MobileControlSystemController in Devices"); return null; } } private bool CreateWebsocket() { _wsClient2?.Close(); _wsClient2 = null; if (string.IsNullOrEmpty(SystemUuid)) { this.LogError( "System UUID not defined. Unable to connect to Mobile Control" ); return false; } var wsHost = Host.Replace("http", "ws"); var url = string.Format("{0}/system/join/{1}", wsHost, SystemUuid); _wsClient2 = new WebSocket(url) { Log = { Output = (data, message) => Utilities.ConvertWebsocketLog(data, message, this) } }; // setting to trace to let level be controlled by appdebug _wsClient2.Log.Level = LogLevel.Trace; _wsClient2.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12; _wsClient2.OnMessage += HandleMessage; _wsClient2.OnOpen += HandleOpen; _wsClient2.OnError += HandleError; _wsClient2.OnClose += HandleClose; return true; } /// /// Link the System Monitor to this App server /// public void LinkSystemMonitorToAppServer() { if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Appliance) { this.LogWarning( "System Monitor does not exist for this platform. Skipping..." ); return; } if (!(DeviceManager.GetDeviceForKey("systemMonitor") is SystemMonitorController sysMon)) { return; } var key = sysMon.Key + "-" + Key; var messenger = new SystemMonitorMessenger(key, sysMon, "/device/systemMonitor"); AddDeviceMessenger(messenger); } #endregion private void SetWebsocketDebugLevel(string cmdparameters) { if (string.IsNullOrEmpty(cmdparameters)) { this.LogInformation("Current Websocket debug level: {webSocketDebugLevel}", _wsLogLevel); return; } if (cmdparameters.ToLower().Contains("help") || cmdparameters.ToLower().Contains("?")) { CrestronConsole.ConsoleCommandResponse( $"valid options are:\r\n{LogLevel.Trace}\r\n{LogLevel.Debug}\r\n{LogLevel.Info}\r\n{LogLevel.Warn}\r\n{LogLevel.Error}\r\n{LogLevel.Fatal}\r\n" ); } try { var debugLevel = (LogLevel)Enum.Parse(typeof(LogLevel), cmdparameters, true); _wsLogLevel = debugLevel; if (_wsClient2 != null) { _wsClient2.Log.Level = _wsLogLevel; } _directServer?.SetWebsocketLogLevel(_wsLogLevel); CrestronConsole.ConsoleCommandResponse($"Websocket log level set to {debugLevel}"); } catch { CrestronConsole.ConsoleCommandResponse( $"{cmdparameters} is not a valid debug level. Valid options are:\r\n{LogLevel.Trace}\r\n{LogLevel.Debug}\r\n{LogLevel.Info}\r\n{LogLevel.Warn}\r\n{LogLevel.Error}\r\n{LogLevel.Fatal}\r\n" ); } } private void CrestronEnvironment_ProgramStatusEventHandler( eProgramStatusEventType programEventType ) { if ( programEventType != eProgramStatusEventType.Stopping || _wsClient2 == null || !_wsClient2.IsAlive ) { return; } _disableReconnect = true; StopServerReconnectTimer(); CleanUpWebsocketClient(); } /// /// PrintActionDictionaryPaths method /// public void PrintActionDictionaryPaths(object o) { CrestronConsole.ConsoleCommandResponse("ActionDictionary Contents:\r\n"); foreach (var (messengerKey, actionPath) in GetActionDictionaryPaths()) { CrestronConsole.ConsoleCommandResponse($"<{messengerKey}> {actionPath}\r\n"); } } /// /// Get action paths for the current actions /// public List<(string, string)> GetActionDictionaryPaths() { var paths = new List<(string, string)>(); foreach (var item in _actionDictionary) { var messengers = item.Value.Select(a => a.Messenger).Cast(); foreach (var messenger in messengers) { foreach (var actionPath in messenger.GetActionPaths()) { paths.Add((messenger.Key, $"{item.Key}{actionPath}")); } } } return paths; } /// /// Adds an action to the dictionary /// /// The messenger for the API command /// The action to be triggered by the commmand public void AddAction(T messenger, Action action) where T : IMobileControlMessenger { if ( _actionDictionary.TryGetValue( messenger.MessagePath, out List actionList ) ) { if ( actionList.Any(a => a.Messenger.GetType() == messenger.GetType() && a.Messenger.DeviceKey == messenger.DeviceKey ) ) { this.LogWarning("Messenger of type {messengerType} already exists. Skipping actions for {messengerKey}", messenger.GetType().Name, messenger.Key); return; } actionList.Add(new MobileControlAction(messenger, action)); return; } actionList = new List { new MobileControlAction(messenger, action) }; _actionDictionary.Add(messenger.MessagePath, actionList); } /// /// Removes an action from the dictionary /// /// /// /// RemoveAction method /// public void RemoveAction(string key) { if (_actionDictionary.ContainsKey(key)) { _actionDictionary.Remove(key); } } /// /// Get the room bridge with the provided key /// /// The key of the room bridge public MobileControlBridgeBase GetRoomBridge(string key) { return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key)); } /// /// Get the room messenger with the provided key /// /// The Key of the rooom messenger public IMobileControlRoomMessenger GetRoomMessenger(string key) { return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key)); } private void Bridge_ConfigurationIsReady(object sender, EventArgs e) { this.LogDebug("Bridge ready. Registering"); // send the configuration object to the server if (_wsClient2 == null) { RegisterSystemToServer(); } else if (!_wsClient2.IsAlive) { ConnectWebsocketClient(); } else { SendInitialMessage(); } } private void ReconnectToServerTimerCallback(object o) { this.LogDebug("Attempting to reconnect to server..."); ConnectWebsocketClient(); } private void AuthorizeSystem(string code) { if ( string.IsNullOrEmpty(SystemUuid) || SystemUuid.Equals("missing url", StringComparison.OrdinalIgnoreCase) ) { CrestronConsole.ConsoleCommandResponse( "System does not have a UUID. Please ensure proper configuration is loaded and restart." ); return; } if (string.IsNullOrEmpty(code)) { CrestronConsole.ConsoleCommandResponse( "Please enter a grant code to authorize a system" ); return; } if (string.IsNullOrEmpty(Config.ServerUrl)) { CrestronConsole.ConsoleCommandResponse( "Mobile control API address is not set. Check portal configuration" ); return; } var authTask = ApiService.SendAuthorizationRequest(Host, code, SystemUuid); authTask.ContinueWith(t => { var response = t.Result; if (response.Authorized) { this.LogDebug("System authorized, sending config."); RegisterSystemToServer(); return; } this.LogInformation(response.Reason); }); } private void ShowInfo() { var url = Config != null ? Host : "No config"; string name; string code; if (_roomBridges != null && _roomBridges.Count > 0) { name = _roomBridges[0].RoomName; code = _roomBridges[0].UserCode; } else { name = "No config"; code = "Not available"; } var conn = _wsClient2 == null ? "No client" : (_wsClient2.IsAlive ? "Yes" : "No"); var secSinceLastAck = DateTime.Now - _lastAckMessage; if (Config.EnableApiServer) { CrestronConsole.ConsoleCommandResponse( "Mobile Control Edge Server API Information:\r\n\r\n" + "\tServer address: {0}\r\n" + "\tSystem Name: {1}\r\n" + "\tSystem URL: {2}\r\n" + "\tSystem UUID: {3}\r\n" + "\tSystem User code: {4}\r\n" + "\tConnected?: {5}\r\n" + "\tSeconds Since Last Ack: {6}\r\n", url, name, ConfigReader.ConfigObject.SystemUrl, SystemUuid, code, conn, secSinceLastAck.Seconds ); } else { CrestronConsole.ConsoleCommandResponse( "\r\nMobile Control Edge Server API Information:\r\n" + " Not Enabled in Config.\r\n" ); } if ( Config.DirectServer != null && Config.DirectServer.EnableDirectServer && _directServer != null ) { CrestronConsole.ConsoleCommandResponse( "\r\nMobile Control Direct Server Information:\r\n" + " User App URL: {0}\r\n" + " Server port: {1}\r\n", string.Format("{0}[insert_client_token]", _directServer.UserAppUrlPrefix), _directServer.Port ); CrestronConsole.ConsoleCommandResponse( "\r\n UI Client Info:\r\n" + " Tokens Defined: {0}\r\n" + " Clients Connected: {1}\r\n", _directServer.UiClientContexts.Count, _directServer.ConnectedUiClientsCount ); var clientNo = 1; foreach (var clientContext in _directServer.UiClientContexts) { var clients = _directServer.UiClients.Values.Where(c => c.TokenKey == clientContext.Key); CrestronConsole.ConsoleCommandResponse( $"\r\nClient {clientNo}:\r\n" + $" Room Key: {clientContext.Value.Token.RoomKey}\r\n" + $" Touchpanel Key: {clientContext.Value.Token.TouchpanelKey}\r\n" + $" Token: {clientContext.Key}\r\n" + $" Client URL: {_directServer.UserAppUrlPrefix}{clientContext.Key}\r\n" + $" Clients:\r\n" ); if (!clients.Any()) { CrestronConsole.ConsoleCommandResponse(" No clients connected"); } foreach (var client in clients) { CrestronConsole.ConsoleCommandResponse( $" ID: {client.Id}\r\n" + $" Connected: {client.Context.WebSocket.IsAlive}\r\n" + $" Duration: {(client.Context.WebSocket.IsAlive ? client.ConnectedDuration.TotalSeconds.ToString() : "Not Connected")}\r\n" ); } clientNo++; } } else { CrestronConsole.ConsoleCommandResponse( "\r\nMobile Control Direct Server Information:\r\n" + " Not Enabled in Config.\r\n" ); } } /// /// Register this system to the Mobile Control Edge Server /// public void RegisterSystemToServer() { if (!Config.EnableApiServer) { this.LogInformation( "ApiServer disabled via config. Cancelling attempt to register to server." ); return; } var result = CreateWebsocket(); if (!result) { this.LogFatal("Unable to create websocket."); return; } ConnectWebsocketClient(); } private void ConnectWebsocketClient() { try { _wsCriticalSection.Enter(); // set to 99999 to let things work on 4-Series if ( (CrestronEnvironment.ProgramCompatibility & eCrestronSeries.Series4) == eCrestronSeries.Series4 ) { _wsClient2.Log.Level = (LogLevel)99999; } else if ( (CrestronEnvironment.ProgramCompatibility & eCrestronSeries.Series3) == eCrestronSeries.Series3 ) { _wsClient2.Log.Level = _wsLogLevel; } //This version of the websocket client is TLS1.2 ONLY //Fires OnMessage event when PING is received. _wsClient2.EmitOnPing = true; this.LogDebug( "Connecting mobile control client to {mobileControlUrl}", _wsClient2.Url ); TryConnect(); } finally { _wsCriticalSection.Leave(); } } private void TryConnect() { try { IsAuthorized = false; _wsClient2.Connect(); } catch (InvalidOperationException) { this.LogError( "Maximum retries exceeded. Restarting websocket" ); HandleConnectFailure(); } catch (IOException ex) { this.LogException(ex, "IO Exception on connect"); HandleConnectFailure(); } catch (Exception ex) { this.LogException( ex, "Error on Websocket Connect" ); HandleConnectFailure(); } } private void HandleConnectFailure() { _wsClient2 = null; var wsHost = Host.Replace("http", "ws"); var url = string.Format("{0}/system/join/{1}", wsHost, SystemUuid); _wsClient2 = new WebSocket(url) { Log = { Output = (data, s) => this.LogDebug( "Message from websocket: {message}", data ) } }; _wsClient2.OnMessage -= HandleMessage; _wsClient2.OnOpen -= HandleOpen; _wsClient2.OnError -= HandleError; _wsClient2.OnClose -= HandleClose; _wsClient2.OnMessage += HandleMessage; _wsClient2.OnOpen += HandleOpen; _wsClient2.OnError += HandleError; _wsClient2.OnClose += HandleClose; StartServerReconnectTimer(); } private void HandleOpen(object sender, EventArgs e) { StopServerReconnectTimer(); StartPingTimer(); this.LogInformation("Mobile Control API connected"); SendMessageObject(new MobileControlMessage { Type = "hello" }); } private void HandleMessage(object sender, MessageEventArgs e) { if (e.IsPing) { _lastAckMessage = DateTime.Now; IsAuthorized = true; ResetPingTimer(); return; } if (e.IsText && e.Data.Length > 0) { _receiveQueue.Enqueue(new ProcessStringMessage(e.Data, ParseStreamRx)); } } private void HandleError(object sender, ErrorEventArgs e) { this.LogError("Websocket error {0}", e.Message); IsAuthorized = false; StartServerReconnectTimer(); } private void HandleClose(object sender, CloseEventArgs e) { this.LogDebug( "Websocket close {code} {reason}, clean={wasClean}", e.Code, e.Reason, e.WasClean ); IsAuthorized = false; StopPingTimer(); // Start the reconnect timer only if disableReconnect is false and the code isn't 4200. 4200 indicates system is not authorized; if (_disableReconnect || e.Code == 4200) { return; } StartServerReconnectTimer(); } private void SendInitialMessage() { this.LogInformation("Sending initial join message"); var touchPanels = DeviceManager .AllDevices.OfType() .Where(tp => !tp.UseDirectServer) .Select( (tp) => { return new { touchPanelKey = tp.Key, roomKey = tp.DefaultRoomKey }; } ); var msg = new MobileControlMessage { Type = "join", Content = JToken.FromObject( new { config = GetConfigWithPluginVersion(), touchPanels } ) }; SendMessageObject(msg); } /// /// Get the Essentials configuration with version data /// public MobileControlEssentialsConfig GetConfigWithPluginVersion() { // Populate the application name and version number var confObject = new MobileControlEssentialsConfig(ConfigReader.ConfigObject); confObject.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name; var essentialsVersion = Global.AssemblyVersion; confObject.Info.RuntimeInfo.AssemblyVersion = essentialsVersion; // // Set for local testing // confObject.RuntimeInfo.PluginVersion = "4.0.0-localBuild"; // Populate the plugin version var pluginVersion = Assembly .GetExecutingAssembly() .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false); if (pluginVersion[0] is AssemblyInformationalVersionAttribute fullVersionAtt) { var pluginInformationalVersion = fullVersionAtt.InformationalVersion; confObject.RuntimeInfo.PluginVersion = pluginInformationalVersion; confObject.RuntimeInfo.EssentialsVersion = Global.AssemblyVersion; confObject.RuntimeInfo.PepperDashCoreVersion = PluginLoader.PepperDashCoreAssembly.Version; confObject.RuntimeInfo.EssentialsPlugins = PluginLoader.EssentialsPluginAssemblies; } return confObject; } /// /// Set the Client URL for a given room /// /// new App URL /// room key. Default is null /// /// If roomKey is null, the URL will be set for the entire system. /// public void SetClientUrl(string path, string roomKey = null) { var message = new MobileControlMessage { Type = string.IsNullOrEmpty(roomKey) ? $"/event/system/setUrl" : $"/event/room/{roomKey}/setUrl", Content = JToken.FromObject(new MobileControlSimpleContent { Value = path }) }; SendMessageObject(message); } /// /// Sends any object type to server /// /// public void SendMessageObject(IMobileControlMessage o) { if (Config.EnableApiServer) { _transmitToServerQueue.Enqueue(new TransmitMessage(o, _wsClient2)); } if ( Config.DirectServer != null && Config.DirectServer.EnableDirectServer && _directServer != null ) { _transmitToClientsQueue.Enqueue(new MessageToClients(o, _directServer)); } } /// /// Send a message to a client using the Direct Server /// /// object to send public void SendMessageObjectToDirectClient(object o) { if ( Config.DirectServer != null && Config.DirectServer.EnableDirectServer && _directServer != null ) { _transmitToClientsQueue.Enqueue(new MessageToClients(o, _directServer)); } } private void CleanUpWebsocketClient() { if (_wsClient2 == null) { return; } this.LogDebug("Disconnecting websocket"); _wsClient2.Close(); } private void ResetPingTimer() { // This tells us we're online with the API and getting pings _pingTimer.Reset(PingInterval); } private void StartPingTimer() { StopPingTimer(); _pingTimer = new CTimer(PingTimerCallback, null, PingInterval); } private void StopPingTimer() { if (_pingTimer == null) { return; } _pingTimer.Stop(); _pingTimer.Dispose(); _pingTimer = null; } private void PingTimerCallback(object o) { this.LogDebug( "Ping timer expired. Closing websocket" ); try { _wsClient2.Close(); } catch (Exception ex) { this.LogException(ex, "Exception closing websocket" ); HandleConnectFailure(); } } private void StartServerReconnectTimer() { StopServerReconnectTimer(); _serverReconnectTimer = new CTimer( ReconnectToServerTimerCallback, ServerReconnectInterval ); this.LogDebug("Reconnect Timer Started."); } private void StopServerReconnectTimer() { if (_serverReconnectTimer == null) { return; } _serverReconnectTimer.Stop(); _serverReconnectTimer = null; } private void HandleHeartBeat(JToken content) { SendMessageObject(new MobileControlMessage { Type = "/system/heartbeatAck" }); var code = content["userCode"]; if (code == null) { return; } foreach (var b in _roomBridges) { b.SetUserCode(code.Value()); } } private void HandleClientJoined(JToken content) { var clientId = content["clientId"].Value(); var roomKey = content["roomKey"].Value(); var touchpanelKey = content.SelectToken("touchpanelKey"); if (_roomCombiner == null) { var message = new MobileControlMessage { Type = "/system/roomKey", ClientId = clientId, Content = roomKey }; SendMessageObject(message); SendDeviceInterfaces(clientId); SendTouchpanelKey(clientId, touchpanelKey); return; } if (_roomCombiner.CurrentScenario == null) { var message = new MobileControlMessage { Type = "/system/roomKey", ClientId = clientId, Content = roomKey }; SendMessageObject(message); SendDeviceInterfaces(clientId); SendTouchpanelKey(clientId, touchpanelKey); return; } if (!_roomCombiner.CurrentScenario.UiMap.ContainsKey(roomKey)) { this.LogWarning( "Unable to find correct roomKey for {roomKey} in current scenario. Returning {roomKey} as roomKey", roomKey); var message = new MobileControlMessage { Type = "/system/roomKey", ClientId = clientId, Content = roomKey }; SendMessageObject(message); SendDeviceInterfaces(clientId); SendTouchpanelKey(clientId, touchpanelKey); return; } var newRoomKey = _roomCombiner.CurrentScenario.UiMap[roomKey]; var newMessage = new MobileControlMessage { Type = "/system/roomKey", ClientId = clientId, Content = newRoomKey }; SendMessageObject(newMessage); SendDeviceInterfaces(clientId); SendTouchpanelKey(clientId, touchpanelKey); } private void SendTouchpanelKey(string clientId, JToken touchpanelKeyToken) { if (touchpanelKeyToken == null) { this.LogWarning("Touchpanel key not found for client {clientId}", clientId); return; } SendMessageObject(new MobileControlMessage { Type = "/system/touchpanelKey", ClientId = clientId, Content = touchpanelKeyToken.Value() }); } private void SendDeviceInterfaces(string clientId) { this.LogDebug("Sending Device interfaces"); var devices = DeviceManager.GetDevices(); Dictionary deviceInterfaces = new Dictionary(); foreach (var device in devices) { var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List(); deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo { Key = device.Key, Name = (device as IKeyName)?.Name ?? "", Interfaces = interfaces }); } var message = new MobileControlMessage { Type = "/system/deviceInterfaces", ClientId = clientId, Content = JToken.FromObject(new { deviceInterfaces }) }; SendMessageObject(message); } private void HandleUserCode(JToken content, Action action = null) { var code = content["userCode"]; JToken qrChecksum; try { qrChecksum = content.SelectToken("qrChecksum", false); } catch { qrChecksum = new JValue(string.Empty); } if (code == null) { return; } if (action == null) { foreach (var bridge in _roomBridges) { bridge.SetUserCode(code.Value(), qrChecksum.Value()); } return; } action(code.Value(), qrChecksum.Value()); } /// /// Enqueue an incoming message for processing /// public void HandleClientMessage(string message) { _receiveQueue.Enqueue(new ProcessStringMessage(message, ParseStreamRx)); } private void ParseStreamRx(string messageText) { if (string.IsNullOrEmpty(messageText)) { return; } if (!messageText.Contains("/system/heartbeat")) { this.LogDebug( "Message RX: {messageText}", messageText ); } try { var message = JsonConvert.DeserializeObject(messageText); switch (message.Type) { case "hello": SendInitialMessage(); break; case "/system/heartbeat": HandleHeartBeat(message.Content); break; case "/system/userCode": HandleUserCode(message.Content); break; case "/system/clientJoined": HandleClientJoined(message.Content); break; case "/system/reboot": SystemMonitorController.ProcessorReboot(); break; case "/system/programReset": SystemMonitorController.ProgramReset(InitialParametersClass.ApplicationNumber); break; case "raw": var wrapper = message.Content.ToObject(); DeviceJsonApi.DoDeviceAction(wrapper); break; case "close": this.LogDebug("Received close message from server"); break; default: // Incoming message example // /room/roomA/status // /room/roomAB/status // ActionDictionary Keys example // /room/roomA // /room/roomAB // Can't do direct comparison because it will match /room/roomA with /room/roomA/xxx instead of /room/roomAB/xxx var handlers = _actionDictionary.Where(kv => message.Type.StartsWith(kv.Key + "/")).SelectMany(kv => kv.Value).ToList(); // adds trailing slash to ensure above case is handled if (handlers.Count == 0) { this.LogInformation("-- Warning: Incoming message has no registered handler {type}", message.Type); break; } foreach (var handler in handlers) { Task.Run(() => { try { handler.Action(message.Type, message.ClientId, message.Content); } catch (Exception ex) { this.LogError( "Exception in handler for message type {type}, ClientId {clientId}", message.Type, message.ClientId ); this.LogDebug(ex, "Stack Trace: "); } }).ContinueWith(task => { if (task.IsFaulted && task.Exception != null) { this.LogError( "Unhandled exception in Task for message type {type}, ClientId {clientId}", message.Type, message.ClientId ); this.LogDebug(task.Exception.GetBaseException(), "Stack Trace: "); } }, TaskContinuationOptions.OnlyOnFaulted); } break; } } catch (Exception err) { this.LogException( err, "Unable to parse {message}", messageText ); } } private void TestHttpRequest(string s) { { s = s.Trim(); if (string.IsNullOrEmpty(s)) { PrintTestHttpRequestUsage(); return; } var tokens = s.Split(' '); if (tokens.Length < 2) { CrestronConsole.ConsoleCommandResponse("Too few paramaters\r"); PrintTestHttpRequestUsage(); return; } try { var url = tokens[1]; switch (tokens[0].ToLower()) { case "get": { var resp = new HttpClient().Get(url); CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); } break; case "post": { var resp = new HttpClient().Post(url, new byte[] { }); CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); } break; default: CrestronConsole.ConsoleCommandResponse("Only get or post supported\r"); PrintTestHttpRequestUsage(); break; } } catch (HttpException e) { CrestronConsole.ConsoleCommandResponse("Exception in request:\r"); CrestronConsole.ConsoleCommandResponse( "Response URL: {0}\r", e.Response.ResponseUrl ); CrestronConsole.ConsoleCommandResponse( "Response Error Code: {0}\r", e.Response.Code ); CrestronConsole.ConsoleCommandResponse( "Response body: {0}\r", e.Response.ContentString ); } } } private void PrintTestHttpRequestUsage() { CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r"); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj ================================================  PepperDash.Essentials net472 true false epi-essentials-mobile-control epi-essentials-mobile-control PepperDash Technologies epi-essentials-mobile-control This software is a plugin designed to work as a part of PepperDash Essentials for Crestron control processors. This plugin allows for connection to a PepperDash Mobile Control server. Copyright 2020 true true $(Version) false bin\$(Configuration)\ PepperDash Technologies PepperDash.Essentials.MobileControl crestron 4series TRACE;DEBUG;SERIES4 pdbonly TRACE;SERIES4 bin\$(Configuration)\epi-essentials-mobile-control.xml false runtime false runtime false runtime ================================================ FILE: src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlBridgeBase.cs ================================================ using System; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.RoomBridges { /// /// Base class for a Mobile Control Bridge that's used to control a room /// public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomMessenger { /// /// Triggered when the user Code changes /// public event EventHandler UserCodeChanged; /// /// Triggered when a user should be prompted for the new code /// public event EventHandler UserPromptedForCode; /// /// Triggered when a client joins to control this room /// public event EventHandler ClientJoined; /// /// Triggered when the App URL for this room changes /// public event EventHandler AppUrlChanged; /// /// Gets or sets the Parent /// public IMobileControl Parent { get; private set; } /// /// Gets or sets the AppUrl /// public string AppUrl { get; private set; } /// /// Gets or sets the UserCode /// public string UserCode { get; private set; } /// /// Gets or sets the QrCodeUrl /// public string QrCodeUrl { get; protected set; } /// /// Gets or sets the QrCodeChecksum /// public string QrCodeChecksum { get; protected set; } /// /// Gets or sets the McServerUrl /// public string McServerUrl { get; private set; } /// /// Room Name /// public abstract string RoomName { get; } /// /// Room key /// public abstract string RoomKey { get; } /// /// Create an instance of the class /// /// The unique key for this bridge /// The message path for this bridge protected MobileControlBridgeBase(string key, string messagePath) : base(key, messagePath) { } /// /// Create an instance of the class /// /// The unique key for this bridge /// The message path for this bridge /// The device associated with this bridge protected MobileControlBridgeBase(string key, string messagePath, IKeyName device) : base(key, messagePath, device) { } /// /// Set the parent. Does nothing else. Override to add functionality such /// as adding actions to parent /// /// /// /// AddParent method /// public virtual void AddParent(IMobileControl parent) { Parent = parent; McServerUrl = Parent.ClientAppUrl; } /// /// Sets the UserCode on the bridge object. Called from controller. A changed code will /// fire method UserCodeChange. Override that to handle changes /// /// /// /// SetUserCode method /// public void SetUserCode(string code) { var changed = UserCode != code; UserCode = code; if (changed) { UserCodeChange(); } } /// /// Sets the UserCode on the bridge object. Called from controller. A changed code will /// fire method UserCodeChange. Override that to handle changes /// /// /// Checksum of the QR code. Used for Cisco codec branding command public void SetUserCode(string code, string qrChecksum) { QrCodeChecksum = qrChecksum; SetUserCode(code); } /// /// Update the App Url with the provided URL /// /// The new App URL public virtual void UpdateAppUrl(string url) { AppUrl = url; var handler = AppUrlChanged; if (handler == null) return; handler(this, new EventArgs()); } /// /// Empty method in base class. Override this to add functionality /// when code changes /// protected virtual void UserCodeChange() { this.LogDebug("Server user code changed: {userCode}", UserCode); var qrUrl = string.Format($"{Parent.Host}/api/rooms/{Parent.SystemUuid}/{RoomKey}/qr?x={new Random().Next()}"); QrCodeUrl = qrUrl; this.LogDebug("Server user code changed: {userCode} - {qrCodeUrl}", UserCode, qrUrl); OnUserCodeChanged(); } /// /// Trigger the UserCodeChanged event /// protected void OnUserCodeChanged() { UserCodeChanged?.Invoke(this, new EventArgs()); } /// /// Trigger the UserPromptedForCode event /// protected void OnUserPromptedForCode() { UserPromptedForCode?.Invoke(this, new EventArgs()); } /// /// Trigger the ClientJoined event /// protected void OnClientJoined() { ClientJoined?.Invoke(this, new EventArgs()); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.CrestronIO; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Lighting; using PepperDash.Essentials.Core.Shades; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Room; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Room.Config; using PepperDash.Essentials.WebSocketServer; using IShades = PepperDash.Essentials.Core.Shades.IShades; using ShadeBase = PepperDash.Essentials.Devices.Common.Shades.ShadeBase; namespace PepperDash.Essentials.RoomBridges { /// /// Represents a MobileControlEssentialsRoomBridge /// public class MobileControlEssentialsRoomBridge : MobileControlBridgeBase { private List _touchPanelTokens = new List(); /// /// Gets or sets the Room /// public IEssentialsRoom Room { get; private set; } /// /// Gets or sets the DefaultRoomKey /// public string DefaultRoomKey { get; private set; } /// /// Gets the name of the room /// public override string RoomName { get { return Room.Name; } } /// /// Gets the key of the room /// public override string RoomKey { get { return Room.Key; } } /// /// Initializes a new instance of the class with the specified room /// /// The essentials room to bridge public MobileControlEssentialsRoomBridge(IEssentialsRoom room) : this($"mobileControlBridge-{room.Key}", room.Key, room) { Room = room; } /// /// Initializes a new instance of the class with the specified parameters /// /// The unique key for this bridge /// The key of the room to bridge /// The essentials room to bridge public MobileControlEssentialsRoomBridge(string key, string roomKey, IEssentialsRoom room) : base(key, $"/room/{room.Key}", room as Device) { DefaultRoomKey = roomKey; AddPreActivationAction(GetRoom); } /// /// Registers all message handling actions with the AppServer for this room bridge /// protected override void RegisterActions() { // we add actions to the messaging system with a path, and a related action. Custom action // content objects can be handled in the controller's LineReceived method - and perhaps other // sub-controller parsing could be attached to these classes, so that the systemController // doesn't need to know about everything. this.LogInformation("Registering Actions with AppServer"); AddAction("/promptForCode", (id, content) => OnUserPromptedForCode()); AddAction("/clientJoined", (id, content) => OnClientJoined()); AddAction("/touchPanels", (id, content) => OnTouchPanelsUpdated(content)); AddAction($"/userApp", (id, content) => OnUserAppUpdated(content)); AddAction("/userCode", (id, content) => { var msg = content.ToObject(); SetUserCode(msg.UserCode, msg.QrChecksum ?? string.Empty); }); // Source Changes and room off AddAction("/status", (id, content) => { SendFullStatusForClientId(id, Room); }); if (Room is IRunRouteAction routeRoom) AddAction("/source", (id, content) => { var msg = content.ToObject(); this.LogVerbose("Received request to route to source: {sourceListKey} on list: {sourceList}", msg.SourceListItemKey, msg.SourceListKey); routeRoom.RunRouteAction(msg.SourceListItemKey, msg.SourceListKey); }); if (Room is IRunDirectRouteAction directRouteRoom) { AddAction("/directRoute", (id, content) => { var msg = content.ToObject(); this.LogVerbose("Running direct route from {sourceKey} to {destinationKey} with signal type {signalType}", msg.SourceKey, msg.DestinationKey, msg.SignalType); directRouteRoom.RunDirectRoute(msg.SourceKey, msg.DestinationKey, msg.SignalType); }); } if (Room is IRunDefaultPresentRoute defaultRoom) AddAction("/defaultsource", (id, content) => defaultRoom.RunDefaultPresentRoute()); if (Room is IHasCurrentSourceInfoChange sscRoom) sscRoom.CurrentSourceChange += Room_CurrentSingleSourceChange; if (Room is IEssentialsHuddleVtc1Room vtcRoom) { if (vtcRoom.ScheduleSource != null) { var key = vtcRoom.Key + "-" + Key; if (!AppServerController.CheckForDeviceMessenger(key)) { var scheduleMessenger = new IHasScheduleAwarenessMessenger(key, vtcRoom.ScheduleSource, $"/room/{vtcRoom.Key}"); AppServerController.AddDeviceMessenger(scheduleMessenger); } } vtcRoom.InCallFeedback.OutputChange += InCallFeedback_OutputChange; } if (Room is IPrivacy privacyRoom) { AddAction("/volumes/master/privacyMuteToggle", (id, content) => privacyRoom.PrivacyModeToggle()); privacyRoom.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; } if (Room is IRunDefaultCallRoute defCallRm) { AddAction("/activityVideo", (id, content) => defCallRm.RunDefaultCallRoute()); } Room.OnFeedback.OutputChange += OnFeedback_OutputChange; Room.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; Room.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange; AddTechRoomActions(); if (Room is IHasCurrentVolumeControls volumeRoom) { volumeRoom.CurrentVolumeDeviceChange += Room_CurrentVolumeDeviceChange; if (volumeRoom.CurrentVolumeControls == null) return; AddAction("/volumes/master/level", (id, content) => { var msg = content.ToObject>(); if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) basicVolumeWithFeedback.SetVolume(msg.Value); }); AddAction("/volumes/master/muteToggle", (id, content) => volumeRoom.CurrentVolumeControls.MuteToggle()); AddAction("/volumes/master/muteOn", (id, content) => { if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) basicVolumeWithFeedback.MuteOn(); }); AddAction("/volumes/master/muteOff", (id, content) => { if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) basicVolumeWithFeedback.MuteOff(); }); AddAction("/volumes/master/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => { if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) { basicVolumeWithFeedback.VolumeUp(b); } } )); AddAction("/volumes/master/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => { if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) { basicVolumeWithFeedback.VolumeDown(b); } } )); // Registers for initial volume events, if possible if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback currentVolumeDevice) { this.LogVerbose("Registering for volume feedback events"); currentVolumeDevice.MuteFeedback.OutputChange += MuteFeedback_OutputChange; currentVolumeDevice.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; } } } private void OnTouchPanelsUpdated(JToken content) { var message = content.ToObject(); _touchPanelTokens = message.TouchPanels; UpdateTouchPanelAppUrls(message.UserAppUrl); } private void UpdateTouchPanelAppUrls(string userAppUrl) { foreach (var tp in _touchPanelTokens) { var dev = DeviceManager.AllDevices.OfType().FirstOrDefault((tpc) => tpc.Key.Equals(tp.TouchpanelKey, StringComparison.InvariantCultureIgnoreCase)); if (dev == null) { continue; } //UpdateAppUrl($"{userAppUrl}?token={tp.Token}"); dev.SetAppUrl($"{userAppUrl}?token={tp.Token}"); } } private void OnUserAppUpdated(JToken content) { var message = content.ToObject(); Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Updating User App URL to {userAppUrl}. Full Message: {@message}", this, message.UserAppUrl, content); UpdateTouchPanelAppUrls(message.UserAppUrl); } private void InCallFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new RoomStateMessage { IsInCall = e.BoolValue }; PostStatusMessage(state); } private void GetRoom() { if (Room != null) { this.LogInformation("Room with key {key} already linked.", DefaultRoomKey); return; } if (!(DeviceManager.GetDeviceForKey(DefaultRoomKey) is IEssentialsRoom tempRoom)) { this.LogInformation("Room with key {key} not found or is not an Essentials Room", DefaultRoomKey); return; } Room = tempRoom; } /// /// Handles user code changes and generates QR code URL /// protected override void UserCodeChange() { Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Server user code changed: {userCode}", this, UserCode); var qrUrl = string.Format("{0}/rooms/{1}/{3}/qr?x={2}", Parent?.Host, Parent?.SystemUuid, new Random().Next(), DefaultRoomKey); QrCodeUrl = qrUrl; this.LogDebug("Server user code changed: {userCode} - {qrUrl}", UserCode, qrUrl); OnUserCodeChanged(); } /* /// /// Override of base: calls base to add parent and then registers actions and events. /// /// /// /// AddParent method /// /// public override void AddParent(MobileControlSystemController parent) { base.AddParent(parent); }*/ private void AddTechRoomActions() { if (!(Room is IEssentialsTechRoom techRoom)) { return; } AddAction("/roomPowerOn", (id, content) => techRoom.RoomPowerOn()); AddAction("/roomPowerOff", (id, content) => techRoom.RoomPowerOff()); } private void PrivacyModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new RoomStateMessage(); var volumes = new Dictionary { { "master", new Volume("master") { PrivacyMuted = e.BoolValue } } }; state.Volumes = volumes; PostStatusMessage(state); } /// /// /// /// /// private void IsSharingFeedback_OutputChange(object sender, FeedbackEventArgs e) { // sharing source string shareText; bool isSharing; if (Room is IHasCurrentSourceInfoChange srcInfoRoom && Room is IHasVideoCodec vcRoom && vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && srcInfoRoom.CurrentSourceInfo != null) { shareText = srcInfoRoom.CurrentSourceInfo.PreferredName; isSharing = true; } else { shareText = "None"; isSharing = false; } var state = new RoomStateMessage { Share = new ShareState { CurrentShareText = shareText, IsSharing = isSharing } }; PostStatusMessage(state); } /// /// /// /// /// private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new { isWarmingUp = e.BoolValue }; PostStatusMessage(JToken.FromObject(state)); } /// /// /// /// /// private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new { isCoolingDown = e.BoolValue }; PostStatusMessage(JToken.FromObject(state)); } /// /// /// /// /// private void OnFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new { isOn = e.BoolValue }; PostStatusMessage(JToken.FromObject(state)); } private void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e) { if (e.OldDev is IBasicVolumeWithFeedback) { var oldDev = e.OldDev as IBasicVolumeWithFeedback; oldDev.MuteFeedback.OutputChange -= MuteFeedback_OutputChange; oldDev.VolumeLevelFeedback.OutputChange -= VolumeLevelFeedback_OutputChange; } if (e.NewDev is IBasicVolumeWithFeedback) { var newDev = e.NewDev as IBasicVolumeWithFeedback; newDev.MuteFeedback.OutputChange += MuteFeedback_OutputChange; newDev.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; } } /// /// Event handler for mute changes /// private void MuteFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new RoomStateMessage(); var volumes = new Dictionary { { "master", new Volume("master", e.BoolValue) } }; state.Volumes = volumes; PostStatusMessage(state); } /// /// Handles Volume changes on room /// private void VolumeLevelFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new { volumes = new Dictionary { { "master", new Volume("master", e.IntValue) } } }; PostStatusMessage(JToken.FromObject(state)); } private void Room_CurrentSingleSourceChange(SourceListItem info, ChangeType type) { /* Example message * {    "type":"/room/status",    "content": {      "selectedSourceKey": "off",    } } */ } /// /// Sends the full status of the room to the server /// /// /// private void SendFullStatusForClientId(string id, IEssentialsRoom room) { //Parent.SendMessageObject(GetFullStatus(room)); var message = GetFullStatusForClientId(room); if (message == null) { return; } PostStatusMessage(message, id); } /// /// Gets full room status /// /// The room to get status of /// The status response message private RoomStateMessage GetFullStatusForClientId(IEssentialsRoom room) { try { this.LogVerbose("GetFullStatus"); var sourceKey = room is IHasCurrentSourceInfoChange ? (room as IHasCurrentSourceInfoChange).CurrentSourceInfoKey : null; var volumes = new Dictionary(); if (room is IHasCurrentVolumeControls rmVc) { if (rmVc.CurrentVolumeControls is IBasicVolumeWithFeedback vc) { var volume = new Volume("master", vc.VolumeLevelFeedback.UShortValue, vc.MuteFeedback.BoolValue, "Volume", true, ""); if (room is IPrivacy privacyRoom) { volume.HasPrivacyMute = true; volume.PrivacyMuted = privacyRoom.PrivacyModeIsOnFeedback.BoolValue; } volumes.Add("master", volume); } } var state = new RoomStateMessage { Configuration = GetRoomConfiguration(room), ActivityMode = 1, IsOn = room.OnFeedback.BoolValue, SelectedSourceKey = sourceKey, Volumes = volumes, IsWarmingUp = room.IsWarmingUpFeedback.BoolValue, IsCoolingDown = room.IsCoolingDownFeedback.BoolValue }; if (room is IEssentialsHuddleVtc1Room vtcRoom) { state.IsInCall = vtcRoom.InCallFeedback.BoolValue; } return state; } catch (Exception ex) { Debug.LogMessage(ex, "Error getting full status", this); return null; } } /// /// Determines the configuration of the room and the details about the devices associated with the room /// /// /// private RoomConfiguration GetRoomConfiguration(IEssentialsRoom room) { try { var configuration = new RoomConfiguration { //ShutdownPromptSeconds = room.ShutdownPromptSeconds, TouchpanelKeys = DeviceManager.AllDevices. OfType() .Where((tp) => tp.DefaultRoomKey.Equals(room.Key, StringComparison.InvariantCultureIgnoreCase)) .Select(tp => tp.Key).ToList() }; try { var zrcTp = DeviceManager.AllDevices.OfType().SingleOrDefault((tp) => tp.ZoomRoomController); configuration.ZoomRoomControllerKey = zrcTp?.Key; } catch { configuration.ZoomRoomControllerKey = room.Key; } if (room is IHasCiscoNavigatorTouchpanel ciscoNavRoom) { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting CiscoNavigatorKey to: {ciscoNavRoom.CiscoNavigatorTouchpanelKey}", this); configuration.CiscoNavigatorKey = ciscoNavRoom.CiscoNavigatorTouchpanelKey; } // find the room combiner for this room by checking if the room is in the list of rooms for the room combiner var roomCombiner = DeviceManager.AllDevices.OfType().FirstOrDefault(); configuration.RoomCombinerKey = roomCombiner?.Key; if (room is IEssentialsRoomPropertiesConfig propertiesConfig) { configuration.HelpMessage = propertiesConfig.PropertiesConfig.HelpMessageForDisplay; } if (room is IEssentialsHuddleSpaceRoom huddleRoom && !string.IsNullOrEmpty(huddleRoom.PropertiesConfig.HelpMessageForDisplay)) { this.LogVerbose("Getting huddle room config"); configuration.HelpMessage = huddleRoom.PropertiesConfig.HelpMessageForDisplay; configuration.UiBehavior = huddleRoom.PropertiesConfig.UiBehavior; configuration.DefaultPresentationSourceKey = huddleRoom.PropertiesConfig.DefaultSourceItem; } if (room is IEssentialsHuddleVtc1Room vtc1Room && !string.IsNullOrEmpty(vtc1Room.PropertiesConfig.HelpMessageForDisplay)) { this.LogVerbose("Getting vtc room config"); configuration.HelpMessage = vtc1Room.PropertiesConfig.HelpMessageForDisplay; configuration.UiBehavior = vtc1Room.PropertiesConfig.UiBehavior; configuration.DefaultPresentationSourceKey = vtc1Room.PropertiesConfig.DefaultSourceItem; } if (room is IEssentialsTechRoom techRoom && !string.IsNullOrEmpty(techRoom.PropertiesConfig.HelpMessage)) { this.LogVerbose("Getting tech room config"); configuration.HelpMessage = techRoom.PropertiesConfig.HelpMessage; } if (room is IHasVideoCodec vcRoom) { if (vcRoom.VideoCodec != null) { this.LogVerbose("Getting codec config"); var type = vcRoom.VideoCodec.GetType(); configuration.HasVideoConferencing = true; configuration.VideoCodecKey = vcRoom.VideoCodec.Key; configuration.VideoCodecIsZoomRoom = type.Name.Equals("ZoomRoom", StringComparison.InvariantCultureIgnoreCase); } } ; if (room is IHasAudioCodec acRoom) { if (acRoom.AudioCodec != null) { this.LogVerbose("Getting audio codec config"); configuration.HasAudioConferencing = true; configuration.AudioCodecKey = acRoom.AudioCodec.Key; } } if (room is IHasMatrixRouting matrixRoutingRoom) { this.LogVerbose("Getting matrix routing config"); configuration.MatrixRoutingKey = matrixRoutingRoom.MatrixRoutingDeviceKey; configuration.EndpointKeys = matrixRoutingRoom.EndpointKeys; } if (room is IEnvironmentalControls envRoom) { this.LogVerbose("Getting environmental controls config. RoomHasEnvironmentalControls: {hasEnvironmentalControls}", envRoom.HasEnvironmentalControlDevices); configuration.HasEnvironmentalControls = envRoom.HasEnvironmentalControlDevices; if (envRoom.HasEnvironmentalControlDevices) { this.LogVerbose("Room Has {count} Environmental Control Devices.", envRoom.EnvironmentalControlDevices.Count); foreach (var dev in envRoom.EnvironmentalControlDevices) { this.LogVerbose("Adding environmental device: {key}", dev.Key); eEnvironmentalDeviceTypes type = eEnvironmentalDeviceTypes.None; if (dev is ILightingScenes) { type = eEnvironmentalDeviceTypes.Lighting; } else if (dev is ShadeBase || dev is IShadesOpenCloseStop || dev is IShadesOpenClosePreset) { type = eEnvironmentalDeviceTypes.Shade; } else if (dev is IShades) { type = eEnvironmentalDeviceTypes.ShadeController; } else if (dev is ISwitchedOutput) { type = eEnvironmentalDeviceTypes.Relay; } this.LogVerbose("Environmental Device Type: {type}", type); var envDevice = new EnvironmentalDeviceConfiguration(dev.Key, type); configuration.EnvironmentalDevices.Add(envDevice); } } else { this.LogVerbose("Room Has No Environmental Control Devices"); } } if (room is IHasDefaultDisplay defDisplayRoom) { this.LogVerbose("Getting default display config"); configuration.DefaultDisplayKey = defDisplayRoom.DefaultDisplay.Key; configuration.Destinations.Add(eSourceListItemDestinationTypes.defaultDisplay, defDisplayRoom.DefaultDisplay.Key); } if (room is IHasMultipleDisplays multiDisplayRoom) { this.LogVerbose("Getting multiple display config"); if (multiDisplayRoom.Displays == null) { this.LogVerbose("Displays collection is null"); } else { this.LogVerbose("Displays collection exists"); configuration.Destinations = multiDisplayRoom.Displays.ToDictionary(kv => kv.Key, kv => kv.Value.Key); } } if (room is IHasAccessoryDevices accRoom) { Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Getting accessory devices config", this); if (accRoom.AccessoryDeviceKeys == null) { Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Accessory devices collection is null", this); } else { Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Accessory devices collection exists", this); configuration.AccessoryDeviceKeys = accRoom.AccessoryDeviceKeys; } } var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); if (sourceList != null) { this.LogVerbose("Getting source list config"); configuration.SourceList = sourceList; configuration.HasRoutingControls = true; foreach (var source in sourceList) { if (source.Value.SourceDevice is Devices.Common.IRSetTopBoxBase) { configuration.HasSetTopBoxControls = true; continue; } else if (source.Value.SourceDevice is CameraBase) { configuration.HasCameraControls = true; continue; } } } var destinationList = ConfigReader.ConfigObject.GetDestinationListForKey(room.DestinationListKey); if (destinationList != null) { configuration.DestinationList = destinationList; } var audioControlPointList = ConfigReader.ConfigObject.GetAudioControlPointListForKey(room.AudioControlPointListKey); if (audioControlPointList != null) { configuration.AudioControlPointList = audioControlPointList; } var cameraList = ConfigReader.ConfigObject.GetCameraListForKey(room.CameraListKey); if (cameraList != null) { configuration.CameraList = cameraList; } return configuration; } catch (Exception ex) { Debug.LogMessage(ex, "Exception getting room configuration"); return new RoomConfiguration(); } } } /// /// Represents a RoomStateMessage /// public class RoomStateMessage : DeviceStateMessageBase { /// /// Gets or sets the Configuration /// [JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)] public RoomConfiguration Configuration { get; set; } /// /// Gets or sets the activity mode of the room /// [JsonProperty("activityMode", NullValueHandling = NullValueHandling.Ignore)] public int? ActivityMode { get; set; } /// /// Gets or sets whether advanced sharing is active /// [JsonProperty("advancedSharingActive", NullValueHandling = NullValueHandling.Ignore)] public bool? AdvancedSharingActive { get; set; } /// /// Gets or sets whether the room is powered on /// [JsonProperty("isOn", NullValueHandling = NullValueHandling.Ignore)] public bool? IsOn { get; set; } /// /// Gets or sets whether the room is warming up /// [JsonProperty("isWarmingUp", NullValueHandling = NullValueHandling.Ignore)] public bool? IsWarmingUp { get; set; } /// /// Gets or sets whether the room is cooling down /// [JsonProperty("isCoolingDown", NullValueHandling = NullValueHandling.Ignore)] public bool? IsCoolingDown { get; set; } /// /// Gets or sets the SelectedSourceKey /// [JsonProperty("selectedSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string SelectedSourceKey { get; set; } /// /// Gets or sets the Share /// [JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)] public ShareState Share { get; set; } /// /// Gets or sets the volume controls collection /// [JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)] public Dictionary Volumes { get; set; } /// /// Gets or sets whether the room is in a call /// [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] public bool? IsInCall { get; set; } } /// /// Represents a ShareState /// public class ShareState { /// /// Gets or sets the CurrentShareText /// [JsonProperty("currentShareText", NullValueHandling = NullValueHandling.Ignore)] public string CurrentShareText { get; set; } /// /// Gets or sets whether sharing is enabled /// [JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)] public bool? Enabled { get; set; } /// /// Gets or sets whether content is currently being shared /// [JsonProperty("isSharing", NullValueHandling = NullValueHandling.Ignore)] public bool? IsSharing { get; set; } } /// /// Represents a RoomConfiguration /// public class RoomConfiguration { /// /// Gets or sets whether the room has video conferencing capabilities /// [JsonProperty("hasVideoConferencing", NullValueHandling = NullValueHandling.Ignore)] public bool? HasVideoConferencing { get; set; } /// /// Gets or sets whether the video codec is a Zoom Room /// [JsonProperty("videoCodecIsZoomRoom", NullValueHandling = NullValueHandling.Ignore)] public bool? VideoCodecIsZoomRoom { get; set; } /// /// Gets or sets whether the room has audio conferencing capabilities /// [JsonProperty("hasAudioConferencing", NullValueHandling = NullValueHandling.Ignore)] public bool? HasAudioConferencing { get; set; } /// /// Gets or sets whether the room has environmental controls (lighting, shades, etc.) /// [JsonProperty("hasEnvironmentalControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasEnvironmentalControls { get; set; } /// /// Gets or sets whether the room has camera controls /// [JsonProperty("hasCameraControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasCameraControls { get; set; } /// /// Gets or sets whether the room has set-top box controls /// [JsonProperty("hasSetTopBoxControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasSetTopBoxControls { get; set; } /// /// Gets or sets whether the room has routing controls /// [JsonProperty("hasRoutingControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasRoutingControls { get; set; } /// /// Gets or sets the TouchpanelKeys /// [JsonProperty("touchpanelKeys", NullValueHandling = NullValueHandling.Ignore)] public List TouchpanelKeys { get; set; } /// /// Gets or sets the ZoomRoomControllerKey /// [JsonProperty("zoomRoomControllerKey", NullValueHandling = NullValueHandling.Ignore)] public string ZoomRoomControllerKey { get; set; } /// /// Gets or sets the CiscoNavigatorKey /// [JsonProperty("ciscoNavigatorKey", NullValueHandling = NullValueHandling.Ignore)] public string CiscoNavigatorKey { get; set; } /// /// Gets or sets the VideoCodecKey /// [JsonProperty("videoCodecKey", NullValueHandling = NullValueHandling.Ignore)] public string VideoCodecKey { get; set; } /// /// Gets or sets the AudioCodecKey /// [JsonProperty("audioCodecKey", NullValueHandling = NullValueHandling.Ignore)] public string AudioCodecKey { get; set; } /// /// Gets or sets the MatrixRoutingKey /// [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] public string MatrixRoutingKey { get; set; } /// /// Gets or sets the EndpointKeys /// [JsonProperty("endpointKeys", NullValueHandling = NullValueHandling.Ignore)] public List EndpointKeys { get; set; } /// /// Gets or sets the AccessoryDeviceKeys /// [JsonProperty("accessoryDeviceKeys", NullValueHandling = NullValueHandling.Ignore)] public List AccessoryDeviceKeys { get; set; } /// /// Gets or sets the DefaultDisplayKey /// [JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultDisplayKey { get; set; } /// /// Gets or sets the destinations dictionary keyed by destination type /// [JsonProperty("destinations", NullValueHandling = NullValueHandling.Ignore)] public Dictionary Destinations { get; set; } /// /// Gets or sets the EnvironmentalDevices /// [JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)] public List EnvironmentalDevices { get; set; } /// /// Gets or sets the source list for the room /// [JsonProperty("sourceList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary SourceList { get; set; } /// /// Gets or sets the destination list for the room /// [JsonProperty("destinationList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary DestinationList { get; set; } /// /// Gets or sets the AudioControlPointList /// [JsonProperty("audioControlPointList", NullValueHandling = NullValueHandling.Ignore)] public AudioControlPointListItem AudioControlPointList { get; set; } /// /// Gets or sets the camera list for the room /// [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary CameraList { get; set; } /// /// Gets or sets the DefaultPresentationSourceKey /// [JsonProperty("defaultPresentationSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultPresentationSourceKey { get; set; } /// /// Gets or sets the HelpMessage /// [JsonProperty("helpMessage", NullValueHandling = NullValueHandling.Ignore)] public string HelpMessage { get; set; } /// /// Gets or sets the TechPassword /// [JsonProperty("techPassword", NullValueHandling = NullValueHandling.Ignore)] public string TechPassword { get; set; } /// /// Gets or sets the UiBehavior /// [JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)] public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } /// /// Gets or sets whether the room supports advanced sharing features /// [JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)] public bool? SupportsAdvancedSharing { get; set; } /// /// Gets or sets whether the user can change the share mode /// [JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)] public bool? UserCanChangeShareMode { get; set; } /// /// Gets or sets the RoomCombinerKey /// [JsonProperty("roomCombinerKey", NullValueHandling = NullValueHandling.Ignore)] public string RoomCombinerKey { get; set; } /// /// Initializes a new instance of the class /// public RoomConfiguration() { Destinations = new Dictionary(); EnvironmentalDevices = new List(); SourceList = new Dictionary(); TouchpanelKeys = new List(); } } /// /// Represents a EnvironmentalDeviceConfiguration /// public class EnvironmentalDeviceConfiguration { /// /// Gets or sets the DeviceKey /// [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Ignore)] public string DeviceKey { get; private set; } /// /// Gets or sets the DeviceType /// [JsonConverter(typeof(StringEnumConverter))] [JsonProperty("deviceType", NullValueHandling = NullValueHandling.Ignore)] public eEnvironmentalDeviceTypes DeviceType { get; private set; } /// /// Initializes a new instance of the class /// /// The device key /// The environmental device type public EnvironmentalDeviceConfiguration(string key, eEnvironmentalDeviceTypes type) { DeviceKey = key; DeviceType = type; } } /// /// Enumeration of environmental device types /// public enum eEnvironmentalDeviceTypes { /// /// No environmental device type specified /// None, /// /// Lighting device type /// Lighting, /// /// Shade device type /// Shade, /// /// Shade controller device type /// ShadeController, /// /// Relay device type /// Relay, } /// /// Represents a ApiTouchPanelToken /// public class ApiTouchPanelToken { /// /// Gets or sets the TouchPanels /// [JsonProperty("touchPanels", NullValueHandling = NullValueHandling.Ignore)] public List TouchPanels { get; set; } = new List(); /// /// Gets or sets the UserAppUrl /// [JsonProperty("userAppUrl", NullValueHandling = NullValueHandling.Ignore)] public string UserAppUrl { get; set; } = ""; } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlSIMPLRoomBridge.cs ================================================ using Crestron.SimplSharp; using Crestron.SimplSharp.Reflection; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.EthernetCommunication; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Room.Config; using System; using System.Collections.Generic; namespace PepperDash.Essentials.Room.MobileControl { // ReSharper disable once InconsistentNaming /// /// Represents a MobileControlSIMPLRoomBridge /// public class MobileControlSIMPLRoomBridge : MobileControlBridgeBase, IDelayedConfiguration { private const int SupportedDisplayCount = 10; /// /// Fires when config is ready to go /// public event EventHandler ConfigurationIsReady; /// /// Gets or sets the Eisc /// public ThreeSeriesTcpIpEthernetIntersystemCommunications Eisc { get; private set; } /// /// Gets or sets the JoinMap /// public MobileControlSIMPLRoomJoinMap JoinMap { get; private set; } public Dictionary DeviceMessengers { get; private set; } /// /// Gets or sets the ConfigIsLoaded /// public bool ConfigIsLoaded { get; private set; } /// public override string RoomName { get { var name = Eisc.StringOutput[JoinMap.ConfigRoomName.JoinNumber].StringValue; return string.IsNullOrEmpty(name) ? "Not Loaded" : name; } } /// public override string RoomKey { get { return "room1"; } } private readonly MobileControlSimplDeviceBridge _sourceBridge; private SIMPLAtcMessenger _atcMessenger; private SIMPLVtcMessenger _vtcMessenger; private SimplDirectRouteMessenger _directRouteMessenger; private const string _syntheticDeviceKey = "syntheticDevice"; /// /// /// /// /// /// public MobileControlSIMPLRoomBridge(string key, string name, uint ipId) : base(key, "") { Eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(ipId, "127.0.0.2", Global.ControlSystem); var reg = Eisc.Register(); if (reg != eDeviceRegistrationUnRegistrationResponse.Success) Debug.Console(0, this, "Cannot connect EISC at IPID {0}: \r{1}", ipId, reg); JoinMap = new MobileControlSIMPLRoomJoinMap(1); _sourceBridge = new MobileControlSimplDeviceBridge(key + "-sourceBridge", "SIMPL source bridge", Eisc); DeviceManager.AddDevice(_sourceBridge); CrestronConsole.AddNewConsoleCommand((s) => JoinMap.PrintJoinMapInfo(), "printmobilejoinmap", "Prints the MobileControlSIMPLRoomBridge JoinMap", ConsoleAccessLevelEnum.AccessOperator); AddPostActivationAction(() => { // Inform the SIMPL program that config can be sent Eisc.BooleanInput[JoinMap.ReadyForConfig.JoinNumber].BoolValue = true; Eisc.SigChange += EISC_SigChange; Eisc.OnlineStatusChange += (o, a) => { if (!a.DeviceOnLine) { return; } Debug.Console(1, this, "SIMPL EISC online={0}. Config is ready={1}. Use Essentials Config={2}", a.DeviceOnLine, Eisc.BooleanOutput[JoinMap.ConfigIsReady.JoinNumber].BoolValue, Eisc.BooleanOutput[JoinMap.ConfigIsLocal.JoinNumber].BoolValue); if (Eisc.BooleanOutput[JoinMap.ConfigIsReady.JoinNumber].BoolValue) LoadConfigValues(); if (Eisc.BooleanOutput[JoinMap.ConfigIsLocal.JoinNumber].BoolValue) UseEssentialsConfig(); }; // load config if it's already there if (Eisc.BooleanOutput[JoinMap.ConfigIsReady.JoinNumber].BoolValue) { LoadConfigValues(); } if (Eisc.BooleanOutput[JoinMap.ConfigIsLocal.JoinNumber].BoolValue) { UseEssentialsConfig(); } }); } /// /// Finish wiring up everything after all devices are created. The base class will hunt down the related /// parent controller and link them up. /// /// /// /// CustomActivate method /// public override bool CustomActivate() { Debug.Console(0, this, "Final activation. Setting up actions and feedbacks"); //SetupFunctions(); //SetupFeedbacks(); var atcKey = string.Format("atc-{0}-{1}", Key, Key); _atcMessenger = new SIMPLAtcMessenger(atcKey, Eisc, "/device/audioCodec"); _atcMessenger.RegisterWithAppServer(Parent); var vtcKey = string.Format("atc-{0}-{1}", Key, Key); _vtcMessenger = new SIMPLVtcMessenger(vtcKey, Eisc, "/device/videoCodec"); _vtcMessenger.RegisterWithAppServer(Parent); var drKey = string.Format("directRoute-{0}-{1}", Key, Key); _directRouteMessenger = new SimplDirectRouteMessenger(drKey, Eisc, "/routing"); _directRouteMessenger.RegisterWithAppServer(Parent); CrestronConsole.AddNewConsoleCommand(s => { JoinMap.PrintJoinMapInfo(); _atcMessenger.JoinMap.PrintJoinMapInfo(); _vtcMessenger.JoinMap.PrintJoinMapInfo(); _directRouteMessenger.JoinMap.PrintJoinMapInfo(); // TODO: Update Source Bridge to use new JoinMap scheme //_sourceBridge.JoinMap.PrintJoinMapInfo(); }, "printmobilebridge", "Prints MC-SIMPL bridge EISC data", ConsoleAccessLevelEnum.AccessOperator); return base.CustomActivate(); } private void UseEssentialsConfig() { ConfigIsLoaded = false; SetupDeviceMessengers(); Debug.Console(0, this, "******* ESSENTIALS CONFIG: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented)); ConfigurationIsReady?.Invoke(this, new EventArgs()); ConfigIsLoaded = true; } protected override void RegisterActions() { SetupFunctions(); SetupFeedbacks(); } /// /// Setup the actions to take place on various incoming API calls /// private void SetupFunctions() { AddAction(@"/promptForCode", (id, content) => Eisc.PulseBool(JoinMap.PromptForCode.JoinNumber)); AddAction(@"/clientJoined", (id, content) => Eisc.PulseBool(JoinMap.ClientJoined.JoinNumber)); AddAction(@"/status", (id, content) => SendFullStatus()); AddAction(@"/source", (id, content) => { var msg = content.ToObject(); Eisc.SetString(JoinMap.CurrentSourceKey.JoinNumber, msg.SourceListItemKey); Eisc.PulseBool(JoinMap.SourceHasChanged.JoinNumber); }); AddAction(@"/defaultsource", (id, content) => Eisc.PulseBool(JoinMap.ActivityShare.JoinNumber)); AddAction(@"/activityPhone", (id, content) => Eisc.PulseBool(JoinMap.ActivityPhoneCall.JoinNumber)); AddAction(@"/activityVideo", (id, content) => Eisc.PulseBool(JoinMap.ActivityVideoCall.JoinNumber)); AddAction(@"/volumes/master/level", (id, content) => { var value = content["value"].Value(); Eisc.SetUshort(JoinMap.MasterVolume.JoinNumber, value); }); AddAction(@"/volumes/master/muteToggle", (id, content) => Eisc.PulseBool(JoinMap.MasterVolume.JoinNumber)); AddAction(@"/volumes/master/privacyMuteToggle", (id, content) => Eisc.PulseBool(JoinMap.PrivacyMute.JoinNumber)); // /xyzxyz/volumes/master/muteToggle ---> BoolInput[1] var volumeStart = JoinMap.VolumeJoinStart.JoinNumber; var volumeEnd = JoinMap.VolumeJoinStart.JoinNumber + JoinMap.VolumeJoinStart.JoinSpan; for (uint i = volumeStart; i <= volumeEnd; i++) { var index = i; AddAction(string.Format(@"/volumes/level-{0}/level", index), (id, content) => { var value = content["value"].Value(); Eisc.SetUshort(index, value); }); AddAction(string.Format(@"/volumes/level-{0}/muteToggle", index), (id, content) => Eisc.PulseBool(index)); } AddAction(@"/shutdownStart", (id, content) => Eisc.PulseBool(JoinMap.ShutdownStart.JoinNumber)); AddAction(@"/shutdownEnd", (id, content) => Eisc.PulseBool(JoinMap.ShutdownEnd.JoinNumber)); AddAction(@"/shutdownCancel", (id, content) => Eisc.PulseBool(JoinMap.ShutdownCancel.JoinNumber)); } /// /// /// /// private void SetupSourceFunctions(string devKey) { var sourceJoinMap = new SourceDeviceMapDictionary(); var prefix = string.Format("/device/{0}/", devKey); foreach (var item in sourceJoinMap) { var join = item.Value; AddAction(string.Format("{0}{1}", prefix, item.Key), (id, content) => { HandlePressAndHoldEisc(content, b => Eisc.SetBool(join, b)); }); } } private void HandlePressAndHoldEisc(JToken content, Action action) { var state = content.ToObject>(); var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); if (timerHandler == null) { return; } timerHandler(state.Value, action); action(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); } /// /// Links feedbacks to whatever is gonna happen! /// private void SetupFeedbacks() { // Power Eisc.SetBoolSigAction(JoinMap.RoomIsOn.JoinNumber, b => PostStatus(new { isOn = b })); // Source change things Eisc.SetSigTrueAction(JoinMap.SourceHasChanged.JoinNumber, () => PostStatus(new { selectedSourceKey = Eisc.StringOutput[JoinMap.CurrentSourceKey.JoinNumber].StringValue })); // Volume things Eisc.SetUShortSigAction(JoinMap.MasterVolume.JoinNumber, u => PostStatus(new { volumes = new { master = new { level = u } } })); // map MasterVolumeIsMuted join -> status/volumes/master/muted // Eisc.SetBoolSigAction(JoinMap.MasterVolume.JoinNumber, b => PostStatus(new { volumes = new { master = new { muted = b } } })); Eisc.SetBoolSigAction(JoinMap.PrivacyMute.JoinNumber, b => PostStatus(new { volumes = new { master = new { privacyMuted = b } } })); var volumeStart = JoinMap.VolumeJoinStart.JoinNumber; var volumeEnd = JoinMap.VolumeJoinStart.JoinNumber + JoinMap.VolumeJoinStart.JoinSpan; for (uint i = volumeStart; i <= volumeEnd; i++) { var index = i; // local scope for lambdas Eisc.SetUShortSigAction(index, u => // start at join 2 { // need a dict in order to create the level-n property on auxFaders var dict = new Dictionary { { "level-" + index, new { level = u } } }; PostStatus(new { volumes = new { auxFaders = dict, } }); }); Eisc.SetBoolSigAction(index, b => { // need a dict in order to create the level-n property on auxFaders var dict = new Dictionary { { "level-" + index, new { muted = b } } }; PostStatus(new { volumes = new { auxFaders = dict, } }); }); } Eisc.SetUShortSigAction(JoinMap.NumberOfAuxFaders.JoinNumber, u => PostStatus(new { volumes = new { numberOfAuxFaders = u, } })); // shutdown things Eisc.SetSigTrueAction(JoinMap.ShutdownCancel.JoinNumber, () => PostMessage("/shutdown/", new { state = "wasCancelled" })); Eisc.SetSigTrueAction(JoinMap.ShutdownEnd.JoinNumber, () => PostMessage("/shutdown/", new { state = "hasFinished" })); Eisc.SetSigTrueAction(JoinMap.ShutdownStart.JoinNumber, () => PostMessage("/shutdown/", new { state = "hasStarted", duration = Eisc.UShortOutput[JoinMap.ShutdownPromptDuration.JoinNumber].UShortValue })); // Config things Eisc.SetSigTrueAction(JoinMap.ConfigIsReady.JoinNumber, LoadConfigValues); // Activity modes Eisc.SetSigTrueAction(JoinMap.ActivityShare.JoinNumber, () => UpdateActivity(1)); Eisc.SetSigTrueAction(JoinMap.ActivityPhoneCall.JoinNumber, () => UpdateActivity(2)); Eisc.SetSigTrueAction(JoinMap.ActivityVideoCall.JoinNumber, () => UpdateActivity(3)); AppServerController.ApiOnlineAndAuthorized.LinkInputSig(Eisc.BooleanInput[JoinMap.ApiOnlineAndAuthorized.JoinNumber]); } /// /// Updates activity states /// private void UpdateActivity(int mode) { PostStatus(new { activityMode = mode, }); } /// /// Synthesizes a source device config from the SIMPL config join data /// /// /// /// /// private DeviceConfig GetSyntheticSourceDevice(SourceListItem sli, string type, uint i) { var groupMap = GetSourceGroupDictionary(); var key = sli.SourceKey; var name = sli.Name; // If not, synthesize the device config var group = "genericsource"; if (groupMap.ContainsKey(type)) { group = groupMap[type]; } // add dev to devices list var devConf = new DeviceConfig { Group = group, Key = key, Name = name, Type = type, Properties = new JObject(new JProperty(_syntheticDeviceKey, true)), }; if (group.ToLower().StartsWith("settopbox")) // Add others here as needed { SetupSourceFunctions(key); } if (group.ToLower().Equals("simplmessenger")) { if (type.ToLower().Equals("simplcameramessenger")) { var props = new SimplMessengerPropertiesConfig { DeviceKey = key, JoinMapKey = "" }; var joinStart = 1000 + (i * 100) + 1; // 1001, 1101, 1201, 1301... etc. props.JoinStart = joinStart; devConf.Properties = JToken.FromObject(props); } } return devConf; } /// /// Reads in config values when the Simpl program is ready /// private void LoadConfigValues() { Debug.Console(1, this, "Loading configuration from SIMPL EISC bridge"); ConfigIsLoaded = false; var co = ConfigReader.ConfigObject; if (!string.IsNullOrEmpty(Eisc.StringOutput[JoinMap.PortalSystemUrl.JoinNumber].StringValue)) { ConfigReader.ConfigObject.SystemUrl = Eisc.StringOutput[JoinMap.PortalSystemUrl.JoinNumber].StringValue; } co.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name; var version = Assembly.GetExecutingAssembly().GetName().Version; co.Info.RuntimeInfo.AssemblyVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); //Room //if (co.Rooms == null) // always start fresh in case simpl changed co.Rooms = new List(); var rm = new DeviceConfig(); if (co.Rooms.Count == 0) { Debug.Console(0, this, "Adding room to config"); co.Rooms.Add(rm); } else { Debug.Console(0, this, "Replacing Room[0] in config"); co.Rooms[0] = rm; } rm.Name = Eisc.StringOutput[JoinMap.ConfigRoomName.JoinNumber].StringValue; rm.Key = "room1"; rm.Type = "SIMPL01"; var rmProps = rm.Properties == null ? new SimplRoomPropertiesConfig() : JsonConvert.DeserializeObject(rm.Properties.ToString()); rmProps.Help = new EssentialsHelpPropertiesConfig { CallButtonText = Eisc.StringOutput[JoinMap.ConfigHelpNumber.JoinNumber].StringValue, Message = Eisc.StringOutput[JoinMap.ConfigHelpMessage.JoinNumber].StringValue }; rmProps.Environment = new EssentialsEnvironmentPropertiesConfig(); // enabled defaults to false rmProps.RoomPhoneNumber = Eisc.StringOutput[JoinMap.ConfigRoomPhoneNumber.JoinNumber].StringValue; rmProps.RoomURI = Eisc.StringOutput[JoinMap.ConfigRoomUri.JoinNumber].StringValue; rmProps.SpeedDials = new List(); // This MAY need a check if (Eisc.BooleanOutput[JoinMap.ActivityPhoneCallEnable.JoinNumber].BoolValue) { rmProps.AudioCodecKey = "audioCodec"; } if (Eisc.BooleanOutput[JoinMap.ActivityVideoCallEnable.JoinNumber].BoolValue) { rmProps.VideoCodecKey = "videoCodec"; } // volume control names //// use Volumes object or? //rmProps.VolumeSliderNames = new List(); //for(uint i = 701; i <= 700 + volCount; i++) //{ // rmProps.VolumeSliderNames.Add(EISC.StringInput[i].StringValue); //} // There should be Mobile Control devices in here, I think... if (co.Devices == null) co.Devices = new List(); // clear out previous SIMPL devices co.Devices.RemoveAll(d => d.Key.StartsWith("source-", StringComparison.OrdinalIgnoreCase) || d.Key.Equals("audioCodec", StringComparison.OrdinalIgnoreCase) || d.Key.Equals("videoCodec", StringComparison.OrdinalIgnoreCase) || d.Key.StartsWith("destination-", StringComparison.OrdinalIgnoreCase)); rmProps.SourceListKey = "default"; rm.Properties = JToken.FromObject(rmProps); // Source list! This might be brutal!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! co.SourceLists = new Dictionary>(); var newSl = new Dictionary(); // add "none" source if VTC present if (!string.IsNullOrEmpty(rmProps.VideoCodecKey)) { var codecOsd = new SourceListItem { Name = "None", IncludeInSourceList = true, Order = 1, Type = eSourceListItemType.Route, SourceKey = "" }; newSl.Add("Source-None", codecOsd); } // add sources... var useSourceEnabled = Eisc.BooleanOutput[JoinMap.UseSourceEnabled.JoinNumber].BoolValue; for (uint i = 0; i <= 19; i++) { var name = Eisc.StringOutput[JoinMap.SourceNameJoinStart.JoinNumber + i].StringValue; if (!Eisc.BooleanOutput[JoinMap.UseSourceEnabled.JoinNumber].BoolValue && string.IsNullOrEmpty(name)) { this.LogDebug("Source at join {join} does not have a name", JoinMap.SourceNameJoinStart.JoinNumber + i); break; } var icon = Eisc.StringOutput[JoinMap.SourceIconJoinStart.JoinNumber + i].StringValue; var key = Eisc.StringOutput[JoinMap.SourceKeyJoinStart.JoinNumber + i].StringValue; var type = Eisc.StringOutput[JoinMap.SourceTypeJoinStart.JoinNumber + i].StringValue; var disableShare = Eisc.BooleanOutput[JoinMap.SourceShareDisableJoinStart.JoinNumber + i].BoolValue; var sourceEnabled = Eisc.BooleanOutput[JoinMap.SourceIsEnabledJoinStart.JoinNumber + i].BoolValue; var controllable = Eisc.BooleanOutput[JoinMap.SourceIsControllableJoinStart.JoinNumber + i].BoolValue; var audioSource = Eisc.BooleanOutput[JoinMap.SourceIsAudioSourceJoinStart.JoinNumber + i].BoolValue; Debug.Console(0, this, "Adding source {0} '{1}'", key, name); var sourceKey = Eisc.StringOutput[JoinMap.SourceControlDeviceKeyJoinStart.JoinNumber + i].StringValue; var newSli = new SourceListItem { Icon = icon, Name = name, Order = (int)i + 10, SourceKey = string.IsNullOrEmpty(sourceKey) ? key : sourceKey, // Use the value from the join if defined Type = eSourceListItemType.Route, DisableCodecSharing = disableShare, IncludeInSourceList = !useSourceEnabled || sourceEnabled, IsControllable = controllable, IsAudioSource = audioSource }; newSl.Add(key, newSli); var existingSourceDevice = co.GetDeviceForKey(newSli.SourceKey); var syntheticDevice = GetSyntheticSourceDevice(newSli, type, i); // Look to see if this is a device that already exists in Essentials and get it if (existingSourceDevice != null) { Debug.Console(0, this, "Found device with key: {0} in Essentials.", key); if (existingSourceDevice.Properties.Value(_syntheticDeviceKey)) { Debug.Console(0, this, "Updating previous device config with new values"); existingSourceDevice = syntheticDevice; } else { Debug.Console(0, this, "Using existing Essentials device (non synthetic)"); } } else { co.Devices.Add(syntheticDevice); } } co.SourceLists.Add("default", newSl); if (Eisc.BooleanOutput[JoinMap.SupportsAdvancedSharing.JoinNumber].BoolValue) { if (co.DestinationLists == null) { co.DestinationLists = new Dictionary>(); } CreateDestinationList(co); } // Build "audioCodec" config if we need if (!string.IsNullOrEmpty(rmProps.AudioCodecKey)) { var acFavs = new List(); for (uint i = 0; i < 4; i++) { if (!Eisc.GetBool(JoinMap.SpeedDialVisibleStartJoin.JoinNumber + i)) { break; } acFavs.Add(new CodecActiveCallItem { Name = Eisc.GetString(JoinMap.SpeedDialNameStartJoin.JoinNumber + i), Number = Eisc.GetString(JoinMap.SpeedDialNumberStartJoin.JoinNumber + i), Type = eCodecCallType.Audio }); } var acProps = new { favorites = acFavs }; const string acStr = "audioCodec"; var acConf = new DeviceConfig { Group = acStr, Key = acStr, Name = acStr, Type = acStr, Properties = JToken.FromObject(acProps) }; co.Devices.Add(acConf); } // Build Video codec config if (!string.IsNullOrEmpty(rmProps.VideoCodecKey)) { // No favorites, for now? var favs = new List(); // cameras var camsProps = new List(); for (uint i = 0; i < 9; i++) { var name = Eisc.GetString(i + JoinMap.CameraNearNameStart.JoinNumber); if (!string.IsNullOrEmpty(name)) { camsProps.Add(new { name, selector = "camera" + (i + 1), }); } } var farName = Eisc.GetString(JoinMap.CameraFarName.JoinNumber); if (!string.IsNullOrEmpty(farName)) { camsProps.Add(new { name = farName, selector = "cameraFar", }); } var props = new { favorites = favs, cameras = camsProps, }; const string str = "videoCodec"; var conf = new DeviceConfig { Group = str, Key = str, Name = str, Type = str, Properties = JToken.FromObject(props) }; co.Devices.Add(conf); } SetupDeviceMessengers(); Debug.Console(0, this, "******* CONFIG FROM SIMPL: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented)); ConfigurationIsReady?.Invoke(this, new EventArgs()); ConfigIsLoaded = true; } private DeviceConfig GetSyntheticDestinationDevice(string key, string name) { // If not, synthesize the device config var devConf = new DeviceConfig { Group = "genericdestination", Key = key, Name = name, Type = "genericdestination", Properties = new JObject(new JProperty(_syntheticDeviceKey, true)), }; return devConf; } private void CreateDestinationList(BasicConfig co) { var useDestEnable = Eisc.BooleanOutput[JoinMap.UseDestinationEnable.JoinNumber].BoolValue; var newDl = new Dictionary(); for (uint i = 0; i < SupportedDisplayCount; i++) { var name = Eisc.StringOutput[JoinMap.DestinationNameJoinStart.JoinNumber + i].StringValue; var routeType = Eisc.StringOutput[JoinMap.DestinationTypeJoinStart.JoinNumber + i].StringValue; var key = Eisc.StringOutput[JoinMap.DestinationDeviceKeyJoinStart.JoinNumber + i].StringValue; //var order = Eisc.UShortOutput[JoinMap.DestinationOrderJoinStart.JoinNumber + i].UShortValue; var enabled = Eisc.BooleanOutput[JoinMap.DestinationIsEnabledJoinStart.JoinNumber + i].BoolValue; if (useDestEnable && !enabled) { continue; } if (string.IsNullOrEmpty(key)) { continue; } Debug.Console(0, this, "Adding destination {0} - {1}", key, name); eRoutingSignalType parsedType; try { parsedType = (eRoutingSignalType)Enum.Parse(typeof(eRoutingSignalType), routeType, true); } catch { Debug.Console(0, this, "Error parsing destination type: {0}", routeType); parsedType = eRoutingSignalType.AudioVideo; } var newDli = new DestinationListItem { Name = name, Order = (int)i, SinkKey = key, SinkType = parsedType, }; if (!newDl.ContainsKey(key)) { newDl.Add(key, newDli); } else { newDl[key] = newDli; } if (!_directRouteMessenger.DestinationList.ContainsKey(newDli.SinkKey)) { //add same DestinationListItem to dictionary for messenger in order to allow for correlation by index _directRouteMessenger.DestinationList.Add(key, newDli); } else { _directRouteMessenger.DestinationList[key] = newDli; } var existingDev = co.GetDeviceForKey(key); var syntheticDisplay = GetSyntheticDestinationDevice(key, name); if (existingDev != null) { Debug.Console(0, this, "Found device with key: {0} in Essentials.", key); if (existingDev.Properties.Value(_syntheticDeviceKey)) { Debug.Console(0, this, "Updating previous device config with new values"); } else { Debug.Console(0, this, "Using existing Essentials device (non synthetic)"); } } else { co.Devices.Add(syntheticDisplay); } } if (!co.DestinationLists.ContainsKey("default")) { co.DestinationLists.Add("default", newDl); } else { co.DestinationLists["default"] = newDl; } _directRouteMessenger.RegisterForDestinationPaths(); } /// /// Iterates device config and adds messengers as neede for each device type /// private void SetupDeviceMessengers() { DeviceMessengers = new Dictionary(); try { foreach (var device in ConfigReader.ConfigObject.Devices) { if (device.Group.Equals("simplmessenger")) { var props = JsonConvert.DeserializeObject(device.Properties.ToString()); var messengerKey = string.Format("device-{0}-{1}", Key, Key); if (DeviceManager.GetDeviceForKey(messengerKey) != null) { Debug.Console(2, this, "Messenger with key: {0} already exists. Skipping...", messengerKey); continue; } var dev = ConfigReader.ConfigObject.GetDeviceForKey(props.DeviceKey); if (dev == null) { Debug.Console(1, this, "Unable to find device config for key: '{0}'", props.DeviceKey); continue; } var type = device.Type.ToLower(); MessengerBase messenger = null; if (type.Equals("simplcameramessenger")) { Debug.Console(2, this, "Adding SIMPLCameraMessenger for: '{0}'", props.DeviceKey); messenger = new SIMPLCameraMessenger(messengerKey, Eisc, "/device/" + props.DeviceKey, props.JoinStart); } else if (type.Equals("simplroutemessenger")) { Debug.Console(2, this, "Adding SIMPLRouteMessenger for: '{0}'", props.DeviceKey); messenger = new SIMPLRouteMessenger(messengerKey, Eisc, "/device/" + props.DeviceKey, props.JoinStart); } if (messenger != null) { DeviceManager.AddDevice(messenger); DeviceMessengers.Add(device.Key, messenger); messenger.RegisterWithAppServer(Parent); } else { Debug.Console(2, this, "Unable to add messenger for device: '{0}' of type: '{1}'", props.DeviceKey, type); } } else { var dev = DeviceManager.GetDeviceForKey(device.Key); if (dev != null) { if (dev is CameraBase) { var camDevice = dev as CameraBase; Debug.Console(1, this, "Adding CameraBaseMessenger for device: {0}", dev.Key); var cameraMessenger = new CameraBaseMessenger(device.Key + "-" + Key, camDevice, "/device/" + device.Key); DeviceMessengers.Add(device.Key, cameraMessenger); DeviceManager.AddDevice(cameraMessenger); cameraMessenger.RegisterWithAppServer(Parent); continue; } } } } } catch (Exception e) { Debug.Console(2, this, "Error Setting up Device Managers: {0}", e); } } /// /// /// private void SendFullStatus() { if (ConfigIsLoaded) { var count = Eisc.UShortOutput[JoinMap.NumberOfAuxFaders.JoinNumber].UShortValue; Debug.Console(1, this, "The Fader Count is : {0}", count); // build volumes object, serialize and put in content of method below // Create auxFaders var auxFaderDict = new Dictionary(); var volumeStart = JoinMap.VolumeJoinStart.JoinNumber; for (var i = volumeStart; i <= count; i++) { auxFaderDict.Add("level-" + i, new Volume("level-" + i, Eisc.UShortOutput[i].UShortValue, Eisc.BooleanOutput[i].BoolValue, Eisc.StringOutput[i].StringValue, true, "someting.png")); } var volumes = new Volumes { Master = new Volume("master", Eisc.UShortOutput[JoinMap.MasterVolume.JoinNumber].UShortValue, Eisc.BooleanOutput[JoinMap.MasterVolume.JoinNumber].BoolValue, Eisc.StringOutput[JoinMap.MasterVolume.JoinNumber].StringValue, true, "something.png") { HasPrivacyMute = true, PrivacyMuted = Eisc.BooleanOutput[JoinMap.PrivacyMute.JoinNumber].BoolValue }, AuxFaders = auxFaderDict, NumberOfAuxFaders = Eisc.UShortInput[JoinMap.NumberOfAuxFaders.JoinNumber].UShortValue }; // TODO: Add property to status message to indicate if advanced sharing is supported and if users can change share mode PostStatus(new { activityMode = GetActivityMode(), isOn = Eisc.BooleanOutput[JoinMap.RoomIsOn.JoinNumber].BoolValue, selectedSourceKey = Eisc.StringOutput[JoinMap.CurrentSourceKey.JoinNumber].StringValue, volumes, supportsAdvancedSharing = Eisc.BooleanOutput[JoinMap.SupportsAdvancedSharing.JoinNumber].BoolValue, userCanChangeShareMode = Eisc.BooleanOutput[JoinMap.UserCanChangeShareMode.JoinNumber].BoolValue, }); } else { PostStatus(new { error = "systemNotReady" }); } } /// /// Returns the activity mode int /// /// private int GetActivityMode() { if (Eisc.BooleanOutput[JoinMap.ActivityPhoneCall.JoinNumber].BoolValue) return 2; if (Eisc.BooleanOutput[JoinMap.ActivityShare.JoinNumber].BoolValue) return 1; return Eisc.BooleanOutput[JoinMap.ActivityVideoCall.JoinNumber].BoolValue ? 3 : 0; } /// /// Helper for posting status message /// /// The contents of the content object private void PostStatus(object contentObject) { AppServerController.SendMessageObject(new MobileControlMessage { Type = "/status/", Content = JToken.FromObject(contentObject) }); } /// /// /// /// /// private void PostMessage(string messageType, object contentObject) { AppServerController.SendMessageObject(new MobileControlMessage { Type = messageType, Content = JToken.FromObject(contentObject) }); } /// /// /// /// /// private void EISC_SigChange(object currentDevice, SigEventArgs args) { if (Debug.Level >= 1) Debug.Console(1, this, "SIMPL EISC change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); var uo = args.Sig.UserObject; if (uo != null) { if (uo is Action) (uo as Action)(args.Sig.BoolValue); else if (uo is Action) (uo as Action)(args.Sig.UShortValue); else if (uo is Action) (uo as Action)(args.Sig.StringValue); } } /// /// Returns the mapping of types to groups, for setting up devices. /// /// private Dictionary GetSourceGroupDictionary() { //type, group var d = new Dictionary(StringComparer.OrdinalIgnoreCase) { {"laptop", "pc"}, {"pc", "pc"}, {"wireless", "genericsource"}, {"iptv", "settopbox"}, {"simplcameramessenger", "simplmessenger"}, {"camera", "camera"}, }; return d; } /// /// updates the usercode from server /// protected override void UserCodeChange() { Debug.Console(1, this, "Server user code changed: {0}", UserCode); var qrUrl = string.Format("{0}/api/rooms/{1}/{3}/qr?x={2}", AppServerController.Host, AppServerController.SystemUuid, new Random().Next(), "room1"); QrCodeUrl = qrUrl; Debug.Console(1, this, "Server user code changed: {0} - {1}", UserCode, qrUrl); OnUserCodeChanged(); Eisc.StringInput[JoinMap.UserCodeToSystem.JoinNumber].StringValue = UserCode; Eisc.StringInput[JoinMap.ServerUrl.JoinNumber].StringValue = McServerUrl; Eisc.StringInput[JoinMap.QrCodeUrl.JoinNumber].StringValue = QrCodeUrl; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/RoomBridges/SourceDeviceMapDictionary.cs ================================================ using System.Collections.Generic; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a SourceDeviceMapDictionary /// public class SourceDeviceMapDictionary : Dictionary { public SourceDeviceMapDictionary() { var dictionary = new Dictionary { {"preset01", 101}, {"preset02", 102}, {"preset03", 103}, {"preset04", 104}, {"preset05", 105}, {"preset06", 106}, {"preset07", 107}, {"preset08", 108}, {"preset09", 109}, {"preset10", 110}, {"preset11", 111}, {"preset12", 112}, {"preset13", 113}, {"preset14", 114}, {"preset15", 115}, {"preset16", 116}, {"preset17", 117}, {"preset18", 118}, {"preset19", 119}, {"preset20", 120}, {"preset21", 121}, {"preset22", 122}, {"preset23", 123}, {"preset24", 124}, {"num0", 130}, {"num1", 131}, {"num2", 132}, {"num3", 133}, {"num4", 134}, {"num5", 135}, {"num6", 136}, {"num7", 137}, {"num8", 138}, {"num9", 139}, {"numDash", 140}, {"numEnter", 141}, {"chanUp", 142}, {"chanDown", 143}, {"lastChan", 144}, {"exit", 145}, {"powerToggle", 146}, {"red", 147}, {"green", 148}, {"yellow", 149}, {"blue", 150}, {"video", 151}, {"previous", 152}, {"next", 153}, {"rewind", 154}, {"ffwd", 155}, {"closedCaption", 156}, {"stop", 157}, {"pause", 158}, {"up", 159}, {"down", 160}, {"left", 161}, {"right", 162}, {"settings", 163}, {"info", 164}, {"return", 165}, {"guide", 166}, {"reboot", 167}, {"dvrList", 168}, {"replay", 169}, {"play", 170}, {"select", 171}, {"record", 172}, {"menu", 173}, {"topMenu", 174}, {"prevTrack", 175}, {"nextTrack", 176}, {"powerOn", 177}, {"powerOff", 178}, {"dot", 179} }; foreach (var item in dictionary) { Add(item.Key, item.Value); } } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Services/MobileControlApiService.cs ================================================ using System; using System.Net.Http; using System.Threading.Tasks; using PepperDash.Core; namespace PepperDash.Essentials.Services { /// /// Service for interacting with a Mobile Control Edge server instance /// public class MobileControlApiService { private readonly HttpClient _client; /// /// Create an instance of the class. /// /// Mobile Control Edge API URL public MobileControlApiService(string apiUrl) { var handler = new HttpClientHandler { AllowAutoRedirect = false, ServerCertificateCustomValidationCallback = (req, cert, certChain, errors) => true }; _client = new HttpClient(handler); } /// /// Send authorization request to Mobile Control Edge Server /// /// Mobile Control Edge API URL /// Grant code for authorization /// System UUID for authorization /// Authorization response public async Task SendAuthorizationRequest(string apiUrl, string grantCode, string systemUuid) { try { var request = new HttpRequestMessage(HttpMethod.Get, $"{apiUrl}/system/{systemUuid}/authorize?grantCode={grantCode}"); Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Sending authorization request to {host}", null, request.RequestUri); var response = await _client.SendAsync(request); var authResponse = new AuthorizationResponse { Authorized = response.StatusCode == System.Net.HttpStatusCode.OK }; if (authResponse.Authorized) { return authResponse; } if (response.StatusCode == System.Net.HttpStatusCode.Moved) { var location = response.Headers.Location; authResponse.Reason = $"ERROR: Mobile Control API has moved. Please adjust configuration to \"{location}\""; return authResponse; } var responseString = await response.Content.ReadAsStringAsync(); switch (responseString) { case "codeNotFound": authResponse.Reason = $"Authorization failed. Code not found for system UUID {systemUuid}"; break; case "uuidNotFound": authResponse.Reason = $"Authorization failed. System UUID {systemUuid} not found. Check Essentials configuration."; break; default: authResponse.Reason = $"Authorization failed. Response {response.StatusCode}: {responseString}"; break; } return authResponse; } catch (Exception ex) { Debug.LogMessage(ex, "Error authorizing with Mobile Control"); return new AuthorizationResponse { Authorized = false, Reason = ex.Message }; } } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Touchpanel/ITheme.cs ================================================ using PepperDash.Core; namespace PepperDash.Essentials.Touchpanel { /// /// Defines the contract for ITheme /// public interface ITheme : IKeyed { /// /// Current theme /// string Theme { get; } /// /// Set the theme with the given value /// /// The theme to set void UpdateTheme(string theme); } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControl.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Touchpanel { /// /// Defines the contract for ITswAppControl /// public interface ITswAppControl : IKeyed { /// /// Updates when the Zoom Room Control Application opens or closes /// BoolFeedback AppOpenFeedback { get; } /// /// Hide the Zoom App and show the User Control Application /// void HideOpenApp(); /// /// Close the Zoom App and show the User Control Application /// void CloseOpenApp(); /// /// Open the Zoom App /// void OpenApp(); } /// /// Defines the contract for ITswZoomControl /// public interface ITswZoomControl : IKeyed { /// /// Updates when Zoom has an incoming call /// BoolFeedback ZoomIncomingCallFeedback { get; } /// /// Updates when Zoom is in a call /// BoolFeedback ZoomInCallFeedback { get; } /// /// End a Zoom Call /// void EndZoomCall(); } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Touchpanel/ITswAppControlMessenger.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer.Messengers; namespace PepperDash.Essentials.Touchpanel { /// /// Messenger for controlling the Zoom App on a TSW Panel that supports the Zoom Room Control Application /// public class ITswAppControlMessenger : MessengerBase { private readonly ITswAppControl _appControl; /// /// Create an instance of the class. /// /// The key for this messenger /// The message path for this messenger /// The device for this messenger public ITswAppControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) { _appControl = device as ITswAppControl; } /// protected override void RegisterActions() { if (_appControl == null) { this.LogInformation("{deviceKey} does not implement ITswAppControl", _device.Key); return; } AddAction($"/fullStatus", (id, context) => SendFullStatus(id)); AddAction($"/openApp", (id, context) => _appControl.OpenApp()); AddAction($"/closeApp", (id, context) => _appControl.CloseOpenApp()); AddAction($"/hideApp", (id, context) => _appControl.HideOpenApp()); _appControl.AppOpenFeedback.OutputChange += (s, a) => { PostStatusMessage(JToken.FromObject(new { appOpen = a.BoolValue })); }; } private void SendFullStatus(string id = null) { var message = new TswAppStateMessage { AppOpen = _appControl.AppOpenFeedback.BoolValue, }; PostStatusMessage(message, id); } } /// /// Represents a TswAppStateMessage /// public class TswAppStateMessage : DeviceStateMessageBase { /// /// True if the Zoom app is open on a TSW panel /// [JsonProperty("appOpen", NullValueHandling = NullValueHandling.Ignore)] public bool? AppOpen { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Touchpanel/ITswZoomControlMessenger.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer.Messengers; namespace PepperDash.Essentials.Touchpanel { /// /// Messenger to handle Zoom status and control for a TSW panel that supports the Zoom Application /// public class ITswZoomControlMessenger : MessengerBase { private readonly ITswZoomControl _zoomControl; /// /// Create an instance of the class for the given device /// /// The key for this messenger /// The message path for this messenger /// The device for this messenger public ITswZoomControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device) { _zoomControl = device as ITswZoomControl; } /// protected override void RegisterActions() { if (_zoomControl == null) { this.LogInformation("{deviceKey} does not implement ITswZoomControl", _device.Key); return; } AddAction($"/fullStatus", (id, context) => SendFullStatus(id)); AddAction($"/zoomStatus", (id, content) => SendFullStatus(id)); AddAction($"/endCall", (id, context) => _zoomControl.EndZoomCall()); _zoomControl.ZoomIncomingCallFeedback.OutputChange += (s, a) => { PostStatusMessage(JToken.FromObject(new { incomingCall = a.BoolValue, inCall = _zoomControl.ZoomInCallFeedback.BoolValue })); }; _zoomControl.ZoomInCallFeedback.OutputChange += (s, a) => { PostStatusMessage(JToken.FromObject( new { inCall = a.BoolValue, incomingCall = _zoomControl.ZoomIncomingCallFeedback.BoolValue })); }; } private void SendFullStatus(string id = null) { var message = new TswZoomStateMessage { InCall = _zoomControl?.ZoomInCallFeedback.BoolValue, IncomingCall = _zoomControl?.ZoomIncomingCallFeedback.BoolValue }; PostStatusMessage(message, id); } } /// /// Represents a TswZoomStateMessage /// public class TswZoomStateMessage : DeviceStateMessageBase { /// /// True if the panel is in a Zoom call /// [JsonProperty("inCall", NullValueHandling = NullValueHandling.Ignore)] public bool? InCall { get; set; } /// /// True if there is an incoming Zoom call /// [JsonProperty("incomingCall", NullValueHandling = NullValueHandling.Ignore)] public bool? IncomingCall { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs ================================================ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text.RegularExpressions; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.UI; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceInfo; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.UI; using Feedback = PepperDash.Essentials.Core.Feedback; using IPAddress = System.Net.IPAddress; namespace PepperDash.Essentials.Touchpanel { /// /// Mobile Control touchpanel controller that provides app control, Zoom integration, /// and mobile control functionality for Crestron touchpanels. /// public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlCrestronTouchpanelController, ITheme { private readonly MobileControlTouchpanelProperties localConfig; private IMobileControlRoomMessenger _bridge; private string _appUrl; /// /// Gets or sets the AppUrlFeedback /// public StringFeedback AppUrlFeedback { get; private set; } private readonly StringFeedback QrCodeUrlFeedback; private readonly StringFeedback McServerUrlFeedback; private readonly StringFeedback UserCodeFeedback; private readonly BoolFeedback _appOpenFeedback; /// /// Gets feedback indicating whether an application is currently open on the touchpanel. /// public BoolFeedback AppOpenFeedback => _appOpenFeedback; private readonly BoolFeedback _zoomIncomingCallFeedback; /// /// Gets feedback indicating whether there is an incoming Zoom call. /// public BoolFeedback ZoomIncomingCallFeedback => _zoomIncomingCallFeedback; private readonly BoolFeedback _zoomInCallFeedback; /// /// Event that is raised when device information changes. /// public event DeviceInfoChangeHandler DeviceInfoChanged; /// /// Gets feedback indicating whether a Zoom call is currently active. /// public BoolFeedback ZoomInCallFeedback => _zoomInCallFeedback; /// /// Gets or sets the Feedbacks /// public FeedbackCollection Feedbacks { get; private set; } /// /// Gets or sets the ZoomFeedbacks /// public FeedbackCollection ZoomFeedbacks { get; private set; } /// /// Gets the default room key for this touchpanel controller. /// public string DefaultRoomKey => _config.DefaultRoomKey; /// /// Gets a value indicating whether to use direct server communication. /// public bool UseDirectServer => localConfig.UseDirectServer; /// /// Gets a value indicating whether this touchpanel acts as a Zoom Room controller. /// public bool ZoomRoomController => localConfig.ZoomRoomController; /// /// Gets the current theme for the touchpanel interface. /// public string Theme => localConfig.Theme; /// /// Gets or sets the ThemeFeedback /// public StringFeedback ThemeFeedback { get; private set; } /// /// Gets device information including MAC address and IP address. /// public DeviceInfo DeviceInfo => new DeviceInfo(); /// /// Gets the list of connected IPs for this IpId /// public ReadOnlyCollection ConnectedIps => Panel.ConnectedIpList; private readonly IPAddress csIpAddress; private readonly IPAddress csSubnetMask; /// /// Initializes a new instance of the MobileControlTouchpanelController class. /// /// The unique key identifier for this touchpanel controller. /// The friendly name for this touchpanel controller. /// The touchpanel hardware device. /// The configuration properties for this controller. public MobileControlTouchpanelController(string key, string name, BasicTriListWithSmartObject panel, MobileControlTouchpanelProperties config) : base(key, name, panel, config) { localConfig = config; AddPostActivationAction(SubscribeForMobileControlUpdates); ThemeFeedback = new StringFeedback($"{Key}-theme", () => Theme); AppUrlFeedback = new StringFeedback($"{Key}-appUrl", () => _appUrl); QrCodeUrlFeedback = new StringFeedback($"{Key}-qrCodeUrl", () => _bridge?.QrCodeUrl); McServerUrlFeedback = new StringFeedback($"{Key}-mcServerUrl", () => _bridge?.McServerUrl); UserCodeFeedback = new StringFeedback($"{Key}-userCode", () => _bridge?.UserCode); _appOpenFeedback = new BoolFeedback($"{Key}-appOpen", () => { if (Panel is TswX60BaseClass tsX60) { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"x60 sending {tsX60.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.BoolValue}"); return !tsX60.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.BoolValue; } if (Panel is TswX70Base tsX70) { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"x70 sending {tsX70.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue}"); return !tsX70.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue; } return false; }); _zoomIncomingCallFeedback = new BoolFeedback($"{Key}-zoomIncomingCall", () => { if (Panel is TswX60WithZoomRoomAppReservedSigs tsX60) { return tsX60.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.BoolValue; } if (Panel is TswX70Base tsX70) { return tsX70.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.BoolValue; } return false; }); _zoomInCallFeedback = new BoolFeedback($"{Key}-zoomInCall", () => { if (Panel is TswX60WithZoomRoomAppReservedSigs tsX60) { return tsX60.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.BoolValue; } if (Panel is TswX70Base tsX70) { return tsX70.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.BoolValue; } return false; }); Feedbacks = new FeedbackCollection { AppUrlFeedback, QrCodeUrlFeedback, McServerUrlFeedback, UserCodeFeedback }; ZoomFeedbacks = new FeedbackCollection { AppOpenFeedback, _zoomInCallFeedback, _zoomIncomingCallFeedback }; RegisterForExtenders(); try { var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId); var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); this.csSubnetMask = IPAddress.Parse(csSubnetMask); this.csIpAddress = IPAddress.Parse(csIpAddress); } catch (ArgumentException) { Debug.LogInformation("This processor does not have a CS LAN", this); } catch (InvalidOperationException) { Debug.LogInformation("This processor does not have a CS LAN", this); } catch (Exception ex) { Debug.LogError($"Unexpected exception when checking CS LAN: {ex}", this); } } /// /// Updates the theme setting for this touchpanel controller and persists the change to configuration. /// /// The new theme identifier to apply. /// /// UpdateTheme method /// public void UpdateTheme(string theme) { localConfig.Theme = theme; var props = JToken.FromObject(localConfig); var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault((d) => d.Key == Key); if (deviceConfig == null) { return; } deviceConfig.Properties = props; ConfigWriter.UpdateDeviceConfig(deviceConfig); } private void RegisterForExtenders() { if (Panel is TswXX70Base x70Panel) { x70Panel.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => { this.LogVerbose("X70 App Control Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); UpdateZoomFeedbacks(); if (!x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue) { x70Panel.ExtenderButtonToolbarReservedSigs.ShowButtonToolbar(); x70Panel.ExtenderButtonToolbarReservedSigs.Button2On(); } else { x70Panel.ExtenderButtonToolbarReservedSigs.HideButtonToolbar(); x70Panel.ExtenderButtonToolbarReservedSigs.Button2Off(); } }; x70Panel.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => { this.LogVerbose("X70 Zoom Room App Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); if (a.Sig.Number == x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number) { ZoomIncomingCallFeedback.FireUpdate(); } else if (a.Sig.Number == x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.Number) { ZoomInCallFeedback.FireUpdate(); } }; x70Panel.ExtenderEthernetReservedSigs.DeviceExtenderSigChange += (e, a) => { DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress); var handler = DeviceInfoChanged; if (handler == null) { return; } handler(this, new DeviceInfoEventArgs(DeviceInfo)); }; x70Panel.ExtenderButtonToolbarReservedSigs.DeviceExtenderSigChange += (o, a) => { this.LogVerbose("X70 Button Toolbar Device Extender args: {event}:{sig}:{name}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Name, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); }; x70Panel.ExtenderApplicationControlReservedSigs.Use(); x70Panel.ExtenderZoomRoomAppReservedSigs.Use(); x70Panel.ExtenderEthernetReservedSigs.Use(); x70Panel.ExtenderButtonToolbarReservedSigs.Use(); return; } if (Panel is TswX60WithZoomRoomAppReservedSigs x60withZoomApp) { x60withZoomApp.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => { this.LogVerbose("X60 App Control Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); if (a.Sig.Number == x60withZoomApp.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.Number) { AppOpenFeedback.FireUpdate(); } }; x60withZoomApp.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => { this.LogVerbose("X60 Zoom Room App Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); if (a.Sig.Number == x60withZoomApp.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number) { ZoomIncomingCallFeedback.FireUpdate(); } else if (a.Sig.Number == x60withZoomApp.ExtenderZoomRoomAppReservedSigs.ZoomRoomActiveFeedback.Number) { ZoomInCallFeedback.FireUpdate(); } }; x60withZoomApp.ExtenderEthernetReservedSigs.DeviceExtenderSigChange += (e, a) => { DeviceInfo.MacAddress = x60withZoomApp.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; DeviceInfo.IpAddress = x60withZoomApp.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress); var handler = DeviceInfoChanged; if (handler == null) { return; } handler(this, new DeviceInfoEventArgs(DeviceInfo)); }; x60withZoomApp.ExtenderZoomRoomAppReservedSigs.Use(); x60withZoomApp.ExtenderApplicationControlReservedSigs.Use(); x60withZoomApp.ExtenderEthernetReservedSigs.Use(); } } /// /// Performs custom activation setup for the touchpanel controller, including /// registering messengers and linking to mobile control. /// /// True if activation was successful; otherwise, false. /// /// CustomActivate method /// public override bool CustomActivate() { var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this); var zoomMessenger = new ITswZoomControlMessenger($"zoomControlMessenger-{Key}", $"/device/{Key}", this); var themeMessenger = new ThemeMessenger($"themeMessenger-{Key}", $"/device/{Key}", this); var mc = DeviceManager.AllDevices.OfType().FirstOrDefault(); if (mc == null) { return base.CustomActivate(); } if (!(Panel is TswXX70Base) && !(Panel is TswX60WithZoomRoomAppReservedSigs)) { mc.AddDeviceMessenger(themeMessenger); return base.CustomActivate(); } mc.AddDeviceMessenger(appMessenger); mc.AddDeviceMessenger(zoomMessenger); mc.AddDeviceMessenger(themeMessenger); return base.CustomActivate(); } /// /// Handles device extender signal changes for system reserved signals. /// /// The device extender that generated the signal change. /// The signal event arguments containing the changed signal information. protected override void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) { this.LogVerbose("System Device Extender args: {event}:{sig}", args.Event, args.Sig); } /// /// Sets up the panel drivers and signal mappings for the specified room. /// /// The room key to configure the panel drivers for. protected override void SetupPanelDrivers(string roomKey) { AppUrlFeedback.LinkInputSig(Panel.StringInput[1]); QrCodeUrlFeedback.LinkInputSig(Panel.StringInput[2]); McServerUrlFeedback.LinkInputSig(Panel.StringInput[3]); UserCodeFeedback.LinkInputSig(Panel.StringInput[4]); Panel.IpInformationChange -= Panel_IpInformationChange; Panel.IpInformationChange += Panel_IpInformationChange; Panel.OnlineStatusChange -= Panel_OnlineChange; Panel.OnlineStatusChange += Panel_OnlineChange; } private void Panel_OnlineChange(GenericBase sender, OnlineOfflineEventArgs args) { try { if (!args.DeviceOnLine) { this.LogInformation("panel is offline"); return; } this.LogDebug("panel is online"); UpdateFeedbacks(); Panel.StringInput[1].StringValue = _appUrl; Panel.StringInput[2].StringValue = QrCodeUrlFeedback.StringValue; Panel.StringInput[3].StringValue = McServerUrlFeedback.StringValue; Panel.StringInput[4].StringValue = UserCodeFeedback.StringValue; if (Panel is TswXX70Base x70Panel) { this.LogDebug("setting buttons off"); x70Panel.ExtenderButtonToolbarReservedSigs.Button1Off(); x70Panel.ExtenderButtonToolbarReservedSigs.Button3Off(); x70Panel.ExtenderButtonToolbarReservedSigs.Button4Off(); x70Panel.ExtenderButtonToolbarReservedSigs.Button5Off(); x70Panel.ExtenderButtonToolbarReservedSigs.Button6Off(); } SendUrlToPanel(); } catch (Exception ex) { this.LogError("Exception in panel online: {message}", ex.Message); this.LogDebug(ex, "Stack Trace: "); } } private void SendUrlToPanel() { var appUrl = GetUrlWithCorrectIp(_appUrl); this.LogInformation("Sending {appUrl} on join 1", AppUrlFeedback.StringValue); if (Panel.StringInput[1].StringValue == appUrl) { this.LogInformation("App URL already set to {appUrl}, no update needed", AppUrlFeedback.StringValue); return; } Panel.StringInput[1].StringValue = appUrl; SetAppUrl(appUrl); } private void Panel_IpInformationChange(GenericBase sender, ConnectedIpEventArgs args) { if (args.Connected) { this.LogVerbose("Connection from IP: {ip}", args.DeviceIpAddress); SendUrlToPanel(); } else { this.LogVerbose("Disconnection from IP: {ip}", args.DeviceIpAddress); } } /// /// Gets the URL with the correct IP address based on the connected devices and the Crestron processor's IP address. /// /// /// private string GetUrlWithCorrectIp(string url) { var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); if (csIpAddress == null || csSubnetMask == null || url == null) { this.LogWarning("CS IP Address Subnet Mask or url is null, cannot determine correct IP for URL"); return url; } this.LogVerbose("Processor IP: {processorIp}, CS IP: {csIpAddress}, CS Subnet Mask: {csSubnetMask}", processorIp, csIpAddress, csSubnetMask); this.LogVerbose("Connected IP Count: {connectedIps}", ConnectedIps.Count); var ip = ConnectedIps.Any(ipInfo => { if (IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp)) { return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask); } this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress); return false; }) ? csIpAddress.ToString() : processorIp; var match = Regex.Match(url, @"^http://([^:/]+):\d+/mc/app\?token=.+$"); if (match.Success) { string ipa = match.Groups[1].Value; // ip will be "192.168.1.100" } // replace ipa with ip but leave the rest of the string intact var updatedUrl = Regex.Replace(url, @"^http://[^:/]+", $"http://{ip}"); this.LogVerbose("Updated URL: {updatedUrl}", updatedUrl); return updatedUrl; } private void SubscribeForMobileControlUpdates() { foreach (var dev in DeviceManager.AllDevices) { Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"{dev.Key}:{dev.GetType().Name}"); } var mcList = DeviceManager.AllDevices.OfType().ToList(); if (mcList.Count == 0) { this.LogError("No Mobile Control controller found"); return; } // use first in list, since there should only be one. var mc = mcList[0]; var bridge = mc.GetRoomBridge(_config.DefaultRoomKey); if (bridge == null) { this.LogInformation("No Mobile Control bridge for {roomKey} found", _config.DefaultRoomKey); return; } _bridge = bridge; _bridge.UserCodeChanged += UpdateFeedbacks; _bridge.AppUrlChanged += (s, a) => { this.LogInformation("AppURL changed: {appURL}", _bridge.AppUrl); SetAppUrl(_bridge.AppUrl); UpdateFeedbacks(s, a); }; SetAppUrl(_bridge.AppUrl); } /// /// Sets the application URL and updates the corresponding feedback. /// /// The new application URL to set. /// /// SetAppUrl method /// public void SetAppUrl(string url) { _appUrl = GetUrlWithCorrectIp(url); AppUrlFeedback.FireUpdate(); } private void UpdateFeedbacks(object sender, EventArgs args) { UpdateFeedbacks(); } private void UpdateFeedbacks() { foreach (var feedback in Feedbacks) { this.LogDebug("Updating {feedbackKey}", feedback.Key); feedback.FireUpdate(); } } private void UpdateZoomFeedbacks() { foreach (var feedback in ZoomFeedbacks) { this.LogDebug("Updating {feedbackKey}", feedback.Key); feedback.FireUpdate(); } } /// /// HideOpenApp method /// public void HideOpenApp() { if (Panel is TswX70Base x70Panel) { x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplication(); return; } if (Panel is TswX60BaseClass x60Panel) { x60Panel.ExtenderApplicationControlReservedSigs.HideOpenApplication(); return; } } /// /// OpenApp method /// public void OpenApp() { if (Panel is TswX70Base x70Panel) { x70Panel.ExtenderApplicationControlReservedSigs.OpenApplication(); return; } if (Panel is TswX60WithZoomRoomAppReservedSigs) { this.LogInformation("X60 panel does not support zoom app"); return; } } /// /// CloseOpenApp method /// public void CloseOpenApp() { if (Panel is TswX70Base x70Panel) { x70Panel.ExtenderApplicationControlReservedSigs.CloseOpenedApplication(); return; } if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) { x60Panel.ExtenderApplicationControlReservedSigs.CloseOpenedApplication(); return; } } /// /// EndZoomCall method /// public void EndZoomCall() { if (Panel is TswX70Base x70Panel) { x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomEndCall(); return; } if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) { x60Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomEndCall(); return; } } /// /// UpdateDeviceInfo method /// public void UpdateDeviceInfo() { if (Panel is TswXX70Base x70Panel) { DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; var handler = DeviceInfoChanged; if (handler == null) { return; } handler(this, new DeviceInfoEventArgs(DeviceInfo)); } if (Panel is TswX60WithZoomRoomAppReservedSigs x60Panel) { DeviceInfo.MacAddress = x60Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; DeviceInfo.IpAddress = x60Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; var handler = DeviceInfoChanged; if (handler == null) { return; } handler(this, new DeviceInfoEventArgs(DeviceInfo)); } this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress); } /// /// Force a reload of the iframe on the panel connected to this IP ID /// public void ReloadIframe() { this.LogInformation("Pulsing join 1"); Panel.PulseBool(1, 100); } } /// /// Represents a MobileControlTouchpanelControllerFactory /// public class MobileControlTouchpanelControllerFactory : EssentialsPluginDeviceFactory { private Dictionary> factories; /// /// Initializes a new instance of the MobileControlTouchpanelControllerFactory class. /// Sets up supported device type names and minimum framework version requirements. /// public MobileControlTouchpanelControllerFactory() { TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" }; MinimumEssentialsFrameworkVersion = "2.0.0"; factories = new Dictionary> { {"crestronapp", (id, controlSystem, projectName) => { var app = new CrestronApp(id, Global.ControlSystem); app.ParameterProjectName.Value = projectName; return app; }}, {"xpanel", (id, controlSystem, projectName) => new XpanelForHtml5(id, controlSystem)}, {"tsw550", (id, controlSystem, projectName) => new Tsw550(id, controlSystem)}, {"tsw552", (id, controlSystem, projectName) => new Tsw552(id, controlSystem)}, {"tsw560", (id, controlSystem, projectName) => new Tsw560(id, controlSystem)}, {"tsw750", (id, controlSystem, projectName) => new Tsw750(id, controlSystem)}, {"tsw752", (id, controlSystem, projectName) => new Tsw752(id, controlSystem)}, {"tsw760", (id, controlSystem, projectName) => new Tsw760(id, controlSystem)}, {"tsw1050", (id, controlSystem, projectName) => new Tsw1050(id, controlSystem)}, {"tsw1052", (id, controlSystem, projectName) => new Tsw1052(id, controlSystem)}, {"tsw1060", (id, controlSystem, projectName) => new Tsw1060(id, controlSystem)}, {"tsw570", (id, controlSystem, projectName) => new Tsw570(id, controlSystem)}, {"tsw770", (id, controlSystem, projectName) => new Tsw770(id, controlSystem)}, {"ts770", (id, controlSystem, projectName) => new Ts770(id, controlSystem)}, {"tsw1070", (id, controlSystem, projectName) => new Tsw1070(id, controlSystem)}, {"ts1070", (id, controlSystem, projectName) => new Ts1070(id, controlSystem)}, {"dge1000", (id, controlSystem, projectName) => new Dge1000(id, controlSystem)} }; } /// /// Builds a MobileControlTouchpanelController device from the provided device configuration. /// /// The device configuration containing the device properties and settings. /// A configured MobileControlTouchpanelController instance. /// /// BuildDevice method /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { var comm = CommFactory.GetControlPropertiesConfig(dc); var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); var panel = GetPanelForType(dc.Type, comm.IpIdInt, props.ProjectName); if (panel == null) { Debug.LogError("Unable to create Touchpanel for type {type}. Touchpanel Controller WILL NOT function correctly", dc.Type); } Debug.LogDebug("Factory Attempting to create new MobileControlTouchpanelController"); var panelController = new MobileControlTouchpanelController(dc.Key, dc.Name, panel, props); return panelController; } private BasicTriListWithSmartObject GetPanelForType(string type, uint id, string projectName) { type = type.ToLower().Replace("mc", ""); try { if (!factories.TryGetValue(type, out var buildCrestronHardwareDevice)) { Debug.LogError("Cannot create TSW controller with type {type}", type); return null; } return buildCrestronHardwareDevice(id, Global.ControlSystem, projectName); } catch (Exception e) { Debug.LogError("Cannot create TSW base class. Panel will not function: {message}", e.Message); Debug.LogDebug(e, "Stack Trace: "); return null; } } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs ================================================ using Newtonsoft.Json; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Touchpanel { /// /// Represents a MobileControlTouchpanelProperties /// public class MobileControlTouchpanelProperties : CrestronTouchpanelPropertiesConfig { /// /// Gets or sets the UseDirectServer /// [JsonProperty("useDirectServer")] public bool UseDirectServer { get; set; } = false; /// /// Gets or sets the ZoomRoomController /// [JsonProperty("zoomRoomController")] public bool ZoomRoomController { get; set; } = false; /// /// Gets or sets the ButtonToolbarTimoutInS /// [JsonProperty("buttonToolbarTimeoutInS")] public ushort ButtonToolbarTimoutInS { get; set; } = 0; /// /// Gets or sets the Theme /// [JsonProperty("theme")] public string Theme { get; set; } = "light"; } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer; using PepperDash.Essentials.AppServer.Messengers; namespace PepperDash.Essentials.Touchpanel { /// /// Messenger to save the current theme (light/dark) and send to a device /// public class ThemeMessenger : MessengerBase { private readonly ITheme _tpDevice; /// /// Create an instance of the class /// /// The key for this messenger /// The path for this messenger /// The device for this messenger public ThemeMessenger(string key, string path, ITheme device) : base(key, path, device as Device) { _tpDevice = device; } /// protected override void RegisterActions() { AddAction("/fullStatus", (id, content) => { PostStatusMessage(new ThemeUpdateMessage { Theme = _tpDevice.Theme }, id); }); AddAction("/saveTheme", (id, content) => { var theme = content.ToObject>(); this.LogInformation("Setting theme to {theme}", theme.Value); _tpDevice.UpdateTheme(theme.Value); PostStatusMessage(JToken.FromObject(new { theme = theme.Value }), clientId: id); }); } } /// /// Represents a ThemeUpdateMessage /// public class ThemeUpdateMessage : DeviceStateMessageBase { /// /// Gets or sets the Theme /// [JsonProperty("theme")] public string Theme { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/TransmitMessage.cs ================================================ using System; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core.Queues; using WebSocketSharp; namespace PepperDash.Essentials { /// /// Represents a TransmitMessage /// public class TransmitMessage : IQueueMessage { private readonly WebSocket _ws; private readonly object msgToSend; /// /// Initialize a message to send /// /// message object to send /// WebSocket instance public TransmitMessage(object msg, WebSocket ws) { _ws = ws; msgToSend = msg; } /// /// Initialize a message to send /// /// message object to send /// WebSocket instance public TransmitMessage(DeviceStateMessageBase msg, WebSocket ws) { _ws = ws; msgToSend = msg; } #region Implementation of IQueueMessage /// /// Dispatch method /// public void Dispatch() { try { if (_ws == null) { Debug.LogWarning("Cannot send message. Websocket client is null"); return; } if (!_ws.IsAlive) { Debug.LogWarning("Cannot send message. Websocket client is not connected"); return; } var message = JsonConvert.SerializeObject(msgToSend, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } }); Debug.LogVerbose("Message TX: {0}", message); _ws.Send(message); } catch (Exception ex) { Debug.LogError("Caught an exception in the Transmit Processor: {message}", ex.Message); Debug.LogDebug(ex, "Stack Trace: "); } } #endregion } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/UserCodeChanged.cs ================================================ using System; namespace PepperDash.Essentials { /// /// Defines the action to take when the User code changes /// public class UserCodeChanged { /// /// Action to take when the User Code changes /// public Action UpdateUserCode { get; private set; } /// /// create an instance of the class /// /// action to take when the User Code changes public UserCodeChanged(Action updateMethod) { UpdateUserCode = updateMethod; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials { /// /// Represents a UserCodeChangedContent /// public class UserCodeChangedContent { /// /// Gets or sets the UserCode /// [JsonProperty("userCode")] public string UserCode { get; set; } /// /// Gets or sets the QrChecksum /// [JsonProperty("qrChecksum", NullValueHandling = NullValueHandling.Include)] public string QrChecksum { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Utilities.cs ================================================ using System.Threading; using PepperDash.Core; using PepperDash.Core.Logging; using WebSocketSharp; namespace PepperDash.Essentials { /// /// Utility functions for logging and other common tasks. /// public static class Utilities { private static int nextClientId = 0; /// /// Get the next unique client ID (thread-safe) /// /// Client ID public static int GetNextClientId() { return Interlocked.Increment(ref nextClientId); } /// /// Converts a WebSocketServer LogData object to Essentials logging calls. /// /// The LogData object to convert. /// The log message. /// The device associated with the log message. public static void ConvertWebsocketLog(LogData data, string message, IKeyed device = null) { switch (data.Level) { case LogLevel.Trace: if (device == null) { Debug.LogVerbose(message); } else { device.LogVerbose(message); } break; case LogLevel.Debug: if (device == null) { Debug.LogDebug(message); } else { device.LogDebug(message); } break; case LogLevel.Info: if (device == null) { Debug.LogInformation(message); } else { device.LogInformation(message); } break; case LogLevel.Warn: if (device == null) { Debug.LogWarning(message); } else { device.LogWarning(message); } break; case LogLevel.Error: if (device == null) { Debug.LogError(message); } else { device.LogError(message); } break; case LogLevel.Fatal: if (device == null) { Debug.LogFatal(message); } else { device.LogFatal(message); } break; } } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/Volumes.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; namespace PepperDash.Essentials { /// /// Represents a Volumes /// public class Volumes { /// /// Gets or sets the Master /// [JsonProperty("master", NullValueHandling = NullValueHandling.Ignore)] public Volume Master { get; set; } /// /// Aux Faders as configured in the room /// [JsonProperty("auxFaders", NullValueHandling = NullValueHandling.Ignore)] public Dictionary AuxFaders { get; set; } /// /// Count of aux faders for this system /// [JsonProperty("numberOfAuxFaders", NullValueHandling = NullValueHandling.Ignore)] public int? NumberOfAuxFaders { get; set; } } /// /// Represents a Volume /// public class Volume { /// /// Gets or sets the Key /// [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key { get; set; } /// /// Level for this volume object /// [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] public int? Level { get; set; } /// /// True if this volume control is muted /// [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] public bool? Muted { get; set; } /// /// Gets or sets the Label /// [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] public string Label { get; set; } /// /// True if this volume object has mute control /// [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] public bool? HasMute { get; set; } /// /// True if this volume object has Privacy mute control /// [JsonProperty("hasPrivacyMute", NullValueHandling = NullValueHandling.Ignore)] public bool? HasPrivacyMute { get; set; } /// /// True if the privacy mute is muted /// [JsonProperty("privacyMuted", NullValueHandling = NullValueHandling.Ignore)] public bool? PrivacyMuted { get; set; } /// /// Gets or sets the MuteIcon /// [JsonProperty("muteIcon", NullValueHandling = NullValueHandling.Ignore)] public string MuteIcon { get; set; } /// /// Create an instance of the class /// /// The key for this volume object /// The level for this volume object /// True if this volume control is muted /// The label for this volume object /// True if this volume object has mute control /// The mute icon for this volume object public Volume(string key, int level, bool muted, string label, bool hasMute, string muteIcon) : this(key) { Level = level; Muted = muted; Label = label; HasMute = hasMute; MuteIcon = muteIcon; } /// /// Create an instance of the class /// /// The key for this volume object /// The level for this volume object public Volume(string key, int level) : this(key) { Level = level; } /// /// Create an instance of the class /// /// The key for this volume object /// True if this volume control is muted public Volume(string key, bool muted) : this(key) { Muted = muted; } /// /// Create an instance of the class /// /// The key for this volume object public Volume(string key) { Key = key; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs ================================================ using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Essentials.WebApiHandlers { /// /// Represents a ActionPathsHandler /// public class ActionPathsHandler : WebApiBaseRequestHandler { private readonly MobileControlSystemController mcController; /// /// Create an instance of the class. /// /// public ActionPathsHandler(MobileControlSystemController controller) : base(true) { mcController = controller; } /// /// Handle a request to get the action paths /// /// Request Context protected override void HandleGet(HttpCwsContext context) { var response = JsonConvert.SerializeObject(new ActionPathsResponse(mcController)); context.Response.StatusCode = 200; context.Response.ContentType = "application/json"; context.Response.Headers.Add("Content-Type", "application/json"); context.Response.Write(response, false); context.Response.End(); } } /// /// Represents a ActionPathsResponse /// public class ActionPathsResponse { [JsonIgnore] private readonly MobileControlSystemController mcController; /// /// Registered action paths for this system /// [JsonProperty("actionPaths")] public List ActionPaths => mcController.GetActionDictionaryPaths().Select((path) => new ActionPath { MessengerKey = path.Item1, Path = path.Item2 }).ToList(); /// /// Create an instance of the class. /// /// public ActionPathsResponse(MobileControlSystemController mcController) { this.mcController = mcController; } } /// /// Represents a ActionPath /// public class ActionPath { /// /// Gets or sets the MessengerKey /// [JsonProperty("messengerKey")] public string MessengerKey { get; set; } /// /// Gets or sets the Path /// [JsonProperty("path")] public string Path { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebApiHandlers/DeleteAllUiClientsHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.WebSocketServer; namespace PepperDash.Essentials.WebApiHandlers { /// /// Represents a DeleteAllUiClientsHandler /// public class DeleteAllUiClientsHandler : WebApiBaseRequestHandler { private readonly MobileControlWebsocketServer server; /// /// Essentials CWS API handler for the MC Direct Server /// /// Direct Server instance public DeleteAllUiClientsHandler(MobileControlWebsocketServer directServer) : base(true) { server = directServer; } /// /// Deletes all clients from the Direct Server /// /// HTTP Context for this request protected override void HandleDelete(HttpCwsContext context) { server.RemoveAllTokens("confirm"); var res = context.Response; res.StatusCode = 200; res.ContentType = "application/json"; res.Headers.Add("Content-Type", "application/json"); res.Write(JsonConvert.SerializeObject(new { success = true }), false); res.End(); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileAuthRequestHandler.cs ================================================ using System; using System.Threading.Tasks; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Web; namespace PepperDash.Essentials.WebApiHandlers { /// /// Represents a MobileAuthRequestHandler /// public class MobileAuthRequestHandler : WebApiBaseRequestAsyncHandler { private readonly MobileControlSystemController mcController; /// /// Create an instance of the class. /// /// public MobileAuthRequestHandler(MobileControlSystemController controller) : base(true) { mcController = controller; } /// /// Handle authorization request for this processor /// /// request context /// Task protected override async Task HandlePost(HttpCwsContext context) { try { var requestBody = EssentialsWebApiHelpers.GetRequestBody(context.Request); var grantCode = JsonConvert.DeserializeObject(requestBody); if (string.IsNullOrEmpty(grantCode?.GrantCode)) { Debug.LogMessage(Serilog.Events.LogEventLevel.Error, "Missing grant code"); context.Response.StatusCode = 400; context.Response.StatusDescription = "Missing grant code"; context.Response.End(); return; } var response = await mcController.ApiService.SendAuthorizationRequest(mcController.Host, grantCode.GrantCode, mcController.SystemUuid); Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, $"response received"); if (response.Authorized) { mcController.RegisterSystemToServer(); } context.Response.StatusCode = 200; var responseBody = JsonConvert.SerializeObject(response, Formatting.None); context.Response.ContentType = "application/json"; context.Response.Headers.Add("Content-Type", "application/json"); context.Response.Write(responseBody, false); context.Response.End(); } catch (Exception ex) { Debug.LogMessage(ex, "Exception recieved authorizing system"); } } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebApiHandlers/MobileInfoHandler.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.WebSocketServer; namespace PepperDash.Essentials.WebApiHandlers { /// /// Represents a MobileInfoHandler. Used with the Essentials CWS API /// public class MobileInfoHandler : WebApiBaseRequestHandler { private readonly MobileControlSystemController mcController; /// /// Create an instance of the class. /// /// public MobileInfoHandler(MobileControlSystemController controller) : base(true) { mcController = controller; } /// /// Get Mobile Control Information /// /// protected override void HandleGet(HttpCwsContext context) { try { var response = new InformationResponse(mcController); context.Response.StatusCode = 200; context.Response.ContentType = "application/json"; context.Response.Write(JsonConvert.SerializeObject(response), false); context.Response.End(); } catch (Exception ex) { Debug.LogMessage(ex, "exception showing mobile info"); context.Response.StatusCode = 500; context.Response.End(); } } } /// /// Represents a InformationResponse /// public class InformationResponse { [JsonIgnore] private readonly MobileControlSystemController mcController; /// /// Edge Server. Null if edge server is disabled /// [JsonProperty("edgeServer", NullValueHandling = NullValueHandling.Ignore)] public MobileControlEdgeServer EdgeServer => mcController.Config.EnableApiServer ? new MobileControlEdgeServer(mcController) : null; /// /// Direct server. Null if the direct server is disabled /// [JsonProperty("directServer", NullValueHandling = NullValueHandling.Ignore)] public MobileControlDirectServer DirectServer => mcController.Config.DirectServer.EnableDirectServer ? new MobileControlDirectServer(mcController.DirectServer) : null; /// /// Create an instance of the class. /// /// public InformationResponse(MobileControlSystemController controller) { mcController = controller; } } /// /// Represents a MobileControlEdgeServer /// public class MobileControlEdgeServer { [JsonIgnore] private readonly MobileControlSystemController mcController; /// /// Mobile Control Edge Server address for this system /// [JsonProperty("serverAddress")] public string ServerAddress => mcController.Config == null ? "No Config" : mcController.Host; /// /// System Name for this system /// [JsonProperty("systemName")] public string SystemName => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].RoomName : "No Config"; /// /// System URL for this system /// [JsonProperty("systemUrl")] public string SystemUrl => ConfigReader.ConfigObject.SystemUrl; /// /// User code to use in MC UI for this system /// [JsonProperty("userCode")] public string UserCode => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].UserCode : "Not available"; /// /// True if connected to edge server /// [JsonProperty("connected")] public bool Connected => mcController.Connected; /// /// Seconds since last comms with edge server /// [JsonProperty("secondsSinceLastAck")] public int SecondsSinceLastAck => (DateTime.Now - mcController.LastAckMessage).Seconds; /// /// Create an instance of the class. /// /// controller to use for this public MobileControlEdgeServer(MobileControlSystemController controller) { mcController = controller; } } /// /// Represents a MobileControlDirectServer /// public class MobileControlDirectServer { [JsonIgnore] private readonly MobileControlWebsocketServer directServer; /// /// URL to use to interact with this server /// [JsonProperty("userAppUrl")] public string UserAppUrl => $"{directServer.UserAppUrlPrefix}/[insert_client_token]"; /// /// TCP/IP Port this server is configured to use /// [JsonProperty("serverPort")] public int ServerPort => directServer.Port; /// /// Count of defined tokens for this server /// [JsonProperty("tokensDefined")] public int TokensDefined => directServer.UiClientContexts.Count; /// /// Count of connected clients /// [JsonProperty("clientsConnected")] public int ClientsConnected => directServer.ConnectedUiClientsCount; /// /// List of tokens and connected clients for this server /// [JsonProperty("clients")] public List Clients => directServer.UiClientContexts .Select(context => (context, clients: directServer.UiClients.Where(client => client.Value.Token == context.Value.Token.Token).Select(c => c.Value).ToList())) .Select((clientTuple, i) => new MobileControlDirectClient(clientTuple.clients, clientTuple.context, i, directServer.UserAppUrlPrefix)) .ToList(); /// /// Create an instance of the class. /// /// public MobileControlDirectServer(MobileControlWebsocketServer server) { directServer = server; } } /// /// Represents a MobileControlDirectClient /// public class MobileControlDirectClient { [JsonIgnore] private readonly UiClientContext context; [JsonIgnore] private readonly string Key; [JsonIgnore] private readonly int clientNumber; [JsonIgnore] private readonly string urlPrefix; /// /// Client number for this client /// [JsonProperty("clientNumber")] public string ClientNumber => $"{clientNumber}"; /// /// Room Key for this client /// [JsonProperty("roomKey")] public string RoomKey => context.Token.RoomKey; /// /// Touchpanel Key, if defined, for this client /// [JsonProperty("touchpanelKey")] public string TouchpanelKey => context.Token.TouchpanelKey; /// /// URL for this client /// [JsonProperty("url")] public string Url => $"{urlPrefix}{Key}"; /// /// Token for this client /// [JsonProperty("token")] public string Token => Key; private readonly List clients; /// /// List of status for all connected UI Clients /// [JsonProperty("clientStatus")] public List ClientStatus => clients.Select(c => new ClientStatus(c)).ToList(); /// /// Create an instance of the class. /// /// List of Websocket Clients /// Context for the client /// Index of the client /// URL prefix for the client public MobileControlDirectClient(List clients, KeyValuePair context, int index, string urlPrefix) { this.context = context.Value; Key = context.Key; clientNumber = index; this.urlPrefix = urlPrefix; this.clients = clients; } } /// /// Report the status of a UiClient /// public class ClientStatus { private readonly UiClient client; /// /// True if client is connected /// public bool Connected => client != null && client.Context.WebSocket.IsAlive; /// /// Get the time this client has been connected /// public double Duration => client == null ? 0 : client.ConnectedDuration.TotalSeconds; /// /// Create an instance of the class for the specified client /// /// client to report on public ClientStatus(UiClient client) { this.client = client; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs ================================================ using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Essentials.Core.Web; using PepperDash.Essentials.WebSocketServer; using Serilog.Events; namespace PepperDash.Essentials.WebApiHandlers { /// /// Represents a UiClientHandler /// public class UiClientHandler : WebApiBaseRequestHandler { private readonly MobileControlWebsocketServer server; /// /// Essentials CWS API handler for the MC Direct Server /// /// Direct Server instance public UiClientHandler(MobileControlWebsocketServer directServer) : base(true) { server = directServer; } /// /// Create a client for the Direct Server /// /// HTTP Context for this request protected override void HandlePost(HttpCwsContext context) { var req = context.Request; var res = context.Response; var body = EssentialsWebApiHelpers.GetRequestBody(req); var request = JsonConvert.DeserializeObject(body); var response = new ClientResponse(); if (string.IsNullOrEmpty(request?.RoomKey)) { response.Error = "roomKey is required"; res.StatusCode = 400; res.ContentType = "application/json"; res.Headers.Add("Content-Type", "application/json"); res.Write(JsonConvert.SerializeObject(response), false); res.End(); return; } if (string.IsNullOrEmpty(request.GrantCode)) { response.Error = "grantCode is required"; res.StatusCode = 400; res.ContentType = "application/json"; res.Headers.Add("Content-Type", "application/json"); res.Write(JsonConvert.SerializeObject(response), false); res.End(); return; } var (token, path) = server.ValidateGrantCode(request.GrantCode, request.RoomKey); response.Token = token; response.Path = path; res.StatusCode = 200; res.ContentType = "application/json"; res.Headers.Add("Content-Type", "application/json"); res.Write(JsonConvert.SerializeObject(response), false); res.End(); } /// /// Handle DELETE request for a Client /// /// protected override void HandleDelete(HttpCwsContext context) { var req = context.Request; var res = context.Response; var body = EssentialsWebApiHelpers.GetRequestBody(req); var request = JsonConvert.DeserializeObject(body); if (string.IsNullOrEmpty(request?.Token)) { var response = new ClientResponse { Error = "token is required" }; res.StatusCode = 400; res.ContentType = "application/json"; res.Headers.Add("Content-Type", "application/json"); res.Write(JsonConvert.SerializeObject(response), false); res.End(); return; } if (!server.UiClientContexts.TryGetValue(request.Token, out UiClientContext clientContext)) { var response = new ClientResponse { Error = $"Unable to find client with token: {request.Token}" }; res.StatusCode = 200; res.ContentType = "application/json"; res.Headers.Add("Content-Type", "application/json"); res.Write(JsonConvert.SerializeObject(response), false); res.End(); return; } if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive) { clientContext.Client.Context.WebSocket.Close(WebSocketSharp.CloseStatusCode.Normal, "Token removed from server"); } var path = server.WsPath + request.Token; if (!server.Server.RemoveWebSocketService(path)) { Debug.LogMessage(LogEventLevel.Warning, "Unable to remove client with token {token}", request.Token); var response = new ClientResponse { Error = $"Unable to remove client with token {request.Token}" }; res.StatusCode = 500; res.ContentType = "application/json"; res.Headers.Add("Content-Type", "application/json"); res.Write(JsonConvert.SerializeObject(response), false); res.End(); return; } server.UiClientContexts.Remove(request.Token); server.UpdateSecret(); res.StatusCode = 200; res.End(); } } /// /// Represents a ClientRequest /// public class ClientRequest { /// /// Gets or sets the RoomKey /// [JsonProperty("roomKey", NullValueHandling = NullValueHandling.Ignore)] public string RoomKey { get; set; } /// /// Gets or sets the GrantCode /// [JsonProperty("grantCode", NullValueHandling = NullValueHandling.Ignore)] public string GrantCode { get; set; } /// /// Gets or sets the Token /// [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] public string Token { get; set; } } /// /// Represents a ClientResponse /// public class ClientResponse { /// /// Gets or sets the Error /// [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] public string Error { get; set; } /// /// Gets or sets the Token /// [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] public string Token { get; set; } /// /// Gets or sets the Path /// [JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)] public string Path { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/ConnectionClosedEventArgs.cs ================================================ using System; namespace PepperDash.Essentials.WebSocketServer { /// /// Event Args for ConnectionClosed event /// public class ConnectionClosedEventArgs : EventArgs { /// /// Client ID that is being closed /// public string ClientId { get; private set; } /// /// Initialize an instance of the class. /// /// client that's closing public ConnectionClosedEventArgs(string clientId) { ClientId = clientId; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/DeviceInterfaceInfo.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; /// /// Represents info about a device including supproted interfaces /// public class DeviceInterfaceInfo : IKeyName { /// /// Gets or sets the Key /// [JsonProperty("key")] public string Key { get; set; } /// /// Gets or sets the Name /// [JsonProperty("name")] public string Name { get; set; } /// /// Gets or sets the Interfaces /// [JsonProperty("interfaces")] public List Interfaces { get; set; } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinResponse.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; namespace PepperDash.Essentials.WebSocketServer { /// /// Represents a JoinResponse /// public class JoinResponse { /// /// Gets or sets the ClientId /// [JsonProperty("clientId")] public string ClientId { get; set; } /// /// Room Key for this client /// [JsonProperty("roomKey")] public string RoomKey { get; set; } /// /// System UUID for this system /// [JsonProperty("systemUUid")] public string SystemUuid { get; set; } /// /// Gets or sets the RoomUuid /// [JsonProperty("roomUUid")] public string RoomUuid { get; set; } /// /// Gets or sets the Config /// [JsonProperty("config")] public object Config { get; set; } /// /// Gets or sets the CodeExpires /// [JsonProperty("codeExpires")] public DateTime CodeExpires { get; set; } /// /// Gets or sets the UserCode /// [JsonProperty("userCode")] public string UserCode { get; set; } /// /// Gets or sets the UserAppUrl /// [JsonProperty("userAppUrl")] public string UserAppUrl { get; set; } /// /// Gets or sets the WebSocketUrl with clientId query parameter /// [JsonProperty("webSocketUrl")] public string WebSocketUrl { get; set; } /// /// Gets or sets the EnableDebug /// [JsonProperty("enableDebug")] public bool EnableDebug { get; set; } /// /// Gets or sets the DeviceInterfaceSupport /// [JsonProperty("deviceInterfaceSupport")] public Dictionary DeviceInterfaceSupport { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinToken.cs ================================================ namespace PepperDash.Essentials.WebSocketServer { /// /// Represents a JoinToken /// public class JoinToken { /// /// Unique client ID for a client that is joining /// public string Id { get; set; } /// /// Gets or sets the Code /// public string Code { get; set; } /// /// Room Key this token is associated with /// public string RoomKey { get; set; } /// /// Unique ID for this token /// public string Uuid { get; set; } /// /// Touchpanel Key this token is associated with, if this is a touch panel token /// public string TouchpanelKey { get; set; } = ""; /// /// Gets or sets the Token /// public string Token { get; set; } = null; } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs ================================================ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Net.Http; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using Org.BouncyCastle.Crypto.Prng; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Web; using PepperDash.Essentials.RoomBridges; using PepperDash.Essentials.WebApiHandlers; using Serilog.Events; using WebSocketSharp; using WebSocketSharp.Net; using WebSocketSharp.Server; namespace PepperDash.Essentials.WebSocketServer { /// /// Represents a MobileControlWebsocketServer /// public class MobileControlWebsocketServer : EssentialsDevice { private readonly string userAppPath = Global.FilePathPrefix + "mcUserApp" + Global.DirectorySeparator; private readonly string localConfigFolderName = "_local-config"; private readonly string appConfigFileName = "_config.local.json"; private readonly string appConfigCsFileName = "_config.cs.json"; private const string certificateName = "selfCres"; private const string certificatePassword = "cres12345"; /// /// Where the key is the join token and the value is the room key /// //private Dictionary _joinTokens; private HttpServer _server; /// /// Gets the HttpServer instance /// public HttpServer Server => _server; /// /// Gets the collection of UI client contexts /// public Dictionary UiClientContexts { get; private set; } private readonly ConcurrentDictionary uiClients = new ConcurrentDictionary(); /// /// Stores pending client registrations using composite key: token-clientId /// This ensures the correct client ID is matched even when connections establish out of order /// private readonly ConcurrentDictionary pendingClientRegistrations = new ConcurrentDictionary(); /// /// Stores pending client registrations with timestamp for legacy clients /// Key is token, Value is list of (clientId, timestamp) tuples /// Most recent registration is used to handle duplicate join requests /// private readonly ConcurrentDictionary> legacyClientRegistrations = new ConcurrentDictionary>(); /// /// Gets the collection of UI clients /// public IReadOnlyDictionary UiClients => uiClients; private readonly MobileControlSystemController _parent; private WebSocketServerSecretProvider _secretProvider; private ServerTokenSecrets _secret; private static readonly HttpClient LogClient = new HttpClient(); private string SecretProviderKey { get { return string.Format("{0}:{1}-tokens", Global.ControlSystem.ProgramNumber, Key); } } private string LanIpAddress => CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter)); private readonly System.Net.IPAddress csIpAddress; private readonly System.Net.IPAddress csSubnetMask; /// /// The path for the WebSocket messaging /// private readonly string _wsPath = "/mc/api/ui/join/"; /// /// Gets the WebSocket path /// public string WsPath => _wsPath; /// /// The path to the location of the files for the user app (single page Angular app) /// private readonly string _appPath = string.Format("{0}mcUserApp", Global.FilePathPrefix); /// /// The base HREF that the user app uses /// private string _userAppBaseHref = "/mc/app"; /// /// Gets or sets the Port /// public int Port { get; private set; } /// /// Gets the user app URL prefix /// public string UserAppUrlPrefix { get { return string.Format("http://{0}:{1}{2}?token=", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), Port, _userAppBaseHref); } } /// /// Gets the count of connected UI clients /// public int ConnectedUiClientsCount { get { return uiClients.Values.Where(c => c.Context.WebSocket.IsAlive).Count(); } } /// /// Initializes a new instance of the MobileControlWebsocketServer class. /// public MobileControlWebsocketServer(string key, int customPort, MobileControlSystemController parent) : base(key) { _parent = parent; // Set the default port to be 50000 plus the slot number of the program Port = 50000 + (int)Global.ControlSystem.ProgramNumber; if (customPort != 0) { Port = customPort; } if (parent.Config.DirectServer.AutomaticallyForwardPortToCSLAN == true) { try { this.LogInformation("Automatically forwarding port {port} to CS LAN", Port); var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); var csIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); var result = CrestronEthernetHelper.AddPortForwarding((ushort)Port, (ushort)Port, csIp, CrestronEthernetHelper.ePortMapTransport.TCP); if (result != CrestronEthernetHelper.PortForwardingUserPatRetCodes.NoErr) { this.LogError("Error adding port forwarding: {error}", result); } } catch (ArgumentException) { this.LogInformation("This processor does not have a CS LAN", this); } catch (Exception ex) { this.LogError("Error automatically forwarding port to CS LAN: {message}", ex.Message); this.LogDebug(ex, "Stack Trace"); } } try { var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId); var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask); this.csIpAddress = System.Net.IPAddress.Parse(csIpAddress); } catch (ArgumentException) { if (parent.Config.DirectServer.AutomaticallyForwardPortToCSLAN == false) { this.LogInformation("This processor does not have a CS LAN"); } } UiClientContexts = new Dictionary(); //_joinTokens = new Dictionary(); if (Global.Platform == eDevicePlatform.Appliance) { AddConsoleCommands(); } AddPreActivationAction(() => AddWebApiPaths()); } private void AddWebApiPaths() { var apiServer = DeviceManager.AllDevices.OfType().FirstOrDefault(); if (apiServer == null) { this.LogInformation("No API Server available"); return; } var routes = new List { new HttpCwsRoute($"device/{Key}/client") { Name = "ClientHandler", RouteHandler = new UiClientHandler(this) }, new HttpCwsRoute($"device/{Key}/deleteAllUiClients") { Name = "DeleteAllClientsHandler", RouteHandler = new DeleteAllUiClientsHandler(this) }, }; apiServer.AddRoute(routes); } private void AddConsoleCommands() { CrestronConsole.AddNewConsoleCommand(GenerateClientTokenFromConsole, "MobileAddUiClient", "Adds a client and generates a token. ? for more help", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(RemoveToken, "MobileRemoveUiClient", "Removes a client. ? for more help", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand((s) => PrintClientInfo(), "MobileGetClientInfo", "Displays the current client info", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(RemoveAllTokens, "MobileRemoveAllClients", "Removes all clients", ConsoleAccessLevelEnum.AccessOperator); } /// /// Initialize method /// /// public override void Initialize() { try { base.Initialize(); _server = new HttpServer(Port, false); _server.OnGet += Server_OnGet; _server.OnOptions += Server_OnOptions; if (_parent.Config.DirectServer.Logging.EnableRemoteLogging) { _server.OnPost += Server_OnPost; } if (_parent.Config.DirectServer.Secure) { this.LogInformation("Adding SSL Configuration to server"); _server.SslConfiguration = new ServerSslConfiguration(new X509Certificate2($"\\user\\{certificateName}.pfx", certificatePassword)) { ClientCertificateRequired = false, CheckCertificateRevocation = false, EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 }; } _server.Log.Output = (data, message) => Utilities.ConvertWebsocketLog(data, message, this); // setting to trace to allow logging level to be controlled by appdebug _server.Log.Level = LogLevel.Trace; CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; _server.Start(); if (_server.IsListening) { this.LogInformation("Mobile Control WebSocket Server listening on port {port}", _server.Port); } CrestronEnvironment.ProgramStatusEventHandler += OnProgramStop; RetrieveSecret(); CreateFolderStructure(); AddClientsForTouchpanels(); } catch (Exception ex) { this.LogError("Exception initializing direct server: {message}", ex.Message); this.LogDebug(ex, "Stack Trace"); } } /// /// Set the internal logging level for the Websocket Server /// public void SetWebsocketLogLevel(LogLevel level) { CrestronConsole.ConsoleCommandResponse($"Setting direct server debug level to {level}", level.ToString()); _server.Log.Level = level; } private void AddClientsForTouchpanels() { var touchpanels = DeviceManager.AllDevices .OfType().Where(tp => tp.UseDirectServer); var touchpanelsToAdd = new List(); if (_secret != null) { var newTouchpanels = touchpanels.Where(tp => !_secret.Tokens.Any(t => t.Value.TouchpanelKey != null && t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase))); touchpanelsToAdd.AddRange(newTouchpanels); } else { touchpanelsToAdd.AddRange(touchpanels); } foreach (var client in touchpanelsToAdd) { var bridge = _parent.GetRoomBridge(client.DefaultRoomKey); if (bridge == null) { this.LogWarning("Unable to find room with key: {defaultRoomKey}", client.DefaultRoomKey); return; } var (key, path) = GenerateClientToken(bridge, client.Key); if (key == null) { this.LogWarning("Unable to generate a client for {clientKey}", client.Key); continue; } } var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); foreach (var touchpanel in touchpanels.Select(tp => { var token = _secret.Tokens.FirstOrDefault((t) => t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase)); var messenger = _parent.GetRoomBridge(tp.DefaultRoomKey); return new { token.Key, Touchpanel = tp, Messenger = messenger }; })) { if (touchpanel.Key == null) { this.LogWarning("Token for touchpanel {touchpanelKey} not found", touchpanel.Touchpanel.Key); continue; } if (touchpanel.Messenger == null) { this.LogWarning("Unable to find room messenger for {defaultRoomKey}", touchpanel.Touchpanel.DefaultRoomKey); continue; } string ip = processorIp; if (_parent.Config.DirectServer.CSLanUiDeviceKeys != null && _parent.Config.DirectServer.CSLanUiDeviceKeys.Any(k => k.Equals(touchpanel.Touchpanel.Key, StringComparison.InvariantCultureIgnoreCase)) && csIpAddress != null) { ip = csIpAddress.ToString(); } var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; this.LogVerbose("Sending URL {appUrl} to touchpanel {touchpanelKey}", appUrl, touchpanel.Touchpanel.Key); touchpanel.Touchpanel.SetAppUrl($"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"); } } private void OnProgramStop(eProgramStatusEventType programEventType) { switch (programEventType) { case eProgramStatusEventType.Stopping: _server.Stop(); break; } } private void CreateFolderStructure() { if (!Directory.Exists(userAppPath)) { Directory.CreateDirectory(userAppPath); } if (!Directory.Exists($"{userAppPath}{localConfigFolderName}")) { Directory.CreateDirectory($"{userAppPath}{localConfigFolderName}"); } using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigFileName}", FileMode.Create, FileAccess.ReadWrite))) { // Write the LAN application configuration file. Used when a request comes in for the application config from the LAN var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); this.LogDebug("LAN Adapter ID: {lanAdapterId}", lanAdapterId); var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); var config = GetApplicationConfig(processorIp); var contents = JsonConvert.SerializeObject(config, Formatting.Indented); sw.Write(contents); } short csAdapterId; try { csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); } catch (ArgumentException) { this.LogDebug("This processor does not have a CS LAN"); return; } if (csAdapterId == -1) { this.LogDebug("CS LAN Adapter not found"); return; } this.LogDebug("CS LAN Adapter ID: {csAdapterId}. Adding CS Config", csAdapterId); using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigCsFileName}", FileMode.Create, FileAccess.ReadWrite))) { // Write the CS application configuration file. Used when a request comes in for the application config from the CS var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); var config = GetApplicationConfig(processorIp); var contents = JsonConvert.SerializeObject(config, Formatting.Indented); sw.Write(contents); } } private MobileControlApplicationConfig GetApplicationConfig(string processorIp) { try { var config = new MobileControlApplicationConfig { ApiPath = string.Format("http://{0}:{1}/mc/api", processorIp, _parent.Config.DirectServer.Port), GatewayAppPath = "", LogoPath = _parent.Config.ApplicationConfig?.LogoPath ?? "logo/logo.png", EnableDev = _parent.Config.ApplicationConfig?.EnableDev ?? false, IconSet = _parent.Config.ApplicationConfig?.IconSet ?? MCIconSet.GOOGLE, LoginMode = _parent.Config.ApplicationConfig?.LoginMode ?? "room-list", Modes = _parent.Config.ApplicationConfig?.Modes ?? new Dictionary { { "room-list", new McMode { ListPageText = "Please select your room", LoginHelpText = "Please select your room from the list, then enter the code shown on the display.", PasscodePageText = "Please enter the code shown on this room's display" } } }, Logging = _parent.Config.ApplicationConfig?.Logging ?? false, PartnerMetadata = _parent.Config.ApplicationConfig?.PartnerMetadata ?? new List() }; return config; } catch (Exception ex) { this.LogError("Error getting application configuration: {message}", ex.Message); this.LogDebug(ex, "Stack Trace"); return null; } } /// /// Attempts to retrieve secrets previously stored in memory /// private void RetrieveSecret() { try { // Add secret provider _secretProvider = new WebSocketServerSecretProvider(SecretProviderKey); // Check for existing secrets var secret = _secretProvider.GetSecret(SecretProviderKey); if (secret != null) { Debug.LogMessage(LogEventLevel.Information, "Secret successfully retrieved", this); Debug.LogMessage(LogEventLevel.Debug, "Secret: {0}", this, secret.Value.ToString()); // populate the local secrets object _secret = JsonConvert.DeserializeObject(secret.Value.ToString()); if (_secret != null && _secret.Tokens != null) { // populate the _uiClient collection foreach (var token in _secret.Tokens) { if (token.Value == null) { this.LogWarning("Token value is null"); continue; } this.LogInformation("Adding token: {key} for room: {roomKey}", token.Key, token.Value.RoomKey); if (UiClientContexts == null) { UiClientContexts = new Dictionary(); } UiClientContexts.Add(token.Key, new UiClientContext(token.Value)); } } if (UiClientContexts.Count > 0) { this.LogInformation("Restored {uiClientCount} UiClients from secrets data", UiClientContexts.Count); foreach (var client in UiClientContexts) { var key = client.Key; var path = _wsPath + key; var roomKey = client.Value.Token.RoomKey; _server.AddWebSocketService(path, () => { this.LogInformation("Building a UiClient with ID {id}", client.Value.Token.Id); return BuildUiClient(roomKey, client.Value.Token, key); }); } } } else { this.LogWarning("No secret found"); } this.LogDebug("{uiClientCount} UiClients restored from secrets data", UiClientContexts.Count); } catch (Exception ex) { this.LogError("Exception retrieving secret: {message}", ex.Message); this.LogDebug(ex, "Stack Trace"); } } /// /// UpdateSecret method /// public void UpdateSecret() { try { if (_secret == null) { this.LogError("Secret is null"); _secret = new ServerTokenSecrets(string.Empty); } _secret.Tokens.Clear(); foreach (var uiClientContext in UiClientContexts) { _secret.Tokens.Add(uiClientContext.Key, uiClientContext.Value.Token); } var serializedSecret = JsonConvert.SerializeObject(_secret); _secretProvider.SetSecret(SecretProviderKey, serializedSecret); } catch (Exception ex) { this.LogError("Exception updating secret: {message}", ex.Message); this.LogDebug(ex, "Stack Trace"); } } /// /// Generates a new token based on validating a room key and grant code passed in. If valid, returns a token and adds a service to the server for that token's path /// /// private void GenerateClientTokenFromConsole(string s) { if (s == "?" || string.IsNullOrEmpty(s)) { CrestronConsole.ConsoleCommandResponse(@"[RoomKey] [GrantCode] Validates the room key against the grant code and returns a token for use in a UI client"); return; } var values = s.Split(' '); if (values.Length < 2) { CrestronConsole.ConsoleCommandResponse("Invalid number of arguments. Please provide a room key and a grant code"); return; } var roomKey = values[0]; var grantCode = values[1]; var bridge = _parent.GetRoomBridge(roomKey); if (bridge == null) { CrestronConsole.ConsoleCommandResponse(string.Format("Unable to find room with key: {0}", roomKey)); return; } var (token, path) = ValidateGrantCode(grantCode, bridge); if (token == null) { CrestronConsole.ConsoleCommandResponse("Grant Code is not valid"); return; } CrestronConsole.ConsoleCommandResponse($"Added new WebSocket UiClient service at path: {path}"); CrestronConsole.ConsoleCommandResponse($"Token: {token}"); } /// /// Validates the grant code against the room key /// public (string, string) ValidateGrantCode(string grantCode, string roomKey) { var bridge = _parent.GetRoomBridge(roomKey); if (bridge == null) { this.LogWarning("Unable to find room with key: {roomKey}", roomKey); return (null, null); } return ValidateGrantCode(grantCode, bridge); } /// /// Validates the grant code against the room key /// public (string, string) ValidateGrantCode(string grantCode, MobileControlBridgeBase bridge) { // TODO: Authenticate grant code passed in // For now, we just generate a random guid as the token and use it as the ClientId as well var grantCodeIsValid = true; if (grantCodeIsValid) { if (_secret == null) { _secret = new ServerTokenSecrets(grantCode); } return GenerateClientToken(bridge, ""); } else { return (null, null); } } /// /// Generates a new client token for the specified bridge /// public (string, string) GenerateClientToken(MobileControlBridgeBase bridge, string touchPanelKey = "") { var key = Guid.NewGuid().ToString(); var token = new JoinToken { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid, TouchpanelKey = touchPanelKey }; UiClientContexts.Add(key, new UiClientContext(token)); var path = _wsPath + key; _server.AddWebSocketService(path, () => { this.LogInformation("Building a UiClient with ID {id}", token.Id); return BuildUiClient(bridge.RoomKey, token, key); }); this.LogInformation("Added new WebSocket UiClient for path: {path}", path); this.LogInformation("Token: {@token}", token); this.LogVerbose("{serviceCount} websocket services present", _server.WebSocketServices.Count); UpdateSecret(); return (key, path); } private UiClient BuildUiClient(string roomKey, JoinToken token, string key) { // Get the most recent unused clientId for this token (legacy support) // New clients will override this ID in OnOpen with the validated query parameter value var clientId = "pending"; if (legacyClientRegistrations.TryGetValue(key, out var registrations)) { // Get most recent registration var sorted = registrations.OrderByDescending(r => r.timestamp).ToList(); if (sorted.Any()) { clientId = sorted.First().clientId; // Remove it from the bag var newBag = new ConcurrentBag<(string, DateTime)>(sorted.Skip(1)); legacyClientRegistrations.TryUpdate(key, newBag, registrations); this.LogVerbose("Assigned most recent legacy clientId {clientId} for token {token}", clientId, key); } } var c = new UiClient($"uiclient-{key}-{roomKey}-{clientId}", clientId, token.Token, token.TouchpanelKey); this.LogInformation("Constructing UiClient with key {key} and temporary ID (will be set from query param)", key); c.Controller = _parent; c.RoomKey = roomKey; c.TokenKey = key; // Store the URL token key for filtering c.Server = this; // Give UiClient access to server for ID registration // Don't add to uiClients yet - will be added in OnOpen after ID is set from query param c.ConnectionClosed += (o, a) => { uiClients.TryRemove(a.ClientId, out _); // Clean up any pending registrations for this token var keysToRemove = pendingClientRegistrations.Keys .Where(k => k.StartsWith($"{key}-")) .ToList(); foreach (var k in keysToRemove) { pendingClientRegistrations.TryRemove(k, out _); } // Clean up legacy registrations if empty if (legacyClientRegistrations.TryGetValue(key, out var legacyBag) && legacyBag.IsEmpty) { legacyClientRegistrations.TryRemove(key, out _); } }; return c; } /// /// Registers a UiClient with its validated client ID after WebSocket connection /// /// The UiClient to register /// The validated client ID /// The token key for validation /// True if registration successful, false if validation failed public bool RegisterUiClient(UiClient client, string clientId, string tokenKey) { var registrationKey = $"{tokenKey}-{clientId}"; // Verify this clientId was generated during a join request for this token if (!pendingClientRegistrations.TryRemove(registrationKey, out _)) { this.LogWarning("Client attempted to connect with unregistered or expired clientId {clientId} for token {token}", clientId, tokenKey); return false; } // Registration is valid - add to active clients uiClients.AddOrUpdate(clientId, client, (id, existingClient) => { this.LogWarning("Replacing existing client with duplicate id {id}", id); return client; }); this.LogInformation("Successfully registered UiClient with ID {clientId} for token {token}", clientId, tokenKey); return true; } /// /// Updates a client's ID when a mismatch is detected between stored ID and message ID /// /// The current/old client ID /// The new client ID from the message /// The token key for validation /// True if update successful, false otherwise public bool UpdateClientId(string oldClientId, string newClientId, string tokenKey) { if (string.IsNullOrEmpty(oldClientId) || string.IsNullOrEmpty(newClientId)) { this.LogWarning("Cannot update client ID with null or empty values"); return false; } if (oldClientId == newClientId) { return true; // No update needed } // Verify the new clientId was registered for this token var registrationKey = $"{tokenKey}-{newClientId}"; if (!pendingClientRegistrations.TryRemove(registrationKey, out _)) { this.LogWarning("Cannot update to unregistered clientId {newClientId} for token {token}", newClientId, tokenKey); return false; } // Get the existing client if (!uiClients.TryRemove(oldClientId, out var client)) { this.LogWarning("Cannot find client with old ID {oldClientId}", oldClientId); return false; } // Update the client's ID client.UpdateId(newClientId); // Re-add with new ID if (!uiClients.TryAdd(newClientId, client)) { // If add fails, try to restore old entry uiClients.TryAdd(oldClientId, client); client.UpdateId(oldClientId); this.LogError("Failed to update client ID from {oldClientId} to {newClientId}", oldClientId, newClientId); return false; } this.LogInformation("Successfully updated client ID from {oldClientId} to {newClientId}", oldClientId, newClientId); return true; } /// /// Registers a UiClient using legacy flow (for backwards compatibility with older clients) /// /// The UiClient to register public void RegisterLegacyUiClient(UiClient client) { if (string.IsNullOrEmpty(client.Id)) { this.LogError("Cannot register client with null or empty ID"); return; } uiClients.AddOrUpdate(client.Id, client, (id, existingClient) => { this.LogWarning("Replacing existing client with duplicate id {id} (legacy flow)", id); return client; }); this.LogInformation("Successfully registered UiClient with ID {clientId} using legacy flow", client.Id); } /// /// Prints out the session data for each path /// public void PrintSessionData() { foreach (var path in _server.WebSocketServices.Paths) { this.LogInformation("Path: {path}", path); this.LogInformation(" Session Count: {sessionCount}", _server.WebSocketServices[path].Sessions.Count); this.LogInformation(" Active Session Count: {activeSessionCount}", _server.WebSocketServices[path].Sessions.ActiveIDs.Count()); this.LogInformation(" Inactive Session Count: {inactiveSessionCount}", _server.WebSocketServices[path].Sessions.InactiveIDs.Count()); this.LogInformation(" Active Clients:"); foreach (var session in _server.WebSocketServices[path].Sessions.IDs) { this.LogInformation(" Client ID: {id}", (_server.WebSocketServices[path].Sessions[session] as UiClient)?.Id); } } } /// /// Removes all clients from the server /// public void RemoveAllTokens(string s) { if (s == "?" || string.IsNullOrEmpty(s)) { CrestronConsole.ConsoleCommandResponse(@"Remove all clients from the server. To execute add 'confirm' to command"); return; } if (s != "confirm") { CrestronConsole.ConsoleCommandResponse(@"To remove all clients, add 'confirm' to the command"); return; } foreach (var client in UiClientContexts) { if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive) { client.Value.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Server Shutting Down"); } var path = _wsPath + client.Key; if (_server.RemoveWebSocketService(path)) { CrestronConsole.ConsoleCommandResponse(string.Format("Client removed with token: {0}", client.Key)); } else { CrestronConsole.ConsoleCommandResponse(string.Format("Unable to remove client with token : {0}", client.Key)); } } UiClientContexts.Clear(); UpdateSecret(); } /// /// Removes a client with the specified token value /// /// private void RemoveToken(string s) { if (s == "?" || string.IsNullOrEmpty(s)) { CrestronConsole.ConsoleCommandResponse(@"[token] Removes the client with the specified token value"); return; } var key = s; if (UiClientContexts.ContainsKey(key)) { var uiClientContext = UiClientContexts[key]; if (uiClientContext.Client != null && uiClientContext.Client.Context.WebSocket.IsAlive) { uiClientContext.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Token removed from server"); } var path = _wsPath + key; if (_server.RemoveWebSocketService(path)) { UiClientContexts.Remove(key); UpdateSecret(); CrestronConsole.ConsoleCommandResponse(string.Format("Client removed with token: {0}", key)); } else { CrestronConsole.ConsoleCommandResponse(string.Format("Unable to remove client with token : {0}", key)); } } else { CrestronConsole.ConsoleCommandResponse(string.Format("Unable to find client with token: {0}", key)); } } /// /// Prints out info about current client IDs /// private void PrintClientInfo() { CrestronConsole.ConsoleCommandResponse("Mobile Control UI Client Info:\r"); CrestronConsole.ConsoleCommandResponse(string.Format("{0} clients found:\r", UiClientContexts.Count)); foreach (var client in UiClientContexts) { CrestronConsole.ConsoleCommandResponse(string.Format("RoomKey: {0} Token: {1}\r", client.Value.Token.RoomKey, client.Key)); } } private void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType == eProgramStatusEventType.Stopping) { foreach (var client in UiClients.Values) { if (client != null && client.Context.WebSocket.IsAlive) { client.Context.WebSocket.Close(CloseStatusCode.Normal, "Server Shutting Down"); } } StopServer(); } } /// /// Handler for GET requests to server /// /// /// private void Server_OnGet(object sender, HttpRequestEventArgs e) { try { var req = e.Request; var res = e.Response; res.ContentEncoding = Encoding.UTF8; res.AddHeader("Access-Control-Allow-Origin", "*"); var path = req.RawUrl; this.LogVerbose("GET Request received at path: {path}", path); // Call for user app to join the room with a token if (path.StartsWith("/mc/api/ui/joinroom")) { HandleJoinRequest(req, res); } // Call to get the server version else if (path.StartsWith("/mc/api/version")) { HandleVersionRequest(res); } else if (path.StartsWith("/mc/app/logo")) { HandleImageRequest(req, res); } // Call to serve the user app else if (path.StartsWith(_userAppBaseHref)) { HandleUserAppRequest(req, res, path); } else { // All other paths res.StatusCode = 404; res.Close(); } } catch (Exception ex) { this.LogError("Exception in OnGet handler: {message}", ex.Message); this.LogDebug(ex, "Stack Trace"); } } private async void Server_OnPost(object sender, HttpRequestEventArgs e) { try { var req = e.Request; var res = e.Response; res.AddHeader("Access-Control-Allow-Origin", "*"); var path = req.RawUrl; var ip = req.RemoteEndPoint.Address.ToString(); this.LogVerbose("POST Request received at path: {path} from host {host}", path, ip); var body = new StreamReader(req.InputStream).ReadToEnd(); if (path.StartsWith("/mc/api/log")) { res.StatusCode = 200; res.Close(); var logRequest = new HttpRequestMessage(HttpMethod.Post, $"http://{_parent.Config.DirectServer.Logging.Host}:{_parent.Config.DirectServer.Logging.Port}/logs") { Content = new StringContent(body, Encoding.UTF8, "application/json"), }; logRequest.Headers.Add("x-pepperdash-host", ip); await LogClient.SendAsync(logRequest); this.LogVerbose("Log data sent to {host}:{port}", _parent.Config.DirectServer.Logging.Host, _parent.Config.DirectServer.Logging.Port); } else { res.StatusCode = 404; res.Close(); } } catch (Exception ex) { this.LogException(ex, "Caught an exception in the OnPost handler"); } } private void Server_OnOptions(object sender, HttpRequestEventArgs e) { try { var res = e.Response; res.AddHeader("Access-Control-Allow-Origin", "*"); res.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); res.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me"); res.StatusCode = 200; res.Close(); } catch (Exception ex) { Debug.LogMessage(ex, "Caught an exception in the OnPost handler", this); } } /// /// Handle the request to join the room with a token /// /// /// private void HandleJoinRequest(HttpListenerRequest req, HttpListenerResponse res) { var qp = req.QueryString; var token = qp["token"]; this.LogVerbose("Join Room Request with token: {token}", token); byte[] body; if (!UiClientContexts.TryGetValue(token, out UiClientContext clientContext)) { var message = "Token invalid or has expired"; res.StatusCode = 401; res.ContentType = "application/json"; this.LogVerbose("{message}", message); body = Encoding.UTF8.GetBytes(message); res.ContentLength64 = body.LongLength; res.Close(body, true); return; } var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey); if (bridge == null) { var message = string.Format("Unable to find bridge with key: {0}", clientContext.Token.RoomKey); res.StatusCode = 404; res.ContentType = "application/json"; this.LogVerbose("{message}", message); body = Encoding.UTF8.GetBytes(message); res.ContentLength64 = body.LongLength; res.Close(body, true); return; } res.StatusCode = 200; res.ContentType = "application/json"; var devices = DeviceManager.GetDevices(); Dictionary deviceInterfaces = new Dictionary(); foreach (var device in devices) { var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List(); deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo { Key = device.Key, Name = (device as IKeyName)?.Name ?? "", Interfaces = interfaces }); } // Generate a client ID for this join request var clientId = $"{Utilities.GetNextClientId()}"; var now = DateTime.UtcNow; // Store in pending registrations for new clients that send clientId via query param var registrationKey = $"{token}-{clientId}"; pendingClientRegistrations.TryAdd(registrationKey, clientId); // For legacy clients, store with timestamp instead of FIFO queue var legacyBag = legacyClientRegistrations.GetOrAdd(token, _ => new ConcurrentBag<(string, DateTime)>()); legacyBag.Add((clientId, now)); this.LogVerbose("Assigning ClientId: {clientId} for token: {token} at {timestamp}", clientId, token, now); // Construct WebSocket URL with clientId query parameter var wsProtocol = "ws"; var wsUrl = $"{wsProtocol}://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{Port}{_wsPath}{token}?clientId={clientId}"; // Construct the response object JoinResponse jRes = new JoinResponse { ClientId = clientId, RoomKey = bridge.RoomKey, SystemUuid = _parent.SystemUuid, RoomUuid = _parent.SystemUuid, Config = _parent.GetConfigWithPluginVersion(), CodeExpires = new DateTime().AddYears(1), UserCode = bridge.UserCode, UserAppUrl = string.Format("http://{0}:{1}/mc/app", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), Port), WebSocketUrl = wsUrl, EnableDebug = false, DeviceInterfaceSupport = deviceInterfaces }; // Serialize to JSON and convert to Byte[] var json = JsonConvert.SerializeObject(jRes); body = Encoding.UTF8.GetBytes(json); res.ContentLength64 = body.LongLength; // Send the response res.Close(body, true); } /// /// Handles a server version request /// /// private void HandleVersionRequest(HttpListenerResponse res) { res.StatusCode = 200; res.ContentType = "application/json"; var version = new Version() { ServerVersion = _parent.GetConfigWithPluginVersion().RuntimeInfo.PluginVersion }; var message = JsonConvert.SerializeObject(version); this.LogVerbose("{message}", message); var body = Encoding.UTF8.GetBytes(message); res.ContentLength64 = body.LongLength; res.Close(body, true); } /// /// Handler to return images requested by the user app /// /// /// private void HandleImageRequest(HttpListenerRequest req, HttpListenerResponse res) { var path = req.RawUrl; Debug.LogMessage(LogEventLevel.Verbose, "Requesting Image: {0}", this, path); var imageBasePath = Global.DirectorySeparator + "html" + Global.DirectorySeparator + "logo" + Global.DirectorySeparator; var image = path.Split('/').Last(); var filePath = imageBasePath + image; Debug.LogMessage(LogEventLevel.Verbose, "Retrieving Image: {0}", this, filePath); if (File.Exists(filePath)) { if (filePath.EndsWith(".png")) { res.ContentType = "image/png"; } else if (filePath.EndsWith(".jpg")) { res.ContentType = "image/jpeg"; } else if (filePath.EndsWith(".gif")) { res.ContentType = "image/gif"; } else if (filePath.EndsWith(".svg")) { res.ContentType = "image/svg+xml"; } byte[] contents = File.ReadAllBytes(filePath); res.ContentLength64 = contents.LongLength; res.Close(contents, true); } else { res.StatusCode = (int)HttpStatusCode.NotFound; res.Close(); } } /// /// Handles requests to serve files for the Angular single page app /// /// /// /// private void HandleUserAppRequest(HttpListenerRequest req, HttpListenerResponse res, string path) { this.LogVerbose("Requesting User app file"); string filePath = path.Split('?')[0]; // remove the token from the path if found //string filePath = path.Replace(string.Format("?token={0}", token), ""); // if there's no file suffix strip any extra path data after the base href if (filePath != _userAppBaseHref && !filePath.Contains(".") && (!filePath.EndsWith(_userAppBaseHref) || !filePath.EndsWith(_userAppBaseHref += "/"))) { var suffix = filePath.Substring(_userAppBaseHref.Length, filePath.Length - _userAppBaseHref.Length); if (suffix != "/") { //Debug.Console(2, this, "Suffix: {0}", suffix); filePath = filePath.Replace(suffix, ""); } } // swap the base href prefix for the file path prefix filePath = filePath.Replace(_userAppBaseHref, _appPath); this.LogVerbose("filepath: {filePath}", filePath); // append index.html if no specific file is specified if (!filePath.Contains(".")) { if (filePath.EndsWith("/")) { filePath += "index.html"; } else { filePath += "/index.html"; } } // Set ContentType based on file type if (filePath.EndsWith(".html")) { this.LogVerbose("Client requesting User App"); res.ContentType = "text/html"; } else { if (path.EndsWith(".js")) { res.ContentType = "application/javascript"; } else if (path.EndsWith(".css")) { res.ContentType = "text/css"; } else if (path.EndsWith(".json")) { res.ContentType = "application/json"; } } this.LogVerbose("Attempting to serve file: {filePath}", filePath); var remoteIp = req.RemoteEndPoint.Address; // Check if the request is coming from the CS LAN and if so, send the CS config instead of the LAN config if (csSubnetMask != null && csIpAddress != null && remoteIp.IsInSameSubnet(csIpAddress, csSubnetMask) && filePath.Contains(appConfigFileName)) { filePath = filePath.Replace(appConfigFileName, appConfigCsFileName); } byte[] contents; if (File.Exists(filePath)) { this.LogVerbose("File found: {filePath}", filePath); contents = File.ReadAllBytes(filePath); } else { this.LogWarning("File not found: {filePath}", filePath); res.StatusCode = (int)HttpStatusCode.NotFound; res.Close(); return; } res.ContentLength64 = contents.LongLength; res.Close(contents, true); } /// /// StopServer method /// public void StopServer() { this.LogVerbose("Stopping WebSocket Server"); _server.Stop(CloseStatusCode.Normal, "Server Shutting Down"); } /// /// Sends a message to all connectd clients /// /// /// /// SendMessageToAllClients method /// public void SendMessageToAllClients(string message) { foreach (var client in uiClients.Values) { if (!client.Context.WebSocket.IsAlive) { continue; } client.Context.WebSocket.Send(message); } } /// /// Sends a message to a specific client /// /// /// /// /// SendMessageToClient method /// public void SendMessageToClient(object clientId, string message) { if (clientId == null) { return; } if (uiClients.TryGetValue((string)clientId, out var client)) { var socket = client.Context.WebSocket; if (!socket.IsAlive) { this.LogError("Unable to send message to client {id}. Client is disconnected: {message}", clientId, message); return; } socket.Send(message); } else { this.LogWarning("Unable to find client with ID: {clientId}", clientId); } } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/ServerTokenSecrets.cs ================================================ using System.Collections.Generic; namespace PepperDash.Essentials.WebSocketServer { /// /// Represents a ServerTokenSecrets /// public class ServerTokenSecrets { /// /// Gets or sets the GrantCode /// public string GrantCode { get; set; } /// /// Gets or sets the Tokens for this server /// public Dictionary Tokens { get; set; } /// /// Initialize a new instance of the class with the provided grant code /// /// The grant code for this server public ServerTokenSecrets(string grantCode) { GrantCode = grantCode; Tokens = new Dictionary(); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs ================================================ using System; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.RoomBridges; using Serilog.Events; using WebSocketSharp; using WebSocketSharp.Server; using ErrorEventArgs = WebSocketSharp.ErrorEventArgs; namespace PepperDash.Essentials.WebSocketServer { /// /// Represents the behaviour to associate with a UiClient for WebSocket communication /// public class UiClient : WebSocketBehavior, IKeyed { /// public string Key { get; private set; } /// /// Client ID used by client for this connection /// public string Id { get; private set; } /// /// Updates the client ID - only accessible from within the assembly (e.g., by the server) /// /// The new client ID internal void UpdateId(string newId) { Id = newId; } /// /// Token associated with this client /// public string Token { get; private set; } /// /// The URL token key used to connect (from UiClientContexts dictionary key) /// public string TokenKey { get; set; } /// /// Touchpanel Key associated with this client /// public string TouchpanelKey { get; private set; } /// /// Gets or sets the mobile control system controller that handles this client's messages /// public MobileControlSystemController Controller { get; set; } /// /// Gets or sets the server instance for client registration /// public MobileControlWebsocketServer Server { get; set; } /// /// Gets or sets the room key that this client is associated with /// public string RoomKey { get; set; } /// /// The timestamp when this client connection was established /// private DateTime _connectionTime; /// /// Gets the duration that this client has been connected. Returns zero if not currently connected. /// public TimeSpan ConnectedDuration { get { if (Context.WebSocket.IsAlive) { return DateTime.Now - _connectionTime; } else { return new TimeSpan(0); } } } /// /// Triggered when this client closes it's connection /// public event EventHandler ConnectionClosed; /// /// Initializes a new instance of the UiClient class with the specified key /// /// The unique key to identify this client /// The client ID used by the client for this connection /// The token associated with this client /// The touchpanel key associated with this client public UiClient(string key, string id, string token, string touchpanelKey = "") { Key = key; Id = id; Token = token; TouchpanelKey = touchpanelKey; } /// protected override void OnOpen() { base.OnOpen(); _connectionTime = DateTime.Now; Log.Output = (data, message) => Utilities.ConvertWebsocketLog(data, message, this); Log.Level = LogLevel.Trace; // Get clientId from query parameter var queryString = Context.QueryString; var clientId = queryString["clientId"]; if (!string.IsNullOrEmpty(clientId)) { // New behavior: Validate and register with the server using provided clientId if (Server == null || !Server.RegisterUiClient(this, clientId, TokenKey)) { this.LogError("Failed to register client with ID {clientId}. Invalid or expired registration.", clientId); Context.WebSocket.Close(CloseStatusCode.PolicyViolation, "Invalid or expired clientId"); return; } // Update this client's ID to the validated one Id = clientId; Key = $"uiclient-{TokenKey}-{RoomKey}-{clientId}"; this.LogInformation("Client {clientId} successfully connected and registered (new flow)", clientId); } else { // Legacy behavior: Use clientId from Token.Id (generated in HandleJoinRequest) this.LogInformation("Client connected without clientId query parameter. Using legacy registration flow."); // Id is already set from Token in constructor, use it if (string.IsNullOrEmpty(Id)) { this.LogError("Legacy client has no ID from token. Connection will be closed."); Context.WebSocket.Close(CloseStatusCode.PolicyViolation, "No client ID available"); return; } Key = $"uiclient-{TokenKey}-{RoomKey}-{Id}"; // Register directly to active clients (legacy flow) if (Server != null) { Server.RegisterLegacyUiClient(this); } this.LogInformation("Client {clientId} registered using legacy flow", Id); } if (Controller == null) { Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Controller is null"); _connectionTime = DateTime.Now; } var clientJoinedMessage = new MobileControlMessage { Type = "/system/clientJoined", Content = JToken.FromObject(new { clientId = Id, roomKey = RoomKey, touchpanelKey = TouchpanelKey ?? string.Empty, }) }; Controller.HandleClientMessage(JsonConvert.SerializeObject(clientJoinedMessage)); var bridge = Controller.GetRoomBridge(RoomKey); if (bridge == null) return; SendUserCodeToClient(bridge, Id); bridge.UserCodeChanged -= Bridge_UserCodeChanged; bridge.UserCodeChanged += Bridge_UserCodeChanged; // TODO: Future: Check token to see if there's already an open session using that token and reject/close the session } /// /// Handles the UserCodeChanged event from a room bridge and sends the updated user code to the client /// /// The room bridge that raised the event /// Event arguments private void Bridge_UserCodeChanged(object sender, EventArgs e) { SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, Id); } /// /// Sends the current user code and QR code URL to the specified client /// /// The room bridge containing the user code information /// The ID of the client to send the information to private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId) { var content = new { userCode = bridge.UserCode, qrUrl = bridge.QrCodeUrl, }; var message = new MobileControlMessage { Type = "/system/userCodeChanged", ClientId = clientId, Content = JToken.FromObject(content) }; Controller.SendMessageObjectToDirectClient(message); } /// protected override void OnMessage(MessageEventArgs e) { base.OnMessage(e); if (e.IsText && e.Data.Length > 0 && Controller != null) { // Forward the message to the controller to be put on the receive queue Controller.HandleClientMessage(e.Data); } } /// protected override void OnClose(CloseEventArgs e) { base.OnClose(e); this.LogInformation("WebSocket UiClient Closing: {code} reason: {reason}", e.Code, e.Reason); foreach (var messenger in Controller.Messengers) { messenger.Value.UnsubscribeClient(Id); } foreach (var messenger in Controller.DefaultMessengers) { messenger.Value.UnsubscribeClient(Id); } ConnectionClosed?.Invoke(this, new ConnectionClosedEventArgs(Id)); } /// protected override void OnError(ErrorEventArgs e) { base.OnError(e); this.LogError("WebSocket UiClient Error: {message}", e.Message); this.LogDebug(e.Exception, "Stack Trace"); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClientContext.cs ================================================ namespace PepperDash.Essentials.WebSocketServer { /// /// Represents a UiClientContext /// public class UiClientContext { /// /// Gets or sets the Client /// public UiClient Client { get; private set; } /// /// Gets or sets the Token /// public JoinToken Token { get; private set; } /// /// Initialize an instance of the class with the provided token /// /// token for this client public UiClientContext(JoinToken token) { Token = token; } /// /// SetClient method /// public void SetClient(UiClient client) { Client = client; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/Version.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.WebSocketServer { /// /// Represents a Version /// public class Version { /// /// Server version this Websocket is connected to /// [JsonProperty("serverVersion")] public string ServerVersion { get; set; } /// /// True if the server is on a processor /// [JsonProperty("serverIsRunningOnProcessorHardware")] public bool ServerIsRunningOnProcessorHardware { get; private set; } /// /// Initialize an instance of the class /// /// /// The property is set to true by default. /// public Version() { ServerIsRunningOnProcessorHardware = true; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl/WebSocketServer/WebSocketServerSecretProvider.cs ================================================ using Newtonsoft.Json; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.WebSocketServer { internal class WebSocketServerSecretProvider : CrestronLocalSecretsProvider { public WebSocketServerSecretProvider(string key) : base(key) { Key = key; } } /// /// Stores a secret value using the provided secret store provider /// public class WebSocketServerSecret : ISecret { /// /// Gets the Secret Provider associated with this secret /// public ISecretProvider Provider { get; private set; } /// /// Gets the Key associated with this secret /// public string Key { get; private set; } /// /// Gets the Value associated with this secret /// public object Value { get; private set; } /// /// Initialize and instance of the class /// public WebSocketServerSecret(string key, object value, ISecretProvider provider) { Key = key; Value = JsonConvert.SerializeObject(value); Provider = provider; } /// /// DeserializeSecret method /// public ServerTokenSecrets DeserializeSecret() { return JsonConvert.DeserializeObject(Value.ToString()); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/ContentTypes.cs ================================================ using Newtonsoft.Json; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer { /// /// Represents a SourceSelectMessageContent /// public class SourceSelectMessageContent { [JsonProperty("sourceListItemKey")] /// /// Gets or sets the SourceListItemKey /// public string SourceListItemKey { get; set; } [JsonProperty("sourceListKey")] /// /// Gets or sets the SourceListKey /// public string SourceListKey { get; set; } } /// /// Represents a DirectRoute /// public class DirectRoute { [JsonProperty("sourceKey")] /// /// Gets or sets the SourceKey /// public string SourceKey { get; set; } [JsonProperty("destinationKey")] /// /// Gets or sets the DestinationKey /// public string DestinationKey { get; set; } [JsonProperty("signalType")] /// /// Gets or sets the SignalType /// public eRoutingSignalType SignalType { get; set; } } /// /// /// /// /// /// Delegate for PressAndHoldAction /// public delegate void PressAndHoldAction(bool b); } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/DisplayBaseMessenger.cs ================================================ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer; using PepperDash.Essentials.AppServer.Messengers; using System.Linq; using DisplayBase = PepperDash.Essentials.Devices.Common.Displays.DisplayBase; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a DisplayBaseMessenger /// public class DisplayBaseMessenger : MessengerBase { private readonly DisplayBase display; public DisplayBaseMessenger(string key, string messagePath, DisplayBase device) : base(key, messagePath, device) { display = device; } protected override void RegisterActions() { base.RegisterActions(); /*AddAction("/powerOn", (id, content) => display.PowerOn()); AddAction("/powerOff", (id, content) => display.PowerOff()); AddAction("/powerToggle", (id, content) => display.PowerToggle());*/ AddAction("/inputSelect", (id, content) => { var s = content.ToObject>(); var inputPort = display.InputPorts.FirstOrDefault(i => i.Key == s.Value); if (inputPort == null) { this.LogWarning("No input named {inputName} found for {deviceKey}", s, display.Key); return; } display.ExecuteSwitch(inputPort.Selector); }); AddAction("/inputs", (id, content) => { var inputsList = display.InputPorts.Select(p => p.Key).ToList(); var messageObject = new MobileControlMessage { Type = MessagePath + "/inputs", Content = JToken.FromObject(new { inputKeys = inputsList, }) }; AppServerController.SendMessageObject(messageObject); }); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IChannelMessenger.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a IChannelMessenger /// public class IChannelMessenger : MessengerBase { private readonly IChannel channelDevice; public IChannelMessenger(string key, string messagePath, IChannel device) : base(key, messagePath, device as IKeyName) { channelDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/chanUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.ChannelUp(b))); AddAction("/chanDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.ChannelDown(b))); AddAction("/lastChan", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.LastChannel(b))); AddAction("/guide", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Guide(b))); AddAction("/info", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Info(b))); AddAction("/exit", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => channelDevice?.Exit(b))); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IColorMessenger.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a IColorMessenger /// public class IColorMessenger : MessengerBase { private readonly IColor colorDevice; public IColorMessenger(string key, string messagePath, IColor device) : base(key, messagePath, device as IKeyName) { colorDevice = device as IColor; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/red", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Red(b))); AddAction("/green", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Green(b))); AddAction("/yellow", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Yellow(b))); AddAction("/blue", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => colorDevice?.Blue(b))); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDPadMessenger.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a IDPadMessenger /// public class IDPadMessenger : MessengerBase { private readonly IDPad dpadDevice; public IDPadMessenger(string key, string messagePath, IDPad device) : base(key, messagePath, device as IKeyName) { dpadDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/up", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Up(b))); AddAction("/down", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Down(b))); AddAction("/left", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Left(b))); AddAction("/right", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Right(b))); AddAction("/select", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Select(b))); AddAction("/menu", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Menu(b))); AddAction("/exit", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dpadDevice?.Exit(b))); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IDvrMessenger.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a IDvrMessenger /// public class IDvrMessenger : MessengerBase { private readonly IDvr dvrDevice; public IDvrMessenger(string key, string messagePath, IDvr device) : base(key, messagePath, device as IKeyName) { dvrDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/dvrlist", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dvrDevice?.DvrList(b))); AddAction("/record", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => dvrDevice?.Record(b))); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/IHasPowerMessenger.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a IHasPowerMessenger /// public class IHasPowerMessenger : MessengerBase { private readonly IHasPowerControl powerDevice; public IHasPowerMessenger(string key, string messagePath, IHasPowerControl device) : base(key, messagePath, device as IKeyName) { powerDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/powerOn", (id, content) => powerDevice?.PowerOn()); AddAction("/powerOff", (id, content) => powerDevice?.PowerOff()); AddAction("/powerToggle", (id, content) => powerDevice?.PowerToggle()); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/INumericMessenger.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a INumericKeypadMessenger /// public class INumericKeypadMessenger : MessengerBase { private readonly INumericKeypad keypadDevice; public INumericKeypadMessenger(string key, string messagePath, INumericKeypad device) : base(key, messagePath, device as IKeyName) { keypadDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/num0", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit0(b))); AddAction("/num1", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit1(b))); AddAction("/num2", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit2(b))); AddAction("/num3", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit3(b))); AddAction("/num4", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit4(b))); AddAction("/num5", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit5(b))); AddAction("/num6", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit6(b))); AddAction("/num7", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit7(b))); AddAction("/num8", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit8(b))); AddAction("/num9", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.Digit9(b))); AddAction("/numDash", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.KeypadAccessoryButton1(b))); AddAction("/numEnter", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => keypadDevice?.KeypadAccessoryButton2(b))); // Deal with the Accessory functions on the numpad later } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ISetTopBoxControlsMessenger.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a ISetTopBoxControlsMessenger /// public class ISetTopBoxControlsMessenger : MessengerBase { private readonly ISetTopBoxControls stbDevice; public ISetTopBoxControlsMessenger(string key, string messagePath, ISetTopBoxControls device) : base(key, messagePath, device as IKeyName) { stbDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendISetTopBoxControlsFullMessageObject()); AddAction("/dvrList", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => stbDevice?.DvrList(b))); AddAction("/replay", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => stbDevice?.Replay(b))); } /// /// Helper method to build call status for vtc /// /// private void SendISetTopBoxControlsFullMessageObject() { PostStatusMessage(new SetTopBoxControlsState()); } } public class SetTopBoxControlsState : DeviceStateMessageBase { } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/DeviceTypeExtensions/ITransportMessenger.cs ================================================ using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a ITransportMessenger /// public class ITransportMessenger : MessengerBase { private readonly ITransport transportDevice; public ITransportMessenger(string key, string messagePath, ITransport device) : base(key, messagePath, device as IKeyName) { transportDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/play", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Play(b))); AddAction("/pause", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Pause(b))); AddAction("/stop", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Stop(b))); AddAction("/prevTrack", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.ChapPlus(b))); AddAction("/nextTrack", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.ChapMinus(b))); AddAction("/rewind", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Rewind(b))); AddAction("/ffwd", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.FFwd(b))); AddAction("/record", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => transportDevice?.Record(b))); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs ================================================ using System; using System.Linq; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Provides a messaging bridge for an AudioCodecBase device /// public class AudioCodecBaseMessenger : MessengerBase { /// /// Device being bridged /// public AudioCodecBase Codec { get; private set; } /// /// Constuctor /// /// /// /// public AudioCodecBaseMessenger(string key, AudioCodecBase codec, string messagePath) : base(key, messagePath, codec) { Codec = codec ?? throw new ArgumentNullException("codec"); codec.CallStatusChange += Codec_CallStatusChange; } /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendAtcFullMessageObject(id)); AddAction("/audioDialerStatus", (id, content) => SendAtcFullMessageObject(id)); AddAction("/dial", (id, content) => { var msg = content.ToObject>(); Codec.Dial(msg.Value); }); AddAction("/endCallById", (id, content) => { var msg = content.ToObject>(); var call = GetCallWithId(msg.Value); if (call != null) Codec.EndCall(call); }); AddAction("/endAllCalls", (id, content) => Codec.EndAllCalls()); AddAction("/dtmf", (id, content) => { var msg = content.ToObject>(); Codec.SendDtmf(msg.Value); }); AddAction("/rejectById", (id, content) => { var msg = content.ToObject>(); var call = GetCallWithId(msg.Value); if (call != null) Codec.RejectCall(call); }); AddAction("/acceptById", (id, content) => { var msg = content.ToObject>(); var call = GetCallWithId(msg.Value); if (call != null) Codec.AcceptCall(call); }); } /// /// Helper to grab a call with string ID /// /// /// private CodecActiveCallItem GetCallWithId(string id) { return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id); } private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) { SendAtcFullMessageObject(); } /// /// Helper method to build call status for vtc /// /// private void SendAtcFullMessageObject(string id = null) { var info = Codec.CodecInfo; PostStatusMessage(JToken.FromObject(new { isInCall = Codec.IsInCall, calls = Codec.ActiveCalls, info = new { phoneNumber = info.PhoneNumber } }), id ); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Cameras; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Messenger for a CameraBase device /// public class CameraBaseMessenger : MessengerBase where T : IKeyed { /// /// Gets or sets the Camera /// public T Camera { get; set; } /// /// Constructor /// /// /// /// public CameraBaseMessenger(string key, T camera, string messagePath) : base(key, messagePath, camera as IKeyName) { if (camera == null) throw new ArgumentNullException(nameof(camera)); Camera = camera; if (Camera is IHasCameraPresets presetsCamera) { presetsCamera.PresetsListHasChanged += PresetsCamera_PresetsListHasChanged; } } private void PresetsCamera_PresetsListHasChanged(object sender, EventArgs e) { var presetList = new List(); if (Camera is IHasCameraPresets presetsCamera) presetList = presetsCamera.Presets; PostStatusMessage(JToken.FromObject(new { presets = presetList }) ); } /// /// Registers the actions for this messenger. This is called by the base class /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject(id)); AddAction("/cameraStatus", (id, content) => SendCameraFullMessageObject(id)); if (Camera is IHasCameraPtzControl ptzCamera) { // Need to evaluate how to pass through these P&H actions. Need a method that takes a bool maybe? AddAction("/cameraUp", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { ptzCamera.TiltUp(); return; } ptzCamera.TiltStop(); })); AddAction("/cameraDown", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { ptzCamera.TiltDown(); return; } ptzCamera.TiltStop(); })); AddAction("/cameraLeft", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { ptzCamera.PanLeft(); return; } ptzCamera.PanStop(); })); AddAction("/cameraRight", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { ptzCamera.PanRight(); return; } ptzCamera.PanStop(); })); AddAction("/cameraZoomIn", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { ptzCamera.ZoomIn(); return; } ptzCamera.ZoomStop(); })); AddAction("/cameraZoomOut", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { ptzCamera.ZoomOut(); return; } ptzCamera.ZoomStop(); })); } if (Camera is IHasCameraAutoMode) { AddAction("/cameraModeAuto", (id, content) => (Camera as IHasCameraAutoMode).CameraAutoModeOn()); AddAction("/cameraModeManual", (id, content) => (Camera as IHasCameraAutoMode).CameraAutoModeOff()); } if (Camera is IHasPowerControl) { AddAction("/cameraModeOff", (id, content) => (Camera as IHasPowerControl).PowerOff()); AddAction("/cameraModeManual", (id, content) => (Camera as IHasPowerControl).PowerOn()); } if (Camera is IHasCameraPresets presetsCamera) { AddAction("/recallPreset", (id, content) => { var msg = content.ToObject>(); presetsCamera.PresetSelect(msg.Value); }); AddAction("/storePreset", (id, content) => { var msg = content.ToObject>(); presetsCamera.PresetStore(msg.Value, string.Empty); }); } } private void HandleCameraPressAndHold(JToken content, Action cameraAction) { var state = content.ToObject>(); var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); if (timerHandler == null) { return; } timerHandler(Camera.Key, cameraAction); } /// /// Helper method to update the full status of the camera /// private void SendCameraFullMessageObject(string id = null) { var presetList = new List(); CameraCapabilities capabilities = null; if (Camera is IHasCameraPresets presetsCamera) presetList = presetsCamera.Presets; if (Camera is ICameraCapabilities cameraCapabilities) capabilities = new CameraCapabilities { CanPan = cameraCapabilities.CanPan, CanTilt = cameraCapabilities.CanTilt, CanZoom = cameraCapabilities.CanZoom, CanFocus = cameraCapabilities.CanFocus }; if (Camera is CameraBase cameraBase) capabilities = new CameraCapabilities { CanPan = cameraBase.CanPan, CanTilt = cameraBase.CanTilt, CanZoom = cameraBase.CanZoom, CanFocus = cameraBase.CanFocus }; var message = new CameraStateMessage { CameraManualSupported = Camera is IHasCameraControls, CameraAutoSupported = Camera is IHasCameraAutoMode, CameraOffSupported = Camera is IHasCameraOff, CameraMode = (eCameraControlMode)Enum.Parse(typeof(eCameraControlMode), GetCameraMode(), true), HasPresets = Camera is IHasCameraPresets, Presets = presetList, Capabilities = capabilities, IsFarEnd = Camera is IAmFarEndCamera }; PostStatusMessage(message, id ); } /// /// Computes the current camera mode /// /// private string GetCameraMode() { string m; if (Camera is IHasCameraAutoMode && (Camera as IHasCameraAutoMode).CameraAutoModeIsOnFeedback.BoolValue) m = eCameraControlMode.Auto.ToString().ToLower(); else if (Camera is IHasPowerControlWithFeedback && !(Camera as IHasPowerControlWithFeedback).PowerIsOnFeedback.BoolValue) m = eCameraControlMode.Off.ToString().ToLower(); else m = eCameraControlMode.Manual.ToString().ToLower(); return m; } } /// /// State message for a camera device /// public class CameraStateMessage : DeviceStateMessageBase { /// /// Indicates whether the camera supports manual control /// [JsonProperty("cameraManualSupported", NullValueHandling = NullValueHandling.Ignore)] public bool CameraManualSupported { get; set; } /// /// Indicates whether the camera supports auto control /// [JsonProperty("cameraAutoSupported", NullValueHandling = NullValueHandling.Ignore)] public bool CameraAutoSupported { get; set; } /// /// Indicates whether the camera supports off control /// [JsonProperty("cameraOffSupported", NullValueHandling = NullValueHandling.Ignore)] public bool CameraOffSupported { get; set; } /// /// Indicates the current camera control mode /// [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public eCameraControlMode CameraMode { get; set; } /// /// Indicates whether the camera has presets /// [JsonProperty("hasPresets", NullValueHandling = NullValueHandling.Ignore)] public bool HasPresets { get; set; } /// /// List of presets if the camera supports them /// [JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)] public List Presets { get; set; } /// /// Indicates the capabilities of the camera /// [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] public CameraCapabilities Capabilities { get; set; } /// /// Indicates whether the camera is a far end camera /// [JsonProperty("isFarEnd", NullValueHandling = NullValueHandling.Ignore)] public bool IsFarEnd { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs ================================================ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Routing; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IHasCurrentSourceInfoMessenger /// public class CurrentSourcesMessenger : MessengerBase { private readonly ICurrentSources sourceDevice; /// /// Initializes a new instance of the class. /// /// The key. /// The message path. /// The device. public CurrentSourcesMessenger(string key, string messagePath, ICurrentSources device) : base(key, messagePath, device as IKeyName) { sourceDevice = device; } /// /// Registers the actions for the messenger. /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendCurrentSourceStatus(id)); AddAction("/currentSourceStatus", (id, content) => SendCurrentSourceStatus(id)); sourceDevice.CurrentSourcesChanged += (sender, e) => { // need to copy the dictionaries to avoid enumeration issues var currentSourceKeys = sourceDevice.CurrentSourceKeys.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var currentSources = sourceDevice.CurrentSources.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); PostStatusMessage(JToken.FromObject(new { currentSourceKeys, currentSources, })); }; } private void SendCurrentSourceStatus(string id = null) { var message = new CurrentSourcesStateMessage { CurrentSourceKeys = sourceDevice.CurrentSourceKeys, CurrentSources = sourceDevice.CurrentSources }; PostStatusMessage(message, id); } } /// /// Represents a CurrentSourcesStateMessage /// public class CurrentSourcesStateMessage : DeviceStateMessageBase { /// /// Gets or sets the CurrentSourceKey /// [JsonProperty("currentSourceKeys", NullValueHandling = NullValueHandling.Ignore)] public Dictionary CurrentSourceKeys { get; set; } /// /// Gets or sets the CurrentSource /// [JsonProperty("currentSources")] public Dictionary CurrentSources { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceEventMessageBase.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Base class for event messages that include the type of message and an event type /// public abstract class DeviceEventMessageBase : DeviceMessageBase { /// /// The event type /// [JsonProperty("eventType")] public string EventType { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs ================================================ using System.Timers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceInfo; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Facilitates communication of device information by providing mechanisms for status updates and device /// information reporting. /// /// The class integrates with an to manage device-specific information. It uses a debounce timer to limit the /// frequency of updates, ensuring efficient communication. The timer is initialized with a 1-second interval and /// is disabled by default. This class also subscribes to device information change events and provides actions for /// reporting full device status and triggering updates. public class DeviceInfoMessenger : MessengerBase { private readonly IDeviceInfoProvider _deviceInfoProvider; private readonly Timer debounceTimer; /// /// Initializes a new instance of the class, which facilitates communication /// of device information. /// /// The messenger uses a debounce timer to limit the frequency of certain operations. The /// timer is initialized with a 1-second interval and is disabled by default. /// A unique identifier for the messenger instance. /// The path used for sending and receiving messages. /// An implementation of that provides device-specific information. public DeviceInfoMessenger(string key, string messagePath, IDeviceInfoProvider device) : base(key, messagePath, device as Device) { _deviceInfoProvider = device; debounceTimer = new Timer(1000) { Enabled = false, AutoReset = false }; debounceTimer.Elapsed += DebounceTimer_Elapsed; } private void DebounceTimer_Elapsed(object sender, ElapsedEventArgs e) { PostStatusMessage(JToken.FromObject(new { deviceInfo = _deviceInfoProvider.DeviceInfo })); } /// /// Registers actions and event handlers for device information updates and status reporting. /// /// This method sets up actions for handling device status updates and reporting full /// device status. It also subscribes to the event to /// trigger debounced updates when the device information changes. protected override void RegisterActions() { base.RegisterActions(); _deviceInfoProvider.DeviceInfoChanged += (o, a) => { debounceTimer.Stop(); debounceTimer.Start(); }; AddAction("/fullStatus", (id, context) => SendFullStatus(id)); AddAction("/deviceInfo", (id, content) => SendFullStatus(id)); AddAction("/update", (id, context) => _deviceInfoProvider.UpdateDeviceInfo()); } private void SendFullStatus(string id = null) { PostStatusMessage(new DeviceInfoStateMessage { DeviceInfo = _deviceInfoProvider.DeviceInfo }, id); } } /// /// Represents a message containing the state information of a device, including detailed device information. /// /// This class is used to encapsulate the state of a device along with its associated /// information. It extends to provide additional details about the /// device. /// /// Represents a DeviceInfoStateMessage /// public class DeviceInfoStateMessage : DeviceStateMessageBase { [JsonProperty("deviceInfo")] public DeviceInfo DeviceInfo { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceMessageBase.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Base class for device messages that include the type of message /// public abstract class DeviceMessageBase { /// /// The device key /// [JsonProperty("key")] /// /// Gets or sets the Key /// public string Key { get; set; } /// /// The device name /// [JsonProperty("name")] public string Name { get; set; } /// /// The type of the message class /// [JsonProperty("messageType")] public string MessageType => GetType().Name; /// /// Gets or sets the MessageBasePath /// [JsonProperty("messageBasePath")] public string MessageBasePath { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Presets; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a DevicePresetsModelMessenger /// public class DevicePresetsModelMessenger : MessengerBase { private readonly ITvPresetsProvider _presetsDevice; /// /// Constructor for DevicePresetsModelMessenger /// /// The key. /// The message path. /// The presets device. public DevicePresetsModelMessenger(string key, string messagePath, ITvPresetsProvider presetsDevice) : base(key, messagePath, presetsDevice as Device) { _presetsDevice = presetsDevice; } private void SendPresets(string id = null) { PostStatusMessage(new PresetStateMessage { Favorites = _presetsDevice.TvPresets.PresetsList }, id); } private void RecallPreset(ISetTopBoxNumericKeypad device, string channel) { _presetsDevice.TvPresets.Dial(channel, device); } private void SavePresets(List presets) { _presetsDevice.TvPresets.UpdatePresets(presets); } #region Overrides of MessengerBase /// protected override void RegisterActions() { AddAction("/fullStatus", (id, content) => { this.LogInformation("getting full status for client {id}", id); try { SendPresets(id); } catch (Exception ex) { Debug.LogMessage(ex, "Exception sending preset full status", this); } }); AddAction("/presetsStatus", (id, content) => SendPresets(id)); AddAction("/recall", (id, content) => { var p = content.ToObject(); if (!(DeviceManager.GetDeviceForKey(p.DeviceKey) is ISetTopBoxNumericKeypad dev)) { this.LogDebug("Unable to find device with key {0}", p.DeviceKey); return; } RecallPreset(dev, p.Preset.Channel); }); AddAction("/save", (id, content) => { var presets = content.ToObject>(); SavePresets(presets); }); _presetsDevice.TvPresets.PresetsSaved += (p) => SendPresets(); } #endregion } /// /// Represents a PresetChannelMessage /// public class PresetChannelMessage { /// /// Gets or sets the Preset /// [JsonProperty("preset")] public PresetChannel Preset; /// /// Gets or sets the DeviceKey /// [JsonProperty("deviceKey")] public string DeviceKey; } /// /// Represents a PresetStateMessage /// public class PresetStateMessage : DeviceStateMessageBase { /// /// Gets or sets the Favorites /// [JsonProperty("favorites", NullValueHandling = NullValueHandling.Ignore)] public List Favorites { get; set; } = new List(); } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceStateMessageBase.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a DeviceStateMessageBase /// public class DeviceStateMessageBase : DeviceMessageBase { /// /// The interfaces implmented by the device sending the messsage /// [JsonProperty("interfaces")] public List Interfaces { get; private set; } /// /// Sets the interfaces implemented by the device sending the message /// /// [Obsolete("SetInterfaces is no longer supported and will be removed in a future release. Interfaces for all devices are now retrieved via the /joinroom endpoint in the MobileControlWebsocketServer")] public void SetInterfaces(List interfaces) { Interfaces = interfaces; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs ================================================ using System; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a DeviceVolumeMessenger /// public class DeviceVolumeMessenger : MessengerBase { private readonly IBasicVolumeControls device; /// /// Initializes a new instance of the class. /// /// The key. /// The message path. /// The device. public DeviceVolumeMessenger(string key, string messagePath, IBasicVolumeControls device) : base(key, messagePath, device) { this.device = device; } private void SendStatus(string id = null) { try { if (!(device is IBasicVolumeWithFeedback feedbackDevice)) { return; } var messageObj = new VolumeStateMessage { Volume = new Volume { Level = feedbackDevice?.VolumeLevelFeedback.IntValue ?? -1, Muted = feedbackDevice?.MuteFeedback.BoolValue ?? false, HasMute = true, // assume all devices have mute for now } }; if (device is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) { messageObj.Volume.RawValue = volumeAdvanced.RawVolumeLevel.ToString(); messageObj.Volume.Units = volumeAdvanced.Units; } PostStatusMessage(messageObj, id); } catch (Exception ex) { Debug.LogMessage(ex, "Exception sending full status", this); } } #region Overrides of MessengerBase /// protected override void RegisterActions() { AddAction("/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Calling {localDevice} volume up with {value}", DeviceKey, b); try { device.VolumeUp(b); } catch (Exception ex) { Debug.LogMessage(ex, "Got exception during volume up: {Exception}", null, ex); } })); AddAction("/muteToggle", (id, content) => { device.MuteToggle(); }); AddAction("/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Calling {localDevice} volume down with {value}", DeviceKey, b); try { device.VolumeDown(b); } catch (Exception ex) { Debug.LogMessage(ex, "Got exception during volume down: {Exception}", null, ex); } })); if (!(device is IBasicVolumeWithFeedback feedback)) { this.LogDebug("Skipping feedback methods for {deviceKey}", (device as IKeyName)?.Key); return; } AddAction("/fullStatus", (id, content) => SendStatus(id)); AddAction("/volumeStatus", (id, content) => SendStatus(id)); AddAction("/level", (id, content) => { var volume = content.ToObject>(); feedback.SetVolume(volume.Value); }); AddAction("/muteOn", (id, content) => { feedback.MuteOn(); }); AddAction("/muteOff", (id, content) => { feedback.MuteOff(); }); feedback.MuteFeedback.OutputChange += (sender, args) => { var message = new VolumeStateMessage { Volume = new Volume { Muted = args.BoolValue } }; PostStatusMessage(JToken.FromObject(message)); }; feedback.VolumeLevelFeedback.OutputChange += (sender, args) => { var message = new VolumeStateMessage { Volume = new Volume { Level = args.IntValue, } }; if (device is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) { message.Volume.RawValue = volumeAdvanced.RawVolumeLevel.ToString(); message.Volume.Units = volumeAdvanced.Units; } PostStatusMessage(JToken.FromObject(message)); }; } #endregion } /// /// Represents a VolumeStateMessage /// public class VolumeStateMessage : DeviceStateMessageBase { [JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Volume /// public Volume Volume { get; set; } } /// /// Represents a Volume /// public class Volume { [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] public int? Level { get; set; } [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] public bool? HasMute { get; set; } [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] public bool? Muted { get; set; } [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Label /// public string Label { get; set; } [JsonProperty("rawValue", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the RawValue /// public string RawValue { get; set; } [JsonConverter(typeof(StringEnumConverter))] [JsonProperty("units", NullValueHandling = NullValueHandling.Ignore)] public eVolumeLevelUnits? Units { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a GenericMessenger /// public class GenericMessenger : MessengerBase { /// /// Initializes a new instance of the class. /// /// The key. /// The device. /// The message path. public GenericMessenger(string key, EssentialsDevice device, string messagePath) : base(key, messagePath, device) { } /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); } private void SendFullStatus(string id = null) { var state = new DeviceStateMessageBase(); PostStatusMessage(state, id); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IBasicVideoMuteWithFeedbackMessenger.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IBasicVideoMuteWithFeedbackMessenger /// public class IBasicVideoMuteWithFeedbackMessenger : MessengerBase { private readonly IBasicVideoMuteWithFeedback device; /// /// Initializes a new instance of the class. /// /// /// /// public IBasicVideoMuteWithFeedbackMessenger(string key, string messagePath, IBasicVideoMuteWithFeedback device) : base(key, messagePath, device as IKeyName) { this.device = device; } /// /// SendFullStatus method /// public void SendFullStatus(string id = null) { var messageObj = new IBasicVideoMuteWithFeedbackMessage { VideoMuteState = device.VideoMuteIsOn.BoolValue }; PostStatusMessage(messageObj, id); } /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/videoMuteStatus", (id, content) => SendFullStatus(id)); AddAction("/videoMuteToggle", (id, content) => { device.VideoMuteToggle(); }); AddAction("/videoMuteOn", (id, content) => { device.VideoMuteOn(); }); AddAction("/videoMuteOff", (id, content) => { device.VideoMuteOff(); }); device.VideoMuteIsOn.OutputChange += VideoMuteIsOnFeedback_OutputChange; } private void VideoMuteIsOnFeedback_OutputChange(object sender, FeedbackEventArgs args) { PostStatusMessage(JToken.FromObject(new { videoMuteState = args.BoolValue }) ); } } /// /// Represents a IBasicVideoMuteWithFeedbackMessage /// public class IBasicVideoMuteWithFeedbackMessage : DeviceStateMessageBase { [JsonProperty("videoMuteState")] public bool VideoMuteState { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a ICommunicationMonitorMessenger /// public class ICommunicationMonitorMessenger : MessengerBase { private readonly ICommunicationMonitor _communicationMonitor; public ICommunicationMonitorMessenger(string key, string messagePath, ICommunicationMonitor device) : base(key, messagePath, device as IKeyName) { _communicationMonitor = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => { SendFullStatus(id); }); AddAction("/commStatus", (id, content) => { SendFullStatus(id); }); _communicationMonitor.CommunicationMonitor.StatusChange += (sender, args) => { PostStatusMessage(JToken.FromObject(new { commMonitor = new CommunicationMonitorProps { IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, Status = _communicationMonitor.CommunicationMonitor.Status } })); }; } private void SendFullStatus(string id = null) { PostStatusMessage(new CommunicationMonitorState { CommunicationMonitor = new CommunicationMonitorProps { IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, Status = _communicationMonitor.CommunicationMonitor.Status }, }, id); } } /// /// Represents a CommunicationMonitorState /// public class CommunicationMonitorState : DeviceStateMessageBase { [JsonProperty("commMonitor", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the CommunicationMonitor /// public CommunicationMonitorProps CommunicationMonitor { get; set; } } public class CommunicationMonitorProps { /// /// For devices that implement ICommunicationMonitor, reports the online status of the device /// [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] public bool? IsOnline { get; set; } /// /// For devices that implement ICommunicationMonitor, reports the online status of the device /// [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(StringEnumConverter))] public MonitorStatus Status { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs ================================================ using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IDspPresetsMessenger /// public class IDspPresetsMessenger : MessengerBase { private readonly IDspPresets device; public IDspPresetsMessenger(string key, string messagePath, IDspPresets device) : base(key, messagePath, device as IKeyName) { this.device = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/dspPresetStatus", (id, content) => SendFullStatus(id)); AddAction("/recallPreset", (id, content) => { var presetKey = content.ToObject(); if (!string.IsNullOrEmpty(presetKey)) { device.RecallPreset(presetKey); } }); } private void SendFullStatus(string id = null) { var message = new IHasDspPresetsStateMessage { Presets = device.Presets }; PostStatusMessage(message, id); } } /// /// Represents a IHasDspPresetsStateMessage /// public class IHasDspPresetsStateMessage : DeviceStateMessageBase { [JsonProperty("presets")] public Dictionary Presets { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Provides messaging functionality for managing room combination scenarios and partition states in an instance. Enables external systems to interact with the room combiner via /// predefined actions and status updates. /// /// This class facilitates communication with an by /// exposing actions for toggling modes, managing partitions, and setting room combination scenarios. It also /// listens for feedback changes and broadcasts status updates to connected systems. Typical usage involves /// registering actions for external commands and handling feedback events to synchronize state changes. public class IEssentialsRoomCombinerMessenger : MessengerBase { private readonly IEssentialsRoomCombiner _roomCombiner; /// /// Initializes a new instance of the class, which facilitates /// messaging for an instance. /// /// This class is designed to enable communication and interaction with an through the specified messaging path. Ensure that the parameter is not null when creating an instance. /// The unique key identifying this messenger instance. /// The path used for messaging operations. /// The instance associated with this messenger. public IEssentialsRoomCombinerMessenger(string key, string messagePath, IEssentialsRoomCombiner roomCombiner) : base(key, messagePath, roomCombiner as IKeyName) { _roomCombiner = roomCombiner; } /// /// Registers actions and event handlers for managing room combination scenarios and partition states. /// /// This method sets up various actions that can be triggered via specific endpoints, /// such as toggling modes, setting room combination scenarios, and managing partition states. It also /// subscribes to feedback events to update the status when changes occur in room combination scenarios or /// partition states. protected override void RegisterActions() { AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/combinerStatus", (id, content) => SendFullStatus(id)); AddAction("/setAutoMode", (id, content) => { _roomCombiner.SetAutoMode(); }); AddAction("/setManualMode", (id, content) => { _roomCombiner.SetManualMode(); }); AddAction("/toggleMode", (id, content) => { _roomCombiner.ToggleMode(); }); AddAction("/togglePartitionState", (id, content) => { try { var partitionKey = content.ToObject(); _roomCombiner.TogglePartitionState(partitionKey); } catch (Exception e) { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Error toggling partition state: {e}", this); } }); AddAction("/setRoomCombinationScenario", (id, content) => { try { var scenarioKey = content.ToObject(); _roomCombiner.SetRoomCombinationScenario(scenarioKey); } catch (Exception e) { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Error toggling partition state: {e}", this); } }); _roomCombiner.RoomCombinationScenarioChanged += (sender, args) => { SendFullStatus(); }; _roomCombiner.IsInAutoModeFeedback.OutputChange += (sender, args) => { var message = new { isInAutoMode = _roomCombiner.IsInAutoModeFeedback.BoolValue }; PostStatusMessage(JToken.FromObject(message)); }; foreach (var partition in _roomCombiner.Partitions) { partition.PartitionPresentFeedback.OutputChange += (sender, args) => { var message = new { partitions = _roomCombiner.Partitions }; PostStatusMessage(JToken.FromObject(message)); }; } } private void SendFullStatus(string id = null) { try { var rooms = new List(); foreach (var room in _roomCombiner.Rooms) { rooms.Add(new RoomCombinerRoom { Key = room.Key, Name = room.Name }); } var message = new IEssentialsRoomCombinerStateMessage { DisableAutoMode = _roomCombiner.DisableAutoMode, IsInAutoMode = _roomCombiner.IsInAutoMode, CurrentScenario = _roomCombiner.CurrentScenario, Rooms = rooms, RoomCombinationScenarios = _roomCombiner.RoomCombinationScenarios, Partitions = _roomCombiner.Partitions }; PostStatusMessage(message, id); } catch (Exception e) { this.LogException(e, "Error sending full status"); } } private class RoomCombinerRoom : IKeyName { [JsonProperty("key")] /// /// Gets or sets the Key /// public string Key { get; set; } [JsonProperty("name")] /// /// Gets or sets the Name /// public string Name { get; set; } } } /// /// Represents the state message for a room combiner system, providing information about the current configuration, /// operational mode, and associated rooms, partitions, and scenarios. /// /// This class is used to encapsulate the state of a room combiner system, including its current /// mode of operation, active room combination scenario, and the list of rooms and partitions involved. It is /// typically serialized and transmitted to communicate the state of the system. public class IEssentialsRoomCombinerStateMessage : DeviceStateMessageBase { /// /// Gets or sets a value indicating whether automatic mode is disabled. /// [JsonProperty("disableAutoMode", NullValueHandling = NullValueHandling.Ignore)] public bool DisableAutoMode { get; set; } /// /// Gets or sets a value indicating whether the system is operating in automatic mode. /// [JsonProperty("isInAutoMode", NullValueHandling = NullValueHandling.Ignore)] public bool IsInAutoMode { get; set; } /// /// Gets or sets the current room combination scenario. /// [JsonProperty("currentScenario", NullValueHandling = NullValueHandling.Ignore)] public IRoomCombinationScenario CurrentScenario { get; set; } /// /// Gets or sets the collection of rooms associated with the entity. /// [JsonProperty("rooms", NullValueHandling = NullValueHandling.Ignore)] public List Rooms { get; set; } /// /// Gets or sets the collection of room combination scenarios. /// [JsonProperty("roomCombinationScenarios", NullValueHandling = NullValueHandling.Ignore)] public List RoomCombinationScenarios { get; set; } /// /// Gets or sets the collection of partition controllers. /// [JsonProperty("partitions", NullValueHandling = NullValueHandling.Ignore)] public List Partitions { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs ================================================ using Newtonsoft.Json; using PepperDash.Essentials.Devices.Common.Cameras; using System; using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Messenger for devices that implement the IHasCameras interface. /// [Obsolete("Use IHasCamerasWithControlsMessenger instead. This class will be removed in a future version")] public class IHasCamerasMessenger : MessengerBase { /// /// Device being bridged that implements IHasCameras interface. /// public IHasCameras CameraController { get; private set; } /// /// Messenger for devices that implement IHasCameras interface. /// /// /// /// /// public IHasCamerasMessenger(string key, string messagePath, IHasCameras cameraController) : base(key, messagePath, cameraController) { CameraController = cameraController ?? throw new ArgumentNullException("cameraController"); CameraController.CameraSelected += CameraController_CameraSelected; } private void CameraController_CameraSelected(object sender, CameraSelectedEventArgs e) { PostStatusMessage(new IHasCamerasStateMessage { SelectedCamera = e.SelectedCamera }); } /// /// Registers the actions for this messenger. /// /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, context) => SendFullStatus(id)); AddAction("/cameraListStatus", (id, content) => SendFullStatus(id)); AddAction("/selectCamera", (id, content) => { var cameraKey = content?.ToObject(); if (!string.IsNullOrEmpty(cameraKey)) { CameraController.SelectCamera(cameraKey); } else { throw new ArgumentException("Content must be a string representing the camera key"); } }); } private void SendFullStatus(string clientId) { var state = new IHasCamerasStateMessage { CameraList = CameraController.Cameras, SelectedCamera = CameraController.SelectedCamera }; PostStatusMessage(state, clientId); } } /// /// State message for devices that implement the IHasCameras interface. /// public class IHasCamerasStateMessage : DeviceStateMessageBase { /// /// List of cameras available in the device. /// [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] public List CameraList { get; set; } /// /// The currently selected camera on the device. /// [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] public CameraBase SelectedCamera { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasWithControlMessenger.cs ================================================ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Cameras; using System; using System.Collections.Generic; using System.Linq; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Messenger for devices that implement the IHasCameras interface. /// public class IHasCamerasWithControlMessenger : MessengerBase { /// /// Device being bridged that implements IHasCameras interface. /// public IHasCamerasWithControls CameraController { get; private set; } /// /// Messenger for devices that implement IHasCameras interface. /// /// /// /// /// public IHasCamerasWithControlMessenger(string key, string messagePath, IHasCamerasWithControls cameraController) : base(key, messagePath, cameraController) { CameraController = cameraController ?? throw new ArgumentNullException("cameraController"); CameraController.CameraSelected += CameraController_CameraSelected; } private void CameraController_CameraSelected(object sender, CameraSelectedEventArgs e) { var selectedCamera = new KeyName { Key = e.SelectedCamera.Key, Name = e.SelectedCamera.Name }; PostStatusMessage(new IHasCamerasWithControlsStateMessage { SelectedCamera = selectedCamera }); } /// /// Registers the actions for this messenger. /// /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, context) => SendFullStatus(id)); AddAction("/cameraListStatus", (id, content) => SendFullStatus(id)); AddAction("/selectCamera", (id, content) => { var cameraKey = content?.ToObject(); if (!string.IsNullOrEmpty(cameraKey)) { CameraController.SelectCamera(cameraKey); } else { throw new ArgumentException("Content must be a string representing the camera key"); } }); } private void SendFullStatus(string clientId) { var cameraList = new List(); KeyName selectedCamera = null; foreach (var cam in CameraController.Cameras) { cameraList.Add(new KeyName{ Key = cam.Key, Name = cam.Name }); } if (CameraController.SelectedCamera != null) { selectedCamera = new KeyName { Key = CameraController.SelectedCamera.Key, Name = CameraController.SelectedCamera.Name }; } var state = new IHasCamerasWithControlsStateMessage { CameraList = cameraList, SelectedCamera = selectedCamera }; PostStatusMessage(state, clientId); } } /// /// State message for devices that implement the IHasCameras interface. /// public class IHasCamerasWithControlsStateMessage : DeviceStateMessageBase { /// /// List of cameras available in the device. /// [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] public List CameraList { get; set; } /// /// The currently selected camera on the device. /// [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] public IKeyName SelectedCamera { get; set; } } class KeyName : IKeyName { public string Key { get; set; } public string Name { get; set; } public KeyName() { Key = ""; Name = ""; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IHasCurrentSourceInfoMessenger /// public class IHasCurrentSourceInfoMessenger : MessengerBase { private readonly IHasCurrentSourceInfoChange sourceDevice; public IHasCurrentSourceInfoMessenger(string key, string messagePath, IHasCurrentSourceInfoChange device) : base(key, messagePath, device as IKeyName) { sourceDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/currentSourceInfoStatus", (id, content) => SendFullStatus(id)); sourceDevice.CurrentSourceChange += (sender, e) => { switch (e) { case ChangeType.DidChange: { PostStatusMessage(JToken.FromObject(new { currentSourceKey = string.IsNullOrEmpty(sourceDevice.CurrentSourceInfoKey) ? string.Empty : sourceDevice.CurrentSourceInfoKey, currentSource = sourceDevice.CurrentSourceInfo })); break; } } }; } private void SendFullStatus(string id = null) { var message = new CurrentSourceStateMessage { CurrentSourceKey = sourceDevice.CurrentSourceInfoKey, CurrentSource = sourceDevice.CurrentSourceInfo }; PostStatusMessage(message, id); } } /// /// Represents a CurrentSourceStateMessage /// public class CurrentSourceStateMessage : DeviceStateMessageBase { /// /// Gets or sets the CurrentSourceKey /// [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string CurrentSourceKey { get; set; } /// /// Gets or sets the CurrentSource /// [JsonProperty("currentSource")] public SourceListItem CurrentSource { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IHasInputsMessenger /// public class IHasInputsMessenger : MessengerBase { private readonly IHasInputs itemDevice; /// /// Constructs a messenger for a device that implements IHasInputs /// /// /// /// public IHasInputsMessenger(string key, string messagePath, IHasInputs device) : base(key, messagePath, device) { itemDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, context) => SendFullStatus(id)); AddAction("/inputStatus", (id, content) => SendFullStatus(id)); itemDevice.Inputs.ItemsUpdated += (sender, args) => { SendFullStatus(); }; itemDevice.Inputs.CurrentItemChanged += (sender, args) => { SendFullStatus(); }; foreach (var input in itemDevice.Inputs.Items) { var key = input.Key; var localItem = input.Value; AddAction($"/{key}", (id, content) => { localItem.Select(); }); localItem.ItemUpdated += (sender, args) => { SendFullStatus(); }; } } private void SendFullStatus(string id = null) { try { this.LogInformation("Sending full status"); var stateObject = new IHasInputsStateMessage { Inputs = new Inputs { Items = itemDevice.Inputs.Items, CurrentItem = itemDevice.Inputs.CurrentItem } }; PostStatusMessage(stateObject, id); } catch (Exception e) { this.LogError("Error sending full status: {0}", e.Message); } } } /// /// Represents a IHasInputsStateMessage /// public class IHasInputsStateMessage : DeviceStateMessageBase { [JsonProperty("inputs")] /// /// Gets or sets the Inputs /// public Inputs Inputs { get; set; } } /// /// Represents a Inputs /// public class Inputs { [JsonProperty("items")] public Dictionary Items { get; set; } [JsonProperty("currentItem")] /// /// Gets or sets the CurrentItem /// public TKey CurrentItem { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IHasPowerControlWithFeedbackMessenger /// public class IHasPowerControlWithFeedbackMessenger : MessengerBase { private readonly IHasPowerControlWithFeedback _powerControl; /// /// Initializes a new instance of the class. /// /// The key. /// The message path. /// The power control device public IHasPowerControlWithFeedbackMessenger(string key, string messagePath, IHasPowerControlWithFeedback powerControl) : base(key, messagePath, powerControl as IKeyName) { _powerControl = powerControl; } /// /// SendFullStatus method /// public void SendFullStatus(string id = null) { var messageObj = new PowerControlWithFeedbackStateMessage { PowerState = _powerControl.PowerIsOnFeedback.BoolValue }; PostStatusMessage(messageObj, id); } /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/powerStatus", (id, content) => SendFullStatus(id)); _powerControl.PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; ; } private void PowerIsOnFeedback_OutputChange(object sender, FeedbackEventArgs args) { PostStatusMessage(JToken.FromObject(new { powerState = args.BoolValue }) ); } } /// /// Represents a PowerControlWithFeedbackStateMessage /// public class PowerControlWithFeedbackStateMessage : DeviceStateMessageBase { /// /// Power State /// [JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] public bool? PowerState { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IHasScheduleAwarenessMessenger /// public class IHasScheduleAwarenessMessenger : MessengerBase { /// /// Gets or sets the ScheduleSource /// public IHasScheduleAwareness ScheduleSource { get; private set; } public IHasScheduleAwarenessMessenger(string key, IHasScheduleAwareness scheduleSource, string messagePath) : base(key, messagePath, scheduleSource as IKeyName) { ScheduleSource = scheduleSource ?? throw new ArgumentNullException("scheduleSource"); ScheduleSource.CodecSchedule.MeetingsListHasChanged += new EventHandler(CodecSchedule_MeetingsListHasChanged); ScheduleSource.CodecSchedule.MeetingEventChange += new EventHandler(CodecSchedule_MeetingEventChange); } protected override void RegisterActions() { AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject(id)); AddAction("/schedule/status", (id, content) => SendFullScheduleObject(id)); } private void CodecSchedule_MeetingEventChange(object sender, MeetingEventArgs e) { PostStatusMessage(JToken.FromObject(new MeetingChangeMessage { MeetingChange = new MeetingChange { ChangeType = e.ChangeType.ToString(), Meeting = e.Meeting } }) ); } private void CodecSchedule_MeetingsListHasChanged(object sender, EventArgs e) { SendFullScheduleObject(); } /// /// Helper method to send the full schedule data /// private void SendFullScheduleObject(string id = null) { PostStatusMessage(new FullScheduleMessage { Meetings = ScheduleSource.CodecSchedule.Meetings, MeetingWarningMinutes = ScheduleSource.CodecSchedule.MeetingWarningMinutes }, id); } } /// /// Represents a FullScheduleMessage /// public class FullScheduleMessage : DeviceStateMessageBase { /// /// Gets or sets the Meetings /// [JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)] public List Meetings { get; set; } /// /// Gets or sets the MeetingWarningMinutes /// [JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)] public int MeetingWarningMinutes { get; set; } } /// /// Represents a MeetingChangeMessage /// public class MeetingChangeMessage { /// /// Gets or sets the MeetingChange /// [JsonProperty("meetingChange", NullValueHandling = NullValueHandling.Ignore)] public MeetingChange MeetingChange { get; set; } } /// /// Represents a MeetingChange /// public class MeetingChange { /// /// Gets or sets the ChangeType /// [JsonProperty("changeType", NullValueHandling = NullValueHandling.Ignore)] public string ChangeType { get; set; } /// /// Gets or sets the Meeting /// [JsonProperty("meeting", NullValueHandling = NullValueHandling.Ignore)] public Meeting Meeting { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs ================================================ using System; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IHumiditySensorMessenger /// public class IHumiditySensorMessenger : MessengerBase { private readonly IHumiditySensor device; public IHumiditySensorMessenger(string key, IHumiditySensor device, string messagePath) : base(key, messagePath, device as IKeyName) { this.device = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/humidityStatus", (id, content) => SendFullStatus(id)); device.HumidityFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); } private void SendFullStatus(string id = null) { var state = new IHumiditySensorStateMessage { Humidity = string.Format("{0}%", device.HumidityFeedback.UShortValue) }; PostStatusMessage(state, id); } } /// /// Represents a IHumiditySensorStateMessage /// public class IHumiditySensorStateMessage : DeviceStateMessageBase { /// /// Gets or sets the Humidity /// [JsonProperty("humidity")] public string Humidity { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs ================================================ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a ILevelControlsMessenger /// public class ILevelControlsMessenger : MessengerBase { private ILevelControls levelControlsDevice; public ILevelControlsMessenger(string key, string messagePath, ILevelControls device) : base(key, messagePath, device as IKeyName) { levelControlsDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, context) => SendFullStatus(id)); AddAction("/levelStats", (id, content) => SendFullStatus(id)); foreach (var levelControl in levelControlsDevice.LevelControlPoints) { // reassigning here just in case of lambda closure issues var key = levelControl.Key; var control = levelControl.Value; AddAction($"/{key}/level", (id, content) => { var request = content.ToObject>(); control.SetVolume(request.Value); }); AddAction($"/{key}/muteToggle", (id, content) => { control.MuteToggle(); }); AddAction($"/{key}/muteOn", (id, content) => control.MuteOn()); AddAction($"/{key}/muteOff", (id, content) => control.MuteOff()); AddAction($"/{key}/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => control.VolumeUp(b))); AddAction($"/{key}/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => control.VolumeDown(b))); control.VolumeLevelFeedback.OutputChange += (o, a) => PostStatusMessage(JToken.FromObject(new { levelControls = new Dictionary { {key, new Volume{Level = a.IntValue} } } })); control.MuteFeedback.OutputChange += (o, a) => PostStatusMessage(JToken.FromObject(new { levelControls = new Dictionary { {key, new Volume{Muted = a.BoolValue} } } })); } } private void SendFullStatus(string id = null) { var message = new LevelControlStateMessage { Levels = levelControlsDevice.LevelControlPoints.ToDictionary(kv => kv.Key, kv => new Volume { Level = kv.Value.VolumeLevelFeedback.IntValue, Muted = kv.Value.MuteFeedback.BoolValue }) }; PostStatusMessage(message, id); } } /// /// Represents a LevelControlStateMessage /// public class LevelControlStateMessage : DeviceStateMessageBase { [JsonProperty("levelControls")] public Dictionary Levels { get; set; } } /// /// Represents a LevelControlRequestMessage /// public class LevelControlRequestMessage { [JsonProperty("key")] /// /// Gets or sets the Key /// public string Key { get; set; } [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] public ushort? Level { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Routing; using Serilog.Events; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Messenger for devices that implment IMatrixRouting /// public class IMatrixRoutingMessenger : MessengerBase { private readonly IMatrixRouting matrixDevice; public IMatrixRoutingMessenger(string key, string messagePath, IMatrixRouting device) : base(key, messagePath, device as IKeyName) { matrixDevice = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/matrixStatus", (id, content) => SendFullStatus(id)); AddAction("/route", (id, content) => { var request = content.ToObject(); matrixDevice.Route(request.InputKey, request.OutputKey, request.RouteType); }); foreach (var output in matrixDevice.OutputSlots) { var key = output.Key; var outputSlot = output.Value; outputSlot.OutputSlotChanged += (sender, args) => { PostStatusMessage(JToken.FromObject(new { outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)) })); }; } foreach (var input in matrixDevice.InputSlots) { var key = input.Key; var inputSlot = input.Value; inputSlot.VideoSyncChanged += (sender, args) => { PostStatusMessage(JToken.FromObject(new { inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)) })); }; inputSlot.IsOnline.OutputChange += (sender, args) => { PostStatusMessage(JToken.FromObject(new { inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)) })); }; } } private void SendFullStatus(string id = null) { try { Debug.LogMessage(LogEventLevel.Verbose, "InputCount: {inputCount}, OutputCount: {outputCount}", this, matrixDevice.InputSlots.Count, matrixDevice.OutputSlots.Count); var message = new MatrixStateMessage { Outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)), Inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)), }; PostStatusMessage(message, id); } catch (Exception e) { Debug.LogMessage(e, "Exception Getting full status: {@exception}", this, e); } } } /// /// Represents a MatrixStateMessage /// public class MatrixStateMessage : DeviceStateMessageBase { [JsonProperty("outputs")] public Dictionary Outputs; [JsonProperty("inputs")] public Dictionary Inputs; } /// /// Represents a RoutingInput /// public class RoutingInput { private IRoutingInputSlot _input; [JsonProperty("txDeviceKey", NullValueHandling = NullValueHandling.Ignore)] public string TxDeviceKey => _input?.TxDeviceKey; [JsonProperty("slotNumber", NullValueHandling = NullValueHandling.Ignore)] public int? SlotNumber => _input?.SlotNumber; [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] [JsonProperty("supportedSignalTypes", NullValueHandling = NullValueHandling.Ignore)] public eRoutingSignalType? SupportedSignalTypes => _input?.SupportedSignalTypes; [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name => _input?.Name; [JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)] public bool? IsOnline => _input?.IsOnline.BoolValue; [JsonProperty("videoSyncDetected", NullValueHandling = NullValueHandling.Ignore)] public bool? VideoSyncDetected => _input?.VideoSyncDetected; [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key => _input?.Key; public RoutingInput(IRoutingInputSlot input) { _input = input; } } /// /// Represents a RoutingOutput /// public class RoutingOutput { private IRoutingOutputSlot _output; public RoutingOutput(IRoutingOutputSlot output) { _output = output; } [JsonProperty("rxDeviceKey")] public string RxDeviceKey => _output.RxDeviceKey; [JsonProperty("currentRoutes")] public Dictionary CurrentRoutes => _output.CurrentRoutes.ToDictionary(kvp => kvp.Key.ToString(), kvp => new RoutingInput(kvp.Value)); [JsonProperty("slotNumber")] public int SlotNumber => _output.SlotNumber; [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] [JsonProperty("supportedSignalTypes")] public eRoutingSignalType SupportedSignalTypes => _output.SupportedSignalTypes; [JsonProperty("name")] public string Name => _output.Name; [JsonProperty("key")] public string Key => _output.Key; } /// /// Represents a MatrixRouteRequest /// public class MatrixRouteRequest { [JsonProperty("outputKey")] /// /// Gets or sets the OutputKey /// public string OutputKey { get; set; } [JsonProperty("inputKey")] /// /// Gets or sets the InputKey /// public string InputKey { get; set; } [JsonProperty("routeType")] /// /// Gets or sets the RouteType /// public eRoutingSignalType RouteType { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs ================================================ using System; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IProjectorScreenLiftControlMessenger /// public class IProjectorScreenLiftControlMessenger : MessengerBase { private readonly IProjectorScreenLiftControl device; /// /// Initializes a new instance of the class. /// /// message key /// message path /// screen lift device public IProjectorScreenLiftControlMessenger(string key, string messagePath, IProjectorScreenLiftControl screenLiftDevice) : base(key, messagePath, screenLiftDevice as IKeyName) { device = screenLiftDevice; } /// /// Registers the actions for the messenger. /// protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/screenliftStatus", (id, content) => SendFullStatus(id)); AddAction("/raise", (id, content) => { device.Raise(); }); AddAction("/lower", (id, content) => { device.Lower(); }); device.PositionChanged += Device_PositionChanged; } private void Device_PositionChanged(object sender, EventArgs e) { var state = new { inUpPosition = device.InUpPosition }; PostStatusMessage(JToken.FromObject(state)); } private void SendFullStatus(string id = null) { var state = new ScreenLiftStateMessage { InUpPosition = device.InUpPosition, Type = device.Type, DisplayDeviceKey = device.DisplayDeviceKey }; PostStatusMessage(state, id); } } /// /// Represents a ScreenLiftStateMessage /// public class ScreenLiftStateMessage : DeviceStateMessageBase { /// /// Gets or sets the InUpPosition /// [JsonProperty("inUpPosition", NullValueHandling = NullValueHandling.Ignore)] public bool? InUpPosition { get; set; } /// /// Gets or sets the DisplayDeviceKey /// [JsonProperty("displayDeviceKey", NullValueHandling = NullValueHandling.Ignore)] public string DisplayDeviceKey { get; set; } /// /// Gets or sets the Type /// [JsonConverter(typeof(StringEnumConverter))] [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] public eScreenLiftControlType Type { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs ================================================ using System; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a RunRouteActionMessenger /// public class RunRouteActionMessenger : MessengerBase { /// /// Gets or sets the RoutingDevice /// public IRunRouteAction RoutingDevice { get; private set; } public RunRouteActionMessenger(string key, IRunRouteAction routingDevice, string messagePath) : base(key, messagePath, routingDevice as IKeyName) { RoutingDevice = routingDevice ?? throw new ArgumentNullException("routingDevice"); if (RoutingDevice is IRoutingSink routingSink) { routingSink.CurrentSourceChange += RoutingSink_CurrentSourceChange; } } private void RoutingSink_CurrentSourceChange(SourceListItem info, ChangeType type) { SendRoutingFullMessageObject(); } protected override void RegisterActions() { AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject(id)); AddAction("/routingStatus", (id, content) => SendRoutingFullMessageObject(id)); AddAction("/source", (id, content) => { var c = content.ToObject(); // assume no sourceListKey var sourceListKey = string.Empty; if (!string.IsNullOrEmpty(c.SourceListKey)) { // Check for source list in content of message sourceListKey = c.SourceListKey; } RoutingDevice.RunRouteAction(c.SourceListItemKey, sourceListKey); }); if (RoutingDevice is IRoutingSink sinkDevice) { sinkDevice.CurrentSourceChange += (o, a) => SendRoutingFullMessageObject(); } } /// /// Helper method to update full status of the routing device /// private void SendRoutingFullMessageObject(string id = null) { if (RoutingDevice is IRoutingSink sinkDevice) { var sourceKey = sinkDevice.CurrentSourceInfoKey; if (string.IsNullOrEmpty(sourceKey)) sourceKey = "none"; PostStatusMessage(new RoutingStateMessage { SelectedSourceKey = sourceKey }); } } } /// /// Represents a RoutingStateMessage /// public class RoutingStateMessage : DeviceStateMessageBase { /// /// Gets or sets the SelectedSourceKey /// [JsonProperty("selectedSourceKey")] public string SelectedSourceKey { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a ISelectableItemsMessenger /// public class ISelectableItemsMessenger : MessengerBase { private readonly ISelectableItems itemDevice; private readonly string _propName; private List _itemKeys = new List(); /// /// Constructs a messenger for a device that implements ISelectableItems /// /// /// /// /// public ISelectableItemsMessenger(string key, string messagePath, ISelectableItems device, string propName) : base(key, messagePath, device as IKeyName) { itemDevice = device; _propName = propName; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, context) => SendFullStatus(id) ); AddAction("/itemsStatus", (id, content) => SendFullStatus(id)); AddAction("/selectItem", (id, content) => { try { var key = content.ToObject(); if (key == null) { this.LogError("No key specified to select"); return; } if (itemDevice.Items.ContainsKey((TKey)Convert.ChangeType(key, typeof(TKey)))) { itemDevice.Items[(TKey)Convert.ChangeType(key, typeof(TKey))].Select(); } else { this.LogError("Key {0} not found in items", key); } } catch (Exception e) { this.LogError("Error selecting item: {0}", e.Message); } }); itemDevice.ItemsUpdated += (sender, args) => { SetItems(); }; itemDevice.CurrentItemChanged += (sender, args) => { SendFullStatus(); }; SetItems(); } /// /// Sets the items and registers their update events /// private void SetItems() { if (_itemKeys != null && _itemKeys.Count > 0) { /// Clear out any existing item actions foreach (var item in _itemKeys) { RemoveAction($"/{item}"); } _itemKeys.Clear(); } foreach (var item in itemDevice.Items) { var key = item.Key; var localItem = item.Value; AddAction($"/{key}", (id, content) => { localItem.Select(); }); _itemKeys.Add(key.ToString()); localItem.ItemUpdated -= LocalItem_ItemUpdated; localItem.ItemUpdated += LocalItem_ItemUpdated; } } private void LocalItem_ItemUpdated(object sender, EventArgs e) { SendFullStatus(); } private void SendFullStatus(string id = null) { try { this.LogInformation("Sending full status"); var stateObject = new ISelectableItemsStateMessage { Items = itemDevice.Items, CurrentItem = itemDevice.CurrentItem }; PostStatusMessage(stateObject, id); } catch (Exception e) { this.LogError("Error sending full status: {0}", e.Message); } } } /// /// Represents a ISelectableItemsStateMessage /// public class ISelectableItemsStateMessage : DeviceStateMessageBase { /// /// Gets or sets the Items /// [JsonProperty("items")] public Dictionary Items { get; set; } /// /// Gets or sets the CurrentItem /// [JsonProperty("currentItem")] public TKey CurrentItem { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IShutdownPromptTimerMessenger /// public class IShutdownPromptTimerMessenger : MessengerBase { private readonly IShutdownPromptTimer _room; public IShutdownPromptTimerMessenger(string key, string messagePath, IShutdownPromptTimer room) : base(key, messagePath, room as IKeyName) { _room = room; } protected override void RegisterActions() { AddAction("/status", (id, content) => SendFullStatus(id)); AddAction("/shutdownPromptStatus", (id, content) => SendFullStatus(id)); AddAction("/setShutdownPromptSeconds", (id, content) => { var response = content.ToObject(); _room.SetShutdownPromptSeconds(response); SendFullStatus(); }); AddAction("/shutdownStart", (id, content) => _room.StartShutdown(eShutdownType.Manual)); AddAction("/shutdownEnd", (id, content) => _room.ShutdownPromptTimer.Finish()); AddAction("/shutdownCancel", (id, content) => _room.ShutdownPromptTimer.Cancel()); _room.ShutdownPromptTimer.HasStarted += (sender, args) => { PostEventMessage("timerStarted"); }; _room.ShutdownPromptTimer.HasFinished += (sender, args) => { PostEventMessage("timerFinished"); }; _room.ShutdownPromptTimer.WasCancelled += (sender, args) => { PostEventMessage("timerCancelled"); }; _room.ShutdownPromptTimer.SecondsRemainingFeedback.OutputChange += (sender, args) => { var status = new { secondsRemaining = _room.ShutdownPromptTimer.SecondsRemainingFeedback.IntValue, percentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue }; PostStatusMessage(JToken.FromObject(status)); }; } private void SendFullStatus(string id = null) { var status = new IShutdownPromptTimerStateMessage { ShutdownPromptSeconds = _room.ShutdownPromptTimer.SecondsToCount, SecondsRemaining = _room.ShutdownPromptTimer.SecondsRemainingFeedback.IntValue, PercentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue }; PostStatusMessage(status, id); } } /// /// Represents a IShutdownPromptTimerStateMessage /// public class IShutdownPromptTimerStateMessage : DeviceStateMessageBase { /// /// Gets or sets the SecondsRemaining /// [JsonProperty("secondsRemaining")] public int SecondsRemaining { get; set; } /// /// Gets or sets the PercentageRemaining /// [JsonProperty("percentageRemaining")] public int PercentageRemaining { get; set; } /// /// Gets or sets the ShutdownPromptSeconds /// [JsonProperty("shutdownPromptSeconds")] public int ShutdownPromptSeconds { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs ================================================ using System; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a ISwitchedOutputMessenger /// public class ISwitchedOutputMessenger : MessengerBase { private readonly ISwitchedOutput device; public ISwitchedOutputMessenger(string key, ISwitchedOutput device, string messagePath) : base(key, messagePath, device as IKeyName) { this.device = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/switchedOutputStatus", (id, content) => SendFullStatus(id)); AddAction("/on", (id, content) => { device.On(); }); AddAction("/off", (id, content) => { device.Off(); }); device.OutputIsOnFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); } private void SendFullStatus(string id = null) { var state = new ISwitchedOutputStateMessage { IsOn = device.OutputIsOnFeedback.BoolValue }; PostStatusMessage(state, id); } } /// /// Represents a ISwitchedOutputStateMessage /// public class ISwitchedOutputStateMessage : DeviceStateMessageBase { /// /// Gets or sets the IsOn /// [JsonProperty("isOn")] public bool IsOn { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs ================================================ using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a ITechPasswordMessenger /// public class ITechPasswordMessenger : MessengerBase { private readonly ITechPassword _room; public ITechPasswordMessenger(string key, string messagePath, ITechPassword room) : base(key, messagePath, room as IKeyName) { _room = room; } protected override void RegisterActions() { AddAction("/status", (id, content) => SendFullStatus(id)); AddAction("/techPasswordStatus", (id, content) => SendFullStatus(id)); AddAction("/validateTechPassword", (id, content) => { var password = content.Value("password"); _room.ValidateTechPassword(password); }); AddAction("/setTechPassword", (id, content) => { var response = content.ToObject(); _room.SetTechPassword(response.OldPassword, response.NewPassword); }); _room.TechPasswordChanged += (sender, args) => { PostEventMessage("passwordChangedSuccessfully"); }; _room.TechPasswordValidateResult += (sender, args) => { var evt = new ITechPasswordEventMessage { IsValid = args.IsValid }; PostEventMessage(evt, "passwordValidationResult"); }; } private void SendFullStatus(string id = null) { var status = new ITechPasswordStateMessage { TechPasswordLength = _room.TechPasswordLength }; PostStatusMessage(status, id); } } /// /// Represents a ITechPasswordStateMessage /// public class ITechPasswordStateMessage : DeviceStateMessageBase { [JsonProperty("techPasswordLength", NullValueHandling = NullValueHandling.Ignore)] public int? TechPasswordLength { get; set; } } /// /// Represents a ITechPasswordEventMessage /// public class ITechPasswordEventMessage : DeviceEventMessageBase { [JsonProperty("isValid", NullValueHandling = NullValueHandling.Ignore)] public bool? IsValid { get; set; } } internal class SetTechPasswordContent { [JsonProperty("oldPassword")] /// /// Gets or sets the OldPassword /// public string OldPassword { get; set; } [JsonProperty("newPassword")] /// /// Gets or sets the NewPassword /// public string NewPassword { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs ================================================ using System; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a ITemperatureSensorMessenger /// public class ITemperatureSensorMessenger : MessengerBase { private readonly ITemperatureSensor device; public ITemperatureSensorMessenger(string key, ITemperatureSensor device, string messagePath) : base(key, messagePath, device as IKeyName) { this.device = device; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/temperatureStatus", (id, content) => SendFullStatus(id)); AddAction("/setTemperatureUnitsToCelcius", (id, content) => { device.SetTemperatureFormat(true); }); AddAction("/setTemperatureUnitsToFahrenheit", (id, content) => { device.SetTemperatureFormat(false); }); device.TemperatureFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); device.TemperatureInCFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); } private void SendFullStatus(string id = null) { // format the temperature to a string with one decimal place var tempString = string.Format("{0}.{1}", device.TemperatureFeedback.UShortValue / 10, device.TemperatureFeedback.UShortValue % 10); var state = new ITemperatureSensorStateMessage { Temperature = tempString, TemperatureInCelsius = device.TemperatureInCFeedback.BoolValue }; PostStatusMessage(state, id); } } /// /// Represents a ITemperatureSensorStateMessage /// public class ITemperatureSensorStateMessage : DeviceStateMessageBase { /// /// Gets or sets the Temperature /// [JsonProperty("temperature")] public string Temperature { get; set; } /// /// Gets or sets the TemperatureInCelsius /// [JsonProperty("temperatureInCelsius")] public bool TemperatureInCelsius { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Lighting; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a ILightingScenesMessenger /// public class ILightingScenesMessenger : MessengerBase { private ILightingScenes lightingScenesDevice; public ILightingScenesMessenger(string key, ILightingScenes device, string messagePath) : base(key, messagePath, device as IKeyName) { lightingScenesDevice = device ?? throw new ArgumentNullException("device"); lightingScenesDevice.LightingSceneChange += new EventHandler(LightingDevice_LightingSceneChange); } private void LightingDevice_LightingSceneChange(object sender, LightingSceneChangeEventArgs e) { var state = new LightingBaseStateMessage { CurrentLightingScene = e.CurrentLightingScene }; PostStatusMessage(state); } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/lightingStatus", (id, content) => SendFullStatus(id)); AddAction("/selectScene", (id, content) => { var s = content.ToObject(); lightingScenesDevice.SelectScene(s); }); if (!(lightingScenesDevice is ILightingScenesDynamic lightingScenesDynamic)) return; lightingScenesDynamic.LightingScenesUpdated += (s, e) => SendFullStatus(); } private void SendFullStatus(string id = null) { var state = new LightingBaseStateMessage { Scenes = lightingScenesDevice.LightingScenes, CurrentLightingScene = lightingScenesDevice.CurrentLightingScene }; PostStatusMessage(state, id); } } /// /// Represents a LightingBaseStateMessage /// public class LightingBaseStateMessage : DeviceStateMessageBase { /// /// Gets or sets the Scenes /// [JsonProperty("scenes", NullValueHandling = NullValueHandling.Ignore)] public List Scenes { get; set; } /// /// Gets or sets the CurrentLightingScene /// [JsonProperty("currentLightingScene", NullValueHandling = NullValueHandling.Ignore)] public LightingScene CurrentLightingScene { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp.Net; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Provides a messaging bridge /// public abstract class MessengerBase : EssentialsDevice, IMobileControlMessengerWithSubscriptions { /// /// The device this messenger is associated with /// protected IKeyName _device; /// /// Enable subscriptions /// protected bool enableMessengerSubscriptions; /// /// List of clients subscribed to this messenger /// /// /// Unsoliciited feedback from a device in a messenger will ONLY be sent to devices in this subscription list. When a client disconnects, it's ID will be removed from the collection. /// private readonly HashSet subscriberIds = new HashSet(); /// /// Lock object for thread-safe access to SubscriberIds /// private readonly object _subscriberLock = new object(); private readonly List _deviceInterfaces; private readonly Dictionary> _actions = new Dictionary>(); /// /// Gets the DeviceKey /// public string DeviceKey => _device?.Key ?? ""; /// /// Gets or sets the AppServerController /// public IMobileControl AppServerController { get; private set; } /// /// Gets or sets the MessagePath /// public string MessagePath { get; private set; } /// /// /// /// /// protected MessengerBase(string key, string messagePath) : base(key) { Key = key; if (string.IsNullOrEmpty(messagePath)) throw new ArgumentException("messagePath must not be empty or null"); MessagePath = messagePath; } /// /// Constructor for a messenger associated with a device /// /// /// /// protected MessengerBase(string key, string messagePath, IKeyName device) : this(key, messagePath) { _device = device; _deviceInterfaces = GetInterfaces(_device as Device); } /// /// Gets the interfaces implmented on the device /// /// /// private List GetInterfaces(Device device) { return device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List(); } /// /// Registers this messenger with appserver controller /// /// public void RegisterWithAppServer(IMobileControl appServerController) { AppServerController = appServerController ?? throw new ArgumentNullException("appServerController"); AppServerController.AddAction(this, HandleMessage); RegisterActions(); } /// /// Register this messenger with appserver controller /// /// Parent controller for this messenger /// Enable subscriptions public void RegisterWithAppServer(IMobileControl appServerController, bool enableMessengerSubscriptions) { this.enableMessengerSubscriptions = enableMessengerSubscriptions; AppServerController = appServerController ?? throw new ArgumentNullException("appServerController"); AppServerController.AddAction(this, HandleMessage); RegisterActions(); } private void HandleMessage(string path, string id, JToken content) { // replace base path with empty string. Should leave something like /fullStatus var route = path.Replace(MessagePath, string.Empty); if (!_actions.TryGetValue(route, out var action)) { return; } this.LogDebug("Executing action for path {path}", path); action(id, content); } /// /// Adds an action for a given path /// /// /// protected void AddAction(string path, Action action) { if (_actions.ContainsKey(path)) { return; } _actions.Add(path, action); } /// /// GetActionPaths method /// public List GetActionPaths() { return _actions.Keys.ToList(); } /// /// Removes an action for a given path /// /// protected void RemoveAction(string path) { if (!_actions.ContainsKey(path)) { return; } _actions.Remove(path); } /// /// Implemented in extending classes. Wire up API calls and feedback here /// protected virtual void RegisterActions() { } /// /// Add client to the susbscription list for unsolicited feedback /// /// Client ID to add protected void SubscribeClient(string clientId) { if (!enableMessengerSubscriptions) { return; } lock (_subscriberLock) { if (!subscriberIds.Add(clientId)) { this.LogVerbose("Client {clientId} already subscribed", clientId); return; } } this.LogDebug("Client {clientId} subscribed", clientId); } /// /// Remove a client from the subscription list /// /// Client ID to remove public void UnsubscribeClient(string clientId) { if (!enableMessengerSubscriptions) { return; } bool wasSubscribed; lock (_subscriberLock) { wasSubscribed = subscriberIds.Contains(clientId); if (wasSubscribed) { subscriberIds.Remove(clientId); } } if (!wasSubscribed) { this.LogVerbose("Client with ID {clientId} is not subscribed", clientId); return; } this.LogDebug("Client with ID {clientId} unsubscribed", clientId); } /// /// Helper for posting status message /// /// /// Optional client id that will direct the message back to only that client protected void PostStatusMessage(DeviceStateMessageBase message, string clientId = null) { try { if (message == null) { throw new ArgumentNullException("message"); } if (_device == null) { throw new ArgumentNullException("device"); } message.SetInterfaces(_deviceInterfaces); message.Key = _device.Key; message.Name = _device.Name; var token = JToken.FromObject(message); PostStatusMessage(token, MessagePath, clientId); } catch (Exception ex) { this.LogError("Exception posting status message for {messagePath} to {clientId}: {message}", MessagePath, clientId ?? "all clients", ex.Message); this.LogDebug(ex, "Stack trace: "); } } /// /// Helper for posting status message /// /// /// /// Optional client id that will direct the message back to only that client protected void PostStatusMessage(string type, DeviceStateMessageBase deviceState, string clientId = null) { try { //Debug.Console(2, this, "*********************Setting DeviceStateMessageProperties on MobileControlResponseMessage"); deviceState.SetInterfaces(_deviceInterfaces); deviceState.Key = _device.Key; deviceState.Name = _device.Name; deviceState.MessageBasePath = MessagePath; var token = JToken.FromObject(deviceState); PostStatusMessage(token, type, clientId); } catch (Exception ex) { this.LogError("Exception posting status message for {type} to {clientId}: {message}", type, clientId ?? "all clients", ex.Message); this.LogDebug(ex, "Stack trace: "); } } /// /// Helper for posting status message /// /// /// /// Optional client id that will direct the message back to only that client protected void PostStatusMessage(JToken content, string type = "", string clientId = null) { try { // Allow for legacy method to continue without subscriptions if (!enableMessengerSubscriptions) { AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content }); return; } // handle subscription feedback // If client is null or empty, this message is unsolicited feedback. Iterate through the subscriber list and send to all interested parties if (string.IsNullOrEmpty(clientId)) { // Create a snapshot of subscribers to avoid collection modification during iteration List subscriberSnapshot; lock (_subscriberLock) { subscriberSnapshot = new List(subscriberIds); } foreach (var client in subscriberSnapshot) { AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = client, Content = content }); } return; } SubscribeClient(clientId); AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content }); } catch (Exception ex) { this.LogError("Exception posting status message: {message}", ex.Message); this.LogDebug(ex, "Stack Trace: "); } } /// /// Helper for posting event message /// /// protected void PostEventMessage(DeviceEventMessageBase message) { message.Key = _device.Key; message.Name = _device.Name; AppServerController?.SendMessageObject(new MobileControlMessage { Type = $"/event{MessagePath}/{message.EventType}", Content = JToken.FromObject(message), }); } /// /// Helper for posting event message /// /// /// protected void PostEventMessage(DeviceEventMessageBase message, string eventType) { message.Key = _device.Key; message.Name = _device.Name; message.EventType = eventType; AppServerController?.SendMessageObject(new MobileControlMessage { Type = $"/event{MessagePath}/{eventType}", Content = JToken.FromObject(message), }); } /// /// Helper for posting event message with no content /// /// protected void PostEventMessage(string eventType) { AppServerController?.SendMessageObject(new MobileControlMessage { Type = $"/event{MessagePath}/{eventType}", Content = JToken.FromObject(new { }), }); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs ================================================ using System; using System.Collections.Generic; using Crestron.SimplSharp; using Newtonsoft.Json.Linq; using PepperDash.Core; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Handler for press/hold/release messages /// public static class PressAndHoldHandler { private const long ButtonHeartbeatInterval = 1000; private static readonly Dictionary _pushedActions = new Dictionary(); private static readonly Dictionary>> _pushedActionHandlers; static PressAndHoldHandler() { _pushedActionHandlers = new Dictionary>> { {"pressed", AddTimer }, {"held", ResetTimer }, {"released", StopTimer } }; } private static void AddTimer(string deviceKey, Action action) { Debug.LogDebug("Attempting to add timer for {deviceKey}", deviceKey); if (_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) { Debug.LogDebug("Timer for {deviceKey} already exists", deviceKey); return; } Debug.LogDebug("Adding timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); action(true); cancelTimer = new CTimer(o => { Debug.LogDebug("Timer expired for {deviceKey}", deviceKey); action(false); _pushedActions.Remove(deviceKey); }, ButtonHeartbeatInterval); _pushedActions.Add(deviceKey, cancelTimer); } private static void ResetTimer(string deviceKey, Action action) { Debug.LogDebug("Attempting to reset timer for {deviceKey}", deviceKey); if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) { Debug.LogDebug("Timer for {deviceKey} not found", deviceKey); return; } Debug.LogDebug("Resetting timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); cancelTimer.Reset(ButtonHeartbeatInterval); } private static void StopTimer(string deviceKey, Action action) { Debug.LogDebug("Attempting to stop timer for {deviceKey}", deviceKey); if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) { Debug.LogDebug("Timer for {deviceKey} not found", deviceKey); return; } Debug.LogDebug("Stopping timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); action(false); cancelTimer.Stop(); _pushedActions.Remove(deviceKey); } public static Action> GetPressAndHoldHandler(string value) { Debug.LogDebug("Getting press and hold handler for {value}", value); if (!_pushedActionHandlers.TryGetValue(value, out Action> handler)) { Debug.LogDebug("Press and hold handler for {value} not found", value); return null; } Debug.LogDebug("Got handler for {value}", value); return handler; } /// /// HandlePressAndHold method /// public static void HandlePressAndHold(string deviceKey, JToken content, Action action) { var msg = content.ToObject>(); Debug.LogDebug("Handling press and hold message of {type} for {deviceKey}", msg.Value, deviceKey); var timerHandler = GetPressAndHoldHandler(msg.Value); if (timerHandler == null) { return; } timerHandler(deviceKey, action); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a RoomEventScheduleMessenger /// public class RoomEventScheduleMessenger : MessengerBase { private readonly IRoomEventSchedule _room; public RoomEventScheduleMessenger(string key, string messagePath, IRoomEventSchedule room) : base(key, messagePath, room as IKeyName) { _room = room; } #region Overrides of MessengerBase protected override void RegisterActions() { AddAction("/saveScheduledEvents", (id, content) => SaveScheduledEvents(content.ToObject>())); AddAction("/status", (id, content) => { var events = _room.GetScheduledEvents(); SendFullStatus(events, id); }); AddAction("/scheduledEventsStatus", (id, content) => { var events = _room.GetScheduledEvents(); SendFullStatus(events, id); }); _room.ScheduledEventsChanged += (sender, args) => SendFullStatus(args.ScheduledEvents); } #endregion private void SaveScheduledEvents(List events) { foreach (var evt in events) { SaveScheduledEvent(evt); } } private void SaveScheduledEvent(ScheduledEventConfig eventConfig) { try { _room.AddOrUpdateScheduledEvent(eventConfig); } catch (Exception ex) { this.LogException(ex, "Exception saving event"); } } private void SendFullStatus(List events, string id = null) { var message = new RoomEventScheduleStateMessage { ScheduleEvents = events, }; PostStatusMessage(message, id); } } /// /// Represents a RoomEventScheduleStateMessage /// public class RoomEventScheduleStateMessage : DeviceStateMessageBase { [JsonProperty("scheduleEvents")] /// /// Gets or sets the ScheduleEvents /// public List ScheduleEvents { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SIMPLAtcMessenger.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; using System; using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { // ReSharper disable once InconsistentNaming /// /// Represents a SIMPLAtcMessenger /// public class SIMPLAtcMessenger : MessengerBase { private readonly BasicTriList _eisc; /// /// Gets or sets the JoinMap /// public SIMPLAtcJoinMap JoinMap { get; private set; } /// /// /// private readonly CodecActiveCallItem _currentCallItem; /// /// /// /// /// /// public SIMPLAtcMessenger(string key, BasicTriList eisc, string messagePath) : base(key, messagePath) { _eisc = eisc; JoinMap = new SIMPLAtcJoinMap(201); _currentCallItem = new CodecActiveCallItem { Type = eCodecCallType.Audio, Id = "-audio-" }; } /// /// /// private void SendFullStatus() { PostStatusMessage(JToken.FromObject(new { calls = GetCurrentCallList(), currentCallString = _eisc.GetString(JoinMap.CurrentCallName.JoinNumber), currentDialString = _eisc.GetString(JoinMap.CurrentDialString.JoinNumber), isInCall = _eisc.GetString(JoinMap.HookState.JoinNumber) == "Connected" }) ); } /// /// /// /// protected override void RegisterActions() { //EISC.SetStringSigAction(SCurrentDialString, s => PostStatusMessage(new { currentDialString = s })); _eisc.SetStringSigAction(JoinMap.HookState.JoinNumber, s => { _currentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); //GetCurrentCallList(); SendFullStatus(); }); _eisc.SetStringSigAction(JoinMap.CurrentCallNumber.JoinNumber, s => { _currentCallItem.Number = s; SendCallsList(); }); _eisc.SetStringSigAction(JoinMap.CurrentCallName.JoinNumber, s => { _currentCallItem.Name = s; SendCallsList(); }); _eisc.SetStringSigAction(JoinMap.CallDirection.JoinNumber, s => { _currentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true); SendCallsList(); }); // Add press and holds using helper //Action addPhAction = (s, u) => // AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => _eisc.SetBool(u, b))); // Add straight pulse calls void addAction(string s, uint u) => AddAction(s, (id, content) => _eisc.PulseBool(u, 100)); addAction("/endCallById", JoinMap.EndCall.JoinNumber); addAction("/endAllCalls", JoinMap.EndCall.JoinNumber); addAction("/acceptById", JoinMap.IncomingAnswer.JoinNumber); addAction("/rejectById", JoinMap.IncomingReject.JoinNumber); var speeddialStart = JoinMap.SpeedDialStart.JoinNumber; var speeddialEnd = JoinMap.SpeedDialStart.JoinNumber + JoinMap.SpeedDialStart.JoinSpan; var speedDialIndex = 1; for (uint i = speeddialStart; i < speeddialEnd; i++) { addAction(string.Format("/speedDial{0}", speedDialIndex), i); speedDialIndex++; } // Get status AddAction("/fullStatus", (id, content) => SendFullStatus()); // Dial on string AddAction("/dial", (id, content) => { var msg = content.ToObject>(); _eisc.SetString(JoinMap.CurrentDialString.JoinNumber, msg.Value); }); // Pulse DTMF AddAction("/dtmf", (id, content) => { var s = content.ToObject>(); var join = JoinMap.Joins[s.Value]; if (join != null) { if (join.JoinNumber > 0) { _eisc.PulseBool(join.JoinNumber, 100); } } }); } /// /// /// private void SendCallsList() { PostStatusMessage(JToken.FromObject(new { calls = GetCurrentCallList(), }) ); } /// /// Turns the /// /// private List GetCurrentCallList() { return _currentCallItem.Status == eCodecCallStatus.Disconnected ? new List() : new List { _currentCallItem }; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SIMPLCameraMessenger.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Devices.Common.Cameras; using System; using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { // ReSharper disable once InconsistentNaming /// /// Represents a SIMPLCameraMessenger /// public class SIMPLCameraMessenger : MessengerBase { private readonly BasicTriList _eisc; private readonly CameraControllerJoinMap _joinMap; public SIMPLCameraMessenger(string key, BasicTriList eisc, string messagePath, uint joinStart) : base(key, messagePath) { _eisc = eisc; _joinMap = new CameraControllerJoinMap(joinStart); _eisc.SetUShortSigAction(_joinMap.NumberOfPresets.JoinNumber, u => SendCameraFullMessageObject()); _eisc.SetBoolSigAction(_joinMap.CameraModeAuto.JoinNumber, b => PostCameraMode()); _eisc.SetBoolSigAction(_joinMap.CameraModeManual.JoinNumber, b => PostCameraMode()); _eisc.SetBoolSigAction(_joinMap.CameraModeOff.JoinNumber, b => PostCameraMode()); } protected override void RegisterActions() { AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject()); // Add press and holds using helper action void addPhAction(string s, uint u) => AddAction(s, (id, content) => HandleCameraPressAndHold(content, b => _eisc.SetBool(u, b))); addPhAction("/cameraUp", _joinMap.TiltUp.JoinNumber); addPhAction("/cameraDown", _joinMap.TiltDown.JoinNumber); addPhAction("/cameraLeft", _joinMap.PanLeft.JoinNumber); addPhAction("/cameraRight", _joinMap.PanRight.JoinNumber); addPhAction("/cameraZoomIn", _joinMap.ZoomIn.JoinNumber); addPhAction("/cameraZoomOut", _joinMap.ZoomOut.JoinNumber); void addAction(string s, uint u) => AddAction(s, (id, content) => _eisc.PulseBool(u, 100)); addAction("/cameraModeAuto", _joinMap.CameraModeAuto.JoinNumber); addAction("/cameraModeManual", _joinMap.CameraModeManual.JoinNumber); addAction("/cameraModeOff", _joinMap.CameraModeOff.JoinNumber); var presetStart = _joinMap.PresetRecallStart.JoinNumber; var presetEnd = _joinMap.PresetRecallStart.JoinNumber + _joinMap.PresetRecallStart.JoinSpan; int presetId = 1; // camera presets for (uint i = presetStart; i <= presetEnd; i++) { addAction("/cameraPreset" + (presetId), i); presetId++; } } private void HandleCameraPressAndHold(JToken content, Action cameraAction) { var state = content.ToObject>(); var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); if (timerHandler == null) { return; } timerHandler(state.Value, cameraAction); cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); } /// /// CustomUnregisterWithAppServer method /// public void CustomUnregisterWithAppServer(IMobileControl appServerController) { appServerController.RemoveAction(MessagePath + "/fullStatus"); appServerController.RemoveAction(MessagePath + "/cameraUp"); appServerController.RemoveAction(MessagePath + "/cameraDown"); appServerController.RemoveAction(MessagePath + "/cameraLeft"); appServerController.RemoveAction(MessagePath + "/cameraRight"); appServerController.RemoveAction(MessagePath + "/cameraZoomIn"); appServerController.RemoveAction(MessagePath + "/cameraZoomOut"); appServerController.RemoveAction(MessagePath + "/cameraModeAuto"); appServerController.RemoveAction(MessagePath + "/cameraModeManual"); appServerController.RemoveAction(MessagePath + "/cameraModeOff"); _eisc.SetUShortSigAction(_joinMap.NumberOfPresets.JoinNumber, null); _eisc.SetBoolSigAction(_joinMap.CameraModeAuto.JoinNumber, null); _eisc.SetBoolSigAction(_joinMap.CameraModeManual.JoinNumber, null); _eisc.SetBoolSigAction(_joinMap.CameraModeOff.JoinNumber, null); } /// /// Helper method to update the full status of the camera /// private void SendCameraFullMessageObject() { var presetList = new List(); // Build a list of camera presets based on the names and count if (_eisc.GetBool(_joinMap.SupportsPresets.JoinNumber)) { var presetStart = _joinMap.PresetLabelStart.JoinNumber; var presetEnd = _joinMap.PresetLabelStart.JoinNumber + _joinMap.NumberOfPresets.JoinNumber; var presetId = 1; for (uint i = presetStart; i < presetEnd; i++) { var presetName = _eisc.GetString(i); var preset = new CameraPreset(presetId, presetName, string.IsNullOrEmpty(presetName), true); presetList.Add(preset); presetId++; } } PostStatusMessage(JToken.FromObject(new { cameraMode = GetCameraMode(), hasPresets = _eisc.GetBool(_joinMap.SupportsPresets.JoinNumber), presets = presetList }) ); } /// /// /// private void PostCameraMode() { PostStatusMessage(JToken.FromObject(new { cameraMode = GetCameraMode() })); } /// /// Computes the current camera mode /// /// private string GetCameraMode() { string m; if (_eisc.GetBool(_joinMap.CameraModeAuto.JoinNumber)) m = eCameraControlMode.Auto.ToString().ToLower(); else if (_eisc.GetBool(_joinMap.CameraModeManual.JoinNumber)) m = eCameraControlMode.Manual.ToString().ToLower(); else m = eCameraControlMode.Off.ToString().ToLower(); return m; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SIMPLDirectRouteMessenger.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a SimplDirectRouteMessenger /// public class SimplDirectRouteMessenger : MessengerBase { private readonly BasicTriList _eisc; /// /// Gets or sets the JoinMap /// public MobileControlSIMPLRunDirectRouteActionJoinMap JoinMap { get; private set; } public Dictionary DestinationList { get; set; } public SimplDirectRouteMessenger(string key, BasicTriList eisc, string messagePath) : base(key, messagePath) { _eisc = eisc; JoinMap = new MobileControlSIMPLRunDirectRouteActionJoinMap(851); DestinationList = new Dictionary(); } #region Overrides of MessengerBase protected override void RegisterActions() { Debug.Console(2, "********** Direct Route Messenger CustomRegisterWithAppServer **********"); //Audio source _eisc.SetStringSigAction(JoinMap.SourceForDestinationAudio.JoinNumber, s => PostStatusMessage(JToken.FromObject(new { selectedSourceKey = s, }) )); AddAction("/programAudio/selectSource", (id, content) => { var msg = content.ToObject>(); _eisc.StringInput[JoinMap.SourceForDestinationAudio.JoinNumber].StringValue = msg.Value; }); AddAction("/fullStatus", (id, content) => { foreach (var dest in DestinationList) { var key = dest.Key; var item = dest.Value; var source = _eisc.StringOutput[(uint)(JoinMap.SourceForDestinationJoinStart.JoinNumber + item.Order)].StringValue; UpdateSourceForDestination(source, key); } PostStatusMessage(JToken.FromObject(new { selectedSourceKey = _eisc.StringOutput[JoinMap.SourceForDestinationAudio.JoinNumber].StringValue }) ); PostStatusMessage(JToken.FromObject(new { advancedSharingActive = _eisc.BooleanOutput[JoinMap.AdvancedSharingModeFb.JoinNumber].BoolValue }) ); }); AddAction("/advancedSharingMode", (id, content) => { var b = content.ToObject>(); Debug.Console(1, "Current Sharing Mode: {2}\r\nadvanced sharing mode: {0} join number: {1}", b.Value, JoinMap.AdvancedSharingModeOn.JoinNumber, _eisc.BooleanOutput[JoinMap.AdvancedSharingModeOn.JoinNumber].BoolValue); _eisc.SetBool(JoinMap.AdvancedSharingModeOn.JoinNumber, b.Value); _eisc.SetBool(JoinMap.AdvancedSharingModeOff.JoinNumber, !b.Value); _eisc.PulseBool(JoinMap.AdvancedSharingModeToggle.JoinNumber); }); _eisc.SetBoolSigAction(JoinMap.AdvancedSharingModeFb.JoinNumber, (b) => PostStatusMessage(JToken.FromObject(new { advancedSharingActive = b }) )); } /// /// RegisterForDestinationPaths method /// public void RegisterForDestinationPaths() { //handle routing feedback from SIMPL foreach (var destination in DestinationList) { var key = destination.Key; var dest = destination.Value; _eisc.SetStringSigAction((uint)(JoinMap.SourceForDestinationJoinStart.JoinNumber + dest.Order), s => UpdateSourceForDestination(s, key)); AddAction($"/{key}/selectSource", (id, content) => { var s = content.ToObject>(); _eisc.StringInput[(uint)(JoinMap.SourceForDestinationJoinStart.JoinNumber + dest.Order)].StringValue = s.Value; }); } } #endregion private void UpdateSourceForDestination(string sourceKey, string destKey) { PostStatusMessage(JToken.FromObject(new { selectedSourceKey = sourceKey }), $"{MessagePath}/{destKey}/currentSource"); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SIMPLRouteMessenger.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a SIMPLRouteMessenger /// public class SIMPLRouteMessenger : MessengerBase { private readonly BasicTriList _eisc; private readonly uint _joinStart; /// /// Represents a StringJoin /// public class StringJoin { /// /// 1 /// public const uint CurrentSource = 1; } public SIMPLRouteMessenger(string key, BasicTriList eisc, string messagePath, uint joinStart) : base(key, messagePath) { _eisc = eisc; _joinStart = joinStart - 1; _eisc.SetStringSigAction(_joinStart + StringJoin.CurrentSource, SendRoutingFullMessageObject); } protected override void RegisterActions() { AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject(_eisc.GetString(_joinStart + StringJoin.CurrentSource))); AddAction("/source", (id, content) => { var c = content.ToObject(); _eisc.SetString(_joinStart + StringJoin.CurrentSource, c.SourceListItemKey); }); } /// /// CustomUnregisterWithAppServer method /// public void CustomUnregisterWithAppServer(IMobileControl appServerController) { appServerController.RemoveAction(MessagePath + "/fullStatus"); appServerController.RemoveAction(MessagePath + "/source"); _eisc.SetStringSigAction(_joinStart + StringJoin.CurrentSource, null); } /// /// Helper method to update full status of the routing device /// private void SendRoutingFullMessageObject(string sourceKey) { if (string.IsNullOrEmpty(sourceKey)) sourceKey = "none"; PostStatusMessage(JToken.FromObject(new { selectedSourceKey = sourceKey }) ); } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SIMPLVtcMessenger.cs ================================================ using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Codec; using System; using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { // ReSharper disable once InconsistentNaming /// /// Represents a SIMPLVtcMessenger /// public class SIMPLVtcMessenger : MessengerBase { private readonly BasicTriList _eisc; /// /// Gets or sets the JoinMap /// public SIMPLVtcJoinMap JoinMap { get; private set; } private readonly CodecActiveCallItem _currentCallItem; private CodecActiveCallItem _incomingCallItem; private ushort _previousDirectoryLength = 701; /// /// /// /// /// /// public SIMPLVtcMessenger(string key, BasicTriList eisc, string messagePath) : base(key, messagePath) { _eisc = eisc; JoinMap = new SIMPLVtcJoinMap(1001); _currentCallItem = new CodecActiveCallItem { Type = eCodecCallType.Video, Id = "-video-" }; } /// /// /// /// protected override void RegisterActions() { _eisc.SetStringSigAction(JoinMap.HookState.JoinNumber, s => { _currentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); PostFullStatus(); // SendCallsList(); }); _eisc.SetStringSigAction(JoinMap.CurrentCallNumber.JoinNumber, s => { _currentCallItem.Number = s; PostCallsList(); }); _eisc.SetStringSigAction(JoinMap.CurrentCallName.JoinNumber, s => { _currentCallItem.Name = s; PostCallsList(); }); _eisc.SetStringSigAction(JoinMap.CallDirection.JoinNumber, s => { _currentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true); PostCallsList(); }); _eisc.SetBoolSigAction(JoinMap.IncomingCall.JoinNumber, b => { if (b) { var ica = new CodecActiveCallItem { Direction = eCodecCallDirection.Incoming, Id = "-video-incoming", Name = _eisc.GetString(JoinMap.IncomingCallName.JoinNumber), Number = _eisc.GetString(JoinMap.IncomingCallNumber.JoinNumber), Status = eCodecCallStatus.Ringing, Type = eCodecCallType.Video }; _incomingCallItem = ica; } else { _incomingCallItem = null; } PostCallsList(); }); _eisc.SetStringSigAction(JoinMap.IncomingCallName.JoinNumber, s => { if (_incomingCallItem != null) { _incomingCallItem.Name = s; PostCallsList(); } }); _eisc.SetStringSigAction(JoinMap.IncomingCallNumber.JoinNumber, s => { if (_incomingCallItem != null) { _incomingCallItem.Number = s; PostCallsList(); } }); _eisc.SetBoolSigAction(JoinMap.CameraSupportsAutoMode.JoinNumber, b => PostStatusMessage(JToken.FromObject(new { cameraSupportsAutoMode = b }))); _eisc.SetBoolSigAction(JoinMap.CameraSupportsOffMode.JoinNumber, b => PostStatusMessage(JToken.FromObject(new { cameraSupportsOffMode = b }))); // Directory insanity _eisc.SetUShortSigAction(JoinMap.DirectoryRowCount.JoinNumber, u => { // The length of the list comes in before the list does. // Splice the sig change operation onto the last string sig that will be changing // when the directory entries make it through. if (_previousDirectoryLength > 0) { _eisc.ClearStringSigAction(JoinMap.DirectoryEntriesStart.JoinNumber + _previousDirectoryLength - 1); } _eisc.SetStringSigAction(JoinMap.DirectoryEntriesStart.JoinNumber + u - 1, s => PostDirectory()); _previousDirectoryLength = u; }); _eisc.SetStringSigAction(JoinMap.DirectoryEntrySelectedName.JoinNumber, s => PostStatusMessage(JToken.FromObject(new { directoryContactSelected = new { name = _eisc.GetString(JoinMap.DirectoryEntrySelectedName.JoinNumber), } }))); _eisc.SetStringSigAction(JoinMap.DirectoryEntrySelectedNumber.JoinNumber, s => PostStatusMessage(JToken.FromObject(new { directoryContactSelected = new { number = _eisc.GetString(JoinMap.DirectoryEntrySelectedNumber.JoinNumber), } }))); _eisc.SetStringSigAction(JoinMap.DirectorySelectedFolderName.JoinNumber, s => PostStatusMessage(JToken.FromObject(new { directorySelectedFolderName = _eisc.GetString(JoinMap.DirectorySelectedFolderName.JoinNumber) }))); _eisc.SetSigTrueAction(JoinMap.CameraModeAuto.JoinNumber, PostCameraMode); _eisc.SetSigTrueAction(JoinMap.CameraModeManual.JoinNumber, PostCameraMode); _eisc.SetSigTrueAction(JoinMap.CameraModeOff.JoinNumber, PostCameraMode); _eisc.SetBoolSigAction(JoinMap.CameraSelfView.JoinNumber, b => PostStatusMessage(JToken.FromObject(new { cameraSelfView = b }))); _eisc.SetUShortSigAction(JoinMap.CameraNumberSelect.JoinNumber, u => PostSelectedCamera()); // Add press and holds using helper action void addPhAction(string s, uint u) => AddAction(s, (id, content) => HandleCameraPressAndHold(content, b => _eisc.SetBool(u, b))); addPhAction("/cameraUp", JoinMap.CameraTiltUp.JoinNumber); addPhAction("/cameraDown", JoinMap.CameraTiltDown.JoinNumber); addPhAction("/cameraLeft", JoinMap.CameraPanLeft.JoinNumber); addPhAction("/cameraRight", JoinMap.CameraPanRight.JoinNumber); addPhAction("/cameraZoomIn", JoinMap.CameraZoomIn.JoinNumber); addPhAction("/cameraZoomOut", JoinMap.CameraZoomOut.JoinNumber); // Add straight pulse calls using helper action void addAction(string s, uint u) => AddAction(s, (id, content) => _eisc.PulseBool(u, 100)); addAction("/endCallById", JoinMap.EndCall.JoinNumber); addAction("/endAllCalls", JoinMap.EndCall.JoinNumber); addAction("/acceptById", JoinMap.IncomingAnswer.JoinNumber); addAction("/rejectById", JoinMap.IncomingReject.JoinNumber); var speeddialStart = JoinMap.SpeedDialStart.JoinNumber; var speeddialEnd = JoinMap.SpeedDialStart.JoinNumber + JoinMap.SpeedDialStart.JoinSpan; var speedDialIndex = 1; for (uint i = speeddialStart; i < speeddialEnd; i++) { addAction(string.Format("/speedDial{0}", speedDialIndex), i); speedDialIndex++; } addAction("/cameraModeAuto", JoinMap.CameraModeAuto.JoinNumber); addAction("/cameraModeManual", JoinMap.CameraModeManual.JoinNumber); addAction("/cameraModeOff", JoinMap.CameraModeOff.JoinNumber); addAction("/cameraSelfView", JoinMap.CameraSelfView.JoinNumber); addAction("/cameraLayout", JoinMap.CameraLayout.JoinNumber); AddAction("/cameraSelect", (id, content) => { var s = content.ToObject>(); SelectCamera(s.Value); }); // camera presets for (uint i = 0; i < 6; i++) { addAction("/cameraPreset" + (i + 1), JoinMap.CameraPresetStart.JoinNumber + i); } AddAction("/isReady", (id, content) => PostIsReady()); // Get status AddAction("/fullStatus", (id, content) => PostFullStatus()); // Dial on string AddAction("/dial", (id, content) => { var s = content.ToObject>(); _eisc.SetString(JoinMap.CurrentDialString.JoinNumber, s.Value); }); // Pulse DTMF AddAction("/dtmf", (id, content) => { var s = content.ToObject>(); var join = JoinMap.Joins[s.Value]; if (join != null) { if (join.JoinNumber > 0) { _eisc.PulseBool(join.JoinNumber, 100); } } }); // Directory madness AddAction("/directoryRoot", (id, content) => _eisc.PulseBool(JoinMap.DirectoryRoot.JoinNumber)); AddAction("/directoryBack", (id, content) => _eisc.PulseBool(JoinMap.DirectoryFolderBack.JoinNumber)); AddAction("/directoryById", (id, content) => { var s = content.ToObject>(); // the id should contain the line number to forward to simpl try { var u = ushort.Parse(s.Value); _eisc.SetUshort(JoinMap.DirectorySelectRow.JoinNumber, u); _eisc.PulseBool(JoinMap.DirectoryLineSelected.JoinNumber); } catch (Exception) { Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "/directoryById request contains non-numeric ID incompatible with SIMPL bridge"); } }); AddAction("/directorySelectContact", (id, content) => { var s = content.ToObject>(); try { var u = ushort.Parse(s.Value); _eisc.SetUshort(JoinMap.DirectorySelectRow.JoinNumber, u); _eisc.PulseBool(JoinMap.DirectoryLineSelected.JoinNumber); } catch { Debug.Console(2, this, "Error parsing contact from {0} for path /directorySelectContact", s); } }); AddAction("/directoryDialContact", (id, content) => _eisc.PulseBool(JoinMap.DirectoryDialSelectedLine.JoinNumber)); AddAction("/getDirectory", (id, content) => { if (_eisc.GetUshort(JoinMap.DirectoryRowCount.JoinNumber) > 0) { PostDirectory(); } else { _eisc.PulseBool(JoinMap.DirectoryRoot.JoinNumber); } }); } private void HandleCameraPressAndHold(JToken content, Action cameraAction) { var state = content.ToObject>(); var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); if (timerHandler == null) { return; } timerHandler(state.Value, cameraAction); cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); } /// /// /// /// private void PostFullStatus() { PostStatusMessage(JToken.FromObject(new { calls = GetCurrentCallList(), cameraMode = GetCameraMode(), cameraSelfView = _eisc.GetBool(JoinMap.CameraSelfView.JoinNumber), cameraSupportsAutoMode = _eisc.GetBool(JoinMap.CameraSupportsAutoMode.JoinNumber), cameraSupportsOffMode = _eisc.GetBool(JoinMap.CameraSupportsOffMode.JoinNumber), currentCallString = _eisc.GetString(JoinMap.CurrentCallNumber.JoinNumber), currentDialString = _eisc.GetString(JoinMap.CurrentDialString.JoinNumber), directoryContactSelected = new { name = _eisc.GetString(JoinMap.DirectoryEntrySelectedName.JoinNumber), number = _eisc.GetString(JoinMap.DirectoryEntrySelectedNumber.JoinNumber) }, directorySelectedFolderName = _eisc.GetString(JoinMap.DirectorySelectedFolderName.JoinNumber), isInCall = _eisc.GetString(JoinMap.HookState.JoinNumber) == "Connected", hasDirectory = true, hasDirectorySearch = false, hasRecents = !_eisc.BooleanOutput[502].BoolValue, hasCameras = true, showCamerasWhenNotInCall = _eisc.BooleanOutput[503].BoolValue, selectedCamera = GetSelectedCamera(), })); } /// /// /// private void PostDirectory() { var u = _eisc.GetUshort(JoinMap.DirectoryRowCount.JoinNumber); var items = new List(); for (uint i = 0; i < u; i++) { var name = _eisc.GetString(JoinMap.DirectoryEntriesStart.JoinNumber + i); var id = (i + 1).ToString(); // is folder or contact? if (name.StartsWith("[+]")) { items.Add(new { folderId = id, name }); } else { items.Add(new { contactId = id, name }); } } var directoryMessage = new { currentDirectory = new { isRootDirectory = _eisc.GetBool(JoinMap.DirectoryIsRoot.JoinNumber), directoryResults = items } }; PostStatusMessage(JToken.FromObject(directoryMessage)); } /// /// /// private void PostCameraMode() { PostStatusMessage(JToken.FromObject(new { cameraMode = GetCameraMode() })); } /// /// /// private string GetCameraMode() { string m; if (_eisc.GetBool(JoinMap.CameraModeAuto.JoinNumber)) m = eCameraControlMode.Auto.ToString().ToLower(); else if (_eisc.GetBool(JoinMap.CameraModeManual.JoinNumber)) m = eCameraControlMode.Manual.ToString().ToLower(); else m = eCameraControlMode.Off.ToString().ToLower(); return m; } private void PostSelectedCamera() { PostStatusMessage(JToken.FromObject(new { selectedCamera = GetSelectedCamera() })); } /// /// /// private string GetSelectedCamera() { var num = _eisc.GetUshort(JoinMap.CameraNumberSelect.JoinNumber); string m; if (num == 100) { m = "cameraFar"; } else { m = "camera" + num; } return m; } /// /// /// private void PostIsReady() { PostStatusMessage(JToken.FromObject(new { isReady = true })); } /// /// /// private void PostCallsList() { PostStatusMessage(JToken.FromObject(new { calls = GetCurrentCallList(), })); } /// /// /// /// private void SelectCamera(string s) { var cam = s.Substring(6); _eisc.SetUshort(JoinMap.CameraNumberSelect.JoinNumber, (ushort)(cam.ToLower() == "far" ? 100 : ushort.Parse(cam))); } /// /// Turns the /// /// private List GetCurrentCallList() { var list = new List(); if (_currentCallItem.Status != eCodecCallStatus.Disconnected) { list.Add(_currentCallItem); } if (_eisc.GetBool(JoinMap.IncomingCall.JoinNumber)) { list.Add(_incomingCallItem); } return list; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs ================================================ using System; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Shades; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a IShadesOpenCloseStopMessenger /// public class IShadesOpenCloseStopMessenger : MessengerBase { private readonly IShadesOpenCloseStop device; public IShadesOpenCloseStopMessenger(string key, IShadesOpenCloseStop shades, string messagePath) : base(key, messagePath, shades as IKeyName) { device = shades; } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/shadesStatus", (id, content) => SendFullStatus(id)); AddAction("/shadeUp", (id, content) => { device.Open(); }); AddAction("/shadeDown", (id, content) => { device.Close(); }); var stopDevice = device; if (stopDevice != null) { AddAction("/stopOrPreset", (id, content) => { stopDevice.Stop(); }); } if (device is IShadesOpenClosedFeedback feedbackDevice) { feedbackDevice.ShadeIsOpenFeedback.OutputChange += new EventHandler(ShadeIsOpenFeedback_OutputChange); feedbackDevice.ShadeIsClosedFeedback.OutputChange += new EventHandler(ShadeIsClosedFeedback_OutputChange); } } private void ShadeIsOpenFeedback_OutputChange(object sender, Core.FeedbackEventArgs e) { var state = new ShadeBaseStateMessage { IsOpen = e.BoolValue }; PostStatusMessage(state); } private void ShadeIsClosedFeedback_OutputChange(object sender, Core.FeedbackEventArgs e) { var state = new ShadeBaseStateMessage { IsClosed = e.BoolValue }; PostStatusMessage(state); } private void SendFullStatus(string id = null) { var state = new ShadeBaseStateMessage(); if (device is IShadesOpenClosedFeedback feedbackDevice) { state.IsOpen = feedbackDevice.ShadeIsOpenFeedback.BoolValue; state.IsClosed = feedbackDevice.ShadeIsClosedFeedback.BoolValue; } PostStatusMessage(state, id); } } /// /// Represents a ShadeBaseStateMessage /// public class ShadeBaseStateMessage : DeviceStateMessageBase { /// /// Gets or sets the MiddleButtonLabel /// [JsonProperty("middleButtonLabel", NullValueHandling = NullValueHandling.Ignore)] public string MiddleButtonLabel { get; set; } [JsonProperty("isOpen", NullValueHandling = NullValueHandling.Ignore)] public bool? IsOpen { get; set; } [JsonProperty("isClosed", NullValueHandling = NullValueHandling.Ignore)] public bool? IsClosed { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SimplMessengerPropertiesConfig.cs ================================================ using PepperDash.Essentials.Core.Bridges; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a SimplMessengerPropertiesConfig /// public class SimplMessengerPropertiesConfig : EiscApiPropertiesConfig.ApiDevicePropertiesConfig { } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs ================================================ using System; using System.Threading.Tasks; using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.Monitoring; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a SystemMonitorMessenger /// public class SystemMonitorMessenger : MessengerBase { private readonly SystemMonitorController systemMonitor; public SystemMonitorMessenger(string key, SystemMonitorController sysMon, string messagePath) : base(key, messagePath, sysMon) { systemMonitor = sysMon ?? throw new ArgumentNullException("sysMon"); systemMonitor.SystemMonitorPropertiesChanged += SysMon_SystemMonitorPropertiesChanged; foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) { p.Value.ProgramInfoChanged += ProgramInfoChanged; } CrestronConsole.AddNewConsoleCommand(s => SendFullStatusMessage(), "SendFullSysMonStatus", "Sends the full System Monitor Status", ConsoleAccessLevelEnum.AccessOperator); } /// /// Posts the program information message /// /// /// private void ProgramInfoChanged(object sender, ProgramInfoEventArgs e) { if (e.ProgramInfo != null) { //Debug.Console(1, "Posting Status Message: {0}", e.ProgramInfo.ToString()); PostStatusMessage(JToken.FromObject(e.ProgramInfo) ); } } /// /// Posts the system monitor properties /// /// /// private void SysMon_SystemMonitorPropertiesChanged(object sender, EventArgs e) { SendSystemMonitorStatusMessage(); } private void SendFullStatusMessage(string id = null) { SendSystemMonitorStatusMessage(id); foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) { PostStatusMessage(JToken.FromObject(p.Value.ProgramInfo), id); } } private void SendSystemMonitorStatusMessage(string id = null) { // This takes a while, launch a new thread Task.Run(() => PostStatusMessage(JToken.FromObject(new SystemMonitorStateMessage { TimeZone = systemMonitor.TimeZoneFeedback.IntValue, TimeZoneName = systemMonitor.TimeZoneTextFeedback.StringValue, IoControllerVersion = systemMonitor.IoControllerVersionFeedback.StringValue, SnmpVersion = systemMonitor.SnmpVersionFeedback.StringValue, BacnetVersion = systemMonitor.BaCnetAppVersionFeedback.StringValue, ControllerVersion = systemMonitor.ControllerVersionFeedback.StringValue }), id )); } protected override void RegisterActions() { AddAction("/fullStatus", (id, content) => SendFullStatusMessage(id)); AddAction("/systemStatus", (id, content) => SendFullStatusMessage(id)); } } /// /// Represents a SystemMonitorStateMessage /// public class SystemMonitorStateMessage { /// /// Gets or sets the TimeZone /// [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] public int TimeZone { get; set; } /// /// Gets or sets the TimeZoneName /// [JsonProperty("timeZoneName", NullValueHandling = NullValueHandling.Ignore)] public string TimeZoneName { get; set; } /// /// Gets or sets the IoControllerVersion /// [JsonProperty("ioControllerVersion", NullValueHandling = NullValueHandling.Ignore)] public string IoControllerVersion { get; set; } /// /// Gets or sets the SnmpVersion /// [JsonProperty("snmpVersion", NullValueHandling = NullValueHandling.Ignore)] public string SnmpVersion { get; set; } /// /// Gets or sets the BacnetVersion /// [JsonProperty("bacnetVersion", NullValueHandling = NullValueHandling.Ignore)] public string BacnetVersion { get; set; } /// /// Gets or sets the ControllerVersion /// [JsonProperty("controllerVersion", NullValueHandling = NullValueHandling.Ignore)] public string ControllerVersion { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Displays; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a TwoWayDisplayBaseMessenger /// public class TwoWayDisplayBaseMessenger : MessengerBase { private readonly TwoWayDisplayBase _display; public TwoWayDisplayBaseMessenger(string key, string messagePath, TwoWayDisplayBase display) : base(key, messagePath, display) { _display = display; } #region Overrides of MessengerBase /// /// SendFullStatus method /// public void SendFullStatus(string id = null) { var messageObj = new TwoWayDisplayBaseStateMessage { //PowerState = _display.PowerIsOnFeedback.BoolValue, CurrentInput = _display.CurrentInputFeedback.StringValue }; PostStatusMessage(messageObj, id); } protected override void RegisterActions() { base.RegisterActions(); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/displayStatus", (id, content) => SendFullStatus(id)); _display.CurrentInputFeedback.OutputChange += CurrentInputFeedbackOnOutputChange; _display.IsCoolingDownFeedback.OutputChange += IsCoolingFeedbackOnOutputChange; _display.IsWarmingUpFeedback.OutputChange += IsWarmingFeedbackOnOutputChange; } private void CurrentInputFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) { PostStatusMessage(JToken.FromObject(new { currentInput = feedbackEventArgs.StringValue }) ); } private void IsWarmingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) { PostStatusMessage(JToken.FromObject(new { isWarming = feedbackEventArgs.BoolValue }) ); } private void IsCoolingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) { PostStatusMessage(JToken.FromObject(new { isCooling = feedbackEventArgs.BoolValue }) ); } #endregion } /// /// Represents a TwoWayDisplayBaseStateMessage /// public class TwoWayDisplayBaseStateMessage : DeviceStateMessageBase { //[JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] //public bool? PowerState { get; set; } /// /// Gets or sets the CurrentInput /// [JsonProperty("currentInput", NullValueHandling = NullValueHandling.Ignore)] public string CurrentInput { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Provides a messaging bridge for a VideoCodecBase device /// public class VideoCodecBaseMessenger : MessengerBase { /// /// /// protected VideoCodecBase Codec { get; private set; } /// /// /// /// /// /// public VideoCodecBaseMessenger(string key, VideoCodecBase codec, string messagePath) : base(key, messagePath, codec) { Codec = codec ?? throw new ArgumentNullException("codec"); codec.CallStatusChange += Codec_CallStatusChange; codec.IsReadyChange += Codec_IsReadyChange; if (codec is IHasDirectory dirCodec) { dirCodec.DirectoryResultReturned += DirCodec_DirectoryResultReturned; } if (codec is IHasCallHistory recCodec) { recCodec.CallHistory.RecentCallsListHasChanged += CallHistory_RecentCallsListHasChanged; } if (codec is IPasswordPrompt pwPromptCodec) { pwPromptCodec.PasswordRequired += OnPasswordRequired; } } private void OnPasswordRequired(object sender, PasswordPromptEventArgs args) { var eventMsg = new PasswordPromptEventMessage { Message = args.Message, LastAttemptWasIncorrect = args.LastAttemptWasIncorrect, LoginAttemptFailed = args.LoginAttemptFailed, LoginAttemptCancelled = args.LoginAttemptCancelled, EventType = "passwordPrompt" }; PostEventMessage(eventMsg); } /// /// /// /// /// private void CallHistory_RecentCallsListHasChanged(object sender, EventArgs e) { try { var state = new VideoCodecBaseStateMessage(); if (!(sender is CodecCallHistory codecCallHistory)) return; var recents = codecCallHistory.RecentCalls; if (recents != null) { state.RecentCalls = recents; PostStatusMessage(state); } } catch (Exception ex) { this.LogError(ex, "Error posting call history"); } } /// /// /// /// /// protected virtual void DirCodec_DirectoryResultReturned(object sender, DirectoryEventArgs e) { if (Codec is IHasDirectory) SendDirectory(e.Directory); } /// /// Posts the current directory /// protected void SendDirectory(CodecDirectory directory) { try { var state = new VideoCodecBaseStateMessage(); if (Codec is IHasDirectory dirCodec) { this.LogVerbose("Sending Directory. Directory Item Count: {directoryItemCount}", directory.CurrentDirectoryResults.Count); //state.CurrentDirectory = PrefixDirectoryFolderItems(directory); state.CurrentDirectory = directory; CrestronInvoke.BeginInvoke((o) => PostStatusMessage(state)); } } catch (Exception ex) { this.LogError(ex, "Error sending directory"); } } /// /// /// /// /// private void Codec_IsReadyChange(object sender, EventArgs e) { try { var state = new VideoCodecBaseStateMessage { IsReady = true }; PostStatusMessage(state); SendFullStatus(); } catch (Exception ex) { this.LogError(ex, "Error sending codec ready status"); } } /// /// Called from base's RegisterWithAppServer method /// /// protected override void RegisterActions() { try { base.RegisterActions(); AddAction("/isReady", (id, content) => SendIsReady()); AddAction("/fullStatus", (id, content) => SendFullStatus(id)); AddAction("/codecStatus", (id, content) => SendFullStatus(id)); AddAction("/dial", (id, content) => { var value = content.ToObject>(); Codec.Dial(value.Value); }); AddAction("/dialMeeting", (id, content) => Codec.Dial(content.ToObject())); AddAction("/endCallById", (id, content) => { var s = content.ToObject>(); var call = GetCallWithId(s.Value); if (call != null) Codec.EndCall(call); }); AddAction("/endAllCalls", (id, content) => Codec.EndAllCalls()); AddAction("/dtmf", (id, content) => { var s = content.ToObject>(); Codec.SendDtmf(s.Value); }); AddAction("/rejectById", (id, content) => { var s = content.ToObject>(); var call = GetCallWithId(s.Value); if (call != null) Codec.RejectCall(call); }); AddAction("/acceptById", (id, content) => { var s = content.ToObject>(); var call = GetCallWithId(s.Value); if (call != null) Codec.AcceptCall(call); }); Codec.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange; Codec.SharingSourceFeedback.OutputChange += SharingSourceFeedback_OutputChange; // Directory actions if (Codec is IHasDirectory dirCodec) { AddAction("/getDirectory", (id, content) => GetDirectoryRoot()); AddAction("/directoryById", (id, content) => { var msg = content.ToObject>(); GetDirectory(msg.Value); }); AddAction("/directorySearch", (id, content) => { var msg = content.ToObject>(); GetDirectory(msg.Value); }); AddAction("/directoryBack", (id, content) => GetPreviousDirectory()); dirCodec.PhonebookSyncState.InitialSyncCompleted += PhonebookSyncState_InitialSyncCompleted; } // History actions if (Codec is IHasCallHistory recCodec) { AddAction("/getCallHistory", (id, content) => PostCallHistory()); } if (Codec is IHasCodecCameras cameraCodec) { this.LogVerbose("Adding IHasCodecCameras Actions"); cameraCodec.CameraSelected += CameraCodec_CameraSelected; AddAction("/cameraSelect", (id, content) => { var msg = content.ToObject>(); cameraCodec.SelectCamera(msg.Value); }); MapCameraActions(); if (Codec is IHasCodecRoomPresets presetsCodec) { this.LogVerbose("Adding IHasCodecRoomPresets Actions"); presetsCodec.CodecRoomPresetsListHasChanged += PresetsCodec_CameraPresetsListHasChanged; AddAction("/cameraPreset", (id, content) => { var msg = content.ToObject>(); presetsCodec.CodecRoomPresetSelect(msg.Value); }); AddAction("/cameraPresetStore", (id, content) => { var msg = content.ToObject(); presetsCodec.CodecRoomPresetStore(msg.ID, msg.Description); }); } if (Codec is IHasCameraAutoMode speakerTrackCodec) { this.LogVerbose("Adding IHasCameraAutoMode Actions"); speakerTrackCodec.CameraAutoModeIsOnFeedback.OutputChange += CameraAutoModeIsOnFeedback_OutputChange; AddAction("/cameraModeAuto", (id, content) => speakerTrackCodec.CameraAutoModeOn()); AddAction("/cameraModeManual", (id, content) => speakerTrackCodec.CameraAutoModeOff()); } if (Codec is IHasCameraOff cameraOffCodec) { this.LogVerbose("Adding IHasCameraOff Actions"); cameraOffCodec.CameraIsOffFeedback.OutputChange += (CameraIsOffFeedback_OutputChange); AddAction("/cameraModeOff", (id, content) => cameraOffCodec.CameraOff()); } } if (Codec is IHasCodecSelfView selfViewCodec) { this.LogVerbose("Adding IHasCodecSelfView Actions"); AddAction("/cameraSelfView", (id, content) => selfViewCodec.SelfViewModeToggle()); selfViewCodec.SelfviewIsOnFeedback.OutputChange += new EventHandler(SelfviewIsOnFeedback_OutputChange); } if (Codec is IHasCodecLayouts layoutsCodec) { this.LogVerbose("Adding IHasCodecLayouts Actions"); AddAction("/cameraRemoteView", (id, content) => layoutsCodec.LocalLayoutToggle()); AddAction("/cameraLayout", (id, content) => layoutsCodec.LocalLayoutToggle()); } if (Codec is IPasswordPrompt pwCodec) { this.LogVerbose("Adding IPasswordPrompt Actions"); AddAction("/password", (id, content) => { var msg = content.ToObject>(); pwCodec.SubmitPassword(msg.Value); }); } if (Codec is IHasFarEndContentStatus farEndContentStatus) { farEndContentStatus.ReceivingContent.OutputChange += (sender, args) => PostReceivingContent(args.BoolValue); } this.LogVerbose("Adding Privacy & Standby Actions"); AddAction("/privacyModeOn", (id, content) => Codec.PrivacyModeOn()); AddAction("/privacyModeOff", (id, content) => Codec.PrivacyModeOff()); AddAction("/privacyModeToggle", (id, content) => Codec.PrivacyModeToggle()); AddAction("/sharingStart", (id, content) => Codec.StartSharing()); AddAction("/sharingStop", (id, content) => Codec.StopSharing()); AddAction("/standbyOn", (id, content) => Codec.StandbyActivate()); AddAction("/standbyOff", (id, content) => Codec.StandbyDeactivate()); } catch (Exception e) { this.LogException(e, "Exception adding paths"); } } private void SharingSourceFeedback_OutputChange(object sender, FeedbackEventArgs e) { try { var state = new VideoCodecBaseStateMessage { SharingSource = e.StringValue }; PostStatusMessage(state); } catch (Exception ex) { this.LogError(ex, "Error posting sharing source"); } } private void SharingContentIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) { try { var state = new VideoCodecBaseStateMessage { SharingContentIsOn = e.BoolValue }; PostStatusMessage(state); } catch (Exception ex) { this.LogError(ex, "Error posting sharing content"); } } private void PhonebookSyncState_InitialSyncCompleted(object sender, EventArgs e) { try { var state = new VideoCodecBaseStateMessage { InitialPhonebookSyncComplete = true }; PostStatusMessage(state); } catch (Exception ex) { this.LogError(ex, "Error posting phonebook sync state"); } } private void CameraIsOffFeedback_OutputChange(object sender, FeedbackEventArgs e) { PostCameraMode(); } private void SelfviewIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) { PostCameraSelfView(); } private void PresetsCodec_CameraPresetsListHasChanged(object sender, EventArgs e) { PostCameraPresets(); } private void CameraAutoModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) { PostCameraMode(); } private void CameraCodec_CameraSelected(object sender, CameraSelectedEventArgs e) { try { MapCameraActions(); PostSelectedCamera(); } catch (Exception ex) { this.LogError(ex, "Exception handling camera selected event"); } } /// /// Maps the camera control actions to the current selected camera on the codec /// private void MapCameraActions() { if (Codec is IHasCameras cameraCodec && cameraCodec.SelectedCamera != null) { RemoveAction("/cameraUp"); RemoveAction("/cameraDown"); RemoveAction("/cameraLeft"); RemoveAction("/cameraRight"); RemoveAction("/cameraZoomIn"); RemoveAction("/cameraZoomOut"); RemoveAction("/cameraHome"); if (cameraCodec.SelectedCamera is IHasCameraPtzControl camera) { AddAction("/cameraUp", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { camera.TiltUp(); return; } camera.TiltStop(); })); AddAction("/cameraDown", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { camera.TiltDown(); return; } camera.TiltStop(); })); AddAction("/cameraLeft", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { camera.PanLeft(); return; } camera.PanStop(); })); AddAction("/cameraRight", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { camera.PanRight(); return; } camera.PanStop(); })); AddAction("/cameraZoomIn", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { camera.ZoomIn(); return; } camera.ZoomStop(); })); AddAction("/cameraZoomOut", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { camera.ZoomOut(); return; } camera.ZoomStop(); })); AddAction("/cameraHome", (id, content) => camera.PositionHome()); RemoveAction("/cameraAutoFocus"); RemoveAction("/cameraFocusNear"); RemoveAction("/cameraFocusFar"); if (cameraCodec is IHasCameraFocusControl focusCamera) { AddAction("/cameraAutoFocus", (id, content) => focusCamera.TriggerAutoFocus()); AddAction("/cameraFocusNear", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { focusCamera.FocusNear(); return; } focusCamera.FocusStop(); })); AddAction("/cameraFocusFar", (id, content) => HandleCameraPressAndHold(content, (b) => { if (b) { focusCamera.FocusFar(); return; } focusCamera.FocusStop(); })); } } } } private void HandleCameraPressAndHold(JToken content, Action cameraAction) { var state = content.ToObject>(); var timerHandler = PressAndHoldHandler.GetPressAndHoldHandler(state.Value); if (timerHandler == null) { return; } timerHandler(state.Value, cameraAction); cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)); } private string GetCameraMode() { string m = ""; if (Codec is IHasCameraAutoMode speakerTrackCodec) { m = speakerTrackCodec.CameraAutoModeIsOnFeedback.BoolValue ? eCameraControlMode.Auto.ToString().ToLower() : eCameraControlMode.Manual.ToString().ToLower(); } if (Codec is IHasCameraOff cameraOffCodec) { if (cameraOffCodec.CameraIsOffFeedback.BoolValue) m = eCameraControlMode.Off.ToString().ToLower(); } return m; } private void PostCallHistory() { try { var codec = (Codec as IHasCallHistory); if (codec != null) { var status = new VideoCodecBaseStateMessage(); var recents = codec.CallHistory.RecentCalls; if (recents != null) { status.RecentCalls = codec.CallHistory.RecentCalls; PostStatusMessage(status); } } } catch (Exception ex) { this.LogError(ex, "Error posting call history"); } } /// /// Helper to grab a call with string ID /// /// /// private CodecActiveCallItem GetCallWithId(string id) { return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id); } /// /// /// /// private void GetDirectory(string id) { if (!(Codec is IHasDirectory dirCodec)) { return; } dirCodec.GetDirectoryFolderContents(id); } /// /// /// private void GetDirectoryRoot() { try { if (!(Codec is IHasDirectory dirCodec)) { // do something else? return; } if (!dirCodec.PhonebookSyncState.InitialSyncComplete) { var state = new VideoCodecBaseStateMessage { InitialPhonebookSyncComplete = false }; PostStatusMessage(state); return; } dirCodec.SetCurrentDirectoryToRoot(); } catch (Exception ex) { this.LogError(ex, "Error getting directory root"); } } /// /// Requests the parent folder contents /// private void GetPreviousDirectory() { if (!(Codec is IHasDirectory dirCodec)) { return; } dirCodec.GetDirectoryParentFolderContents(); } /// /// Handler for codec changes /// private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) { SendFullStatus(); } /// /// /// private void SendIsReady() { try { var status = new VideoCodecBaseStateMessage(); var codecType = Codec.GetType(); status.IsReady = Codec.IsReady; status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null; PostStatusMessage(status); } catch (Exception ex) { this.LogError(ex, "Error sending codec ready status"); } } /// /// Helper method to build call status for vtc /// /// protected VideoCodecBaseStateMessage GetStatus() { try { var status = new VideoCodecBaseStateMessage(); if (Codec is IHasCodecCameras camerasCodec) { status.Cameras = new CameraStatus { CameraManualIsSupported = true, CameraAutoIsSupported = Codec.SupportsCameraAutoMode, CameraOffIsSupported = Codec.SupportsCameraOff, CameraMode = GetCameraMode(), Cameras = camerasCodec.Cameras, SelectedCamera = GetSelectedCamera(camerasCodec) }; } if (Codec is IHasDirectory directoryCodec) { status.HasDirectory = true; status.HasDirectorySearch = true; status.CurrentDirectory = directoryCodec.CurrentDirectoryResult; } var codecType = Codec.GetType(); status.CameraSelfViewIsOn = Codec is IHasCodecSelfView && (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue; status.IsInCall = Codec.IsInCall; status.PrivacyModeIsOn = Codec.PrivacyModeIsOnFeedback.BoolValue; status.SharingContentIsOn = Codec.SharingContentIsOnFeedback.BoolValue; status.SharingSource = Codec.SharingSourceFeedback.StringValue; status.StandbyIsOn = Codec.StandbyIsOnFeedback.BoolValue; status.Calls = Codec.ActiveCalls; status.Info = Codec.CodecInfo; status.ShowSelfViewByDefault = Codec.ShowSelfViewByDefault; status.SupportsAdHocMeeting = Codec is IHasStartMeeting; status.HasRecents = Codec is IHasCallHistory; status.HasCameras = Codec is IHasCameras; status.Presets = GetCurrentPresets(); status.IsZoomRoom = codecType.GetInterface("IHasZoomRoomLayouts") != null; status.ReceivingContent = Codec is IHasFarEndContentStatus && (Codec as IHasFarEndContentStatus).ReceivingContent.BoolValue; if (Codec is IHasMeetingInfo meetingInfoCodec) { status.MeetingInfo = meetingInfoCodec.MeetingInfo; } return status; } catch (Exception ex) { this.LogError(ex, "Error getting codec status"); return null; } } protected virtual void SendFullStatus(string id = null) { if (!Codec.IsReady) { return; } Task.Run(() => PostStatusMessage(GetStatus(), id)); } private void PostReceivingContent(bool receivingContent) { try { var state = new VideoCodecBaseStateMessage { ReceivingContent = receivingContent }; PostStatusMessage(state); } catch (Exception ex) { this.LogError(ex, "Error posting receiving content"); } } private void PostCameraSelfView() { try { var status = new VideoCodecBaseStateMessage { CameraSelfViewIsOn = Codec is IHasCodecSelfView && (Codec as IHasCodecSelfView).SelfviewIsOnFeedback.BoolValue }; PostStatusMessage(status); } catch (Exception ex) { this.LogError(ex, "Error posting camera self view"); } } /// /// /// private void PostCameraMode() { try { var status = new VideoCodecBaseStateMessage { CameraMode = GetCameraMode() }; PostStatusMessage(status); } catch (Exception ex) { this.LogError(ex, "Error posting camera mode"); } } private void PostSelectedCamera() { try { var camerasCodec = Codec as IHasCodecCameras; var status = new VideoCodecBaseStateMessage { Cameras = new CameraStatus() { SelectedCamera = GetSelectedCamera(camerasCodec) }, Presets = GetCurrentPresets() }; PostStatusMessage(status); } catch (Exception e) { this.LogError(e, "Error posting selected camera"); } } private void PostCameraPresets() { try { var status = new VideoCodecBaseStateMessage { Presets = GetCurrentPresets() }; PostStatusMessage(status); } catch (Exception e) { this.LogError(e, "Error posting camera presets"); } } private Camera GetSelectedCamera(IHasCodecCameras camerasCodec) { var camera = new Camera(); if (camerasCodec.SelectedCameraFeedback != null) camera.Key = camerasCodec.SelectedCameraFeedback.StringValue; if (camerasCodec.SelectedCamera != null) { camera.Name = camerasCodec.SelectedCamera.Name; camera.Capabilities = new CameraCapabilities() { CanPan = camerasCodec.SelectedCamera.CanPan, CanTilt = camerasCodec.SelectedCamera.CanTilt, CanZoom = camerasCodec.SelectedCamera.CanZoom, CanFocus = camerasCodec.SelectedCamera.CanFocus, }; } if (camerasCodec.ControllingFarEndCameraFeedback != null) camera.IsFarEnd = camerasCodec.ControllingFarEndCameraFeedback.BoolValue; return camera; } private List GetCurrentPresets() { var presetsCodec = Codec as IHasCodecRoomPresets; List currentPresets = null; if (presetsCodec != null && Codec is IHasFarEndCameraControl && (Codec as IHasFarEndCameraControl).ControllingFarEndCameraFeedback.BoolValue) currentPresets = presetsCodec.FarEndRoomPresets; else if (presetsCodec != null) currentPresets = presetsCodec.NearEndPresets; return currentPresets; } } /// /// Represents a VideoCodecBaseStateMessage /// public class VideoCodecBaseStateMessage : DeviceStateMessageBase { [JsonProperty("calls", NullValueHandling = NullValueHandling.Ignore)] public List Calls { get; set; } [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] public string CameraMode { get; set; } [JsonProperty("cameraSelfView", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraSelfViewIsOn { get; set; } [JsonProperty("cameras", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Cameras /// public CameraStatus Cameras { get; set; } [JsonProperty("cameraSupportsAutoMode", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraSupportsAutoMode { get; set; } [JsonProperty("cameraSupportsOffMode", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraSupportsOffMode { get; set; } /// /// Gets or sets the CurrentDialString /// [JsonProperty("currentDialString", NullValueHandling = NullValueHandling.Ignore)] public string CurrentDialString { get; set; } /// /// Gets or sets the CurrentDirectory /// [JsonProperty("currentDirectory", NullValueHandling = NullValueHandling.Ignore)] public CodecDirectory CurrentDirectory { get; set; } /// /// Gets or sets the DirectorySelectedFolderName /// [JsonProperty("directorySelectedFolderName", NullValueHandling = NullValueHandling.Ignore)] public string DirectorySelectedFolderName { get; set; } [JsonProperty("hasCameras", NullValueHandling = NullValueHandling.Ignore)] public bool? HasCameras { get; set; } [JsonProperty("hasDirectory", NullValueHandling = NullValueHandling.Ignore)] public bool? HasDirectory { get; set; } [JsonProperty("hasDirectorySearch", NullValueHandling = NullValueHandling.Ignore)] public bool? HasDirectorySearch { get; set; } [JsonProperty("hasPresets", NullValueHandling = NullValueHandling.Ignore)] public bool? HasPresets { get; set; } [JsonProperty("hasRecents", NullValueHandling = NullValueHandling.Ignore)] public bool? HasRecents { get; set; } [JsonProperty("initialPhonebookSyncComplete", NullValueHandling = NullValueHandling.Ignore)] public bool? InitialPhonebookSyncComplete { get; set; } /// /// Gets or sets the Info /// [JsonProperty("info", NullValueHandling = NullValueHandling.Ignore)] public VideoCodecInfo Info { get; set; } [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] public bool? IsInCall { get; set; } [JsonProperty("isReady", NullValueHandling = NullValueHandling.Ignore)] public bool? IsReady { get; set; } [JsonProperty("isZoomRoom", NullValueHandling = NullValueHandling.Ignore)] public bool? IsZoomRoom { get; set; } /// /// Gets or sets the MeetingInfo /// [JsonProperty("meetingInfo", NullValueHandling = NullValueHandling.Ignore)] public MeetingInfo MeetingInfo { get; set; } /// /// Gets or sets the Presets /// [JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)] public List Presets { get; set; } [JsonProperty("privacyModeIsOn", NullValueHandling = NullValueHandling.Ignore)] public bool? PrivacyModeIsOn { get; set; } [JsonProperty("receivingContent", NullValueHandling = NullValueHandling.Ignore)] public bool? ReceivingContent { get; set; } [JsonProperty("recentCalls", NullValueHandling = NullValueHandling.Ignore)] public List RecentCalls { get; set; } [JsonProperty("sharingContentIsOn", NullValueHandling = NullValueHandling.Ignore)] public bool? SharingContentIsOn { get; set; } /// /// Gets or sets the SharingSource /// [JsonProperty("sharingSource", NullValueHandling = NullValueHandling.Ignore)] public string SharingSource { get; set; } [JsonProperty("showCamerasWhenNotInCall", NullValueHandling = NullValueHandling.Ignore)] public bool? ShowCamerasWhenNotInCall { get; set; } [JsonProperty("showSelfViewByDefault", NullValueHandling = NullValueHandling.Ignore)] public bool? ShowSelfViewByDefault { get; set; } [JsonProperty("standbyIsOn", NullValueHandling = NullValueHandling.Ignore)] public bool? StandbyIsOn { get; set; } [JsonProperty("supportsAdHocMeeting", NullValueHandling = NullValueHandling.Ignore)] public bool? SupportsAdHocMeeting { get; set; } } /// /// Represents a CameraStatus /// public class CameraStatus { [JsonProperty("cameraManualSupported", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraManualIsSupported { get; set; } [JsonProperty("cameraAutoSupported", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraAutoIsSupported { get; set; } [JsonProperty("cameraOffSupported", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraOffIsSupported { get; set; } /// /// Gets or sets the CameraMode /// [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] public string CameraMode { get; set; } /// /// Gets or sets the Cameras /// [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] public List Cameras { get; set; } /// /// Gets or sets the SelectedCamera /// [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] public Camera SelectedCamera { get; set; } } /// /// Represents a Camera /// public class Camera { /// /// Gets or sets the Key /// [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key { get; set; } /// /// Gets or sets the Name /// [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } [JsonProperty("isFarEnd", NullValueHandling = NullValueHandling.Ignore)] public bool? IsFarEnd { get; set; } /// /// Gets or sets the Capabilities /// [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] public CameraCapabilities Capabilities { get; set; } } /// /// Represents a CameraCapabilities /// public class CameraCapabilities { [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] public bool? CanPan { get; set; } [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] public bool? CanTilt { get; set; } [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] public bool? CanZoom { get; set; } [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] public bool? CanFocus { get; set; } } /// /// Represents a VideoCodecBaseEventMessage /// public class VideoCodecBaseEventMessage : DeviceEventMessageBase { } /// /// Represents a PasswordPromptEventMessage /// public class PasswordPromptEventMessage : VideoCodecBaseEventMessage { /// /// Gets or sets the Message /// [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)] public string Message { get; set; } /// /// Gets or sets the LastAttemptWasIncorrect /// [JsonProperty("lastAttemptWasIncorrect", NullValueHandling = NullValueHandling.Ignore)] public bool LastAttemptWasIncorrect { get; set; } /// /// Gets or sets the LoginAttemptFailed /// [JsonProperty("loginAttemptFailed", NullValueHandling = NullValueHandling.Ignore)] public bool LoginAttemptFailed { get; set; } /// /// Gets or sets the LoginAttemptCancelled /// [JsonProperty("loginAttemptCancelled", NullValueHandling = NullValueHandling.Ignore)] public bool LoginAttemptCancelled { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/MobileControlMessage.cs ================================================ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Represents a MobileControlMessage /// public class MobileControlMessage : IMobileControlMessage { [JsonProperty("type")] /// /// Gets or sets the Type /// public string Type { get; set; } [JsonProperty("clientId")] /// /// Gets or sets the ClientId /// public string ClientId { get; set; } [JsonProperty("content")] /// /// Gets or sets the Content /// public JToken Content { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/MobileControlSimpleContent.cs ================================================ using Newtonsoft.Json; namespace PepperDash.Essentials.AppServer { /// /// Represents a MobileControlSimpleContent /// public class MobileControlSimpleContent { [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Value /// public T Value { get; set; } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj ================================================  PepperDash.Essentials.AppServer net472 mobile-control-messengers mobile-control-messengers mobile-control-messengers Copyright © 2024 bin\$(Configuration)\ true true $(Version) false PepperDash Technology PepperDash.Essentials.MobileControl.Messengers crestron 4series full $(DefineConstants);SERIES4 pdbonly $(DefineConstants);SERIES4 bin\$(Configuration)\mobile-control-messengers.xml false runtime false runtime ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRoomJoinMap.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer { // ReSharper disable once InconsistentNaming /// /// Represents a MobileControlSIMPLRoomJoinMap /// public class MobileControlSIMPLRoomJoinMap : JoinMapBaseAdvanced { [JoinName("QrCodeUrl")] public JoinDataComplete QrCodeUrl = new JoinDataComplete(new JoinData { JoinNumber = 403, JoinSpan = 1 }, new JoinMetadata { Description = "QR Code URL", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("PortalSystemUrl")] public JoinDataComplete PortalSystemUrl = new JoinDataComplete(new JoinData { JoinNumber = 404, JoinSpan = 1 }, new JoinMetadata { Description = "Portal System URL", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("MasterVolume")] public JoinDataComplete MasterVolume = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Master Volume Mute Toggle/FB/Level/Label", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalAnalogSerial }); [JoinName("VolumeJoinStart")] public JoinDataComplete VolumeJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 8 }, new JoinMetadata { Description = "Volume Mute Toggle/FB/Level/Label", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalAnalogSerial }); [JoinName("PrivacyMute")] public JoinDataComplete PrivacyMute = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata { Description = "Privacy Mute Toggle/FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("PromptForCode")] public JoinDataComplete PromptForCode = new JoinDataComplete(new JoinData { JoinNumber = 41, JoinSpan = 1 }, new JoinMetadata { Description = "Prompt User for Code", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("ClientJoined")] public JoinDataComplete ClientJoined = new JoinDataComplete(new JoinData { JoinNumber = 42, JoinSpan = 1 }, new JoinMetadata { Description = "Client Joined", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("ActivityPhoneCallEnable")] public JoinDataComplete ActivityPhoneCallEnable = new JoinDataComplete(new JoinData { JoinNumber = 48, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Activity Phone Call", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ActivityVideoCallEnable")] public JoinDataComplete ActivityVideoCallEnable = new JoinDataComplete(new JoinData { JoinNumber = 49, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Activity Video Call", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ActivityShare")] public JoinDataComplete ActivityShare = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata { Description = "Activity Share", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ActivityPhoneCall")] public JoinDataComplete ActivityPhoneCall = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata { Description = "Activity Phone Call", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ActivityVideoCall")] public JoinDataComplete ActivityVideoCall = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1 }, new JoinMetadata { Description = "Activity Video Call", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ShutdownPromptDuration")] public JoinDataComplete ShutdownPromptDuration = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "Shutdown Cancel", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); [JoinName("ShutdownCancel")] public JoinDataComplete ShutdownCancel = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "Shutdown Cancel", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ShutdownEnd")] public JoinDataComplete ShutdownEnd = new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 1 }, new JoinMetadata { Description = "Shutdown End", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ShutdownStart")] public JoinDataComplete ShutdownStart = new JoinDataComplete(new JoinData { JoinNumber = 63, JoinSpan = 1 }, new JoinMetadata { Description = "Shutdown Start", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("SourceHasChanged")] public JoinDataComplete SourceHasChanged = new JoinDataComplete(new JoinData { JoinNumber = 71, JoinSpan = 1 }, new JoinMetadata { Description = "Source Changed", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("CurrentSourceKey")] public JoinDataComplete CurrentSourceKey = new JoinDataComplete(new JoinData { JoinNumber = 71, JoinSpan = 1 }, new JoinMetadata { Description = "Key of selected source", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); [JoinName("ConfigIsLocal")] public JoinDataComplete ConfigIsLocal = new JoinDataComplete(new JoinData { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata { Description = "Config is local to Essentials", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("NumberOfAuxFaders")] public JoinDataComplete NumberOfAuxFaders = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata { Description = "Number of Auxilliary Faders", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); [JoinName("SpeedDialNameStartJoin")] public JoinDataComplete SpeedDialNameStartJoin = new JoinDataComplete(new JoinData { JoinNumber = 241, JoinSpan = 10 }, new JoinMetadata { Description = "Speed Dial names", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SpeedDialNumberStartJoin")] public JoinDataComplete SpeedDialNumberStartJoin = new JoinDataComplete(new JoinData { JoinNumber = 251, JoinSpan = 10 }, new JoinMetadata { Description = "Speed Dial numbers", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SpeedDialVisibleStartJoin")] public JoinDataComplete SpeedDialVisibleStartJoin = new JoinDataComplete(new JoinData { JoinNumber = 261, JoinSpan = 10 }, new JoinMetadata { Description = "Speed Dial Visible", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("RoomIsOn")] public JoinDataComplete RoomIsOn = new JoinDataComplete(new JoinData { JoinNumber = 301, JoinSpan = 1 }, new JoinMetadata { Description = "Room Is On", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("UserCodeToSystem")] public JoinDataComplete UserCodeToSystem = new JoinDataComplete(new JoinData { JoinNumber = 401, JoinSpan = 1 }, new JoinMetadata { Description = "User Code", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("ServerUrl")] public JoinDataComplete ServerUrl = new JoinDataComplete(new JoinData { JoinNumber = 402, JoinSpan = 1 }, new JoinMetadata { Description = "Server URL", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("ConfigRoomName")] public JoinDataComplete ConfigRoomName = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, new JoinMetadata { Description = "Room Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("ConfigHelpMessage")] public JoinDataComplete ConfigHelpMessage = new JoinDataComplete(new JoinData { JoinNumber = 502, JoinSpan = 1 }, new JoinMetadata { Description = "Room help message", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("ConfigHelpNumber")] public JoinDataComplete ConfigHelpNumber = new JoinDataComplete(new JoinData { JoinNumber = 503, JoinSpan = 1 }, new JoinMetadata { Description = "Room help number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("ConfigRoomPhoneNumber")] public JoinDataComplete ConfigRoomPhoneNumber = new JoinDataComplete(new JoinData { JoinNumber = 504, JoinSpan = 1 }, new JoinMetadata { Description = "Room phone number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("ConfigRoomURI")] public JoinDataComplete ConfigRoomUri = new JoinDataComplete(new JoinData { JoinNumber = 505, JoinSpan = 1 }, new JoinMetadata { Description = "Room URI", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("ApiOnlineAndAuthorized")] public JoinDataComplete ApiOnlineAndAuthorized = new JoinDataComplete(new JoinData { JoinNumber = 500, JoinSpan = 1 }, new JoinMetadata { Description = "Config info from SIMPL is ready", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("ConfigIsReady")] public JoinDataComplete ConfigIsReady = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, new JoinMetadata { Description = "Config info from SIMPL is ready", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ReadyForConfig")] public JoinDataComplete ReadyForConfig = new JoinDataComplete(new JoinData { JoinNumber = 501, JoinSpan = 1 }, new JoinMetadata { Description = "Config info from SIMPL is ready", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("HideVideoConfRecents")] public JoinDataComplete HideVideoConfRecents = new JoinDataComplete(new JoinData { JoinNumber = 502, JoinSpan = 1 }, new JoinMetadata { Description = "Hide Video Conference Recents", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("ShowCameraWhenNotInCall")] public JoinDataComplete ShowCameraWhenNotInCall = new JoinDataComplete(new JoinData { JoinNumber = 503, JoinSpan = 1 }, new JoinMetadata { Description = "Show camera when not in call", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("UseSourceEnabled")] public JoinDataComplete UseSourceEnabled = new JoinDataComplete(new JoinData { JoinNumber = 504, JoinSpan = 1 }, new JoinMetadata { Description = "Use Source Enabled Joins", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("SourceShareDisableJoinStart")] public JoinDataComplete SourceShareDisableJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 601, JoinSpan = 20 }, new JoinMetadata { Description = "Source is not sharable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("SourceIsEnabledJoinStart")] public JoinDataComplete SourceIsEnabledJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 621, JoinSpan = 20 }, new JoinMetadata { Description = "Source is enabled/visible", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("SourceIsControllableJoinStart")] public JoinDataComplete SourceIsControllableJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 641, JoinSpan = 20 }, new JoinMetadata { Description = "Source is controllable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("SourceIsAudioSourceJoinStart")] public JoinDataComplete SourceIsAudioSourceJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 661, JoinSpan = 20 }, new JoinMetadata { Description = "Source is Audio Source", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("SourceNameJoinStart")] public JoinDataComplete SourceNameJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 601, JoinSpan = 20 }, new JoinMetadata { Description = "Source Names", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SourceIconJoinStart")] public JoinDataComplete SourceIconJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 621, JoinSpan = 20 }, new JoinMetadata { Description = "Source Icons", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SourceKeyJoinStart")] public JoinDataComplete SourceKeyJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 641, JoinSpan = 20 }, new JoinMetadata { Description = "Source Keys", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SourceControlDeviceKeyJoinStart")] public JoinDataComplete SourceControlDeviceKeyJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 701, JoinSpan = 20 }, new JoinMetadata { Description = "Source Control Device Keys", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SourceTypeJoinStart")] public JoinDataComplete SourceTypeJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 661, JoinSpan = 20 }, new JoinMetadata { Description = "Source Types", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("CameraNearNameStart")] public JoinDataComplete CameraNearNameStart = new JoinDataComplete(new JoinData { JoinNumber = 761, JoinSpan = 10 }, new JoinMetadata { Description = "Near End Camera Names", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("CameraFarName")] public JoinDataComplete CameraFarName = new JoinDataComplete(new JoinData { JoinNumber = 771, JoinSpan = 1 }, new JoinMetadata { Description = "Far End Camera Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); #region Advanced Sharing [JoinName("SupportsAdvancedSharing")] public JoinDataComplete SupportsAdvancedSharing = new JoinDataComplete(new JoinData { JoinNumber = 505, JoinSpan = 1 }, new JoinMetadata { Description = "Supports Advanced Sharing", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("UseDestinationEnable")] public JoinDataComplete UseDestinationEnable = new JoinDataComplete(new JoinData { JoinNumber = 506, JoinSpan = 1 }, new JoinMetadata { Description = "Use Destination Enable", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("UserCanChangeShareMode")] public JoinDataComplete UserCanChangeShareMode = new JoinDataComplete(new JoinData { JoinNumber = 507, JoinSpan = 1 }, new JoinMetadata { Description = "Share Mode Toggle Visible to User", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("DestinationNameJoinStart")] public JoinDataComplete DestinationNameJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 801, JoinSpan = 10 }, new JoinMetadata { Description = "Destination Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("DestinationDeviceKeyJoinStart")] public JoinDataComplete DestinationDeviceKeyJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 811, JoinSpan = 10 }, new JoinMetadata { Description = "Destination Device Key", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("DestinationTypeJoinStart")] public JoinDataComplete DestinationTypeJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 821, JoinSpan = 10 }, new JoinMetadata { Description = "Destination type. Should be Audio, Video, AudioVideo", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("DestinationIsEnabledJoinStart")] public JoinDataComplete DestinationIsEnabledJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 801, JoinSpan = 10 }, new JoinMetadata { Description = "Show Destination on UI", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); #endregion public MobileControlSIMPLRoomJoinMap(uint joinStart) : base(joinStart, typeof(MobileControlSIMPLRoomJoinMap)) { } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/MobileControlSIMPLRunDirectRouteActionJoinMap.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer { /// /// Represents a MobileControlSIMPLRunDirectRouteActionJoinMap /// public class MobileControlSIMPLRunDirectRouteActionJoinMap : JoinMapBaseAdvanced { [JoinName("AdvancedSharingModeFb")] public JoinDataComplete AdvancedSharingModeFb = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Use Advanced Sharing Mode", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("AdvancedSharingModeOn")] public JoinDataComplete AdvancedSharingModeOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata { Description = "Use Advanced Sharing Mode", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("AdvancedSharingModeOff")] public JoinDataComplete AdvancedSharingModeOff = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata { Description = "Use Advanced Sharing Mode", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("AdvancedSharingModeToggle")] public JoinDataComplete AdvancedSharingModeToggle = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata { Description = "Use Advanced Sharing Mode", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("SourceForDestinationJoinStart")] public JoinDataComplete SourceForDestinationJoinStart = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 10 }, new JoinMetadata { Description = "Source to Route to Destination & FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); [JoinName("SourceForDestinationAudio")] public JoinDataComplete SourceForDestinationAudio = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1 }, new JoinMetadata { Description = "Source to Route to Destination & FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); public MobileControlSIMPLRunDirectRouteActionJoinMap(uint joinStart) : base(joinStart, typeof(MobileControlSIMPLRunDirectRouteActionJoinMap)) { } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLAtcJoinMap.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer { /// /// Represents a SIMPLAtcJoinMap /// public class SIMPLAtcJoinMap : JoinMapBaseAdvanced { [JoinName("EndCall")] public JoinDataComplete EndCall = new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata() { Description = "Hang Up", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("IncomingAnswer")] public JoinDataComplete IncomingAnswer = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Description = "Answer Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("IncomingReject")] public JoinDataComplete IncomingReject = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Description = "Reject Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("SpeedDialStart")] public JoinDataComplete SpeedDialStart = new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, new JoinMetadata() { Description = "Speed Dial", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CurrentDialString")] public JoinDataComplete CurrentDialString = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Dial String", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); [JoinName("CurrentCallNumber")] public JoinDataComplete CurrentCallNumber = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("CurrentCallName")] public JoinDataComplete CurrentCallName = new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("HookState")] public JoinDataComplete HookState = new JoinDataComplete(new JoinData() { JoinNumber = 21, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Hook State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("CallDirection")] public JoinDataComplete CallDirection = new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Direction", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("IncomingCallName")] public JoinDataComplete IncomingCallName = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("IncomingCallNumber")] public JoinDataComplete IncomingCallNumber = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("0")] public JoinDataComplete Dtmf0 = new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 0", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("1")] public JoinDataComplete Dtmf1 = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("2")] public JoinDataComplete Dtmf2 = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("3")] public JoinDataComplete Dtmf3 = new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 3", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("4")] public JoinDataComplete Dtmf4 = new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 4", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("5")] public JoinDataComplete Dtmf5 = new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 5", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("6")] public JoinDataComplete Dtmf6 = new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 6", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("7")] public JoinDataComplete Dtmf7 = new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 7", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("8")] public JoinDataComplete Dtmf8 = new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 8", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("9")] public JoinDataComplete Dtmf9 = new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 9", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("*")] public JoinDataComplete DtmfStar = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF *", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("#")] public JoinDataComplete DtmfPound = new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF #", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); /// /// Constructor that passes the joinStart to the base class /// /// public SIMPLAtcJoinMap(uint joinStart) : base(joinStart, typeof(SIMPLAtcJoinMap)) { } } } ================================================ FILE: src/PepperDash.Essentials.MobileControl.Messengers/SIMPLJoinMaps/SIMPLVtcJoinMap.cs ================================================ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.AppServer { /// /// Represents a SIMPLVtcJoinMap /// public class SIMPLVtcJoinMap : JoinMapBaseAdvanced { [JoinName("EndCall")] public JoinDataComplete EndCall = new JoinDataComplete(new JoinData() { JoinNumber = 24, JoinSpan = 1 }, new JoinMetadata() { Description = "Hang Up", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("IncomingCall")] public JoinDataComplete IncomingCall = new JoinDataComplete(new JoinData() { JoinNumber = 50, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("IncomingAnswer")] public JoinDataComplete IncomingAnswer = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Description = "Answer Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("IncomingReject")] public JoinDataComplete IncomingReject = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Description = "Reject Incoming Call", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("SpeedDialStart")] public JoinDataComplete SpeedDialStart = new JoinDataComplete(new JoinData() { JoinNumber = 41, JoinSpan = 4 }, new JoinMetadata() { Description = "Speed Dial", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("DirectorySearchBusy")] public JoinDataComplete DirectorySearchBusy = new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Search Busy FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("DirectoryLineSelected")] public JoinDataComplete DirectoryLineSelected = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Line Selected FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("DirectoryEntryIsContact")] public JoinDataComplete DirectoryEntryIsContact = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Selected Entry Is Contact FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("DirectoryIsRoot")] public JoinDataComplete DirectoryIsRoot = new JoinDataComplete(new JoinData() { JoinNumber = 102, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory is on Root FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("DDirectoryHasChanged")] public JoinDataComplete DDirectoryHasChanged = new JoinDataComplete(new JoinData() { JoinNumber = 103, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory has changed FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("DirectoryRoot")] public JoinDataComplete DirectoryRoot = new JoinDataComplete(new JoinData() { JoinNumber = 104, JoinSpan = 1 }, new JoinMetadata() { Description = "Go to Directory Root", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("DirectoryFolderBack")] public JoinDataComplete DirectoryFolderBack = new JoinDataComplete(new JoinData() { JoinNumber = 105, JoinSpan = 1 }, new JoinMetadata() { Description = "Go back one directory level", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("DirectoryDialSelectedLine")] public JoinDataComplete DirectoryDialSelectedLine = new JoinDataComplete(new JoinData() { JoinNumber = 106, JoinSpan = 1 }, new JoinMetadata() { Description = "Dial selected directory line", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraTiltUp")] public JoinDataComplete CameraTiltUp = new JoinDataComplete(new JoinData() { JoinNumber = 111, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Tilt Up", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraTiltDown")] public JoinDataComplete CameraTiltDown = new JoinDataComplete(new JoinData() { JoinNumber = 112, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Tilt Down", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraPanLeft")] public JoinDataComplete CameraPanLeft = new JoinDataComplete(new JoinData() { JoinNumber = 113, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Pan Left", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraPanRight")] public JoinDataComplete CameraPanRight = new JoinDataComplete(new JoinData() { JoinNumber = 114, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Pan Right", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraZoomIn")] public JoinDataComplete CameraZoomIn = new JoinDataComplete(new JoinData() { JoinNumber = 115, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Zoom In", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraZoomOut")] public JoinDataComplete CameraZoomOut = new JoinDataComplete(new JoinData() { JoinNumber = 116, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Zoom Out", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraPresetStart")] public JoinDataComplete CameraPresetStart = new JoinDataComplete(new JoinData() { JoinNumber = 121, JoinSpan = 5 }, new JoinMetadata() { Description = "Camera Presets", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraModeAuto")] public JoinDataComplete CameraModeAuto = new JoinDataComplete(new JoinData() { JoinNumber = 131, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Mode Auto", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraModeManual")] public JoinDataComplete CameraModeManual = new JoinDataComplete(new JoinData() { JoinNumber = 132, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Mode Manual", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraModeOff")] public JoinDataComplete CameraModeOff = new JoinDataComplete(new JoinData() { JoinNumber = 133, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Mode Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraSelfView")] public JoinDataComplete CameraSelfView = new JoinDataComplete(new JoinData() { JoinNumber = 141, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Self View Toggle/FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraLayout")] public JoinDataComplete CameraLayout = new JoinDataComplete(new JoinData() { JoinNumber = 142, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Layout Toggle", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraSupportsAutoMode")] public JoinDataComplete CameraSupportsAutoMode = new JoinDataComplete(new JoinData() { JoinNumber = 143, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Supports Auto Mode FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraSupportsOffMode")] public JoinDataComplete CameraSupportsOffMode = new JoinDataComplete(new JoinData() { JoinNumber = 144, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Supports Off Mode FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital }); [JoinName("CameraNumberSelect")] public JoinDataComplete CameraNumberSelect = new JoinDataComplete(new JoinData() { JoinNumber = 60, JoinSpan = 1 }, new JoinMetadata() { Description = "Camera Number Select/FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); [JoinName("DirectorySelectRow")] public JoinDataComplete DirectorySelectRow = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Select Row", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog }); [JoinName("DirectoryRowCount")] public JoinDataComplete DirectoryRowCount = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Row Count FB", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); [JoinName("CurrentDialString")] public JoinDataComplete CurrentDialString = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Dial String", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Serial }); [JoinName("CurrentCallName")] public JoinDataComplete CurrentCallName = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("CurrentCallNumber")] public JoinDataComplete CurrentCallNumber = new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("HookState")] public JoinDataComplete HookState = new JoinDataComplete(new JoinData() { JoinNumber = 31, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Hook State", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("CallDirection")] public JoinDataComplete CallDirection = new JoinDataComplete(new JoinData() { JoinNumber = 22, JoinSpan = 1 }, new JoinMetadata() { Description = "Current Call Direction", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("IncomingCallName")] public JoinDataComplete IncomingCallName = new JoinDataComplete(new JoinData() { JoinNumber = 51, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("IncomingCallNumber")] public JoinDataComplete IncomingCallNumber = new JoinDataComplete(new JoinData() { JoinNumber = 52, JoinSpan = 1 }, new JoinMetadata() { Description = "Incoming Call Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("DirectorySearchString")] public JoinDataComplete DirectorySearchString = new JoinDataComplete(new JoinData() { JoinNumber = 100, JoinSpan = 1 }, new JoinMetadata() { Description = "Directory Search String", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); [JoinName("DirectoryEntriesStart")] public JoinDataComplete DirectoryEntriesStart = new JoinDataComplete(new JoinData() { JoinNumber = 101, JoinSpan = 255 }, new JoinMetadata() { Description = "Directory Entries", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("DirectoryEntrySelectedName")] public JoinDataComplete DirectoryEntrySelectedName = new JoinDataComplete(new JoinData() { JoinNumber = 356, JoinSpan = 1 }, new JoinMetadata() { Description = "Selected Directory Entry Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("DirectoryEntrySelectedNumber")] public JoinDataComplete DirectoryEntrySelectedNumber = new JoinDataComplete(new JoinData() { JoinNumber = 357, JoinSpan = 1 }, new JoinMetadata() { Description = "Selected Directory Entry Number", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("DirectorySelectedFolderName")] public JoinDataComplete DirectorySelectedFolderName = new JoinDataComplete(new JoinData() { JoinNumber = 358, JoinSpan = 1 }, new JoinMetadata() { Description = "Selected Directory Folder Name", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Serial }); [JoinName("1")] public JoinDataComplete Dtmf1 = new JoinDataComplete(new JoinData() { JoinNumber = 1, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 1", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("2")] public JoinDataComplete Dtmf2 = new JoinDataComplete(new JoinData() { JoinNumber = 2, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 2", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("3")] public JoinDataComplete Dtmf3 = new JoinDataComplete(new JoinData() { JoinNumber = 3, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 3", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("4")] public JoinDataComplete Dtmf4 = new JoinDataComplete(new JoinData() { JoinNumber = 4, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 4", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("5")] public JoinDataComplete Dtmf5 = new JoinDataComplete(new JoinData() { JoinNumber = 5, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 5", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("6")] public JoinDataComplete Dtmf6 = new JoinDataComplete(new JoinData() { JoinNumber = 6, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 6", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("7")] public JoinDataComplete Dtmf7 = new JoinDataComplete(new JoinData() { JoinNumber = 7, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 7", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("8")] public JoinDataComplete Dtmf8 = new JoinDataComplete(new JoinData() { JoinNumber = 8, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 8", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("9")] public JoinDataComplete Dtmf9 = new JoinDataComplete(new JoinData() { JoinNumber = 9, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 9", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("0")] public JoinDataComplete Dtmf0 = new JoinDataComplete(new JoinData() { JoinNumber = 10, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF 0", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("*")] public JoinDataComplete DtmfStar = new JoinDataComplete(new JoinData() { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF *", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); [JoinName("#")] public JoinDataComplete DtmfPound = new JoinDataComplete(new JoinData() { JoinNumber = 12, JoinSpan = 1 }, new JoinMetadata() { Description = "DTMF #", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); public SIMPLVtcJoinMap(uint joinStart) : base(joinStart, typeof(SIMPLVtcJoinMap)) { } } }